/// <summary> /// Publishes all system debug output to all DebugOutput handlers. /// </summary> private static void ListenThreadProc() { EventWaitHandle dataAcknowledged = null; EventWaitHandle dataReady = null; IntPtr debugOutputPages = IntPtr.Zero; IntPtr mappedDebugOutput = IntPtr.Zero; try { // Create event handles for the two named system events dataAcknowledged = CreateEventWaitHandle("DBWIN_BUFFER_READY"); if (dataAcknowledged == null) { TestServices.Trace( "Could not listen for debug output. Check if another application is already listening."); return; } dataReady = CreateEventWaitHandle("DBWIN_DATA_READY"); if (dataReady == null) { TestServices.Trace( "Could not listen for debug output. Check if another application is already listening."); return; } // Open the file mapping for the buffer debugOutputPages = CreateFileMapping("DBWIN_BUFFER"); // Map the shared file to memory mappedDebugOutput = CreateMemoryMapping(debugOutputPages); // Set the events to indicate that we are listening _started.Set(); dataAcknowledged.Set(); // Create the set of events that we will break on: // - when the buffer is ready // - when the thread has been told to stop listening WaitHandle[] waitEvents = new WaitHandle[] { dataReady, _stop }; // WaitAny returns the array index of the event that triggered // the wait to return. We will loop until the stop listening // event is signaled. while (WaitHandle.WaitAny(waitEvents) == 0) { // Read the output and send it to the DebugOutput event // handlers int pid; string output; ReadNextOutput(mappedDebugOutput, out pid, out output); WriteOutput(pid, output); // Acknowledge that the data has been read out of the buffer dataAcknowledged.Set(); } } finally { // Reset the started event to indicate we have stopped listening if (_started != null) { _started.Reset(); } if (dataAcknowledged != null) { dataAcknowledged.Close(); dataAcknowledged = null; } if (dataReady != null) { dataReady.Close(); dataReady = null; } if (mappedDebugOutput != IntPtr.Zero) { NativeMethods.UnmapViewOfFile(mappedDebugOutput); mappedDebugOutput = IntPtr.Zero; } if (debugOutputPages != IntPtr.Zero) { NativeMethods.CloseHandle(debugOutputPages); debugOutputPages = IntPtr.Zero; } } }
/// <summary> /// Will construct the default execution plan. The default plan orders /// test steps by Order parameter, then by phsyical order in the class. /// </summary> /// <param name="invoker">The invoker to use in the plan.</param> /// <param name="test">The test to generate the plan for.</param> /// <returns>An execution plan.</returns> private static ExecutionPlan BuildDefaultExecutionPlan( MethodInvoker invoker, object test) { // all methods in the test MethodInfo[] methods = test.GetType().GetMethods(); int count = methods.Length; // use to store all the calls in the execution plan // default plan will only execute a test step method once so the // number of calls <= the count of methods Dictionary<string, Call> calls = new Dictionary<string, Call>(count); // use to get the TestStep attribute for the call // testSteps are attributes on methods thus they are <= the count // of methods. Dictionary<Call, TestStepAttribute> testSteps = new Dictionary<Call, TestStepAttribute>(count); // use to get the orginal physical order of the call // default plan will only execute a test step method once so the // number of calls <= the count of methods Dictionary<Call, int> physicalOrder = new Dictionary<Call, int>(count); // for every method in the test object for (int i = 0; i < count; i++) { MethodInfo method = methods[i]; TestStepAttribute attrib = TestServices.GetFirstAttribute(typeof(TestStepAttribute), method) as TestStepAttribute; // if an attribute was found, it is a TestStep if (attrib != null) { // again in the default plan calls map 1:1 to methods that // are test steps, so create a call for the method Call call = new Call( invoker, method, test, new object[method.GetParameters().Length], GetDependencies(attrib, calls)); if (!calls.ContainsKey(method.Name)) { calls.Add(method.Name, call); physicalOrder.Add(call, i); testSteps.Add(call, attrib); } else { TestServices.Warning( "Skipping TestStep \"{0}\".\n" + "Overloads are not allowed for methods marked with TestStep attribute.", method.Name); } } } // goal: order calls by oder parameter, then by position List<Call> sorted = new List<Call>(calls.Values); sorted.Sort(delegate(Call left, Call right) { int result = left.Order.CompareTo(right.Order); // if the order is the same sub sort by physical order if (result == 0) { result = physicalOrder[left] .CompareTo(physicalOrder[right]); } return result; }); // build the execution plan ExecutionPlan plan; plan.TestSteps = testSteps; plan.Calls = sorted; return plan; }
/// <summary> /// Write a message to our trace handler. /// </summary> private static void TraceMessage(Guid requestId, string format, params object[] args) { TestServices.Trace("WebServer: {0}: {1}", requestId, string.Format(format, args)); }