99
public void DequeueEmpty()
101
EventQueue q = new EventQueue();
102
Assert.IsNull(q.Dequeue(false));
106
public class DequeueBlocking_StopTest : ProducerConsumerTest
108
private EventQueue q;
109
private volatile int receivedEvents;
113
public void DequeueBlocking_Stop()
115
this.q = new EventQueue();
116
this.receivedEvents = 0;
117
this.RunProducerConsumer();
118
Assert.AreEqual(events.Length + 1, this.receivedEvents);
121
protected override void Producer()
123
EnqueueEvents(this.q);
124
while (this.receivedEvents < events.Length)
132
protected override void Consumer()
137
e = this.q.Dequeue(true);
138
this.receivedEvents++;
139
Thread.MemoryBarrier();
146
public class SetWaitHandle_Enqueue_SynchronousTest : ProducerConsumerTest
148
private EventQueue q;
149
private AutoResetEvent waitHandle;
150
private volatile bool afterEnqueue;
154
public void SetWaitHandle_Enqueue_Synchronous()
156
using (this.waitHandle = new AutoResetEvent(false))
158
this.q = new EventQueue();
159
this.q.SetWaitHandleForSynchronizedEvents(this.waitHandle);
160
this.afterEnqueue = false;
161
this.RunProducerConsumer();
165
protected override void Producer()
167
Event synchronousEvent = new RunStartedEvent(string.Empty, 0);
168
Assert.IsTrue(synchronousEvent.IsSynchronous);
169
this.q.Enqueue(synchronousEvent);
170
this.afterEnqueue = true;
171
Thread.MemoryBarrier();
174
protected override void Consumer()
176
this.q.Dequeue(true);
178
Assert.IsFalse(this.afterEnqueue);
179
this.waitHandle.Set();
181
Assert.IsTrue(this.afterEnqueue);
186
public class SetWaitHandle_Enqueue_AsynchronousTest : ProducerConsumerTest
188
private EventQueue q;
189
private volatile bool afterEnqueue;
193
public void SetWaitHandle_Enqueue_Asynchronous()
195
using (AutoResetEvent waitHandle = new AutoResetEvent(false))
197
this.q = new EventQueue();
198
this.q.SetWaitHandleForSynchronizedEvents(waitHandle);
199
this.afterEnqueue = false;
200
this.RunProducerConsumer();
204
protected override void Producer()
206
Event asynchronousEvent = new OutputEvent(new TestOutput(string.Empty, TestOutputType.Trace));
207
Assert.IsFalse(asynchronousEvent.IsSynchronous);
208
this.q.Enqueue(asynchronousEvent);
209
this.afterEnqueue = true;
210
Thread.MemoryBarrier();
213
protected override void Consumer()
215
this.q.Dequeue(true);
217
Assert.IsTrue(this.afterEnqueue);
221
#endregion EventQueue tests
223
#region QueuingEventListener tests
89
226
public void SendEvents()
93
230
VerifyQueue(el.Events);
235
#region EventPump tests
97
238
public void StartAndStopPumpOnEmptyQueue()
99
EventPump pump = new EventPump(NullListener.NULL, new EventQueue(), false);
100
StartPump(pump, 1000);
101
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
102
StopPump(pump, 1000);
103
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
240
EventQueue q = new EventQueue();
241
using (EventPump pump = new EventPump(NullListener.NULL, q, false))
243
pump.Name = "StartAndStopPumpOnEmptyQueue";
244
StartPump(pump, 1000);
245
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
246
StopPump(pump, 1000);
247
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
107
252
public void PumpAutoStopsOnRunFinished()
109
254
EventQueue q = new EventQueue();
110
EventPump pump = new EventPump(NullListener.NULL, q, true);
111
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
112
StartPump(pump, 1000);
113
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
114
q.Enqueue(new RunFinishedEvent(new Exception()));
115
WaitForPumpToStop(pump, 1000);
116
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
255
using (EventPump pump = new EventPump(NullListener.NULL, q, true))
257
pump.Name = "PumpAutoStopsOnRunFinished";
258
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
259
StartPump(pump, 1000);
260
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
261
q.Enqueue(new RunFinishedEvent(new Exception()));
262
WaitForPumpToStop(pump, 1000);
263
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
120
269
public void PumpEvents()
122
271
EventQueue q = new EventQueue();
124
272
QueuingEventListener el = new QueuingEventListener();
125
EventPump pump = new EventPump(el, q, false);
126
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
127
StartPump(pump, 1000);
128
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
129
StopPump(pump, 1000);
130
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
273
using (EventPump pump = new EventPump(el, q, false))
275
pump.Name = "PumpEvents";
276
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
277
StartPump(pump, 1000);
278
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Pumping));
280
StopPump(pump, 1000);
281
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
131
283
VerifyQueue(el.Events);
135
288
public void PumpEventsWithAutoStop()
290
EventQueue q = new EventQueue();
291
QueuingEventListener el = new QueuingEventListener();
292
using (EventPump pump = new EventPump(el, q, true))
294
pump.Name = "PumpEventsWithAutoStop";
298
while (--tries > 0 && q.Count > 0)
302
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
308
public void PumpPendingEventsAfterAutoStop()
137
310
EventQueue q = new EventQueue();
138
311
EnqueueEvents(q);
139
Assert.AreEqual(6, q.Count);
312
Event[] eventsAfterStop =
314
new OutputEvent(new TestOutput("foo", TestOutputType.Out)),
315
new OutputEvent(new TestOutput("bar", TestOutputType.Trace)),
317
foreach (Event e in eventsAfterStop)
140
322
QueuingEventListener el = new QueuingEventListener();
141
EventPump pump = new EventPump(el, q, true);
144
while (--tries > 0 && q.Count > 0)
148
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
323
using (EventPump pump = new EventPump(el, q, true))
325
pump.Name = "PumpPendingEventsAfterAutoStop";
328
while (--tries > 0 && q.Count > 0)
333
Assert.That(pump.PumpState, Is.EqualTo(EventPumpState.Stopped));
335
Assert.That(el.Events.Count, Is.EqualTo(events.Length + eventsAfterStop.Length));
340
public void PumpSynchronousAndAsynchronousEvents()
342
EventQueue q = new EventQueue();
343
using (EventPump pump = new EventPump(NullListener.NULL, q, false))
345
pump.Name = "PumpSynchronousAndAsynchronousEvents";
348
int numberOfAsynchronousEvents = 0;
349
int sumOfAsynchronousQueueLength = 0;
350
const int Repetitions = 2;
351
for (int i = 0; i < Repetitions; i++)
353
foreach (Event e in events)
358
Assert.That(q.Count, Is.EqualTo(0));
362
sumOfAsynchronousQueueLength += q.Count;
363
numberOfAsynchronousEvents++;
368
Console.WriteLine("Average queue length: {0}", (float)sumOfAsynchronousQueueLength / numberOfAsynchronousEvents);
373
/// Verifies that when
374
/// (1) Traces are captured and fed into the EventListeners, and
375
/// (2) an EventListener writes Traces,
376
/// the Trace / EventPump / EventListener do not deadlock.
379
/// This mainly simulates the object structure created by RemoteTestRunner.Run.
383
public void TracingEventListenerDoesNotDeadlock()
385
QueuingEventListener upstreamListener = new QueuingEventListener();
386
EventQueue upstreamListenerQueue = upstreamListener.Events;
388
// Install a TraceListener sending TestOutput events to the upstreamListener.
389
// This simulates RemoteTestRunner.StartTextCapture, where TestContext installs such a TraceListener.
390
TextWriter traceWriter = new EventListenerTextWriter(upstreamListener, TestOutputType.Trace);
391
const string TraceListenerName = "TracingEventListenerDoesNotDeadlock";
392
TraceListener feedingTraceToUpstreamListener = new TextWriterTraceListener(traceWriter, TraceListenerName);
396
Trace.Listeners.Add(feedingTraceToUpstreamListener);
398
// downstreamListenerToTrace simulates an EventListener installed e.g. by an Addin,
399
// which may call Trace within the EventListener methods:
400
TracingEventListener downstreamListenerToTrace = new TracingEventListener();
401
using (EventPump pump = new EventPump(downstreamListenerToTrace, upstreamListenerQueue, false))
403
pump.Name = "TracingEventListenerDoesNotDeadlock";
406
const int Repetitions = 10;
407
for (int i = 0; i < Repetitions; i++)
409
foreach (Event e in events)
411
Trace.WriteLine("Before sending {0} event.", e.GetType().Name);
412
e.Send(upstreamListener);
413
Trace.WriteLine("After sending {0} event.", e.GetType().Name);
420
Trace.Listeners.Remove(TraceListenerName);
421
feedingTraceToUpstreamListener.Dispose();
426
/// Floods the queue of an EventPump with multiple concurrent event producers.
427
/// Prints the maximum queue length to Console, but does not implement an
428
/// oracle on what the maximum queue length should be.
430
/// <param name="numberOfProducers">The number of concurrent producer threads.</param>
431
/// <param name="producerDelay">
432
/// If <c>true</c>, the producer threads slow down by adding a short delay time.
437
[Explicit("Takes several seconds. Just prints the queue length of the EventPump to Console, but has no oracle regarding this.")]
438
public void EventPumpQueueLength(int numberOfProducers, bool producerDelay)
440
EventQueue q = new EventQueue();
441
EventProducer[] producers = new EventProducer[numberOfProducers];
442
for (int i = 0; i < numberOfProducers; i++)
444
producers[i] = new EventProducer(q, i, producerDelay);
447
using (EventPump pump = new EventPump(NullListener.NULL, q, false))
449
pump.Name = "EventPumpQueueLength";
452
foreach (EventProducer p in producers)
454
p.ProducerThread.Start();
456
foreach (EventProducer p in producers)
458
p.ProducerThread.Join();
462
Assert.That(q.Count, Is.EqualTo(0));
464
foreach (EventProducer p in producers)
467
"#Events: {0}, MaxQueueLength: {1}", p.SentEventsCount, p.MaxQueueLength);
468
Assert.IsNull(p.Exception, "{0}", p.Exception);
474
public abstract class ProducerConsumerTest
476
private volatile Exception myConsumerException;
478
protected void RunProducerConsumer()
480
this.myConsumerException = null;
481
Thread consumerThread = new Thread(new ThreadStart(this.ConsumerThreadWrapper));
484
consumerThread.Start();
486
bool consumerStopped = consumerThread.Join(1000);
487
Assert.IsTrue(consumerStopped);
491
consumerThread.Abort();
492
if ((consumerThread.ThreadState & ThreadState.WaitSleepJoin) != 0)
494
consumerThread.Interrupt();
498
Assert.IsNull(this.myConsumerException);
501
protected abstract void Producer();
503
protected abstract void Consumer();
505
private void ConsumerThreadWrapper()
511
catch (ThreadAbortException)
517
this.myConsumerException = ex;
522
private class EventProducer
524
public readonly Thread ProducerThread;
525
public int SentEventsCount;
526
public int MaxQueueLength;
527
public Exception Exception;
528
private readonly EventQueue queue;
529
private readonly bool delay;
531
public EventProducer(EventQueue q, int id, bool delay)
534
this.ProducerThread = new Thread(new ThreadStart(this.Produce));
535
this.ProducerThread.Name = this.GetType().FullName + id;
539
private void Produce()
543
Event e = new OutputEvent(new TestOutput(this.ProducerThread.Name, TestOutputType.Log));
544
DateTime start = DateTime.Now;
545
while (DateTime.Now - start <= TimeSpan.FromSeconds(3))
547
this.queue.Enqueue(e);
548
this.SentEventsCount++;
549
this.MaxQueueLength = Math.Max(this.queue.Count, this.MaxQueueLength);
551
// without Sleep or with just a Sleep(0), the EventPump thread does not keep up and the queue gets very long
565
private class TracingEventListener : EventListener
567
#region EventListener Members
568
public void RunStarted(string name, int testCount)
570
WriteTrace("RunStarted({0},{1})", name, testCount);
573
public void RunFinished(TestResult result)
575
WriteTrace("RunFinished({0})", result);
578
public void RunFinished(Exception exception)
580
WriteTrace("RunFinished({0})", exception);
583
public void TestStarted(TestName testName)
585
WriteTrace("TestStarted({0})", testName);
588
public void TestFinished(TestResult result)
590
WriteTrace("TestFinished({0})", result);
593
public void SuiteStarted(TestName testName)
595
WriteTrace("SuiteStarted({0})", testName);
598
public void SuiteFinished(TestResult result)
600
WriteTrace("SuiteFinished({0})", result);
603
public void UnhandledException(Exception exception)
605
WriteTrace("UnhandledException({0})", exception);
608
public void TestOutput(TestOutput testOutput)
610
if (testOutput.Type != TestOutputType.Trace)
612
WriteTrace("TestOutput {0}: '{1}'", testOutput.Type, testOutput.Text);
618
private static void WriteTrace(string message, params object[] args)
620
Trace.TraceInformation(message, args);
623
private static void WriteTrace(string message, params object[] args)
625
Trace.WriteLine(string.Format(message, args));