2746253de58653f31b04a21d63ef990f89680b44
[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.logging.Level;
24
25 import javax.xml.transform.dom.DOMSource;
26
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.wamblee.general.SystemClock;
30 import org.wamblee.xmlrouter.common.Id;
31 import org.wamblee.xmlrouter.config.DocumentType;
32 import org.wamblee.xmlrouter.config.Filter;
33 import org.wamblee.xmlrouter.config.RouterConfig;
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 Id<RouterConfig>(
83             "routerconfig"));
84         config = new XMLRouterConfigurationImpl(routerConfig);
85         EventListener logListener = new LoggingEventListener(Level.INFO);
86         listener = spy(logListener);
87         router = new XMLRouter(new SystemClock(), config, listener);
88         source1 = mock(DOMSource.class);
89         source2 = mock(DOMSource.class);
90         source3 = mock(DOMSource.class);
91     }
92
93     @Test
94     public void testNoInputDocumentsRegistered() {
95         Destination destination = new MyDestination(true, Arrays.asList("any"));
96         destinationSpy = spy(destination);
97
98         destinationId = router.registerDestination(destinationSpy);
99         router.publish("any", source1);
100         verify(listener).notDelivered(any(EventInfo.class));
101     }
102
103     @Test
104     public void testMisBehavingDocumentType() {
105         DocumentType type = mock(DocumentType.class);
106         doThrow(new RuntimeException("x")).when(type).isInstance(
107             any(DOMSource.class));
108         routerConfig.documentTypeConfig().add(type);
109         router.publish("xx", mock(DOMSource.class));
110         verify(listener).notDelivered(any(EventInfo.class));
111         // no exception should occur.
112     }
113
114     @Test
115     public void testMisBehavingFilter() {
116         registerDocumentType("any");
117         Filter filter = mock(Filter.class);
118         doThrow(new RuntimeException("x")).when(filter).isAllowed(anyString(),
119             any(DOMSource.class));
120         routerConfig.filterConfig().add(filter);
121         router.publish("xx", mock(DOMSource.class));
122         verify(listener).notDelivered(any(EventInfo.class));
123         // no exception should occur.
124     }
125
126     @Test
127     public void testOneDestinationNoTransformationSuccess() {
128         destinationSpy = registerDestination(true, "any");
129         registerDocumentType("any");
130
131         router.publish("any", source1);
132         verify(listener).delivered(any(EventInfo.class),
133             anyListOf(Transformation.class), anyString(), eq(true));
134         verify(destinationSpy).receive(same(source1));
135
136         // Unregister the destination.
137         router.unregisterDestination(destinationId);
138         resetMocks();
139         router.publish("any", source2);
140         verify(listener).notDelivered(any(EventInfo.class));
141         verifyNoMoreInteractions(destinationSpy);
142     }
143
144     private void resetMocks() {
145         reset(destinationSpy);
146         reset(listener);
147     }
148
149     private void registerDocumentType(String aType) {
150         DocumentType type = mock(DocumentType.class);
151         when(type.isInstance(any(DOMSource.class))).thenReturn(true);
152         when(type.getName()).thenReturn(aType);
153         routerConfig.documentTypeConfig().add(type);
154     }
155
156     private void registerDocumentType(String aType, DOMSource aSource) {
157         DocumentType type = mock(DocumentType.class);
158         when(type.isInstance(same(aSource))).thenReturn(true);
159         when(type.getName()).thenReturn(aType);
160         routerConfig.documentTypeConfig().add(type);
161     }
162
163     private Destination registerDestination(boolean aResult, String... types) {
164         Destination destination = new MyDestination(aResult,
165             Arrays.asList(types));
166         Destination myspy = spy(destination);
167         destinationId = router.registerDestination(myspy);
168         return myspy;
169     }
170
171     @Test
172     public void testOneDestinationNotMatches() {
173         destinationSpy = registerDestination(true);
174         registerDocumentType("any");
175
176         router.publish("any", source1);
177         verify(listener).notDelivered(any(EventInfo.class));
178         verify(destinationSpy, never()).receive(any(DOMSource.class));
179     }
180
181     @Test
182     public void testOneDestinationThrowsException() {
183         destinationSpy = registerDestination(true, "any");
184         registerDocumentType("any");
185
186         doThrow(new RuntimeException()).when(destinationSpy).receive(
187             any(DOMSource.class));
188
189         router.publish("any", source1);
190         verify(listener).notDelivered(any(EventInfo.class));
191         verify(destinationSpy).receive(same(source1));
192     }
193
194     @Test
195     public void testOneDestinationThrowsExceptionSecondDestinationStillHandled() {
196         testOneDestinationThrowsException();
197         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
198         Destination destinationSpy2 = spy(destination2);
199         Id<Destination> destinationId2 = router
200             .registerDestination(destinationSpy2);
201
202         router.publish("any", source1);
203         verify(listener).delivered(any(EventInfo.class),
204             anyListOf(Transformation.class), anyString(), eq(true));
205
206         verify(destinationSpy2).receive(same(source1));
207
208     }
209
210     @Test
211     public void testDestinationChooseFromTargetTypesThrowsException() {
212         destinationSpy = registerDestination(true, "any");
213         registerDocumentType("any");
214
215         doThrow(new RuntimeException()).when(destinationSpy)
216             .chooseFromTargetTypes((Collection<String>) anyObject());
217
218         router.publish("any", source1);
219         verify(listener).notDelivered(any(EventInfo.class));
220         verify(destinationSpy, never()).receive(same(source1));
221     }
222
223     @Test
224     public void testDestinationChooseFromTargetTypesThrowsExceptionSecondDestinationStillOk() {
225         testDestinationChooseFromTargetTypesThrowsException();
226
227         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
228         Destination destinationSpy2 = spy(destination2);
229         Id<Destination> destinationId2 = router
230             .registerDestination(destinationSpy2);
231         router.publish("any", source1);
232         verify(listener).delivered(any(EventInfo.class),
233             anyListOf(Transformation.class), anyString(), eq(true));
234
235         verify(destinationSpy, never()).receive(same(source1));
236         verify(destinationSpy2).receive(same(source1));
237     }
238
239     @Test
240     public void testDestinationChooseFromTargetTypesReturnsNull() {
241         destinationSpy = registerDestination(true, "any");
242         registerDocumentType("any");
243
244         when(
245             destinationSpy
246                 .chooseFromTargetTypes((Collection<String>) anyObject()))
247             .thenReturn(null);
248
249         router.publish("any", source1);
250         verify(listener).notDelivered(any(EventInfo.class));
251         verify(destinationSpy, never()).receive(same(source1));
252     }
253
254     @Test
255     public void testDestinationChooseFromTargetTypesReturnsNullSecondDestinationStillOk() {
256         testDestinationChooseFromTargetTypesReturnsNull();
257
258         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
259         Destination destinationSpy2 = spy(destination2);
260         Id<Destination> destinationId2 = router
261             .registerDestination(destinationSpy2);
262         router.publish("any", source1);
263         verify(listener).delivered(any(EventInfo.class),
264             anyListOf(Transformation.class), anyString(), eq(true));
265
266         verify(destinationSpy, never()).receive(same(source1));
267         verify(destinationSpy2).receive(same(source1));
268     }
269
270     @Test
271     public void testOneTransformationOneDestination() {
272         registerDocumentType("any");
273         Transformation transformation = mock(Transformation.class);
274         when(transformation.getId())
275             .thenReturn(new Id<Transformation>("trans"));
276         when(transformation.getFromType()).thenReturn("any");
277         when(transformation.getToType()).thenReturn("bla");
278         when(transformation.transform(same(source1))).thenReturn(source2);
279         routerConfig.transformationConfig().add(transformation);
280         config.setRouterConfig(routerConfig);
281
282         Destination destination = mock(Destination.class);
283         when(
284             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
285             .thenReturn(Arrays.asList("bla"));
286
287         router.registerDestination(destination);
288
289         when(destination.receive(any(DOMSource.class))).thenReturn(true);
290         router.publish("bla", source1);
291         verify(listener).delivered(any(EventInfo.class),
292             anyListOf(Transformation.class), anyString(), eq(true));
293
294         verify(transformation).transform(source1);
295         verify(destination).receive(same(source2));
296
297         // now the same when the destination rejects the event.
298         when(destination.receive(any(DOMSource.class))).thenReturn(false);
299         router.publish("bla", source1);
300         verify(listener).notDelivered(any(EventInfo.class));
301     }
302
303     @Test
304     public void testMisbehavingTransformationOneDestination() {
305         registerDocumentType("any");
306         Transformation transformation = mock(Transformation.class);
307         when(transformation.getId())
308             .thenReturn(new Id<Transformation>("trans"));
309         when(transformation.getFromType()).thenReturn("any");
310         when(transformation.getToType()).thenReturn("bla");
311         doThrow(new RuntimeException("x")).when(transformation).transform(
312             same(source1));
313         routerConfig.transformationConfig().add(transformation);
314
315         Destination destination = mock(Destination.class);
316         when(
317             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
318             .thenReturn(Arrays.asList("bla"));
319
320         router.registerDestination(destination);
321
322         when(destination.receive(any(DOMSource.class))).thenReturn(true);
323         router.publish("bla", source1);
324         verify(listener).notDelivered(any(EventInfo.class));
325     }
326
327     private Transformation createTransformation(String aFrom, String aTo,
328         DOMSource aSource, DOMSource aTarget) {
329         Transformation transformation = mock(Transformation.class);
330         when(transformation.getId())
331             .thenReturn(new Id<Transformation>("trans"));
332         when(transformation.getFromType()).thenReturn(aFrom);
333         when(transformation.getToType()).thenReturn(aTo);
334         when(transformation.transform(same(aSource))).thenReturn(aTarget);
335         return transformation;
336     }
337
338     @Test
339     public void testOneTransformationReturnsNull() {
340         registerDocumentType("any");
341         Transformation transformation = createTransformation("any", "bla",
342             source1, null);
343
344         routerConfig.transformationConfig().add(transformation);
345         config.setRouterConfig(routerConfig);
346         Destination destination = mock(Destination.class);
347         when(
348             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
349             .thenReturn(Arrays.asList("bla"));
350         router.registerDestination(destination);
351
352         router.publish("bla", source1);
353         verify(listener).notDelivered(any(EventInfo.class));
354
355         verify(transformation).transform(source1);
356         verify(destination, never()).receive(any(DOMSource.class));
357
358         // add second transformation that behaves normally
359         Transformation transformation2 = createTransformation("any", "bla2",
360             source1, source2);
361
362         routerConfig.transformationConfig().add(transformation2);
363         config.setRouterConfig(routerConfig);
364         when(
365             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
366             .thenReturn(Arrays.asList("bla", "bla2"));
367
368         reset(transformation);
369         when(transformation.getId())
370             .thenReturn(new Id<Transformation>("trans"));
371         when(transformation.getFromType()).thenReturn("any");
372         when(transformation.getToType()).thenReturn("bla");
373         when(transformation.transform(same(source1))).thenReturn(null);
374
375         when(destination.receive(any(DOMSource.class))).thenReturn(true);
376         router.publish("bla", source1);
377         verify(listener).delivered(any(EventInfo.class),
378             anyListOf(Transformation.class), anyString(), eq(true));
379
380         verify(transformation).transform(source1);
381         verify(transformation2).transform(source1);
382
383         verify(destination).receive(same(source2));
384
385     }
386
387     @Test
388     public void testChooseMultipleDestinationsOneType() {
389         Destination dest1 = registerDestination(true, "any");
390         Destination dest2 = registerDestination(true, "any");
391         registerDocumentType("any");
392
393         router.publish("source", source1);
394         verify(listener, times(2)).delivered(any(EventInfo.class),
395             anyListOf(Transformation.class), anyString(), eq(true));
396
397         verify(dest1).receive(same(source1));
398         verify(dest2).receive(same(source1));
399     }
400
401     @Test
402     public void testMultipleDeliveryToOneDestination() {
403         Destination dest = registerDestination(true, "any", "other");
404         registerDocumentType("any", source1);
405         registerDocumentType("other", source2);
406         Transformation transformation = createTransformation("any", "other",
407             source1, source2);
408         routerConfig.transformationConfig().add(transformation);
409         config.setRouterConfig(routerConfig);
410
411         router.publish("source", source1);
412         verify(listener, times(2)).delivered(any(EventInfo.class),
413             anyListOf(Transformation.class), 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.setRouterConfig(routerConfig);
432
433         router.publish("source", source1);
434         verify(listener).delivered(any(EventInfo.class),
435             anyListOf(Transformation.class), anyString(), eq(true));
436
437         verify(dest).receive(same(source3));
438     }
439
440     @Test
441     public void testDestinationGivesError() {
442         Destination destination = mock(Destination.class);
443         when(destination.getName()).thenReturn("name");
444         when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
445             .thenReturn(Arrays.asList("any"));
446         doThrow(new RuntimeException("x")).when(destination).receive(
447             any(DOMSource.class));
448         router.registerDestination(destination);
449
450         registerDocumentType("any");
451
452         router.publish("source", source1);
453
454         verify(listener).delivered(any(EventInfo.class),
455             anyListOf(Transformation.class), anyString(), eq(false));
456
457     }
458 }