2 * Copyright 2005-2011 the original author or authors.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.wamblee.xmlrouter.impl;
18 import static org.mockito.Matchers.*;
19 import static org.mockito.Mockito.*;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.UUID;
24 import java.util.logging.Handler;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
28 import javax.xml.transform.dom.DOMSource;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.wamblee.general.SystemClock;
33 import org.wamblee.xmlrouter.common.Id;
34 import org.wamblee.xmlrouter.config.DocumentType;
35 import org.wamblee.xmlrouter.config.Filter;
36 import org.wamblee.xmlrouter.config.Transformation;
37 import org.wamblee.xmlrouter.listener.EventInfo;
38 import org.wamblee.xmlrouter.listener.EventListener;
39 import org.wamblee.xmlrouter.listener.LoggingEventListener;
40 import org.wamblee.xmlrouter.subscribe.Destination;
42 public class XMLRouterTest {
44 public static class MyDestination implements Destination {
46 private boolean receiveResult;
47 private Collection<String> types;
49 public MyDestination(boolean aReceiveResult, Collection<String> aTypes) {
50 receiveResult = aReceiveResult;
55 public Collection<String> chooseFromTargetTypes(
56 Collection<String> aPossibleTargetTypes) {
61 public String getName() {
66 public boolean receive(DOMSource aEvent) {
71 private ExtendedRouterConfig routerConfig;
72 private XMLRouterConfiguration config;
73 private XMLRouter router;
74 private DOMSource source1;
75 private DOMSource source2;
76 private DOMSource source3;
78 private Destination destinationSpy;
79 private Id<Destination> destinationId;
80 private EventListener listener;
85 Logger logger = Logger.getLogger(XMLRouter.class.getName());
86 setLogLevel(logger, Level.FINEST);
88 routerConfig = new SingleRouterConfig("routerconfig");
89 config = new XMLRouterConfigurationImpl(routerConfig);
90 EventListener logListener = new LoggingEventListener(Level.INFO);
91 listener = spy(logListener);
92 router = new XMLRouter(new SystemClock(), config, listener);
93 source1 = mock(DOMSource.class);
94 source2 = mock(DOMSource.class);
95 source3 = mock(DOMSource.class);
98 private void setLogLevel(Logger aLogger, Level aLevel) {
99 aLogger.setLevel(aLevel);
100 for (Handler handler : aLogger.getHandlers()) {
101 handler.setLevel(Level.FINEST);
103 Logger parent = aLogger.getParent();
104 if (parent != null) {
105 setLogLevel(parent, aLevel);
110 public void testNoInputDocumentsRegistered() {
111 Destination destination = new MyDestination(true, Arrays.asList("any"));
112 destinationSpy = spy(destination);
114 destinationId = router.registerDestination(destinationSpy);
115 router.publish("any", source1);
116 verify(listener).notDelivered(any(EventInfo.class));
120 public void testMisBehavingDocumentType() {
121 DocumentType type = mockDocument("docid");
122 doThrow(new RuntimeException("x")).when(type).isInstance(
123 any(DOMSource.class));
124 routerConfig.documentTypeConfig().add(type);
125 router.publish("xx", mock(DOMSource.class));
126 verify(listener).notDelivered(any(EventInfo.class));
127 // no exception should occur.
130 private DocumentType mockDocument(String docid) {
131 DocumentType type = mock(DocumentType.class);
132 when(type.getId()).thenReturn(new Id<DocumentType>(docid));
137 public void testMisBehavingFilter() {
138 registerDocumentType("any");
139 Filter filter = mockFilter("filterid");
140 doThrow(new RuntimeException("x")).when(filter).isAllowed(anyString(),
141 any(DOMSource.class));
142 routerConfig.filterConfig().add(filter);
143 router.publish("xx", mock(DOMSource.class));
144 verify(listener).notDelivered(any(EventInfo.class));
145 // no exception should occur.
148 private Filter mockFilter(String filterId) {
149 Filter filter = mock(Filter.class);
150 when(filter.getId()).thenReturn(new Id<Filter>(filterId));
155 public void testOneDestinationNoTransformationSuccess() {
156 destinationSpy = registerDestination(true, "any");
157 registerDocumentType("any");
159 router.publish("any", source1);
160 verify(listener).delivered(any(EventInfo.class),
161 anyListOf(Transformation.class), anyString(), eq(true));
162 verify(destinationSpy).receive(same(source1));
164 // Unregister the destination.
165 router.unregisterDestination(destinationId);
167 router.publish("any", source2);
168 verify(listener).notDelivered(any(EventInfo.class));
169 verifyNoMoreInteractions(destinationSpy);
172 private void resetMocks() {
173 reset(destinationSpy);
177 private void registerDocumentType(String aType) {
178 DocumentType type = mockDocument(UUID.randomUUID().toString());
179 when(type.isInstance(any(DOMSource.class))).thenReturn(true);
180 when(type.getName()).thenReturn(aType);
181 routerConfig.documentTypeConfig().add(type);
184 private void registerDocumentType(String aType, DOMSource aSource) {
185 DocumentType type = mock(DocumentType.class);
186 when(type.isInstance(same(aSource))).thenReturn(true);
187 when(type.getName()).thenReturn(aType);
188 when(type.getId()).thenReturn(new Id<DocumentType>(aType));
189 routerConfig.documentTypeConfig().add(type);
192 private Destination registerDestination(boolean aResult, String... types) {
193 Destination destination = new MyDestination(aResult,
194 Arrays.asList(types));
195 Destination myspy = spy(destination);
196 destinationId = router.registerDestination(myspy);
201 public void testOneDestinationNotMatches() {
202 destinationSpy = registerDestination(true);
203 registerDocumentType("any");
205 router.publish("any", source1);
206 verify(listener).notDelivered(any(EventInfo.class));
207 verify(destinationSpy, never()).receive(any(DOMSource.class));
211 public void testOneDestinationThrowsException() {
212 destinationSpy = registerDestination(true, "any");
213 registerDocumentType("any");
215 doThrow(new RuntimeException()).when(destinationSpy).receive(
216 any(DOMSource.class));
218 router.publish("any", source1);
219 verify(listener).notDelivered(any(EventInfo.class));
220 verify(destinationSpy).receive(same(source1));
224 public void testOneDestinationThrowsExceptionSecondDestinationStillHandled() {
225 testOneDestinationThrowsException();
226 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
227 Destination destinationSpy2 = spy(destination2);
228 Id<Destination> destinationId2 = router
229 .registerDestination(destinationSpy2);
231 router.publish("any", source1);
232 verify(listener).delivered(any(EventInfo.class),
233 anyListOf(Transformation.class), anyString(), eq(true));
235 verify(destinationSpy2).receive(same(source1));
240 public void testDestinationChooseFromTargetTypesThrowsException() {
241 destinationSpy = registerDestination(true, "any");
242 registerDocumentType("any");
244 doThrow(new RuntimeException()).when(destinationSpy)
245 .chooseFromTargetTypes((Collection<String>) anyObject());
247 router.publish("any", source1);
248 verify(listener).notDelivered(any(EventInfo.class));
249 verify(destinationSpy, never()).receive(same(source1));
253 public void testDestinationChooseFromTargetTypesThrowsExceptionSecondDestinationStillOk() {
254 testDestinationChooseFromTargetTypesThrowsException();
256 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
257 Destination destinationSpy2 = spy(destination2);
258 Id<Destination> destinationId2 = router
259 .registerDestination(destinationSpy2);
260 router.publish("any", source1);
261 verify(listener).delivered(any(EventInfo.class),
262 anyListOf(Transformation.class), anyString(), eq(true));
264 verify(destinationSpy, never()).receive(same(source1));
265 verify(destinationSpy2).receive(same(source1));
269 public void testDestinationChooseFromTargetTypesReturnsNull() {
270 destinationSpy = registerDestination(true, "any");
271 registerDocumentType("any");
275 .chooseFromTargetTypes((Collection<String>) anyObject()))
278 router.publish("any", source1);
279 verify(listener).notDelivered(any(EventInfo.class));
280 verify(destinationSpy, never()).receive(same(source1));
284 public void testDestinationChooseFromTargetTypesReturnsNullSecondDestinationStillOk() {
285 testDestinationChooseFromTargetTypesReturnsNull();
287 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
288 Destination destinationSpy2 = spy(destination2);
289 Id<Destination> destinationId2 = router
290 .registerDestination(destinationSpy2);
291 router.publish("any", source1);
292 verify(listener).delivered(any(EventInfo.class),
293 anyListOf(Transformation.class), anyString(), eq(true));
295 verify(destinationSpy, never()).receive(same(source1));
296 verify(destinationSpy2).receive(same(source1));
300 public void testOneTransformationOneDestination() {
301 registerDocumentType("any");
302 Transformation transformation = mock(Transformation.class);
303 when(transformation.getId())
304 .thenReturn(new Id<Transformation>("trans"));
305 when(transformation.getFromType()).thenReturn("any");
306 when(transformation.getToType()).thenReturn("bla");
307 when(transformation.transform(same(source1))).thenReturn(source2);
308 routerConfig.transformationConfig().add(transformation);
309 config.setRouterConfig(routerConfig);
311 Destination destination = mock(Destination.class);
313 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
314 .thenReturn(Arrays.asList("bla"));
316 router.registerDestination(destination);
318 when(destination.receive(any(DOMSource.class))).thenReturn(true);
319 router.publish("bla", source1);
320 verify(listener).delivered(any(EventInfo.class),
321 anyListOf(Transformation.class), anyString(), eq(true));
323 verify(transformation).transform(source1);
324 verify(destination).receive(same(source2));
326 // now the same when the destination rejects the event.
327 when(destination.receive(any(DOMSource.class))).thenReturn(false);
328 router.publish("bla", source1);
329 verify(listener).notDelivered(any(EventInfo.class));
333 public void testOneTransformationOneDestinationFilterRejectsDestinationDocType() {
334 registerDocumentType("any");
336 Transformation transformation = mock(Transformation.class);
337 when(transformation.getId())
338 .thenReturn(new Id<Transformation>("trans"));
339 when(transformation.getFromType()).thenReturn("any");
340 when(transformation.getToType()).thenReturn("bla");
341 when(transformation.transform(same(source1))).thenReturn(source2);
342 routerConfig.transformationConfig().add(transformation);
344 Filter filter = mock(Filter.class);
345 when(filter.getId()).thenReturn(new Id<Filter>("f"));
346 when(filter.isAllowed(anyString(), same(source2))).thenReturn(false);
347 when(filter.isAllowed(anyString(), same(source1))).thenReturn(true);
348 routerConfig.filterConfig().add(filter);
350 config.setRouterConfig(routerConfig);
352 Destination destination = mock(Destination.class);
354 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
355 .thenReturn(Arrays.asList("bla"));
357 router.registerDestination(destination);
359 when(destination.receive(any(DOMSource.class))).thenReturn(true);
360 router.publish("bla", source1);
361 verify(listener).notDelivered(any(EventInfo.class));
363 verify(transformation).transform(source1);
364 verify(destination, never()).receive(any(DOMSource.class));
368 public void testMisbehavingTransformationOneDestination() {
369 registerDocumentType("any");
370 Transformation transformation = mock(Transformation.class);
371 when(transformation.getId())
372 .thenReturn(new Id<Transformation>("trans"));
373 when(transformation.getFromType()).thenReturn("any");
374 when(transformation.getToType()).thenReturn("bla");
375 doThrow(new RuntimeException("x")).when(transformation).transform(
377 routerConfig.transformationConfig().add(transformation);
379 Destination destination = mock(Destination.class);
381 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
382 .thenReturn(Arrays.asList("bla"));
384 router.registerDestination(destination);
386 when(destination.receive(any(DOMSource.class))).thenReturn(true);
387 router.publish("bla", source1);
388 verify(listener).notDelivered(any(EventInfo.class));
391 private Transformation createTransformation(String aFrom, String aTo,
392 DOMSource aSource, DOMSource aTarget) {
393 Transformation transformation = mock(Transformation.class);
394 when(transformation.getId()).thenReturn(
395 new Id<Transformation>(UUID.randomUUID().toString()));
396 when(transformation.getFromType()).thenReturn(aFrom);
397 when(transformation.getToType()).thenReturn(aTo);
398 when(transformation.transform(same(aSource))).thenReturn(aTarget);
399 return transformation;
403 public void testOneTransformationReturnsNull() {
404 registerDocumentType("any");
405 Transformation transformation = createTransformation("any", "bla",
408 routerConfig.transformationConfig().add(transformation);
409 config.setRouterConfig(routerConfig);
410 Destination destination = mock(Destination.class);
412 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
413 .thenReturn(Arrays.asList("bla"));
414 router.registerDestination(destination);
416 router.publish("bla", source1);
417 verify(listener).notDelivered(any(EventInfo.class));
419 verify(transformation).transform(source1);
420 verify(destination, never()).receive(any(DOMSource.class));
422 // add second transformation that behaves normally
423 Transformation transformation2 = createTransformation("any", "bla2",
426 routerConfig.transformationConfig().add(transformation2);
427 config.setRouterConfig(routerConfig);
429 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
430 .thenReturn(Arrays.asList("bla", "bla2"));
432 reset(transformation);
433 when(transformation.getId())
434 .thenReturn(new Id<Transformation>("trans"));
435 when(transformation.getFromType()).thenReturn("any");
436 when(transformation.getToType()).thenReturn("bla");
437 when(transformation.transform(same(source1))).thenReturn(null);
439 when(destination.receive(any(DOMSource.class))).thenReturn(true);
440 router.publish("bla", source1);
441 verify(listener).delivered(any(EventInfo.class),
442 anyListOf(Transformation.class), anyString(), eq(true));
444 verify(transformation).transform(source1);
445 verify(transformation2).transform(source1);
447 verify(destination).receive(same(source2));
452 public void testChooseMultipleDestinationsOneType() {
453 Destination dest1 = registerDestination(true, "any");
454 Destination dest2 = registerDestination(true, "any");
455 registerDocumentType("any");
457 router.publish("source", source1);
458 verify(listener, times(2)).delivered(any(EventInfo.class),
459 anyListOf(Transformation.class), anyString(), eq(true));
461 verify(dest1).receive(same(source1));
462 verify(dest2).receive(same(source1));
466 public void testMultipleDeliveryToOneDestination() {
467 Destination dest = registerDestination(true, "any", "other");
468 registerDocumentType("any", source1);
469 registerDocumentType("other", source2);
470 Transformation transformation = createTransformation("any", "other",
472 routerConfig.transformationConfig().add(transformation);
473 config.setRouterConfig(routerConfig);
475 router.publish("source", source1);
476 verify(listener, times(2)).delivered(any(EventInfo.class),
477 anyListOf(Transformation.class), anyString(), eq(true));
479 verify(dest).receive(same(source1));
480 verify(dest).receive(same(source2));
484 public void testMultipleTransformations() {
485 Destination dest = registerDestination(true, "other");
486 registerDocumentType("any", source1);
487 registerDocumentType("other", source3);
489 Transformation t1 = createTransformation("any", "intermediate",
491 routerConfig.transformationConfig().add(t1);
492 Transformation t2 = createTransformation("intermediate", "other",
494 routerConfig.transformationConfig().add(t2);
495 config.setRouterConfig(routerConfig);
497 router.publish("source", source1);
498 verify(listener).delivered(any(EventInfo.class),
499 anyListOf(Transformation.class), anyString(), eq(true));
501 verify(dest).receive(same(source3));
505 public void testMultipleTransformationsFilterRejectsIntermediateDocument() {
506 Destination dest = registerDestination(true, "other");
507 registerDocumentType("any", source1);
508 registerDocumentType("other", source3);
510 Transformation t1 = createTransformation("any", "intermediate",
512 routerConfig.transformationConfig().add(t1);
513 Transformation t2 = createTransformation("intermediate", "other",
515 routerConfig.transformationConfig().add(t2);
516 config.setRouterConfig(routerConfig);
518 Filter filter = mock(Filter.class);
519 when(filter.getId()).thenReturn(new Id<Filter>("f"));
520 when(filter.isAllowed(anyString(), same(source1))).thenReturn(true);
521 when(filter.isAllowed(anyString(), same(source2))).thenReturn(false);
522 when(filter.isAllowed(anyString(), same(source3))).thenReturn(true);
523 routerConfig.filterConfig().add(filter);
525 router.publish("source", source1);
526 verify(listener).notDelivered(any(EventInfo.class));
527 verify(dest, never()).receive(any(DOMSource.class));
531 public void testDestinationGivesError() {
532 Destination destination = mock(Destination.class);
533 when(destination.getName()).thenReturn("name");
534 when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
535 .thenReturn(Arrays.asList("any"));
536 doThrow(new RuntimeException("x")).when(destination).receive(
537 any(DOMSource.class));
538 router.registerDestination(destination);
540 registerDocumentType("any");
542 router.publish("source", source1);
544 verify(listener).delivered(any(EventInfo.class),
545 anyListOf(Transformation.class), anyString(), eq(false));