1 // ***********************************************************************
2 // Copyright (c) 2012 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
32 using System.Threading;
34 namespace NUnit.Framework.Internal.Execution
37 /// A TestWorker pulls work items from a queue
38 /// and executes them.
40 public class TestWorker
42 private static Logger log = InternalTrace.GetLogger("TestWorker");
44 private WorkItemQueue _readyQueue;
45 private Thread _workerThread;
47 private int _workItemCount = 0;
49 private bool _running;
52 /// Event signaled immediately before executing a WorkItem
54 public event EventHandler Busy;
57 /// Event signaled immediately after executing a WorkItem
59 public event EventHandler Idle;
63 /// Construct a new TestWorker.
65 /// <param name="queue">The queue from which to pull work items</param>
66 /// <param name="name">The name of this worker</param>
67 public TestWorker(WorkItemQueue queue, string name)
70 /// Construct a new TestWorker.
72 /// <param name="queue">The queue from which to pull work items</param>
73 /// <param name="name">The name of this worker</param>
74 /// <param name="apartmentState">The apartment state to use for running tests</param>
75 public TestWorker(WorkItemQueue queue, string name, ApartmentState apartmentState)
80 _workerThread = new Thread(new ThreadStart(TestWorkerThreadProc));
81 _workerThread.Name = name;
83 _workerThread.SetApartmentState(apartmentState);
88 /// The name of this worker - also used for the thread
92 get { return _workerThread.Name; }
96 /// Indicates whether the worker thread is running
101 get { return !_workerThread.Join(0); }
103 get { return _workerThread.IsAlive; }
108 /// Our ThreadProc, which pulls and runs tests in a loop
110 private WorkItem _currentWorkItem;
112 private void TestWorkerThreadProc()
114 log.Info("{0} starting ", _workerThread.Name);
122 _currentWorkItem = _readyQueue.Dequeue();
123 if (_currentWorkItem == null)
126 log.Info("{0} executing {1}", _workerThread.Name, _currentWorkItem.Test.Name);
129 Busy(this, EventArgs.Empty);
131 _currentWorkItem.WorkerId = Name;
132 _currentWorkItem.Execute();
135 Idle(this, EventArgs.Empty);
142 log.Info("{0} stopping - {1} WorkItems processed.", _workerThread.Name, _workItemCount);
147 /// Start processing work items.
151 _workerThread.Start();
154 private object cancelLock = new object();
157 /// Stop the thread, either immediately or after finishing the current WorkItem
159 /// <param name="force">true if the thread should be aborted, false if it should allow the currently running test to complete</param>
160 public void Cancel(bool force)
166 if (_workerThread != null && _currentWorkItem != null)
168 _currentWorkItem.Cancel(force);
170 _currentWorkItem = null;