internal Handler(TestBase test, Uri uri) : this() { this.test = test; this.Uri = uri; }
protected void RunCore(T1 party1Object, T2 party2Object) { Thread party1Thread = null, party2Thread = null; Exception failingException = null; // Each thread we create needs a surrounding exception catcher so that we can // terminate the other thread and inform the test host that the test failed. Action <Action> safeWrapper = (action) => { try { TestBase.SetMockHttpContext(); action(); } catch (Exception ex) { // We may be the second thread in an ThreadAbortException, so check the "flag" lock (this) { if (failingException == null || (failingException is ThreadAbortException && !(ex is ThreadAbortException))) { failingException = ex; if (Thread.CurrentThread == party1Thread) { party2Thread.Abort(); } else { party1Thread.Abort(); } } } } }; // Run the threads, and wait for them to complete. // If this main thread is aborted (test run aborted), go ahead and abort the other two threads. party1Thread = new Thread(() => { safeWrapper(() => { this.party1Action(party1Object); }); }); party2Thread = new Thread(() => { safeWrapper(() => { this.party2Action(party2Object); }); }); party1Thread.Name = "P1"; party2Thread.Name = "P2"; try { party1Thread.Start(); party2Thread.Start(); party1Thread.Join(); party2Thread.Join(); } catch (ThreadAbortException) { party1Thread.Abort(); party2Thread.Abort(); throw; } catch (ThreadStartException ex) { if (ex.InnerException is ThreadAbortException) { // if party1Thread threw an exception // (which may even have been intentional for the test) // before party2Thread even started, then this exception // can be thrown, and should be ignored. } else { throw; } } // Use the failing reason of a failing sub-thread as our reason, if anything failed. if (failingException != null) { throw new AssertionException("Coordinator thread threw unhandled exception: " + failingException, failingException); } }