64aefa1a8ca9f77e8746d7b0f94c5eacb192a00c
[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.setRouterConfig(routerConfig);
279
280         Destination destination = mock(Destination.class);
281         when(
282             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
283             .thenReturn(Arrays.asList("bla"));
284
285         router.registerDestination(destination);
286
287         when(destination.receive(any(DOMSource.class))).thenReturn(true);
288         router.publish("bla", source1);
289         verify(listener).delivered(any(EventInfo.class),
290             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
291
292         verify(transformation).transform(source1);
293         verify(destination).receive(same(source2));
294
295         // now the same when the destination rejects the event.
296         when(destination.receive(any(DOMSource.class))).thenReturn(false);
297         router.publish("bla", source1);
298         verify(listener).notDelivered(any(EventInfo.class));
299     }
300
301     @Test
302     public void testMisbehavingTransformationOneDestination() {
303         registerDocumentType("any");
304         Transformation transformation = mock(Transformation.class);
305         when(transformation.getName()).thenReturn("trans");
306         when(transformation.getFromType()).thenReturn("any");
307         when(transformation.getToType()).thenReturn("bla");
308         doThrow(new RuntimeException("x")).when(transformation).transform(
309             same(source1));
310         routerConfig.transformationConfig().add(transformation);
311
312         Destination destination = mock(Destination.class);
313         when(
314             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
315             .thenReturn(Arrays.asList("bla"));
316
317         router.registerDestination(destination);
318
319         when(destination.receive(any(DOMSource.class))).thenReturn(true);
320         router.publish("bla", source1);
321         verify(listener).notDelivered(any(EventInfo.class));
322     }
323
324     private Transformation createTransformation(String aFrom, String aTo,
325         DOMSource aSource, DOMSource aTarget) {
326         Transformation transformation = mock(Transformation.class);
327         when(transformation.getName()).thenReturn("trans");
328         when(transformation.getFromType()).thenReturn(aFrom);
329         when(transformation.getToType()).thenReturn(aTo);
330         when(transformation.transform(same(aSource))).thenReturn(aTarget);
331         return transformation;
332     }
333
334     @Test
335     public void testOneTransformationReturnsNull() {
336         registerDocumentType("any");
337         Transformation transformation = createTransformation("any", "bla",
338             source1, null);
339
340         routerConfig.transformationConfig().add(transformation);
341         config.setRouterConfig(routerConfig);
342         Destination destination = mock(Destination.class);
343         when(
344             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
345             .thenReturn(Arrays.asList("bla"));
346         router.registerDestination(destination);
347
348         router.publish("bla", source1);
349         verify(listener).notDelivered(any(EventInfo.class));
350
351         verify(transformation).transform(source1);
352         verify(destination, never()).receive(any(DOMSource.class));
353
354         // add second transformation that behaves normally
355         Transformation transformation2 = createTransformation("any", "bla2",
356             source1, source2);
357
358         routerConfig.transformationConfig().add(transformation2);
359         config.setRouterConfig(routerConfig);
360         when(
361             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
362             .thenReturn(Arrays.asList("bla", "bla2"));
363
364         reset(transformation);
365         when(transformation.getName()).thenReturn("trans");
366         when(transformation.getFromType()).thenReturn("any");
367         when(transformation.getToType()).thenReturn("bla");
368         when(transformation.transform(same(source1))).thenReturn(null);
369
370         when(destination.receive(any(DOMSource.class))).thenReturn(true);
371         router.publish("bla", source1);
372         verify(listener).delivered(any(EventInfo.class),
373             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
374
375         verify(transformation).transform(source1);
376         verify(transformation2).transform(source1);
377
378         verify(destination).receive(same(source2));
379
380     }
381
382     @Test
383     public void testChooseMultipleDestinationsOneType() {
384         Destination dest1 = registerDestination(true, "any");
385         Destination dest2 = registerDestination(true, "any");
386         registerDocumentType("any");
387
388         router.publish("source", source1);
389         verify(listener, times(2)).delivered(any(EventInfo.class),
390             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
391
392         verify(dest1).receive(same(source1));
393         verify(dest2).receive(same(source1));
394     }
395
396     @Test
397     public void testMultipleDeliveryToOneDestination() {
398         Destination dest = registerDestination(true, "any", "other");
399         registerDocumentType("any", source1);
400         registerDocumentType("other", source2);
401         Transformation transformation = createTransformation("any", "other",
402             source1, source2);
403         routerConfig.transformationConfig().add(transformation);
404         config.setRouterConfig(routerConfig);
405
406         router.publish("source", source1);
407         verify(listener, times(2)).delivered(any(EventInfo.class),
408             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
409
410         verify(dest).receive(same(source1));
411         verify(dest).receive(same(source2));
412     }
413
414     @Test
415     public void testMultipleTransformations() {
416         Destination dest = registerDestination(true, "other");
417         registerDocumentType("any", source1);
418         registerDocumentType("other", source3);
419
420         Transformation t1 = createTransformation("any", "intermediate",
421             source1, source2);
422         routerConfig.transformationConfig().add(t1);
423         Transformation t2 = createTransformation("intermediate", "other",
424             source2, source3);
425         routerConfig.transformationConfig().add(t2);
426         config.setRouterConfig(routerConfig);
427
428         router.publish("source", source1);
429         verify(listener).delivered(any(EventInfo.class),
430             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
431
432         verify(dest).receive(same(source3));
433     }
434
435     @Test
436     public void testDestinationGivesError() {
437         Destination destination = mock(Destination.class);
438         when(destination.getName()).thenReturn("name");
439         when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
440             .thenReturn(Arrays.asList("any"));
441         doThrow(new RuntimeException("x")).when(destination).receive(
442             any(DOMSource.class));
443         router.registerDestination(destination);
444
445         registerDocumentType("any");
446
447         router.publish("source", source1);
448
449         verify(listener).delivered(any(EventInfo.class),
450             anyListOf(Transformation.class), anyLong(), anyString(), eq(false));
451
452     }
453 }