PageRenderTime 19ms CodeModel.GetById 12ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/core/TestThread.cs

#
C# | 194 lines | 127 code | 28 blank | 39 comment | 7 complexity | 3eebceeded363f40564833cc9cb4b466 MD5 | raw file
  1// ****************************************************************
  2// Copyright 2008, Charlie Poole
  3// This is free software licensed under the NUnit license. You may
  4// obtain a copy of the license at http://nunit.org.
  5// ****************************************************************
  6using System;
  7using System.Runtime.Remoting.Messaging;
  8using System.Threading;
  9
 10namespace NUnit.Core
 11{
 12    /// <summary>
 13    /// Represents a thread of test execution and runs a test
 14    /// on a thread, implementing timeout and setting the 
 15    /// apartment state appropriately.
 16    /// </summary>
 17    public abstract class TestThread
 18    {
 19        static Logger log = InternalTrace.GetLogger(typeof(TestThread));
 20
 21		private Test test;
 22		
 23        #region Protected Fields
 24        /// <summary>
 25        /// The Thread object used to run tests
 26        /// </summary>
 27        protected Thread thread;
 28
 29		/// <summary>
 30		/// The result of running the test, which must be kept
 31		/// separate from the returned TestResult while the thread
 32        /// is running to avoid race conditions.
 33		/// </summary>
 34		protected TestResult threadResult;
 35		
 36        protected EventListener listener;
 37
 38        protected ITestFilter filter;
 39		
 40		protected TestMethod.ContextDictionary contextDictionary;
 41
 42        /// <summary>
 43        /// Unexpected exception thrown by test thread
 44        /// </summary>
 45        protected Exception thrownException;
 46        #endregion
 47
 48        #region Constructor
 49        protected TestThread(Test test)
 50        {
 51			this.test = test;
 52			
 53            this.thread = new Thread(new ThreadStart(RunTestProc));
 54            thread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
 55            thread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
 56
 57            // Setting to Unknown causes an error under the Mono 1.0 profile
 58            if ( test.ApartmentState != ApartmentState.Unknown )
 59                this.ApartmentState = test.ApartmentState;		
 60        }
 61        #endregion
 62
 63        #region Properties
 64        public ApartmentState ApartmentState
 65        {
 66#if NET_2_0
 67            get { return thread.GetApartmentState(); }
 68            set { thread.SetApartmentState(value); }
 69#else
 70            get { return thread.ApartmentState; }
 71            set { thread.ApartmentState = value; }
 72#endif
 73        }
 74        #endregion
 75
 76        /// <summary>
 77        /// Run the test, honoring any timeout value provided. If the
 78        /// timeout is exceeded, set the testresult as a failure. As
 79        /// currently implemented, the thread proc calls test.doRun,
 80        /// which handles all exceptions itself. However, for safety,
 81        /// any exception thrown is rethrown upwards.
 82        /// 
 83        /// TODO: It would be cleaner to call test.Run, since that's
 84        /// part of the pubic interface, but it would require some
 85        /// restructuring of the Test hierarchy.
 86        /// </summary>
 87        public TestResult Run(EventListener listener, ITestFilter filter)
 88        {
 89			TestResult testResult = new TestResult(test);
 90			
 91            this.thrownException = null;
 92            this.listener = listener;
 93            this.filter = filter;
 94			this.contextDictionary = (TestMethod.ContextDictionary)CallContext.GetData("NUnit.Framework.TestContext");
 95
 96            log.Debug("Starting test in separate thread");
 97            thread.Start();
 98            thread.Join(this.Timeout);
 99
100            // Timeout?
101            if (thread.IsAlive)
102            {
103				log.Debug("Test timed out - aborting thread");
104                thread.Abort();
105                //thread.Join();
106                testResult.Failure(string.Format("Test exceeded Timeout value of {0}ms", Timeout), null);
107            }
108			else if (thrownException != null)
109			{
110				log.Debug("Test threw " + thrownException.GetType().Name);
111				throw thrownException;
112			}
113			else
114			{
115				log.Debug("Test completed normally");
116                testResult = threadResult;
117            }
118			
119			return testResult;
120        }
121
122        /// <summary>
123        /// This is the engine of this class; the actual call to test.doRun!
124        /// Note that any thrown exception is saved for later use!
125        /// </summary>
126        private void RunTestProc()
127        {
128			CallContext.SetData("NUnit.Framework.TestContext", contextDictionary);
129			
130            try
131            {
132                RunTest();
133            }
134            catch (Exception e)
135            {
136                thrownException = e;
137            }
138			finally
139			{
140				CallContext.FreeNamedDataSlot("NUnit.Framework.TestContext");
141			}
142        }
143
144        protected abstract int Timeout { get; }
145        protected abstract void RunTest();
146    }
147
148    public class TestMethodThread : TestThread
149    {
150        private TestMethod testMethod;
151
152        public TestMethodThread(TestMethod testMethod)
153            : base(testMethod)
154        {
155            this.testMethod = testMethod;
156        }
157
158        protected override int Timeout
159        {
160            get 
161            { 
162                return testMethod.Timeout == 0 //|| System.Diagnostics.Debugger.IsAttached
163                    ? System.Threading.Timeout.Infinite
164                    : testMethod.Timeout;
165            }
166        }
167
168        protected override void RunTest()
169        {
170			this.threadResult = testMethod.RunTest();
171        }
172    }
173
174    public class TestSuiteThread : TestThread
175    {
176        private TestSuite suite;
177
178        public TestSuiteThread(TestSuite suite)
179            : base(suite)
180        {
181            this.suite = suite;
182        }
183
184        protected override int Timeout
185        {
186            get { return System.Threading.Timeout.Infinite; }
187        }
188
189        protected override void RunTest()
190        {
191			this.threadResult = suite.RunSuite(listener, filter);
192        }
193    }
194}