/// <summary> /// Handles Partial Run Complete event coming from a specific concurrent proxy exceution manager /// Each concurrent proxy execution manager will signal the parallel execution manager when its complete /// </summary> /// <param name="proxyExecutionManager">Concurrent Execution manager that completed the run</param> /// <param name="testRunCompleteArgs">RunCompleteArgs for the concurrent run</param> /// <param name="lastChunkArgs">LastChunk testresults for the concurrent run</param> /// <param name="runContextAttachments">RunAttachments for the concurrent run</param> /// <param name="executorUris">ExecutorURIs of the adapters involved in executing the tests</param> /// <returns>True if parallel run is complete</returns> public bool HandlePartialRunComplete( IProxyExecutionManager proxyExecutionManager, TestRunCompleteEventArgs testRunCompleteArgs, TestRunChangedEventArgs lastChunkArgs, ICollection <AttachmentSet> runContextAttachments, ICollection <string> executorUris) { var allRunsCompleted = false; if (!this.SharedHosts) { this.concurrentManagerHandlerMap.Remove(proxyExecutionManager); proxyExecutionManager.Close(); proxyExecutionManager = CreateNewConcurrentManager(); var parallelEventsHandler = new ParallelRunEventsHandler( proxyExecutionManager, this.currentRunEventsHandler, this, this.currentRunDataAggregator); this.concurrentManagerHandlerMap.Add(proxyExecutionManager, parallelEventsHandler); } // In Case of Cancel or Abort, no need to trigger run for rest of the data // If there are no more sources/testcases, a parallel executor is truly done with execution if (testRunCompleteArgs.IsAborted || testRunCompleteArgs.IsCanceled || !this.StartTestRunOnConcurrentManager(proxyExecutionManager)) { lock (this.executionStatusLockObject) { // Each concurrent Executor calls this method // So, we need to keep track of total runcomplete calls this.runCompletedClients++; allRunsCompleted = this.runCompletedClients == this.concurrentManagerInstances.Length; } // verify that all executors are done with the execution and there are no more sources/testcases to execute if (allRunsCompleted) { // Reset enumerators this.sourceEnumerator = null; this.testCaseListEnumerator = null; this.currentRunDataAggregator = null; this.currentRunEventsHandler = null; // Dispose concurrent executors // Do not do the cleanuptask in the current thread as we will unncessarily add to execution time this.lastParallelRunCleanUpTask = Task.Run(() => { this.UpdateParallelLevel(0); }); } } return(allRunsCompleted); }
private int StartTestRunPrivate(ITestRunEventsHandler runEventsHandler) { this.currentRunEventsHandler = runEventsHandler; // Cleanup Task for cleaning up the parallel executors except for the default one // We do not do this in Sync so that this task does not add up to execution time if (this.lastParallelRunCleanUpTask != null) { try { this.lastParallelRunCleanUpTask.Wait(); } catch (Exception ex) { // if there is an exception disposing off concurrent executors ignore it if (EqtTrace.IsWarningEnabled) { EqtTrace.Warning("ParallelTestRunnerServiceClient: Exception while invoking an action on DiscoveryManager: {0}", ex); } } this.lastParallelRunCleanUpTask = null; } // Reset the runcomplete data this.runCompletedClients = 0; // One data aggregator per parallel run this.currentRunDataAggregator = new ParallelRunDataAggregator(); this.concurrentManagerHandlerMap = new Dictionary <IProxyExecutionManager, ITestRunEventsHandler>(); for (int i = 0; i < this.concurrentManagerInstances.Length; i++) { var concurrentManager = this.concurrentManagerInstances[i]; var parallelEventsHandler = new ParallelRunEventsHandler( concurrentManager, runEventsHandler, this, this.currentRunDataAggregator); this.concurrentManagerHandlerMap.Add(concurrentManager, parallelEventsHandler); Task.Run(() => this.StartTestRunOnConcurrentManager(concurrentManager)); } return(1); }