1
2
3
4
5
6
7 package org.mule.processor;
8
9 import static org.junit.Assert.assertEquals;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Matchers.argThat;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.timeout;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.when;
18
19 import org.mule.MessageExchangePattern;
20 import org.mule.api.MuleEvent;
21 import org.mule.api.MuleException;
22 import org.mule.api.MuleRuntimeException;
23 import org.mule.api.config.ThreadingProfile;
24 import org.mule.api.exception.MessagingExceptionHandler;
25 import org.mule.api.lifecycle.Initialisable;
26 import org.mule.api.lifecycle.InitialisationException;
27 import org.mule.api.lifecycle.Lifecycle;
28 import org.mule.api.lifecycle.LifecycleState;
29 import org.mule.api.lifecycle.Startable;
30 import org.mule.api.lifecycle.Stoppable;
31 import org.mule.api.processor.MessageProcessor;
32 import org.mule.config.ChainedThreadingProfile;
33 import org.mule.config.QueueProfile;
34 import org.mule.construct.SimpleFlowConstruct;
35 import org.mule.management.stats.QueueStatistics;
36 import org.mule.service.Pausable;
37 import org.mule.util.concurrent.Latch;
38
39 import java.beans.ExceptionListener;
40
41 import javax.resource.spi.work.Work;
42 import javax.resource.spi.work.WorkEvent;
43 import javax.resource.spi.work.WorkException;
44
45 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
46 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
47
48 import org.junit.Test;
49 import org.mockito.ArgumentMatcher;
50 import org.mockito.invocation.InvocationOnMock;
51 import org.mockito.stubbing.Answer;
52
53 public class SedaStageInterceptingMessageProcessorTestCase extends
54 OptionalAsyncInterceptingMessageProcessorTestCase implements ExceptionListener
55 {
56
57 QueueProfile queueProfile = new QueueProfile();
58 int queueTimeout;
59 QueueStatistics queueStatistics;
60 TestLifeCycleState lifeCycleState;
61
62 @Override
63 protected void doSetUp() throws Exception
64 {
65 queueStatistics = new TestQueueStatistics();
66 queueTimeout = muleContext.getConfiguration().getDefaultQueueTimeout();
67 lifeCycleState = new TestLifeCycleState();
68 super.doSetUp();
69 ((Initialisable) messageProcessor).initialise();
70 ((Startable) messageProcessor).start();
71 lifeCycleState.start();
72 }
73
74 @Override
75 protected boolean isStartContext()
76 {
77 return false;
78 }
79
80 @Override
81 protected void doTearDown() throws Exception
82 {
83 super.doTearDown();
84 ((Stoppable) messageProcessor).stop();
85 lifeCycleState.stop();
86 lifeCycleState.dispose();
87
88 }
89
90 @Test
91 public void testProcessOneWayThreadWaitTimeout() throws Exception
92 {
93 final int threadTimeout = 20;
94 ThreadingProfile threadingProfile = new ChainedThreadingProfile(
95 muleContext.getDefaultThreadingProfile());
96 threadingProfile.setThreadWaitTimeout(threadTimeout);
97
98 threadingProfile.setMaxThreadsActive(3);
99 threadingProfile.setPoolExhaustedAction(ThreadingProfile.WHEN_EXHAUSTED_WAIT);
100 threadingProfile.setMuleContext(muleContext);
101
102 MessageProcessor mockListener = mock(MessageProcessor.class);
103 when(mockListener.process((MuleEvent) any())).thenAnswer(new Answer<MuleEvent>()
104 {
105 public MuleEvent answer(InvocationOnMock invocation) throws Throwable
106 {
107 Thread.sleep(threadTimeout * 2);
108 return (MuleEvent) invocation.getArguments()[0];
109 }
110 });
111
112 SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor = new SedaStageInterceptingMessageProcessor(
113 "testProcessOneWayThreadWaitTimeout", queueProfile, queueTimeout, threadingProfile,
114 queueStatistics, muleContext);
115 sedaStageInterceptingMessageProcessor.setListener(mockListener);
116 sedaStageInterceptingMessageProcessor.initialise();
117 sedaStageInterceptingMessageProcessor.start();
118
119 MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
120 SimpleFlowConstruct flow = mock(SimpleFlowConstruct.class);
121 when(flow.getExceptionListener()).thenReturn(exceptionHandler);
122 final MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);
123
124 for (int i = 0; i < 3; i++)
125 {
126 sedaStageInterceptingMessageProcessor.process(event);
127 }
128
129 ArgumentMatcher<MuleEvent> notSameEvent = new ArgumentMatcher<MuleEvent>()
130 {
131 @Override
132 public boolean matches(Object argument)
133 {
134 return !argument.equals(event);
135 }
136 };
137
138
139 verify(mockListener, timeout(RECEIVE_TIMEOUT).times(2)).process(argThat(notSameEvent));
140
141
142 verify(exceptionHandler, timeout(RECEIVE_TIMEOUT).times(1)).handleException((Exception) any(),
143 argThat(notSameEvent));
144
145 }
146
147 @Test
148 public void testProcessOneWayWithException() throws Exception
149 {
150 final Latch latch = new Latch();
151 ThreadingProfile threadingProfile = new ChainedThreadingProfile(
152 muleContext.getDefaultThreadingProfile());
153 threadingProfile.setMuleContext(muleContext);
154
155 MessageProcessor mockListener = mock(MessageProcessor.class);
156 when(mockListener.process((MuleEvent) any())).thenAnswer(new Answer<MuleEvent>()
157 {
158 public MuleEvent answer(InvocationOnMock invocation) throws Throwable
159 {
160 latch.countDown();
161 throw new RuntimeException();
162 }
163 });
164
165 SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor = new SedaStageInterceptingMessageProcessor(
166 "testProcessOneWayWithException", queueProfile, queueTimeout, threadingProfile, queueStatistics,
167 muleContext);
168 sedaStageInterceptingMessageProcessor.setListener(mockListener);
169 sedaStageInterceptingMessageProcessor.initialise();
170 sedaStageInterceptingMessageProcessor.start();
171
172 MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
173 SimpleFlowConstruct flow = mock(SimpleFlowConstruct.class);
174 when(flow.getExceptionListener()).thenReturn(exceptionHandler);
175 final MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);
176
177 sedaStageInterceptingMessageProcessor.process(event);
178
179 assertTrue(latch.await(RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS));
180
181 ArgumentMatcher<MuleEvent> notSameEvent = new ArgumentMatcher<MuleEvent>()
182 {
183 @Override
184 public boolean matches(Object argument)
185 {
186 return !argument.equals(event);
187 }
188 };
189
190
191 verify(mockListener, timeout(RECEIVE_TIMEOUT).times(1)).process(argThat(notSameEvent));
192
193
194 verify(exceptionHandler, timeout(RECEIVE_TIMEOUT).times(1)).handleException((Exception) any(),
195 argThat(notSameEvent));
196
197 }
198
199 @Test(expected = RuntimeException.class)
200 public void testProcessOneWayNoThreadingWithException() throws Exception
201 {
202 ThreadingProfile threadingProfile = new ChainedThreadingProfile(
203 muleContext.getDefaultThreadingProfile());
204 threadingProfile.setDoThreading(false);
205 threadingProfile.setMuleContext(muleContext);
206
207 MessageProcessor mockListener = mock(MessageProcessor.class);
208 when(mockListener.process((MuleEvent) any())).thenThrow(new RuntimeException());
209
210 SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor = new SedaStageInterceptingMessageProcessor(
211 "testProcessOneWayNoThreadingWithException", queueProfile, queueTimeout, threadingProfile,
212 queueStatistics, muleContext);
213 sedaStageInterceptingMessageProcessor.setListener(mockListener);
214 sedaStageInterceptingMessageProcessor.initialise();
215 sedaStageInterceptingMessageProcessor.start();
216
217 MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
218 SimpleFlowConstruct flow = mock(SimpleFlowConstruct.class);
219 when(flow.getExceptionListener()).thenReturn(exceptionHandler);
220 MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);
221
222 sedaStageInterceptingMessageProcessor.process(event);
223 }
224
225 protected AsyncInterceptingMessageProcessor createAsyncInterceptingMessageProcessor(MessageProcessor listener)
226 throws Exception
227 {
228 SedaStageInterceptingMessageProcessor mp = new SedaStageInterceptingMessageProcessor("name",
229 queueProfile, queueTimeout, muleContext.getDefaultThreadingProfile(), queueStatistics,
230 muleContext);
231 mp.setListener(listener);
232 return mp;
233 }
234
235 @Test
236 public void testSpiWorkThrowableHandling() throws Exception
237 {
238 try
239 {
240 new AsyncWorkListener(getSensingNullMessageProcessor()).handleWorkException(getTestWorkEvent(),
241 "workRejected");
242 }
243 catch (MuleRuntimeException mrex)
244 {
245 assertNotNull(mrex);
246 assertTrue(mrex.getCause().getClass() == Throwable.class);
247 assertEquals("testThrowable", mrex.getCause().getMessage());
248 }
249 }
250
251 private WorkEvent getTestWorkEvent()
252 {
253 return new WorkEvent(this,
254 WorkEvent.WORK_REJECTED, getTestWork(), new WorkException(new Throwable("testThrowable")));
255 }
256
257 private Work getTestWork()
258 {
259 return new Work()
260 {
261 public void release()
262 {
263
264 }
265
266 public void run()
267 {
268
269 }
270 };
271 }
272
273 class TestQueueStatistics implements QueueStatistics
274 {
275 int incCount;
276 int decCount;
277
278 public void decQueuedEvent()
279 {
280 decCount++;
281 }
282
283 public void incQueuedEvent()
284 {
285 incCount++;
286 }
287
288 public boolean isEnabled()
289 {
290 return true;
291 }
292 }
293
294 class TestLifeCycleState implements LifecycleState, Lifecycle
295 {
296
297 AtomicBoolean started = new AtomicBoolean(false);
298 AtomicBoolean stopped = new AtomicBoolean(true);
299 AtomicBoolean disposed = new AtomicBoolean(false);
300 AtomicBoolean initialised = new AtomicBoolean(false);
301 AtomicBoolean paused = new AtomicBoolean(false);
302
303 public boolean isDisposed()
304 {
305 return disposed.get();
306 }
307
308 public boolean isDisposing()
309 {
310 return false;
311 }
312
313 public boolean isInitialised()
314 {
315 return initialised.get();
316 }
317
318 public boolean isInitialising()
319 {
320 return false;
321 }
322
323 public boolean isPhaseComplete(String phase)
324 {
325 if (Pausable.PHASE_NAME.equals(phase))
326 {
327 return paused.get();
328 }
329 else
330 {
331 return false;
332 }
333 }
334
335 public boolean isPhaseExecuting(String phase)
336 {
337 return false;
338 }
339
340 public boolean isStarted()
341 {
342 return started.get();
343 }
344
345 public boolean isStarting()
346 {
347 return false;
348 }
349
350 public boolean isStopped()
351 {
352 return stopped.get();
353 }
354
355 public boolean isStopping()
356 {
357 return false;
358 }
359
360 public void initialise() throws InitialisationException
361 {
362 initialised.set(true);
363 }
364
365 public void start() throws MuleException
366 {
367 initialised.set(false);
368 stopped.set(false);
369 started.set(true);
370 }
371
372 public void stop() throws MuleException
373 {
374 started.set(false);
375 stopped.set(true);
376 }
377
378 public void dispose()
379 {
380 stopped.set(true);
381 disposed.set(true);
382 }
383
384 public boolean isValidTransition(String phase)
385 {
386 return false;
387 }
388 }
389
390 }