View Javadoc

1   /*
2    * $Id: AbstractMuleTestCase.java 20082 2010-11-05 07:37:40Z dirk.olmes $
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.tck;
12  
13  import org.mule.MessageExchangePattern;
14  import org.mule.RequestContext;
15  import org.mule.api.MuleContext;
16  import org.mule.api.MuleEvent;
17  import org.mule.api.MuleEventContext;
18  import org.mule.api.MuleSession;
19  import org.mule.api.config.ConfigurationBuilder;
20  import org.mule.api.context.MuleContextBuilder;
21  import org.mule.api.context.MuleContextFactory;
22  import org.mule.api.context.notification.MuleContextNotificationListener;
23  import org.mule.api.endpoint.ImmutableEndpoint;
24  import org.mule.api.endpoint.InboundEndpoint;
25  import org.mule.api.endpoint.OutboundEndpoint;
26  import org.mule.api.processor.MessageProcessor;
27  import org.mule.api.registry.RegistrationException;
28  import org.mule.api.routing.filter.Filter;
29  import org.mule.api.service.Service;
30  import org.mule.api.transformer.Transformer;
31  import org.mule.api.transport.Connector;
32  import org.mule.config.DefaultMuleConfiguration;
33  import org.mule.config.builders.DefaultsConfigurationBuilder;
34  import org.mule.config.builders.SimpleConfigurationBuilder;
35  import org.mule.context.DefaultMuleContextBuilder;
36  import org.mule.context.DefaultMuleContextFactory;
37  import org.mule.context.notification.MuleContextNotification;
38  import org.mule.tck.testmodels.mule.TestConnector;
39  import org.mule.util.ClassUtils;
40  import org.mule.util.FileUtils;
41  import org.mule.util.IOUtils;
42  import org.mule.util.MuleUrlStreamHandlerFactory;
43  import org.mule.util.StringMessageUtils;
44  import org.mule.util.StringUtils;
45  import org.mule.util.SystemUtils;
46  import org.mule.util.concurrent.Latch;
47  
48  import java.io.IOException;
49  import java.io.InputStream;
50  import java.net.ServerSocket;
51  import java.net.URL;
52  import java.net.URLClassLoader;
53  import java.util.ArrayList;
54  import java.util.Collections;
55  import java.util.HashMap;
56  import java.util.HashSet;
57  import java.util.Iterator;
58  import java.util.List;
59  import java.util.Map;
60  import java.util.Properties;
61  import java.util.Set;
62  import java.util.concurrent.atomic.AtomicReference;
63  
64  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
65  import junit.framework.TestCase;
66  import junit.framework.TestResult;
67  import org.apache.commons.collections.IteratorUtils;
68  import org.apache.commons.collections.Predicate;
69  import org.apache.commons.logging.Log;
70  import org.apache.commons.logging.LogFactory;
71  
72  /**
73   * <code>AbstractMuleTestCase</code> is a base class for Mule testcases. This
74   * implementation provides services to test code for creating mock and test objects.
75   */
76  public abstract class AbstractMuleTestCase extends TestCase implements TestCaseWatchdogTimeoutHandler
77  {
78  
79      /**
80       * Top-level directories under <code>.mule</code> which are not deleted on each
81       * test case recycle. This is required, e.g. to play nice with transaction manager
82       * recovery service object store.
83       */
84      public static final String[] IGNORED_DOT_MULE_DIRS = new String[]{"transaction-log"};
85  
86      /**
87       * Name of a property to override the default test watchdog timeout.
88       *
89       * @see #DEFAULT_MULE_TEST_TIMEOUT_SECS
90       */
91      public static final String PROPERTY_MULE_TEST_TIMEOUT = "mule.test.timeoutSecs";
92  
93      /**
94       * Default test watchdog timeout in seconds.
95       */
96      public static final int DEFAULT_MULE_TEST_TIMEOUT_SECS = 60;
97  
98      /**
99       * If the annotations module is on the classpath, also enable annotations config builder
100      */
101     public static final String CLASSNAME_ANNOTATIONS_CONFIG_BUILDER = "org.mule.config.AnnotationsConfigurationBuilder";
102 
103 
104     protected static MuleContext muleContext;
105 
106     /**
107      * This flag controls whether the text boxes will be logged when starting each test case.
108      */
109     private static final boolean verbose;
110 
111     // A Map of test case extension objects. JUnit creates a new TestCase instance for
112     // every method, so we need to record metainfo outside the test.
113     private static final Map<String, TestInfo> testInfos = Collections.synchronizedMap(new HashMap<String, TestInfo>());
114 
115     // A logger that should be suitable for most test cases.
116     protected final transient Log logger = LogFactory.getLog(this.getClass());
117 
118     /**
119      * Start the muleContext once it's configured (defaults to false for AbstractMuleTestCase, true for FunctionalTestCase).
120      */
121     private boolean startContext = false;
122 
123     // Should be set to a string message describing any prerequisites not met.
124     private boolean offline = "true".equalsIgnoreCase(System.getProperty("org.mule.offline"));
125 
126     // Barks if the test exceeds its time limit
127     private TestCaseWatchdog watchdog;
128 
129     protected int numPorts = 0;
130     
131     public List<Integer> ports = null;    
132 
133     final static private int MIN_PORT = 5000;
134     final static private int MAX_PORT = 6000;    
135     
136     static
137     {
138         String muleOpts = SystemUtils.getenv("MULE_TEST_OPTS");
139         if (StringUtils.isNotBlank(muleOpts))
140         {
141             Map<String, String> parsedOpts = SystemUtils.parsePropertyDefinitions(muleOpts);
142             String optVerbose = parsedOpts.get("mule.verbose");
143             verbose = Boolean.valueOf(optVerbose);
144         }
145         else
146         {
147             // per default, revert to the old behaviour
148             verbose = true;
149         }
150 
151         // register the custom UrlStreamHandlerFactory.
152         MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory();
153     }
154 
155     /**
156      * Convenient test message for unit testing.
157      */
158     public static final String TEST_MESSAGE = "Test Message";
159 
160     /**
161      * Default timeout for multithreaded tests (using CountDownLatch, WaitableBoolean, etc.),
162      * in milliseconds.  The higher this value, the more reliable the test will be, so it
163      * should be set high for Continuous Integration.  However, this can waste time during
164      * day-to-day development cycles, so you may want to temporarily lower it while debugging.
165      */
166     public static final long LOCK_TIMEOUT = 30000;
167 
168     /**
169      * Default timeout for waiting for responses
170      */
171     public static final int RECEIVE_TIMEOUT = 5000;
172 
173     /**
174      * Use this as a semaphore to the unit test to indicate when a callback has successfully been called.
175      */
176     protected Latch callbackCalled;
177 
178     /**
179      * Timeout used for the test watchdog
180      */
181     protected int testTimeoutSecs = DEFAULT_MULE_TEST_TIMEOUT_SECS;
182 
183     /**
184      * When a test case depends on a 3rd-party resource such as a public web service,
185      * it may be desirable to not fail the test upon timeout but rather to simply log
186      * a warning.
187      */
188     private boolean failOnTimeout = true;
189 
190     /**
191      * This is just a reference to the main thread running the current thread. It is
192      * set in the {@link #setUp()} method.
193      */
194     private volatile Thread currentTestRunningThread;
195 
196     public AbstractMuleTestCase()
197     {
198         super();
199 
200         TestInfo info = getTestInfo();
201         if (info == null)
202         {
203             info = this.createTestInfo();
204             testInfos.put(getClass().getName(), info);
205         }
206         registerTestMethod();
207         initTestTimeoutSecs();
208     }
209 
210     protected void registerTestMethod()
211     {
212         if (this.getName() != null)
213         {
214             this.getTestInfo().incTestCount(getName());
215         }
216     }
217 
218     protected void initTestTimeoutSecs()
219     {
220         String timeoutString = System.getProperty(PROPERTY_MULE_TEST_TIMEOUT, null);
221         if (timeoutString == null)
222         {
223             // unix style: MULE_TEST_TIMEOUTSECS
224             String variableName = PROPERTY_MULE_TEST_TIMEOUT.toUpperCase().replace(".", "_");
225             timeoutString = System.getenv(variableName);
226         }
227 
228         if (timeoutString != null)
229         {
230             try
231             {
232                 testTimeoutSecs = Integer.parseInt(timeoutString);
233             }
234             catch (NumberFormatException nfe)
235             {
236                 // the default still applies
237             }
238         }
239     }
240 
241     @Override
242     public void setName(String name)
243     {
244         super.setName(name);
245         registerTestMethod();
246     }
247 
248     protected TestInfo createTestInfo()
249     {
250         return new TestInfo(this);
251     }
252 
253     protected TestInfo getTestInfo()
254     {
255         return testInfos.get(this.getClass().getName());
256     }
257 
258     private void clearInfo()
259     {
260         testInfos.remove(this.getClass().getName());
261     }
262 
263     @Override
264     public void run(TestResult result)
265     {
266         if (this.isExcluded())
267         {
268             if (verbose)
269             {
270                 logger.info(this.getClass().getName() + " excluded");
271             }
272             return;
273         }
274 
275         if (this.isDisabledInThisEnvironment())
276         {
277             if (verbose)
278             {
279                 logger.info(this.getClass().getName() + " disabled");
280             }
281             return;
282         }
283 
284         super.run(result);
285     }
286 
287     /**
288      * Shamelessly copy from Spring's ConditionalTestCase so in MULE-2.0 we can extend
289      * this class from ConditionalTestCase.
290      * <p/>
291      * Subclasses can override <code>isDisabledInThisEnvironment</code> to skip a single test.
292      */
293     @Override
294     public void runBare() throws Throwable
295     {
296         // getName will return the name of the method being run. Use the real JUnit implementation,
297         // this class has a different implementation
298         if (this.isDisabledInThisEnvironment(super.getName()))
299         {
300             logger.warn(this.getClass().getName() + "." + super.getName() + " disabled in this environment");
301             return;
302         }
303 
304         // Let JUnit handle execution
305         super.runBare();
306     }
307 
308     /**
309      * Subclasses can override this method to skip the execution of the entire test class.
310      *
311      * @return <code>true</code> if the test class should not be run.
312      */
313     protected boolean isDisabledInThisEnvironment()
314     {
315         return false;
316     }
317 
318     /**
319      * Indicates whether this test has been explicitly disabled through the configuration
320      * file loaded by TestInfo.
321      *
322      * @return whether the test has been explicitly disabled
323      */
324     protected boolean isExcluded()
325     {
326         return getTestInfo().isExcluded();
327     }
328 
329     /**
330      * Should this test run?
331      *
332      * @param testMethodName name of the test method
333      * @return whether the test should execute in the current envionment
334      */
335     protected boolean isDisabledInThisEnvironment(String testMethodName)
336     {
337         return false;
338     }
339 
340     public boolean isOffline(String method)
341     {
342         if (offline)
343         {
344             logger.warn(StringMessageUtils.getBoilerPlate(
345                     "Working offline cannot run test: " + method, '=', 80));
346         }
347         return offline;
348     }
349 
350     protected boolean isDisposeManagerPerSuite()
351     {
352         return getTestInfo().isDisposeManagerPerSuite();
353     }
354 
355     protected void setDisposeManagerPerSuite(boolean val)
356     {
357         getTestInfo().setDisposeManagerPerSuite(val);
358     }
359 
360     public int getTestTimeoutSecs()
361     {
362         return testTimeoutSecs;
363     }
364 
365     protected TestCaseWatchdog createWatchdog()
366     {
367         return new TestCaseWatchdog(testTimeoutSecs, TimeUnit.SECONDS, this);
368     }
369 
370     public void handleTimeout(long timeout, TimeUnit unit)
371     {
372         String msg = "Timeout of " + unit.toMillis(timeout) + "ms exceeded (modify via -Dmule.test.timeoutSecs=XX)";
373 
374         if (failOnTimeout)
375         {
376             logger.fatal(msg + " - Attempting to interrupt thread for test " + this.getName());
377             if (currentTestRunningThread != null)
378             {
379                 currentTestRunningThread.interrupt();
380             }
381             giveTheTestSomeTimeToCleanUpAndThenKillIt("Interrupting didn't work. Killing the VM!. Test "
382                                                       + this.getName() + " did not finish correctly.");
383         }
384         else
385         {
386             logger.warn(msg);
387         }
388     }
389 
390     protected void giveTheTestSomeTimeToCleanUpAndThenKillIt(String messageIfNeedToKill)
391     {
392         try
393         {
394             Thread.sleep(5000);
395             logger.fatal(messageIfNeedToKill);
396             Runtime.getRuntime().halt(1);
397         }
398         catch (InterruptedException e)
399         {
400             logger.info(
401                 "Test thread has been interrupted, probably bt the call to watchdog.cancel() in teardown method.",
402                 e);
403         }
404     }
405 
406     /**
407      * Normal JUnit method
408      *
409      * @throws Exception
410      * @see #doSetUp()
411      */
412     @Override
413     protected final void setUp() throws Exception
414     {
415         // start a watchdog thread
416         watchdog = createWatchdog();
417         watchdog.start();
418        
419         // set up the free ports
420         if (numPorts > 0)
421         {
422             //find some free ports
423             ports = findFreePorts(numPorts);
424 
425             //set the port properties
426             setPortProperties();
427         }                
428         
429         currentTestRunningThread = Thread.currentThread();
430 
431         if (verbose)
432         {
433             System.out.println(StringMessageUtils.getBoilerPlate("Testing: " + getName(), '=', 80));
434         }
435 
436         try
437         {
438             if (getTestInfo().getRunCount() == 0)
439             {
440                 if (getTestInfo().isDisposeManagerPerSuite())
441                 {
442                     // We dispose here jut in case
443                     disposeManager();
444                 }
445                 suitePreSetUp();
446             }
447             if (!getTestInfo().isDisposeManagerPerSuite())
448             {
449                 // We dispose here just in case
450                 disposeManager();
451             }
452             
453             muleContext = createMuleContext();
454 
455             // wait for Mule to fully start when requested (default)
456 
457             // latch ref needs to be final for listener use, wrap in atomic ref
458             final AtomicReference<Latch> contextStartedLatch = new AtomicReference<Latch>();
459             if (isStartContext() && null != muleContext && muleContext.isStarted() == false)
460             {
461                 contextStartedLatch.set(new Latch());
462                 muleContext.registerListener(new MuleContextNotificationListener<MuleContextNotification>()
463                 {
464                     public void onNotification(MuleContextNotification notification)
465                     {
466                         if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED)
467                         {
468                             contextStartedLatch.get().countDown();
469                         }
470                     }
471                 });
472                 muleContext.start();
473             }
474 
475             // if it's null, than
476             if (contextStartedLatch.get() != null)
477             {
478                 // wait no more than 20 secs
479                 contextStartedLatch.get().await(20, TimeUnit.SECONDS);
480             }
481             doSetUp();
482         }
483         catch (Exception e)
484         {
485             getTestInfo().incRunCount();
486             throw e;
487         }
488     }
489 
490     protected MuleContext createMuleContext() throws Exception
491     {
492         // Should we set up the manager for every method?
493         MuleContext context;
494         if (getTestInfo().isDisposeManagerPerSuite() && muleContext != null)
495         {
496             context = muleContext;
497         }
498         else
499         {
500             MuleContextFactory muleContextFactory = new DefaultMuleContextFactory();
501             List<ConfigurationBuilder> builders = new ArrayList<ConfigurationBuilder>();
502             builders.add(new SimpleConfigurationBuilder(getStartUpProperties()));
503             //If the annotations module is on the classpath, add the annotations config builder to the list
504             //This will enable annotations config for this instance
505             if (ClassUtils.isClassOnPath(CLASSNAME_ANNOTATIONS_CONFIG_BUILDER, getClass()))
506             {
507                 builders.add((ConfigurationBuilder) ClassUtils.instanciateClass(CLASSNAME_ANNOTATIONS_CONFIG_BUILDER,
508                         ClassUtils.NO_ARGS, getClass()));
509             }
510             builders.add(getBuilder());
511             addBuilders(builders);
512             MuleContextBuilder contextBuilder = new DefaultMuleContextBuilder();
513             configureMuleContext(contextBuilder);
514             context = muleContextFactory.createMuleContext(builders, contextBuilder);
515             if (!isGracefulShutdown())
516             {
517                 ((DefaultMuleConfiguration) context.getConfiguration()).setShutdownTimeout(0);
518             }
519         }
520         return context;
521     }
522 
523     //This sohuldn't be needed by Test cases but can be used by base testcases that wish to add further builders when
524     //creating the MuleContext.
525 
526     protected void addBuilders(List<ConfigurationBuilder> builders)
527     {
528         //No op
529     }
530 
531     /**
532      * Override this method to set properties of the MuleContextBuilder before it is
533      * used to create the MuleContext.
534      */
535     protected void configureMuleContext(MuleContextBuilder contextBuilder)
536     {
537         contextBuilder.setWorkListener(new TestingWorkListener());
538     }
539 
540     protected ConfigurationBuilder getBuilder() throws Exception
541     {
542         return new DefaultsConfigurationBuilder();
543     }
544 
545     protected String getConfigurationResources()
546     {
547         return StringUtils.EMPTY;
548     }
549 
550     protected Properties getStartUpProperties()
551     {
552         return null;
553     }
554 
555     /**
556      * Run <strong>before</strong> any testcase setup.
557      * This is called once only before the test suite runs.
558      */
559     protected void suitePreSetUp() throws Exception
560     {
561         // nothing to do
562     }
563 
564     /**
565      * Run <strong>after</strong> all testcase teardowns.
566      * This is called once only after all the tests in the suite have run.
567      */
568     protected void suitePostTearDown() throws Exception
569     {
570         // nothing to do
571     }
572 
573     /**
574      * Normal JUnit method
575      *
576      * @throws Exception
577      * @see #doTearDown()
578      */
579     @Override
580     protected final void tearDown() throws Exception
581     {
582         try
583         {
584             doTearDown();
585 
586             if (!getTestInfo().isDisposeManagerPerSuite())
587             {
588                 disposeManager();
589             }
590         }
591         finally
592         {
593             try
594             {
595                 getTestInfo().incRunCount();
596                 if (getTestInfo().getRunCount() == getTestInfo().getTestCount())
597                 {
598                     try
599                     {
600                         suitePostTearDown();
601                     }
602                     finally
603                     {
604                         clearInfo();
605                         disposeManager();
606                     }
607                 }
608             }
609             finally
610             {
611                 // remove the watchdog thread in any case
612                 watchdog.cancel();
613             }
614         }
615     }
616 
617     protected void disposeManager()
618     {
619         try
620         {
621             if (muleContext != null && !(muleContext.isDisposed() || muleContext.isDisposing()))
622             {
623                 muleContext.dispose();
624 
625                 final String workingDir = muleContext.getConfiguration().getWorkingDirectory();
626                 // do not delete TM recovery object store, everything else is good to
627                 // go
628                 FileUtils.deleteTree(FileUtils.newFile(workingDir), IGNORED_DOT_MULE_DIRS);
629             }
630             FileUtils.deleteTree(FileUtils.newFile("./ActiveMQ"));
631         }
632         finally
633         {
634             muleContext = null;
635         }
636     }
637 
638     /**
639      * Exactly the same a {@link #setUp()} in normal JUnit test cases.  this is called <strong>before</strong> a test
640      * method has been called.
641      *
642      * @throws Exception if something fails that should halt the testcase
643      */
644     protected void doSetUp() throws Exception
645     {
646         // template method
647     }
648 
649     /**
650      * Exactly the same a {@link #tearDown()} in normal JUnit test cases.  this is called <strong>after</strong> a test
651      * method has been called.
652      *
653      * @throws Exception if something fails that should halt the testcase
654      */
655     protected void doTearDown() throws Exception
656     {
657         RequestContext.clear();
658     }
659 
660     public static InboundEndpoint getTestInboundEndpoint(String name) throws Exception
661     {
662         return MuleTestUtils.getTestInboundEndpoint(name, muleContext);
663     }
664 
665     public static OutboundEndpoint getTestOutboundEndpoint(String name) throws Exception
666     {
667         return MuleTestUtils.getTestOutboundEndpoint(name, muleContext);
668     }
669 
670     public static InboundEndpoint getTestInboundEndpoint(MessageExchangePattern mep) throws Exception
671     {
672         return MuleTestUtils.getTestInboundEndpoint(mep, muleContext);
673     }
674 
675     public static InboundEndpoint getTestTransactedInboundEndpoint(MessageExchangePattern mep) throws Exception
676     {
677         return MuleTestUtils.getTestTransactedInboundEndpoint(mep, muleContext);
678     }
679 
680     public static InboundEndpoint getTestInboundEndpoint(String name, String uri) throws Exception
681     {
682         return MuleTestUtils.getTestInboundEndpoint(name, muleContext, uri, null, null, null, null);
683     }
684 
685     public static OutboundEndpoint getTestOutboundEndpoint(String name, String uri) throws Exception
686     {
687         return MuleTestUtils.getTestOutboundEndpoint(name, muleContext, uri, null, null, null);
688     }
689 
690     public static InboundEndpoint getTestInboundEndpoint(String name, List<Transformer> transformers) throws Exception
691     {
692         return MuleTestUtils.getTestInboundEndpoint(name, muleContext, null, transformers, null, null, null);
693     }
694 
695     public static OutboundEndpoint getTestOutboundEndpoint(String name, List<Transformer> transformers) throws Exception
696     {
697         return MuleTestUtils.getTestOutboundEndpoint(name, muleContext, null, transformers, null, null);
698     }
699 
700     public static InboundEndpoint getTestInboundEndpoint(String name, String uri, 
701         List<Transformer> transformers, Filter filter, Map<Object, Object> properties, Connector connector) throws Exception
702     {
703         return MuleTestUtils.getTestInboundEndpoint(name, muleContext, uri, transformers, filter, properties, connector);
704     }
705 
706     public static OutboundEndpoint getTestOutboundEndpoint(String name, String uri, 
707         List<Transformer> transformers, Filter filter, Map<Object, Object> properties) throws Exception
708     {
709         return MuleTestUtils.getTestOutboundEndpoint(name, muleContext, uri, transformers, filter, properties);
710     }
711 
712     public static OutboundEndpoint getTestOutboundEndpoint(String name, String uri, 
713         List<Transformer> transformers, Filter filter, Map<Object, Object> properties, Connector connector) throws Exception
714     {
715         return MuleTestUtils.getTestOutboundEndpoint(name, muleContext, uri, transformers, filter, properties, connector);
716     }
717 
718     public static MuleEvent getTestEvent(Object data, Service service) throws Exception
719     {
720         return MuleTestUtils.getTestEvent(data, service, MessageExchangePattern.REQUEST_RESPONSE, muleContext);
721     }
722 
723     public static MuleEvent getTestEvent(Object data, Service service, MessageExchangePattern mep) throws Exception
724     {
725         return MuleTestUtils.getTestEvent(data, service, mep, muleContext);
726     }
727 
728     public static MuleEvent getTestEvent(Object data) throws Exception
729     {
730         return MuleTestUtils.getTestEvent(data, MessageExchangePattern.REQUEST_RESPONSE, muleContext);
731     }
732 
733     public static MuleEvent getTestEvent(Object data, MessageExchangePattern mep) throws Exception
734     {
735         return MuleTestUtils.getTestEvent(data, mep, muleContext);
736     }
737 
738     public static MuleEvent getTestInboundEvent(Object data, MuleSession session) throws Exception
739     {
740         return MuleTestUtils.getTestInboundEvent(data, session, muleContext);
741     }
742 
743     public static MuleEvent getTestInboundEvent(Object data) throws Exception
744     {
745         return MuleTestUtils.getTestInboundEvent(data, MessageExchangePattern.REQUEST_RESPONSE, muleContext);
746     }
747 
748     public static MuleEvent getTestInboundEvent(Object data, MessageExchangePattern mep) throws Exception
749     {
750         return MuleTestUtils.getTestInboundEvent(data, mep, muleContext);
751     }
752 
753     public static MuleEventContext getTestEventContext(Object data) throws Exception
754     {
755         return MuleTestUtils.getTestEventContext(data, MessageExchangePattern.REQUEST_RESPONSE, muleContext);
756     }
757 
758     public static MuleEventContext getTestEventContext(Object data, MessageExchangePattern mep) throws Exception
759     {
760         return MuleTestUtils.getTestEventContext(data, mep, muleContext);
761     }
762 
763     public static Transformer getTestTransformer() throws Exception
764     {
765         return MuleTestUtils.getTestTransformer();
766     }
767 
768     public static MuleEvent getTestEvent(Object data, ImmutableEndpoint endpoint) throws Exception
769     {
770         return MuleTestUtils.getTestEvent(data, endpoint, muleContext);
771     }
772 
773     public static MuleEvent getTestEvent(Object data, Service service, ImmutableEndpoint endpoint)
774             throws Exception
775     {
776         return MuleTestUtils.getTestEvent(data, service, endpoint, muleContext);
777     }
778 
779     public static MuleSession getTestSession(Service service, MuleContext context)
780     {
781         return MuleTestUtils.getTestSession(service, context);
782     }
783 
784     public static TestConnector getTestConnector() throws Exception
785     {
786         return MuleTestUtils.getTestConnector(muleContext);
787     }
788 
789     public static Service getTestService() throws Exception
790     {
791         return MuleTestUtils.getTestService(muleContext);
792     }
793 
794     public static Service getTestService(String name, Class<?> clazz) throws Exception
795     {
796         return MuleTestUtils.getTestService(name, clazz, muleContext);
797     }
798 
799     public static Service getTestService(String name, Class<?> clazz, Map<?, ?> props) throws Exception
800     {
801         return MuleTestUtils.getTestService(name, clazz, props, muleContext);
802     }
803 
804     public static class TestInfo
805     {
806         /**
807          * Whether to dispose the manager after every method or once all tests for
808          * the class have run
809          */
810         private final String name;
811         private boolean disposeManagerPerSuite = false;
812         private boolean excluded = false;
813         private volatile int testCount = 0;
814         private volatile int runCount = 0;
815         // @GuardedBy(this)
816         private Set<String> registeredTestMethod = new HashSet<String>();
817 
818         public TestInfo(TestCase test)
819         {
820             this.name = test.getClass().getName();
821 
822             // load test exclusions
823             try
824             {
825                 // We find the physical classpath root URL of the test class and
826                 // use that to find the correct resource. Works fine everywhere,
827                 // regardless of classloaders. See MULE-2414
828                 URL classUrl = ClassUtils.getClassPathRoot(test.getClass());
829                 URLClassLoader tempClassLoader = new URLClassLoader(new URL[]{classUrl});
830                 URL fileUrl = tempClassLoader.getResource("mule-test-exclusions.txt");
831                 if (fileUrl != null)
832                 {
833                     InputStream in = null;
834                     try
835                     {
836                         in = fileUrl.openStream();
837 
838                         // this iterates over all lines in the exclusion file
839                         Iterator<?> lines = IOUtils.lineIterator(in, "UTF-8");
840 
841                         // ..and this finds non-comments that match the test case name
842                         excluded = IteratorUtils.filteredIterator(lines, new Predicate()
843                         {
844                             public boolean evaluate(Object object)
845                             {
846                                 return StringUtils.equals(name, StringUtils.trimToEmpty((String) object));
847                             }
848                         }).hasNext();
849                     }
850                     finally
851                     {
852                         IOUtils.closeQuietly(in);
853                     }
854                 }
855             }
856             catch (IOException ioex)
857             {
858                 // ignore
859             }
860         }
861 
862         public int getTestCount()
863         {
864             return testCount;
865         }
866 
867         public synchronized void incTestCount(String testName)
868         {
869             if (!registeredTestMethod.contains(testName))
870             {
871                 testCount++;
872                 registeredTestMethod.add(testName);
873             }
874         }
875 
876         public int getRunCount()
877         {
878             return runCount;
879         }
880 
881         public void incRunCount()
882         {
883             runCount++;
884         }
885 
886         public String getName()
887         {
888             return name;
889         }
890 
891         public boolean isDisposeManagerPerSuite()
892         {
893             return disposeManagerPerSuite;
894         }
895 
896         public void setDisposeManagerPerSuite(boolean disposeManagerPerSuite)
897         {
898             this.disposeManagerPerSuite = disposeManagerPerSuite;
899         }
900 
901         public boolean isExcluded()
902         {
903             return excluded;
904         }
905 
906         @Override
907         public synchronized String toString()
908         {
909             StringBuffer buf = new StringBuffer();
910             return buf.append(name).append(", (").append(runCount).append(" / ").append(testCount).append(
911                     ") tests run, disposePerSuite=").append(disposeManagerPerSuite).toString();
912         }
913     }
914 
915     protected boolean isStartContext()
916     {
917         return startContext;
918     }
919 
920     protected void setStartContext(boolean startContext)
921     {
922         this.startContext = startContext;
923     }
924 
925     public void setFailOnTimeout(boolean failOnTimeout)
926     {
927         this.failOnTimeout = failOnTimeout;
928     }
929 
930     /**
931      * Determines if the test case should perform graceful shutdown or not.
932      * Default is false so that tests run more quickly.
933      *
934      * @return
935      */
936     protected boolean isGracefulShutdown()
937     {
938         return false;
939     }
940 
941     /**
942      * Create an object of instance <code>clazz</code>. It will then register the object with the registry so that any
943      * dependencies are injected and then the object will be initialised.
944      * Note that if the object needs to be configured with additional state that cannot be passed into the constructor you should
945      * create an instance first set any additional data on the object then call {@link #initialiseObject(Object)}.
946      *
947      * @param clazz the class to create an instance of.
948      * @param <T>   Object of this type will be returned
949      * @return an initialised instance of <code>class</code>
950      * @throws Exception if there is a problem creating or initializing the object
951      */
952     protected <T extends Object> T createObject(Class<T> clazz) throws Exception
953     {
954         return createObject(clazz, ClassUtils.NO_ARGS);
955     }
956 
957     /**
958      * Create an object of instance <code>clazz</code>. It will then register the object with the registry so that any
959      * dependencies are injected and then the object will be initialised.
960      * Note that if the object needs to be configured with additional state that cannot be passed into the constructor you should
961      * create an instance first set any additional data on the object then call {@link #initialiseObject(Object)}.
962      *
963      * @param clazz the class to create an instance of.
964      * @param args  constructor parameters
965      * @param <T>   Object of this type will be returned
966      * @return an initialised instance of <code>class</code>
967      * @throws Exception if there is a problem creating or initializing the object
968      */
969     @SuppressWarnings("unchecked")
970     protected <T extends Object> T createObject(Class<T> clazz, Object... args) throws Exception
971     {
972         if (args == null)
973         {
974             args = ClassUtils.NO_ARGS;
975         }
976         Object o = ClassUtils.instanciateClass(clazz, args);
977         muleContext.getRegistry().registerObject(String.valueOf(o.hashCode()), o);
978         return (T) o;
979     }
980 
981     /**
982      * A convenience method that will register an object in the registry using its hashcode as the key.  This will cause the object
983      * to have any objects injected and lifecycle methods called.  Note that the object lifecycle will be called to the same current
984      * lifecycle as the MuleContext
985      *
986      * @param o the object to register and initialise it
987      * @throws RegistrationException
988      */
989     protected void initialiseObject(Object o) throws RegistrationException
990     {
991         muleContext.getRegistry().registerObject(String.valueOf(o.hashCode()), o);
992     }
993     
994     public SensingNullMessageProcessor getSensingNullMessageProcessor()
995     {
996         return new SensingNullMessageProcessor();
997     }
998     
999     public TriggerableMessageSource getTriggerableMessageSource(MessageProcessor listener)
1000     {
1001         return new TriggerableMessageSource(listener);
1002     }
1003 
1004     public TriggerableMessageSource getTriggerableMessageSource()
1005     {
1006         return new TriggerableMessageSource();
1007     }
1008 
1009     /**
1010      * Define the ports as java system properties, starting with 'port1'
1011      */
1012     private void setPortProperties()
1013     {
1014         for (int i = 0; i < ports.size(); i++)
1015         {
1016             System.setProperty("port" + (i + 1), String.valueOf(ports.get(i)));
1017         }
1018     }
1019     
1020     /**
1021      * Find a given number of available ports
1022      * 
1023      * @param numberOfPorts The number of free ports to find
1024      * @return an List with the number of requested ports
1025      */
1026     public List<Integer> findFreePorts(int numberOfPorts)
1027     {
1028         List<Integer> freePorts = new ArrayList<Integer>();
1029         for (int port = MIN_PORT; freePorts.size() != numberOfPorts && port < MAX_PORT; ++port)
1030         {
1031             if (isPortFree(port))
1032             {
1033                 freePorts.add(port);
1034             }
1035         }
1036 
1037         if (freePorts.size() != numberOfPorts)
1038         {
1039             logger.info("requested " + numberOfPorts + " open ports, but returning " + freePorts.size());
1040         }
1041         return freePorts;
1042     }
1043     
1044     /**
1045      * Iterate through the ports and log whether each is available
1046      * @param failIfTaken If true, fails the current test if the port is not available
1047      */
1048     public void checkPorts(boolean failIfTaken, String prefix)
1049     {
1050         for (Integer port : ports)
1051         {
1052             if (isPortFree(port))
1053             {
1054                 logger.info(prefix + " port is free : " + port);
1055             }
1056             else
1057             {
1058                 logger.info(prefix + " port is not free : " + port);
1059                 if (failIfTaken)
1060                 {
1061                     fail("failing test since port is not free : " + port);
1062                 }
1063             }
1064         }
1065     }
1066     
1067 
1068     /**
1069      * Check and log is a given port is available
1070      * 
1071      * @param port the port number to check
1072      * @return true if the port is available, false otherwise
1073      */
1074     public boolean isPortFree(int port)
1075     {
1076         boolean portIsFree = true;
1077         
1078         ServerSocket server = null;
1079         try
1080         {
1081             server = new ServerSocket(port);
1082         }
1083         catch (IOException e)
1084         {
1085             portIsFree = false;
1086         }
1087         finally
1088         {
1089             if (server != null)
1090             {
1091                 try
1092                 {
1093                     server.close();
1094                 }
1095                 catch (IOException e)
1096                 {
1097                     // ignore
1098                 }
1099             }
1100         }
1101         
1102         return portIsFree;
1103     }
1104     
1105     public List<Integer> getPorts()
1106     {
1107         return ports;
1108     }
1109 }