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.Level;
26 import javax.xml.transform.dom.DOMSource;
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.RouterConfig;
35 import org.wamblee.xmlrouter.config.Transformation;
36 import org.wamblee.xmlrouter.listener.EventInfo;
37 import org.wamblee.xmlrouter.listener.EventListener;
38 import org.wamblee.xmlrouter.listener.LoggingEventListener;
39 import org.wamblee.xmlrouter.subscribe.Destination;
41 public class XMLRouterTest {
43 public static class MyDestination implements Destination {
45 private boolean receiveResult;
46 private Collection<String> types;
48 public MyDestination(boolean aReceiveResult, Collection<String> aTypes) {
49 receiveResult = aReceiveResult;
54 public Collection<String> chooseFromTargetTypes(
55 Collection<String> aPossibleTargetTypes) {
60 public String getName() {
65 public boolean receive(DOMSource aEvent) {
70 private ExtendedRouterConfig routerConfig;
71 private XMLRouterConfiguration config;
72 private XMLRouter router;
73 private DOMSource source1;
74 private DOMSource source2;
75 private DOMSource source3;
77 private Destination destinationSpy;
78 private Id<Destination> destinationId;
79 private EventListener listener;
83 routerConfig = new SingleRouterConfig(new Id<RouterConfig>(
85 config = new XMLRouterConfigurationImpl(routerConfig);
86 EventListener logListener = new LoggingEventListener(Level.INFO);
87 listener = spy(logListener);
88 router = new XMLRouter(new SystemClock(), config, listener);
89 source1 = mock(DOMSource.class);
90 source2 = mock(DOMSource.class);
91 source3 = mock(DOMSource.class);
95 public void testNoInputDocumentsRegistered() {
96 Destination destination = new MyDestination(true, Arrays.asList("any"));
97 destinationSpy = spy(destination);
99 destinationId = router.registerDestination(destinationSpy);
100 router.publish("any", source1);
101 verify(listener).notDelivered(any(EventInfo.class));
105 public void testMisBehavingDocumentType() {
106 DocumentType type = mockDocument("docid");
107 doThrow(new RuntimeException("x")).when(type).isInstance(
108 any(DOMSource.class));
109 routerConfig.documentTypeConfig().add(type);
110 router.publish("xx", mock(DOMSource.class));
111 verify(listener).notDelivered(any(EventInfo.class));
112 // no exception should occur.
115 private DocumentType mockDocument(String docid) {
116 DocumentType type = mock(DocumentType.class);
117 when(type.getId()).thenReturn(new Id<DocumentType>(docid));
122 public void testMisBehavingFilter() {
123 registerDocumentType("any");
124 Filter filter = mockFilter("filterid");
125 doThrow(new RuntimeException("x")).when(filter).isAllowed(anyString(),
126 any(DOMSource.class));
127 routerConfig.filterConfig().add(filter);
128 router.publish("xx", mock(DOMSource.class));
129 verify(listener).notDelivered(any(EventInfo.class));
130 // no exception should occur.
133 private Filter mockFilter(String filterId) {
134 Filter filter = mock(Filter.class);
135 when(filter.getId()).thenReturn(new Id<Filter>(filterId));
140 public void testOneDestinationNoTransformationSuccess() {
141 destinationSpy = registerDestination(true, "any");
142 registerDocumentType("any");
144 router.publish("any", source1);
145 verify(listener).delivered(any(EventInfo.class),
146 anyListOf(Transformation.class), anyString(), eq(true));
147 verify(destinationSpy).receive(same(source1));
149 // Unregister the destination.
150 router.unregisterDestination(destinationId);
152 router.publish("any", source2);
153 verify(listener).notDelivered(any(EventInfo.class));
154 verifyNoMoreInteractions(destinationSpy);
157 private void resetMocks() {
158 reset(destinationSpy);
162 private void registerDocumentType(String aType) {
163 DocumentType type = mockDocument(UUID.randomUUID().toString());
164 when(type.isInstance(any(DOMSource.class))).thenReturn(true);
165 when(type.getName()).thenReturn(aType);
166 routerConfig.documentTypeConfig().add(type);
169 private void registerDocumentType(String aType, DOMSource aSource) {
170 DocumentType type = mock(DocumentType.class);
171 when(type.isInstance(same(aSource))).thenReturn(true);
172 when(type.getName()).thenReturn(aType);
173 when(type.getId()).thenReturn(new Id<DocumentType>(aType));
174 routerConfig.documentTypeConfig().add(type);
177 private Destination registerDestination(boolean aResult, String... types) {
178 Destination destination = new MyDestination(aResult,
179 Arrays.asList(types));
180 Destination myspy = spy(destination);
181 destinationId = router.registerDestination(myspy);
186 public void testOneDestinationNotMatches() {
187 destinationSpy = registerDestination(true);
188 registerDocumentType("any");
190 router.publish("any", source1);
191 verify(listener).notDelivered(any(EventInfo.class));
192 verify(destinationSpy, never()).receive(any(DOMSource.class));
196 public void testOneDestinationThrowsException() {
197 destinationSpy = registerDestination(true, "any");
198 registerDocumentType("any");
200 doThrow(new RuntimeException()).when(destinationSpy).receive(
201 any(DOMSource.class));
203 router.publish("any", source1);
204 verify(listener).notDelivered(any(EventInfo.class));
205 verify(destinationSpy).receive(same(source1));
209 public void testOneDestinationThrowsExceptionSecondDestinationStillHandled() {
210 testOneDestinationThrowsException();
211 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
212 Destination destinationSpy2 = spy(destination2);
213 Id<Destination> destinationId2 = router
214 .registerDestination(destinationSpy2);
216 router.publish("any", source1);
217 verify(listener).delivered(any(EventInfo.class),
218 anyListOf(Transformation.class), anyString(), eq(true));
220 verify(destinationSpy2).receive(same(source1));
225 public void testDestinationChooseFromTargetTypesThrowsException() {
226 destinationSpy = registerDestination(true, "any");
227 registerDocumentType("any");
229 doThrow(new RuntimeException()).when(destinationSpy)
230 .chooseFromTargetTypes((Collection<String>) anyObject());
232 router.publish("any", source1);
233 verify(listener).notDelivered(any(EventInfo.class));
234 verify(destinationSpy, never()).receive(same(source1));
238 public void testDestinationChooseFromTargetTypesThrowsExceptionSecondDestinationStillOk() {
239 testDestinationChooseFromTargetTypesThrowsException();
241 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
242 Destination destinationSpy2 = spy(destination2);
243 Id<Destination> destinationId2 = router
244 .registerDestination(destinationSpy2);
245 router.publish("any", source1);
246 verify(listener).delivered(any(EventInfo.class),
247 anyListOf(Transformation.class), anyString(), eq(true));
249 verify(destinationSpy, never()).receive(same(source1));
250 verify(destinationSpy2).receive(same(source1));
254 public void testDestinationChooseFromTargetTypesReturnsNull() {
255 destinationSpy = registerDestination(true, "any");
256 registerDocumentType("any");
260 .chooseFromTargetTypes((Collection<String>) anyObject()))
263 router.publish("any", source1);
264 verify(listener).notDelivered(any(EventInfo.class));
265 verify(destinationSpy, never()).receive(same(source1));
269 public void testDestinationChooseFromTargetTypesReturnsNullSecondDestinationStillOk() {
270 testDestinationChooseFromTargetTypesReturnsNull();
272 Destination destination2 = new MyDestination(true, Arrays.asList("any"));
273 Destination destinationSpy2 = spy(destination2);
274 Id<Destination> destinationId2 = router
275 .registerDestination(destinationSpy2);
276 router.publish("any", source1);
277 verify(listener).delivered(any(EventInfo.class),
278 anyListOf(Transformation.class), anyString(), eq(true));
280 verify(destinationSpy, never()).receive(same(source1));
281 verify(destinationSpy2).receive(same(source1));
285 public void testOneTransformationOneDestination() {
286 registerDocumentType("any");
287 Transformation transformation = mock(Transformation.class);
288 when(transformation.getId())
289 .thenReturn(new Id<Transformation>("trans"));
290 when(transformation.getFromType()).thenReturn("any");
291 when(transformation.getToType()).thenReturn("bla");
292 when(transformation.transform(same(source1))).thenReturn(source2);
293 routerConfig.transformationConfig().add(transformation);
294 config.setRouterConfig(routerConfig);
296 Destination destination = mock(Destination.class);
298 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
299 .thenReturn(Arrays.asList("bla"));
301 router.registerDestination(destination);
303 when(destination.receive(any(DOMSource.class))).thenReturn(true);
304 router.publish("bla", source1);
305 verify(listener).delivered(any(EventInfo.class),
306 anyListOf(Transformation.class), anyString(), eq(true));
308 verify(transformation).transform(source1);
309 verify(destination).receive(same(source2));
311 // now the same when the destination rejects the event.
312 when(destination.receive(any(DOMSource.class))).thenReturn(false);
313 router.publish("bla", source1);
314 verify(listener).notDelivered(any(EventInfo.class));
318 public void testMisbehavingTransformationOneDestination() {
319 registerDocumentType("any");
320 Transformation transformation = mock(Transformation.class);
321 when(transformation.getId())
322 .thenReturn(new Id<Transformation>("trans"));
323 when(transformation.getFromType()).thenReturn("any");
324 when(transformation.getToType()).thenReturn("bla");
325 doThrow(new RuntimeException("x")).when(transformation).transform(
327 routerConfig.transformationConfig().add(transformation);
329 Destination destination = mock(Destination.class);
331 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
332 .thenReturn(Arrays.asList("bla"));
334 router.registerDestination(destination);
336 when(destination.receive(any(DOMSource.class))).thenReturn(true);
337 router.publish("bla", source1);
338 verify(listener).notDelivered(any(EventInfo.class));
341 private Transformation createTransformation(String aFrom, String aTo,
342 DOMSource aSource, DOMSource aTarget) {
343 Transformation transformation = mock(Transformation.class);
344 when(transformation.getId()).thenReturn(
345 new Id<Transformation>(UUID.randomUUID().toString()));
346 when(transformation.getFromType()).thenReturn(aFrom);
347 when(transformation.getToType()).thenReturn(aTo);
348 when(transformation.transform(same(aSource))).thenReturn(aTarget);
349 return transformation;
353 public void testOneTransformationReturnsNull() {
354 registerDocumentType("any");
355 Transformation transformation = createTransformation("any", "bla",
358 routerConfig.transformationConfig().add(transformation);
359 config.setRouterConfig(routerConfig);
360 Destination destination = mock(Destination.class);
362 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
363 .thenReturn(Arrays.asList("bla"));
364 router.registerDestination(destination);
366 router.publish("bla", source1);
367 verify(listener).notDelivered(any(EventInfo.class));
369 verify(transformation).transform(source1);
370 verify(destination, never()).receive(any(DOMSource.class));
372 // add second transformation that behaves normally
373 Transformation transformation2 = createTransformation("any", "bla2",
376 routerConfig.transformationConfig().add(transformation2);
377 config.setRouterConfig(routerConfig);
379 destination.chooseFromTargetTypes((Collection<String>) anyObject()))
380 .thenReturn(Arrays.asList("bla", "bla2"));
382 reset(transformation);
383 when(transformation.getId())
384 .thenReturn(new Id<Transformation>("trans"));
385 when(transformation.getFromType()).thenReturn("any");
386 when(transformation.getToType()).thenReturn("bla");
387 when(transformation.transform(same(source1))).thenReturn(null);
389 when(destination.receive(any(DOMSource.class))).thenReturn(true);
390 router.publish("bla", source1);
391 verify(listener).delivered(any(EventInfo.class),
392 anyListOf(Transformation.class), anyString(), eq(true));
394 verify(transformation).transform(source1);
395 verify(transformation2).transform(source1);
397 verify(destination).receive(same(source2));
402 public void testChooseMultipleDestinationsOneType() {
403 Destination dest1 = registerDestination(true, "any");
404 Destination dest2 = registerDestination(true, "any");
405 registerDocumentType("any");
407 router.publish("source", source1);
408 verify(listener, times(2)).delivered(any(EventInfo.class),
409 anyListOf(Transformation.class), anyString(), eq(true));
411 verify(dest1).receive(same(source1));
412 verify(dest2).receive(same(source1));
416 public void testMultipleDeliveryToOneDestination() {
417 Destination dest = registerDestination(true, "any", "other");
418 registerDocumentType("any", source1);
419 registerDocumentType("other", source2);
420 Transformation transformation = createTransformation("any", "other",
422 routerConfig.transformationConfig().add(transformation);
423 config.setRouterConfig(routerConfig);
425 router.publish("source", source1);
426 verify(listener, times(2)).delivered(any(EventInfo.class),
427 anyListOf(Transformation.class), anyString(), eq(true));
429 verify(dest).receive(same(source1));
430 verify(dest).receive(same(source2));
434 public void testMultipleTransformations() {
435 Destination dest = registerDestination(true, "other");
436 registerDocumentType("any", source1);
437 registerDocumentType("other", source3);
439 Transformation t1 = createTransformation("any", "intermediate",
441 routerConfig.transformationConfig().add(t1);
442 Transformation t2 = createTransformation("intermediate", "other",
444 routerConfig.transformationConfig().add(t2);
445 config.setRouterConfig(routerConfig);
447 router.publish("source", source1);
448 verify(listener).delivered(any(EventInfo.class),
449 anyListOf(Transformation.class), anyString(), eq(true));
451 verify(dest).receive(same(source3));
455 public void testDestinationGivesError() {
456 Destination destination = mock(Destination.class);
457 when(destination.getName()).thenReturn("name");
458 when(destination.chooseFromTargetTypes(anyCollectionOf(String.class)))
459 .thenReturn(Arrays.asList("any"));
460 doThrow(new RuntimeException("x")).when(destination).receive(
461 any(DOMSource.class));
462 router.registerDestination(destination);
464 registerDocumentType("any");
466 router.publish("source", source1);
468 verify(listener).delivered(any(EventInfo.class),
469 anyListOf(Transformation.class), anyString(), eq(false));