View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.test.integration.service;
8   
9   import static org.junit.Assert.assertEquals;
10  import static org.junit.Assert.assertTrue;
11  import org.mule.api.MuleContext;
12  import org.mule.api.MuleException;
13  import org.mule.api.service.Service;
14  import org.mule.config.DefaultMuleConfiguration;
15  import org.mule.context.DefaultMuleContextBuilder;
16  import org.mule.tck.junit4.FunctionalTestCase;
17  import org.mule.util.queue.FilePersistenceStrategy;
18  import org.mule.util.queue.QueueManager;
19  import org.mule.util.queue.TransactionalQueueManager;
20  
21  import java.io.File;
22  
23  import org.apache.commons.io.FileUtils;
24  import org.junit.Ignore;
25  import org.junit.Test;
26  
27  public class ServiceInFlightMessagesTestCase extends FunctionalTestCase
28  {
29  
30      protected static final int WAIT_TIME_MILLIS = 500;
31      protected static final int NUM_MESSAGES = 500;
32  
33      @Override
34      protected String getConfigResources()
35      {
36          return "org/mule/test/integration/service/service-inflight-messages.xml";
37      }
38  
39      @Override
40      protected MuleContext createMuleContext() throws Exception
41      {
42          // Use a graceful shutdown but not the full 5s default
43          MuleContext muleContext = super.createMuleContext();
44          ((DefaultMuleConfiguration) muleContext.getConfiguration()).setShutdownTimeout(WAIT_TIME_MILLIS);
45          return muleContext;
46      }
47  
48      @Override
49      protected void doTearDown() throws Exception
50      {
51          FileUtils.deleteDirectory(new File(muleContext.getConfiguration().getWorkingDirectory()));
52          super.doTearDown();
53      }
54  
55      @Test
56      public void testInFlightMessagesWhenServiceStopped() throws Exception
57      {
58          Service service = muleContext.getRegistry().lookupService("TestService");
59          populateSedaQueue(service, NUM_MESSAGES);
60  
61          stopService(service);
62  
63          assertNoLostMessages(NUM_MESSAGES, service);
64          // Seda queue is empty because queue is not persistent and therefore is
65          // emptied when service is stopped
66          assertSedaQueueEmpty(service);
67      }
68  
69      @Test
70      public void testInFlightMessagesPausedServiceWhenServiceStopped() throws Exception
71      {
72          Service service = muleContext.getRegistry().lookupService("PausedTestService");
73          populateSedaQueue(service, NUM_MESSAGES);
74  
75          stopService(service);
76  
77          // The service is paused so no message get processed. Because the service is
78          // stopped messages aren't lost. If Mule was disposed then messages would be
79          // lost
80          assertNoLostMessages(NUM_MESSAGES, service);
81  
82          assertOutboundEmpty();
83      }
84  
85      @Test
86      @Ignore("MULE-6926: flaky test (caused by usage of Thead.sleep)")
87      public void testInFlightMessagesPersistentQueueServiceWhenServiceStopped() throws Exception
88      {
89          Service service = muleContext.getRegistry().lookupService("TestPersistentQueueService");
90  
91          populateSedaQueue(service, NUM_MESSAGES);
92  
93          stopService(service);
94  
95          assertNoLostMessages(NUM_MESSAGES, service);
96  
97          // Start, process some messages, stop and make sure no messages get lost.
98          startService(service);
99          Thread.sleep(WAIT_TIME_MILLIS * 2);
100         stopService(service);
101 
102         assertNoLostMessages(NUM_MESSAGES, service);
103 
104         // Let mule finish up with the rest of the messages until seda queue is empty
105         startService(service);
106         Thread.sleep(WAIT_TIME_MILLIS * 10);
107         stopService(service);
108 
109         assertNoLostMessages(NUM_MESSAGES, service);
110         assertSedaQueueEmpty(service);
111     }
112 
113     @Test
114     @Ignore("MULE-6926: flaky test (caused by usage of Thead.sleep)")
115     public void testInFlightMessagesPausedPersistentQueueServiceWhenServiceStopped() throws Exception
116     {
117         Service service = muleContext.getRegistry().lookupService("PausedTestPersistentQueueService");
118         populateSedaQueue(service, NUM_MESSAGES);
119 
120         stopService(service);
121 
122         // Paused service does not process messages before or during stop().
123         assertOutboundEmpty();
124         assertNoLostMessages(NUM_MESSAGES, service);
125 
126         // Start, process some messages, stop and make sure no messages get lost.
127         startService(service);
128         service.resume();
129         Thread.sleep(WAIT_TIME_MILLIS * 2);
130         stopService(service);
131 
132         assertNoLostMessages(NUM_MESSAGES, service);
133 
134         // Let mule finish up with the rest of the messages until seda queue is empty
135         startService(service);
136         service.resume();
137         Thread.sleep(WAIT_TIME_MILLIS * 10);
138         stopService(service);
139 
140         assertNoLostMessages(NUM_MESSAGES, service);
141         assertSedaQueueEmpty(service);
142     }
143 
144     @Test
145     @Ignore("MULE-6926: flaky test (caused by usage of Thead.sleep)")
146     public void testInFlightMessagesPersistentQueueServiceWhenMuleDisposed() throws Exception
147     {
148         Service service = muleContext.getRegistry().lookupService("TestPersistentQueueService");
149         populateSedaQueue(service, NUM_MESSAGES);
150 
151         muleContext.dispose();
152 
153         assertNoLostMessages(NUM_MESSAGES, service);
154 
155         recreateAndStartMuleContext();
156         Thread.sleep(WAIT_TIME_MILLIS);
157         muleContext.dispose();
158 
159         assertNoLostMessages(NUM_MESSAGES, service);
160 
161         // Let mule finish up with the rest of the messages until seda queue is empty
162         recreateAndStartMuleContext();
163         Thread.sleep(WAIT_TIME_MILLIS * 10);
164         muleContext.dispose();
165 
166         assertNoLostMessages(NUM_MESSAGES, service);
167         assertSedaQueueEmpty(service);
168     }
169 
170     protected void recreateAndStartMuleContext() throws Exception, MuleException
171     {
172         muleContext = createMuleContext();
173         muleContext.start();
174     }
175 
176     protected void populateSedaQueue(Service service, int numMessages) throws MuleException, Exception
177     {
178         for (int i = 0; i < numMessages; i++)
179         {
180             service.dispatchEvent(getTestEvent("test", service, muleContext.getEndpointFactory()
181                 .getInboundEndpoint("test://test")));
182         }
183     }
184 
185     /**
186      * After each run the following should total 500 events: 1) Event still in SEDA
187      * queue 2) Events dispatched to outbound vm endpooint 3) Events that were unable
188      * to be sent to stopped service and raised exceptions
189      * 
190      * @throws Exception
191      */
192     protected synchronized void assertNoLostMessages(int numMessages, Service service) throws Exception
193     {
194         logger.info("SEDA Queue: " + getSedaQueueSize(service) + ", Outbound endpoint: "
195                     + getOutSize());
196         assertEquals(numMessages, getOutSize() + getSedaQueueSize(service));
197     }
198 
199     protected synchronized void assertSedaQueueEmpty(Service service) throws MuleException
200     {
201         assertEquals(0, getSedaQueueSize(service));
202     }
203 
204     protected synchronized void assertSedaQueueNotEmpty(Service service) throws MuleException
205     {
206         assertTrue(String.format("Seda queue for service '%s' is empty", service.getName()),
207             getSedaQueueSize(service) > 0);
208     }
209 
210     protected synchronized void assertOutboundEmpty() throws Exception
211     {
212         assertEquals(0, getOutSize());
213     }
214 
215     protected synchronized void assertOutboundNotEmpty() throws Exception
216     {
217         assertTrue("VM Out queue is empty", getOutSize() > 0);
218     }
219 
220     protected int getSedaQueueSize(Service service) throws MuleException
221     {
222         return getQueueSize(getSedaQueueName(service));
223     }
224 
225     protected String getSedaQueueName(Service service)
226     {
227         return "seda.queue(" + service.getName() + ")";
228     }
229 
230     protected int getOutSize() throws Exception
231     {
232         return getQueueSize("out");
233     }
234 
235     protected int getQueueSize(String name) throws MuleException
236     {
237         if (muleContext != null && muleContext.isStarted())
238         {
239             return muleContext.getQueueManager().getQueueSession().getQueue(name).size();
240         }
241         else
242         {
243             MuleContext localMuleContext = new DefaultMuleContextBuilder().buildMuleContext();
244             QueueManager queueManager = new TransactionalQueueManager();
245             FilePersistenceStrategy persistenceStrategy = new FilePersistenceStrategy();
246             persistenceStrategy.setMuleContext(localMuleContext);
247             queueManager.setPersistenceStrategy(persistenceStrategy);
248             queueManager.start();
249             int size = queueManager.getQueueSession().getQueue(name).size();
250             queueManager.stop();
251             localMuleContext = null;
252             return size;
253         }
254     }
255 
256     protected void stopService(Service service) throws Exception
257     {
258         service.stop();
259         muleContext.getRegistry().lookupConnector("outPersistentConnector").stop();
260     }
261 
262     protected void startService(Service service) throws Exception
263     {
264         muleContext.getRegistry().lookupConnector("outPersistentConnector").start();
265         service.start();
266     }
267 
268 }