added first version of configuraiton api and simple function test.
[xmlrouter] / impl / src / test / java / org / wamblee / xmlrouter / impl / XMLRouterTest.java
1 /*
2  * Copyright 2005-2011 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.xmlrouter.impl;
17
18 import static org.mockito.Matchers.*;
19 import static org.mockito.Mockito.*;
20
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.concurrent.atomic.AtomicLong;
24 import java.util.logging.Level;
25
26 import javax.xml.transform.dom.DOMSource;
27
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.wamblee.general.SystemClock;
31 import org.wamblee.xmlrouter.common.Id;
32 import org.wamblee.xmlrouter.config.DocumentType;
33 import org.wamblee.xmlrouter.config.Filter;
34 import org.wamblee.xmlrouter.config.Transformation;
35 import org.wamblee.xmlrouter.listener.EventInfo;
36 import org.wamblee.xmlrouter.listener.EventListener;
37 import org.wamblee.xmlrouter.listener.LoggingEventListener;
38 import org.wamblee.xmlrouter.subscribe.Destination;
39
40 public class XMLRouterTest {
41
42     public static class MyDestination implements Destination {
43
44         private boolean receiveResult;
45         private Collection<String> types;
46
47         public MyDestination(boolean aReceiveResult, Collection<String> aTypes) {
48             receiveResult = aReceiveResult;
49             types = aTypes;
50         }
51
52         @Override
53         public Collection<String> chooseFromTargetTypes(
54             Collection<String> aPossibleTargetTypes) {
55             return types;
56         }
57
58         @Override
59         public String getName() {
60             return "xxx";
61         }
62
63         @Override
64         public boolean receive(DOMSource aEvent) {
65             return receiveResult;
66         }
67     }
68
69     private ExtendedRouterConfig routerConfig;
70     private XMLRouterConfiguration config;
71     private XMLRouter router;
72     private DOMSource source1;
73     private DOMSource source2;
74     private DOMSource source3;
75
76     private Destination destinationSpy;
77     private Id<Destination> destinationId;
78     private EventListener listener;
79
80     @Before
81     public void setUp() {
82         routerConfig = new SingleRouterConfig(new AtomicLong(1L));
83         config = new XMLRouterConfigurationImpl(routerConfig);
84         EventListener logListener = new LoggingEventListener(Level.INFO);
85         listener = spy(logListener);
86         router = new XMLRouter(new SystemClock(), config, listener);
87         source1 = mock(DOMSource.class);
88         source2 = mock(DOMSource.class);
89         source3 = mock(DOMSource.class);
90     }
91
92     @Test
93     public void testNoInputDocumentsRegistered() {
94         Destination destination = new MyDestination(true, Arrays.asList("any"));
95         destinationSpy = spy(destination);
96
97         destinationId = router.registerDestination(destinationSpy);
98         router.publish("any", source1);
99         verify(listener).notDelivered(any(EventInfo.class));
100     }
101
102     @Test
103     public void testMisBehavingDocumentType() {
104         DocumentType type = mock(DocumentType.class);
105         doThrow(new RuntimeException("x")).when(type).isInstance(
106             any(DOMSource.class));
107         routerConfig.documentTypeConfig().add(type);
108         router.publish("xx", mock(DOMSource.class));
109         verify(listener).notDelivered(any(EventInfo.class));
110         // no exception should occur.
111     }
112
113     @Test
114     public void testMisBehavingFilter() {
115         registerDocumentType("any");
116         Filter filter = mock(Filter.class);
117         doThrow(new RuntimeException("x")).when(filter).isAllowed(anyString(),
118             any(DOMSource.class));
119         routerConfig.filterConfig().add(filter);
120         router.publish("xx", mock(DOMSource.class));
121         verify(listener).notDelivered(any(EventInfo.class));
122         // no exception should occur.
123     }
124
125     @Test
126     public void testOneDestinationNoTransformationSuccess() {
127         destinationSpy = registerDestination(true, "any");
128         registerDocumentType("any");
129
130         router.publish("any", source1);
131         verify(listener).delivered(any(EventInfo.class),
132             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
133         verify(destinationSpy).receive(same(source1));
134
135         // Unregister the destination.
136         router.unregisterDestination(destinationId);
137         resetMocks();
138         router.publish("any", source2);
139         verify(listener).notDelivered(any(EventInfo.class));
140         verifyNoMoreInteractions(destinationSpy);
141     }
142
143     private void resetMocks() {
144         reset(destinationSpy);
145         reset(listener);
146     }
147
148     private void registerDocumentType(String aType) {
149         DocumentType type = mock(DocumentType.class);
150         when(type.isInstance(any(DOMSource.class))).thenReturn(true);
151         when(type.getName()).thenReturn(aType);
152         Id<DocumentType> typeId = routerConfig.documentTypeConfig().add(type);
153     }
154
155     private void registerDocumentType(String aType, DOMSource aSource) {
156         DocumentType type = mock(DocumentType.class);
157         when(type.isInstance(same(aSource))).thenReturn(true);
158         when(type.getName()).thenReturn(aType);
159         Id<DocumentType> typeId = routerConfig.documentTypeConfig().add(type);
160     }
161
162     private Destination registerDestination(boolean aResult, String... types) {
163         Destination destination = new MyDestination(aResult,
164             Arrays.asList(types));
165         Destination myspy = spy(destination);
166         destinationId = router.registerDestination(myspy);
167         return myspy;
168     }
169
170     @Test
171     public void testOneDestinationNotMatches() {
172         destinationSpy = registerDestination(true);
173         registerDocumentType("any");
174
175         router.publish("any", source1);
176         verify(listener).notDelivered(any(EventInfo.class));
177         verify(destinationSpy, never()).receive(any(DOMSource.class));
178     }
179
180     @Test
181     public void testOneDestinationThrowsException() {
182         destinationSpy = registerDestination(true, "any");
183         registerDocumentType("any");
184
185         doThrow(new RuntimeException()).when(destinationSpy).receive(
186             any(DOMSource.class));
187
188         router.publish("any", source1);
189         verify(listener).notDelivered(any(EventInfo.class));
190         verify(destinationSpy).receive(same(source1));
191     }
192
193     @Test
194     public void testOneDestinationThrowsExceptionSecondDestinationStillHandled() {
195         testOneDestinationThrowsException();
196         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
197         Destination destinationSpy2 = spy(destination2);
198         Id<Destination> destinationId2 = router
199             .registerDestination(destinationSpy2);
200
201         router.publish("any", source1);
202         verify(listener).delivered(any(EventInfo.class),
203             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
204
205         verify(destinationSpy2).receive(same(source1));
206
207     }
208
209     @Test
210     public void testDestinationChooseFromTargetTypesThrowsException() {
211         destinationSpy = registerDestination(true, "any");
212         registerDocumentType("any");
213
214         doThrow(new RuntimeException()).when(destinationSpy)
215             .chooseFromTargetTypes((Collection<String>) anyObject());
216
217         router.publish("any", source1);
218         verify(listener).notDelivered(any(EventInfo.class));
219         verify(destinationSpy, never()).receive(same(source1));
220     }
221
222     @Test
223     public void testDestinationChooseFromTargetTypesThrowsExceptionSecondDestinationStillOk() {
224         testDestinationChooseFromTargetTypesThrowsException();
225
226         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
227         Destination destinationSpy2 = spy(destination2);
228         Id<Destination> destinationId2 = router
229             .registerDestination(destinationSpy2);
230         router.publish("any", source1);
231         verify(listener).delivered(any(EventInfo.class),
232             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
233
234         verify(destinationSpy, never()).receive(same(source1));
235         verify(destinationSpy2).receive(same(source1));
236     }
237
238     @Test
239     public void testDestinationChooseFromTargetTypesReturnsNull() {
240         destinationSpy = registerDestination(true, "any");
241         registerDocumentType("any");
242
243         when(
244             destinationSpy
245                 .chooseFromTargetTypes((Collection<String>) anyObject()))
246             .thenReturn(null);
247
248         router.publish("any", source1);
249         verify(listener).notDelivered(any(EventInfo.class));
250         verify(destinationSpy, never()).receive(same(source1));
251     }
252
253     @Test
254     public void testDestinationChooseFromTargetTypesReturnsNullSecondDestinationStillOk() {
255         testDestinationChooseFromTargetTypesReturnsNull();
256
257         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
258         Destination destinationSpy2 = spy(destination2);
259         Id<Destination> destinationId2 = router
260             .registerDestination(destinationSpy2);
261         router.publish("any", source1);
262         verify(listener).delivered(any(EventInfo.class),
263             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
264
265         verify(destinationSpy, never()).receive(same(source1));
266         verify(destinationSpy2).receive(same(source1));
267     }
268
269     @Test
270     public void testOneTransformationOneDestination() {
271         registerDocumentType("any");
272         Transformation transformation = mock(Transformation.class);
273         when(transformation.getName()).thenReturn("trans");
274         when(transformation.getFromType()).thenReturn("any");
275         when(transformation.getToType()).thenReturn("bla");
276         when(transformation.transform(same(source1))).thenReturn(source2);
277         routerConfig.transformationConfig().add(transformation);
278         config.getTransformations().replaceTransformations(
279             routerConfig.transformationConfig().map());
280
281         Destination destination = mock(Destination.class);
282         when(
283             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
284             .thenReturn(Arrays.asList("bla"));
285
286         router.registerDestination(destination);
287
288         when(destination.receive(any(DOMSource.class))).thenReturn(true);
289         router.publish("bla", source1);
290         verify(listener).delivered(any(EventInfo.class),
291             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
292
293         verify(transformation).transform(source1);
294         verify(destination).receive(same(source2));
295
296         // now the same when the destination rejects the event.
297         when(destination.receive(any(DOMSource.class))).thenReturn(false);
298         router.publish("bla", source1);
299         verify(listener).notDelivered(any(EventInfo.class));
300     }
301
302     @Test
303     public void testMisbehavingTransformationOneDestination() {
304         registerDocumentType("any");
305         Transformation transformation = mock(Transformation.class);
306         when(transformation.getName()).thenReturn("trans");
307         when(transformation.getFromType()).thenReturn("any");
308         when(transformation.getToType()).thenReturn("bla");
309         doThrow(new RuntimeException("x")).when(transformation).transform(
310             same(source1));
311         routerConfig.transformationConfig().add(transformation);
312
313         Destination destination = mock(Destination.class);
314         when(
315             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
316             .thenReturn(Arrays.asList("bla"));
317
318         router.registerDestination(destination);
319
320         when(destination.receive(any(DOMSource.class))).thenReturn(true);
321         router.publish("bla", source1);
322         verify(listener).notDelivered(any(EventInfo.class));
323     }
324
325     private Transformation createTransformation(String aFrom, String aTo,
326         DOMSource aSource, DOMSource aTarget) {
327         Transformation transformation = mock(Transformation.class);
328         when(transformation.getName()).thenReturn("trans");
329         when(transformation.getFromType()).thenReturn(aFrom);
330         when(transformation.getToType()).thenReturn(aTo);
331         when(transformation.transform(same(aSource))).thenReturn(aTarget);
332         return transformation;
333     }
334
335     @Test
336     public void testOneTransformationReturnsNull() {
337         registerDocumentType("any");
338         Transformation transformation = createTransformation("any", "bla",
339             source1, null);
340
341         routerConfig.transformationConfig().add(transformation);
342         config.getTransformations().replaceTransformations(
343             routerConfig.transformationConfig().map());
344
345         Destination destination = mock(Destination.class);
346         when(
347             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
348             .thenReturn(Arrays.asList("bla"));
349         router.registerDestination(destination);
350
351         router.publish("bla", source1);
352         verify(listener).notDelivered(any(EventInfo.class));
353
354         verify(transformation).transform(source1);
355         verify(destination, never()).receive(any(DOMSource.class));
356
357         // add second transformation that behaves normally
358         Transformation transformation2 = createTransformation("any", "bla2",
359             source1, source2);
360
361         routerConfig.transformationConfig().add(transformation2);
362         config.getTransformations().replaceTransformations(
363             routerConfig.transformationConfig().map());
364         when(
365             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
366             .thenReturn(Arrays.asList("bla", "bla2"));
367
368         reset(transformation);
369         when(transformation.getName()).thenReturn("trans");
370         when(transformation.getFromType()).thenReturn("any");
371         when(transformation.getToType()).thenReturn("bla");
372         when(transformation.transform(same(source1))).thenReturn(null);
373
374         when(destination.receive(any(DOMSource.class))).thenReturn(true);
375         router.publish("bla", source1);
376         verify(listener).delivered(any(EventInfo.class),
377             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
378
379         verify(transformation).transform(source1);
380         verify(transformation2).transform(source1);
381
382         verify(destination).receive(same(source2));
383
384     }
385
386     @Test
387     public void testChooseMultipleDestinationsOneType() {
388         Destination dest1 = registerDestination(true, "any");
389         Destination dest2 = registerDestination(true, "any");
390         registerDocumentType("any");
391
392         router.publish("source", source1);
393         verify(listener, times(2)).delivered(any(EventInfo.class),
394             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
395
396         verify(dest1).receive(same(source1));
397         verify(dest2).receive(same(source1));
398     }
399
400     @Test
401     public void testMultipleDeliveryToOneDestination() {
402         Destination dest = registerDestination(true, "any", "other");
403         registerDocumentType("any", source1);
404         registerDocumentType("other", source2);
405         Transformation transformation = createTransformation("any", "other",
406             source1, source2);
407         routerConfig.transformationConfig().add(transformation);
408         config.getTransformations().replaceTransformations(
409             routerConfig.transformationConfig().map());
410
411         router.publish("source", source1);
412         verify(listener, times(2)).delivered(any(EventInfo.class),
413             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
414
415         verify(dest).receive(same(source1));
416         verify(dest).receive(same(source2));
417     }
418
419     @Test
420     public void testMultipleTransformations() {
421         Destination dest = registerDestination(true, "other");
422         registerDocumentType("any", source1);
423         registerDocumentType("other", source3);
424
425         Transformation t1 = createTransformation("any", "intermediate",
426             source1, source2);
427         routerConfig.transformationConfig().add(t1);
428         Transformation t2 = createTransformation("intermediate", "other",
429             source2, source3);
430         routerConfig.transformationConfig().add(t2);
431         config.getTransformations().replaceTransformations(
432             routerConfig.transformationConfig().map());
433
434         router.publish("source", source1);
435         verify(listener).delivered(any(EventInfo.class),
436             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
437
438         verify(dest).receive(same(source3));
439     }
440
441     @Test
442     public void testDestinationGivesError() {
443         Destination destination = mock(Destination.class);
444         when(destination.getName()).thenReturn("name");
445         when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
446             .thenReturn(Arrays.asList("any"));
447         doThrow(new RuntimeException("x")).when(destination).receive(
448             any(DOMSource.class));
449         router.registerDestination(destination);
450
451         registerDocumentType("any");
452
453         router.publish("source", source1);
454
455         verify(listener).delivered(any(EventInfo.class),
456             anyListOf(Transformation.class), anyLong(), anyString(), eq(false));
457
458     }
459 }