event listener is now used by the xml router and the publish method of the gateway is
[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.Transformation;
33 import org.wamblee.xmlrouter.listener.EventInfo;
34 import org.wamblee.xmlrouter.listener.EventListener;
35 import org.wamblee.xmlrouter.listener.LoggingEventListener;
36 import org.wamblee.xmlrouter.subscribe.Destination;
37
38 public class XMLRouterTest {
39
40     public static class MyDestination implements Destination {
41
42         private boolean receiveResult;
43         private Collection<String> types;
44
45         public MyDestination(boolean aReceiveResult, Collection<String> aTypes) {
46             receiveResult = aReceiveResult;
47             types = aTypes;
48         }
49
50         @Override
51         public Collection<String> chooseFromTargetTypes(
52             Collection<String> aPossibleTargetTypes) {
53             return types;
54         }
55
56         @Override
57         public String getName() {
58             return "xxx";
59         }
60
61         @Override
62         public boolean receive(DOMSource aEvent) {
63             return receiveResult;
64         }
65     }
66
67     private XMLRouter router;
68     private DOMSource source1;
69     private DOMSource source2;
70     private DOMSource source3;
71
72     private Destination destinationSpy;
73     private Id<Destination> destinationId;
74     private EventListener listener;
75
76     @Before
77     public void setUp() {
78         EventListener logListener = new LoggingEventListener(Level.INFO);
79         listener = spy(logListener);
80         router = new XMLRouter(new SystemClock(), listener);
81         source1 = mock(DOMSource.class);
82         source2 = mock(DOMSource.class);
83         source3 = mock(DOMSource.class);
84     }
85
86     @Test
87     public void testNoInputDocumentsRegistered() {
88         Destination destination = new MyDestination(true, Arrays.asList("any"));
89         destinationSpy = spy(destination);
90
91         destinationId = router.registerDestination(destinationSpy);
92         router.publish("any", source1);
93         verify(listener).notDelivered(any(EventInfo.class));
94     }
95
96     @Test
97     public void testOneDestinationNoTransformationSuccess() {
98         destinationSpy = registerDestination(true, "any");
99         registerDocumentType("any");
100
101         router.publish("any", source1);
102         verify(listener).delivered(any(EventInfo.class),
103             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
104         verify(destinationSpy).receive(same(source1));
105
106         // Unregister the destination.
107         router.unregisterDestination(destinationId);
108         resetMocks();
109         router.publish("any", source2);
110         verify(listener).notDelivered(any(EventInfo.class));
111         verifyNoMoreInteractions(destinationSpy);
112     }
113
114     private void resetMocks() {
115         reset(destinationSpy);
116         reset(listener);
117     }
118
119     private void registerDocumentType(String aType) {
120         DocumentType type = mock(DocumentType.class);
121         when(type.isInstance(any(DOMSource.class))).thenReturn(true);
122         when(type.getName()).thenReturn(aType);
123         Id<DocumentType> typeId = router.addDocumentType(type);
124     }
125
126     private void registerDocumentType(String aType, DOMSource aSource) {
127         DocumentType type = mock(DocumentType.class);
128         when(type.isInstance(same(aSource))).thenReturn(true);
129         when(type.getName()).thenReturn(aType);
130         Id<DocumentType> typeId = router.addDocumentType(type);
131     }
132
133     private Destination registerDestination(boolean aResult, String... types) {
134         Destination destination = new MyDestination(aResult,
135             Arrays.asList(types));
136         Destination myspy = spy(destination);
137         destinationId = router.registerDestination(myspy);
138         return myspy;
139     }
140
141     @Test
142     public void testOneDestinationNotMatches() {
143         destinationSpy = registerDestination(true);
144         registerDocumentType("any");
145
146         router.publish("any", source1);
147         verify(listener).notDelivered(any(EventInfo.class));
148         verify(destinationSpy, never()).receive(any(DOMSource.class));
149     }
150
151     @Test
152     public void testOneDestinationThrowsException() {
153         destinationSpy = registerDestination(true, "any");
154         registerDocumentType("any");
155
156         doThrow(new RuntimeException()).when(destinationSpy).receive(
157             any(DOMSource.class));
158
159         router.publish("any", source1);
160         verify(listener).notDelivered(any(EventInfo.class));
161         verify(destinationSpy).receive(same(source1));
162     }
163
164     @Test
165     public void testOneDestinationThrowsExceptionSecondDestinationStillHandled() {
166         testOneDestinationThrowsException();
167         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
168         Destination destinationSpy2 = spy(destination2);
169         Id<Destination> destinationId2 = router
170             .registerDestination(destinationSpy2);
171
172         router.publish("any", source1);
173         verify(listener).delivered(any(EventInfo.class),
174             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
175
176         verify(destinationSpy2).receive(same(source1));
177
178     }
179
180     @Test
181     public void testDestinationChooseFromTargetTypesThrowsException() {
182         destinationSpy = registerDestination(true, "any");
183         registerDocumentType("any");
184
185         doThrow(new RuntimeException()).when(destinationSpy)
186             .chooseFromTargetTypes((Collection<String>) anyObject());
187
188         router.publish("any", source1);
189         verify(listener).notDelivered(any(EventInfo.class));
190         verify(destinationSpy, never()).receive(same(source1));
191     }
192
193     @Test
194     public void testDestinationChooseFromTargetTypesThrowsExceptionSecondDestinationStillOk() {
195         testDestinationChooseFromTargetTypesThrowsException();
196
197         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
198         Destination destinationSpy2 = spy(destination2);
199         Id<Destination> destinationId2 = router
200             .registerDestination(destinationSpy2);
201         router.publish("any", source1);
202         verify(listener).delivered(any(EventInfo.class),
203             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
204
205         verify(destinationSpy, never()).receive(same(source1));
206         verify(destinationSpy2).receive(same(source1));
207     }
208
209     @Test
210     public void testDestinationChooseFromTargetTypesReturnsNull() {
211         destinationSpy = registerDestination(true, "any");
212         registerDocumentType("any");
213
214         when(
215             destinationSpy
216                 .chooseFromTargetTypes((Collection<String>) anyObject()))
217             .thenReturn(null);
218
219         router.publish("any", source1);
220         verify(listener).notDelivered(any(EventInfo.class));
221         verify(destinationSpy, never()).receive(same(source1));
222     }
223
224     @Test
225     public void testDestinationChooseFromTargetTypesReturnsNullSecondDestinationStillOk() {
226         testDestinationChooseFromTargetTypesReturnsNull();
227
228         Destination destination2 = new MyDestination(true, Arrays.asList("any"));
229         Destination destinationSpy2 = spy(destination2);
230         Id<Destination> destinationId2 = router
231             .registerDestination(destinationSpy2);
232         router.publish("any", source1);
233         verify(listener).delivered(any(EventInfo.class),
234             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
235
236         verify(destinationSpy, never()).receive(same(source1));
237         verify(destinationSpy2).receive(same(source1));
238     }
239
240     @Test
241     public void testOneTransformationOneDestination() {
242         registerDocumentType("any");
243         Transformation transformation = mock(Transformation.class);
244         when(transformation.getName()).thenReturn("trans");
245         when(transformation.getFromType()).thenReturn("any");
246         when(transformation.getToType()).thenReturn("bla");
247         when(transformation.transform(same(source1))).thenReturn(source2);
248         router.addTransformation(transformation);
249
250         Destination destination = mock(Destination.class);
251         when(
252             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
253             .thenReturn(Arrays.asList("bla"));
254
255         router.registerDestination(destination);
256
257         when(destination.receive(any(DOMSource.class))).thenReturn(true);
258         router.publish("bla", source1);
259         verify(listener).delivered(any(EventInfo.class),
260             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
261
262         verify(transformation).transform(source1);
263         verify(destination).receive(same(source2));
264
265         // now the same when the destination rejects the event.
266         when(destination.receive(any(DOMSource.class))).thenReturn(false);
267         router.publish("bla", source1);
268         verify(listener).notDelivered(any(EventInfo.class));
269     }
270
271     private Transformation createTransformation(String aFrom, String aTo,
272         DOMSource aSource, DOMSource aTarget) {
273         Transformation transformation = mock(Transformation.class);
274         when(transformation.getName()).thenReturn("trans");
275         when(transformation.getFromType()).thenReturn(aFrom);
276         when(transformation.getToType()).thenReturn(aTo);
277         when(transformation.transform(same(aSource))).thenReturn(aTarget);
278         return transformation;
279     }
280
281     @Test
282     public void testOneTransformationReturnsNull() {
283         registerDocumentType("any");
284         Transformation transformation = createTransformation("any", "bla",
285             source1, null);
286
287         router.addTransformation(transformation);
288
289         Destination destination = mock(Destination.class);
290         when(
291             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
292             .thenReturn(Arrays.asList("bla"));
293         router.registerDestination(destination);
294
295         router.publish("bla", source1);
296         verify(listener).notDelivered(any(EventInfo.class));
297
298         verify(transformation).transform(source1);
299         verify(destination, never()).receive(any(DOMSource.class));
300
301         // add second transformation that behaves normally
302         Transformation transformation2 = createTransformation("any", "bla2",
303             source1, source2);
304
305         router.addTransformation(transformation2);
306         when(
307             destination.chooseFromTargetTypes((Collection<String>) anyObject()))
308             .thenReturn(Arrays.asList("bla", "bla2"));
309
310         reset(transformation);
311         when(transformation.getName()).thenReturn("trans");
312         when(transformation.getFromType()).thenReturn("any");
313         when(transformation.getToType()).thenReturn("bla");
314         when(transformation.transform(same(source1))).thenReturn(null);
315
316         when(destination.receive(any(DOMSource.class))).thenReturn(true);
317         router.publish("bla", source1);
318         verify(listener).delivered(any(EventInfo.class),
319             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
320
321         verify(transformation).transform(source1);
322         verify(transformation2).transform(source1);
323
324         verify(destination).receive(same(source2));
325
326     }
327
328     @Test
329     public void testChooseMultipleDestinationsOneType() {
330         Destination dest1 = registerDestination(true, "any");
331         Destination dest2 = registerDestination(true, "any");
332         registerDocumentType("any");
333
334         router.publish("source", source1);
335         verify(listener, times(2)).delivered(any(EventInfo.class),
336             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
337
338         verify(dest1).receive(same(source1));
339         verify(dest2).receive(same(source1));
340     }
341
342     @Test
343     public void testMultipleDeliveryToOneDestination() {
344         Destination dest = registerDestination(true, "any", "other");
345         registerDocumentType("any", source1);
346         registerDocumentType("other", source2);
347         Transformation transformation = createTransformation("any", "other",
348             source1, source2);
349         router.addTransformation(transformation);
350
351         router.publish("source", source1);
352         verify(listener, times(2)).delivered(any(EventInfo.class),
353             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
354
355         verify(dest).receive(same(source1));
356         verify(dest).receive(same(source2));
357     }
358
359     @Test
360     public void testMultipleTransformations() {
361         Destination dest = registerDestination(true, "other");
362         registerDocumentType("any", source1);
363         registerDocumentType("other", source3);
364
365         Transformation t1 = createTransformation("any", "intermediate",
366             source1, source2);
367         router.addTransformation(t1);
368         Transformation t2 = createTransformation("intermediate", "other",
369             source2, source3);
370         router.addTransformation(t2);
371
372         router.publish("source", source1);
373         verify(listener).delivered(any(EventInfo.class),
374             anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
375
376         verify(dest).receive(same(source3));
377     }
378
379     @Test
380     public void testDestinationGivesError() {
381         Destination destination = mock(Destination.class);
382         when(destination.getName()).thenReturn("name");
383         when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
384             .thenReturn(Arrays.asList("any"));
385         doThrow(new RuntimeException("x")).when(destination).receive(
386             any(DOMSource.class));
387         router.registerDestination(destination);
388
389         registerDocumentType("any");
390
391         router.publish("source", source1);
392
393         verify(listener).delivered(any(EventInfo.class),
394             anyListOf(Transformation.class), anyLong(), anyString(), eq(false));
395
396     }
397 }