View Javadoc

1   /*
2    * $Id: DispatcherThreadingProfileTestCase.java 20385 2010-11-29 20:25:26Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleException;
15  import org.mule.api.config.ThreadingProfile;
16  import org.mule.api.endpoint.OutboundEndpoint;
17  import org.mule.api.transport.DispatchException;
18  import org.mule.api.transport.MessageDispatcher;
19  import org.mule.config.ImmutableThreadingProfile;
20  import org.mule.tck.AbstractMuleTestCase;
21  import org.mule.tck.testmodels.mule.TestConnector;
22  import org.mule.tck.testmodels.mule.TestMessageDispatcher;
23  import org.mule.tck.testmodels.mule.TestMessageDispatcherFactory;
24  
25  import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
26  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
27  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
28  
29  /**
30   * This test case tests the both dispatcher threading profile and it's rejection
31   * handlers and AbstractConnector dispatch logic by dispatch events using
32   * TestConnector with varying threading profile configurations and asserting the
33   * correct outcome. See: MULE-4752
34   */
35  public class DispatcherThreadingProfileTestCase extends AbstractMuleTestCase
36  {
37  
38      public static int DELAY_TIME = 500;
39      public static int WAIT_TIME = DELAY_TIME + DELAY_TIME / 4;
40      public static int SERIAL_WAIT_TIME = (DELAY_TIME * 2) + DELAY_TIME / 4;
41      public static int LONGER_WAIT_TIME = DELAY_TIME * 5;
42      private CountDownLatch latch;
43      private AtomicInteger counter = new AtomicInteger();
44  
45      public DispatcherThreadingProfileTestCase()
46      {
47          setStartContext(true);
48      }
49  
50      @Override
51      protected void doTearDown() throws Exception
52      {
53          super.doTearDown();
54          counter.set(0);
55      }
56  
57      public void testDefaultThreadingProfileConfiguration() throws MuleException
58      {
59          TestConnector connector = new TestConnector(muleContext);
60          muleContext.getRegistry().registerConnector(connector);
61          assertEquals(ThreadingProfile.DEFAULT_MAX_THREADS_ACTIVE, connector.getDispatcherThreadingProfile()
62              .getMaxThreadsActive());
63          assertEquals(ThreadingProfile.DEFAULT_MAX_THREADS_IDLE, connector.getDispatcherThreadingProfile()
64              .getMaxThreadsIdle());
65          assertEquals(ThreadingProfile.WHEN_EXHAUSTED_RUN, connector.getDispatcherThreadingProfile()
66              .getPoolExhaustedAction());
67          assertEquals(ThreadingProfile.DEFAULT_MAX_BUFFER_SIZE, connector.getDispatcherThreadingProfile()
68              .getMaxBufferSize());
69          assertEquals(ThreadingProfile.DEFAULT_MAX_THREAD_TTL, connector.getDispatcherThreadingProfile()
70              .getThreadTTL());
71          assertEquals(ThreadingProfile.DEFAULT_THREAD_WAIT_TIMEOUT, connector.getDispatcherThreadingProfile()
72              .getThreadWaitTimeout());
73      }
74  
75      public void testDefaultRunExhaustedAction() throws Exception
76      {
77          // Default is RUN.
78          // To concurrent dispatch operations are possible even with
79          // maxActiveThreads=1.
80          // Note: This also tests the fact with RUN here, the dispatcher pool needs to
81          // GROW on demand.
82          latch = new CountDownLatch(2);
83  
84          createTestConnectorWithSingleDispatcherThread(ThreadingProfile.WHEN_EXHAUSTED_RUN);
85          dispatchTwoAsyncEvents();
86  
87          // Both execute complete at the same time and finish shortly after DELAY_TIME
88          assertTrue(latch.await(WAIT_TIME, TimeUnit.MILLISECONDS));
89      }
90  
91      public void testWaitExhaustedAction() throws Exception
92      {
93          // Second job waits in workQueue for first job to complete.
94          latch = new CountDownLatch(2);
95  
96          createTestConnectorWithSingleDispatcherThread(1, ThreadingProfile.WHEN_EXHAUSTED_WAIT,
97              ThreadingProfile.DEFAULT_THREAD_WAIT_TIMEOUT, ThreadingProfile.DEFAULT_MAX_BUFFER_SIZE);
98          dispatchTwoAsyncEvents();
99  
100         // Both execute in serial as the second job wait for the fist job to complete
101         assertTrue(latch.await(SERIAL_WAIT_TIME, TimeUnit.MILLISECONDS));
102     }
103 
104     public void testWaitTimeoutExhaustedAction() throws Exception
105     {
106         // Second job attempts to wait in workQueue but waiting job times out/
107         latch = new CountDownLatch(1);
108 
109         createTestConnectorWithSingleDispatcherThread(ThreadingProfile.WHEN_EXHAUSTED_WAIT);
110         dispatchTwoAsyncEvents();
111 
112         // The job that executes finishes shortly after DELAY_TIME
113         assertTrue(latch.await(WAIT_TIME, TimeUnit.MILLISECONDS));
114 
115         // Wait even longer and ensure the other message isn't executed.
116         Thread.sleep(LONGER_WAIT_TIME);
117         assertEquals(1, counter.get());
118     }
119 
120     public void testAbortExhaustedAction() throws Exception
121     {
122         // Second job is aborted
123         latch = new CountDownLatch(1);
124 
125         createTestConnectorWithSingleDispatcherThread(ThreadingProfile.WHEN_EXHAUSTED_ABORT);
126         dispatchTwoAsyncEvents();
127 
128         // The job that executes finishes shortly after DELAY_TIME
129         assertTrue(latch.await(WAIT_TIME, TimeUnit.MILLISECONDS));
130 
131         // Wait even longer and ensure the other message isn't executed.
132         Thread.sleep(LONGER_WAIT_TIME);
133         assertEquals(1, counter.get());
134     }
135 
136     public void testDiscardExhaustedAction() throws Exception
137     {
138         // Second job is discarded
139         latch = new CountDownLatch(1);
140 
141         createTestConnectorWithSingleDispatcherThread(ThreadingProfile.WHEN_EXHAUSTED_DISCARD);
142         dispatchTwoAsyncEvents();
143 
144         // The job that executes finishes shortly after DELAY_TIME
145         assertTrue(latch.await(WAIT_TIME, TimeUnit.MILLISECONDS));
146 
147         // Wait even longer and ensure the other message isn't executed.
148         Thread.sleep(LONGER_WAIT_TIME);
149         assertEquals(1, counter.get());
150     }
151 
152     public void testDiscardOldestExhaustedAction() throws Exception
153     {
154         // The third job is discarded when the fourth job is submitted
155         // The fourth job (now third) is discarded when the fifth job is submitted.
156         // The fifth job (now third) is discarded when the sixth job is submitted.
157         // Therefore the first, second and sixth jobs are run
158         latch = new CountDownLatch(3);
159 
160         // In order for a LinkedBlockingDeque to be used rather than a
161         // SynchronousQueue there need to be
162         // i) 2+ maxActiveThreads ii) maxBufferSize>0
163         createTestConnectorWithSingleDispatcherThread(2, ThreadingProfile.WHEN_EXHAUSTED_DISCARD_OLDEST,
164             ThreadingProfile.DEFAULT_THREAD_WAIT_TIMEOUT, 1);
165 
166         dispatchTwoAsyncEvents();
167         dispatchTwoAsyncEvents();
168         dispatchTwoAsyncEvents();
169 
170         assertTrue(latch.await(SERIAL_WAIT_TIME, TimeUnit.MILLISECONDS));
171         Thread.sleep(LONGER_WAIT_TIME);
172         assertEquals(3, counter.get());
173     }
174 
175     protected void createTestConnectorWithSingleDispatcherThread(int exhaustedAction) throws MuleException
176     {
177         createTestConnectorWithSingleDispatcherThread(1, exhaustedAction, 1, 1);
178     }
179 
180     protected void createTestConnectorWithSingleDispatcherThread(int threads,
181                                                                  int exhaustedAction,
182                                                                  long waitTimeout,
183                                                                  int maxBufferSize) throws MuleException
184     {
185         TestConnector connector = new TestConnector(muleContext);
186         ThreadingProfile threadingProfile = new ImmutableThreadingProfile(threads, threads, maxBufferSize,
187             ThreadingProfile.DEFAULT_MAX_THREAD_TTL, waitTimeout, exhaustedAction, true, null, null);
188         threadingProfile.setMuleContext(muleContext);
189         connector.setDispatcherThreadingProfile(threadingProfile);
190         muleContext.getRegistry().registerConnector(connector);
191         connector.setDispatcherFactory(new DelayTestMessageDispatcherFactory());
192     }
193 
194     private void dispatchTwoAsyncEvents() throws DispatchException, Exception
195     {
196         OutboundEndpoint endpoint = muleContext.getEndpointFactory().getOutboundEndpoint(
197             "test://test");
198         endpoint.process(getTestEvent("data", endpoint));
199         endpoint.process(getTestEvent("data", endpoint));
200     }
201 
202     public class DelayTestMessageDispatcher extends TestMessageDispatcher
203     {
204         public DelayTestMessageDispatcher(OutboundEndpoint endpoint)
205         {
206             super(endpoint);
207         }
208 
209         @Override
210         protected void doDispatch(MuleEvent event) throws Exception
211         {
212             super.doDispatch(event);
213             Thread.sleep(DELAY_TIME);
214             counter.incrementAndGet();
215             latch.countDown();
216         }
217     }
218 
219     class DelayTestMessageDispatcherFactory extends TestMessageDispatcherFactory
220     {
221         @Override
222         public MessageDispatcher create(OutboundEndpoint endpoint) throws MuleException
223         {
224             return new DelayTestMessageDispatcher(endpoint);
225         }
226     }
227 
228 }