public void OnMessageReceived(object sender, MessageReceivedEventArgs messageReceivedArgs) { var message = this.dataSerializer.DeserializeMessage(messageReceivedArgs.Data); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("TestRequestHandler.ProcessRequests: received message: {0}", message); } switch (message.MessageType) { case MessageType.VersionCheck: var version = this.dataSerializer.DeserializePayload <int>(message); this.protocolVersion = Math.Min(version, highestSupportedVersion); // Send the negotiated protocol to request sender this.channel.Send(this.dataSerializer.SerializePayload(MessageType.VersionCheck, this.protocolVersion)); // Can only do this after InitializeCommunication because TestHost cannot "Send Log" unless communications are initialized if (!string.IsNullOrEmpty(EqtTrace.LogFile)) { this.SendLog(TestMessageLevel.Informational, string.Format(CrossPlatResources.TesthostDiagLogOutputFile, EqtTrace.LogFile)); } else if (!string.IsNullOrEmpty(EqtTrace.ErrorOnInitialization)) { this.SendLog(TestMessageLevel.Warning, EqtTrace.ErrorOnInitialization); } break; case MessageType.DiscoveryInitialize: { EqtTrace.Info("Discovery Session Initialize."); this.testHostManagerFactoryReady.Wait(); var discoveryEventsHandler = new TestDiscoveryEventHandler(this); var pathToAdditionalExtensions = this.dataSerializer.DeserializePayload <IEnumerable <string> >(message); jobQueue.QueueJob( () => testHostManagerFactory.GetDiscoveryManager().Initialize(pathToAdditionalExtensions, discoveryEventsHandler), 0); break; } case MessageType.StartDiscovery: { EqtTrace.Info("Discovery started."); this.testHostManagerFactoryReady.Wait(); var discoveryEventsHandler = new TestDiscoveryEventHandler(this); var discoveryCriteria = this.dataSerializer.DeserializePayload <DiscoveryCriteria>(message); jobQueue.QueueJob( () => testHostManagerFactory.GetDiscoveryManager() .DiscoverTests(discoveryCriteria, discoveryEventsHandler), 0); break; } case MessageType.ExecutionInitialize: { EqtTrace.Info("Execution Session Initialize."); this.testHostManagerFactoryReady.Wait(); var testInitializeEventsHandler = new TestInitializeEventsHandler(this); var pathToAdditionalExtensions = this.dataSerializer.DeserializePayload <IEnumerable <string> >(message); jobQueue.QueueJob( () => testHostManagerFactory.GetExecutionManager().Initialize(pathToAdditionalExtensions, testInitializeEventsHandler), 0); break; } case MessageType.StartTestExecutionWithSources: { EqtTrace.Info("Execution started."); var testRunEventsHandler = new TestRunEventsHandler(this); this.testHostManagerFactoryReady.Wait(); var testRunCriteriaWithSources = this.dataSerializer.DeserializePayload <TestRunCriteriaWithSources>(message); jobQueue.QueueJob( () => testHostManagerFactory.GetExecutionManager() .StartTestRun( testRunCriteriaWithSources.AdapterSourceMap, testRunCriteriaWithSources.Package, testRunCriteriaWithSources.RunSettings, testRunCriteriaWithSources.TestExecutionContext, this.GetTestCaseEventsHandler(testRunCriteriaWithSources.RunSettings), testRunEventsHandler), 0); break; } case MessageType.StartTestExecutionWithTests: { EqtTrace.Info("Execution started."); var testRunEventsHandler = new TestRunEventsHandler(this); this.testHostManagerFactoryReady.Wait(); var testRunCriteriaWithTests = this.dataSerializer.DeserializePayload <TestRunCriteriaWithTests>(message); jobQueue.QueueJob( () => testHostManagerFactory.GetExecutionManager() .StartTestRun( testRunCriteriaWithTests.Tests, testRunCriteriaWithTests.Package, testRunCriteriaWithTests.RunSettings, testRunCriteriaWithTests.TestExecutionContext, this.GetTestCaseEventsHandler(testRunCriteriaWithTests.RunSettings), testRunEventsHandler), 0); break; } case MessageType.CancelTestRun: jobQueue.Pause(); this.testHostManagerFactoryReady.Wait(); testHostManagerFactory.GetExecutionManager().Cancel(new TestRunEventsHandler(this)); break; case MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback: this.onAckMessageRecieved?.Invoke(message); break; case MessageType.AbortTestRun: jobQueue.Pause(); this.testHostManagerFactoryReady.Wait(); testHostManagerFactory.GetExecutionManager().Abort(new TestRunEventsHandler(this)); break; case MessageType.SessionEnd: { EqtTrace.Info("Session End message received from server. Closing the connection."); sessionCompleted.Set(); this.Close(); break; } case MessageType.SessionAbort: { // Dont do anything for now. break; } default: { EqtTrace.Info("Invalid Message types"); break; } } }
/// <summary> /// Invoked when test run is complete /// </summary> public void HandleTestRunComplete(TestRunCompleteEventArgs runCompleteArgs, TestRunChangedEventArgs lastChunkArgs, ICollection <AttachmentSet> runContextAttachments, ICollection <string> executorUris) { if (runCompleteArgs == null) { throw new ArgumentNullException(nameof(runCompleteArgs)); } bool isAborted = runCompleteArgs.IsAborted; bool isCanceled = runCompleteArgs.IsCanceled; EqtTrace.Verbose("TestRunRequest:TestRunComplete: Starting. IsAborted:{0} IsCanceled:{1}.", isAborted, isCanceled); lock (this.syncObject) { // If this object is disposed, dont do anything if (this.disposed) { EqtTrace.Warning("TestRunRequest.TestRunComplete: Ignoring as the object is disposed."); return; } if (this.runCompletionEvent.WaitOne(0)) { EqtTrace.Info("TestRunRequest:TestRunComplete:Ignoring duplicate event. IsAborted:{0} IsCanceled:{1}.", isAborted, isCanceled); return; } // Disposing off the resources held by the execution manager so that the test host process can shut down. this.ExecutionManager?.Close(); try { this.runRequestTimeTracker.Stop(); if (lastChunkArgs != null) { // Raised the changed event also this.OnRunStatsChange.SafeInvoke(this, lastChunkArgs, "TestRun.RunStatsChanged"); } TestRunCompleteEventArgs runCompletedEvent = new TestRunCompleteEventArgs( runCompleteArgs.TestRunStatistics, runCompleteArgs.IsCanceled, runCompleteArgs.IsAborted, runCompleteArgs.Error, runContextAttachments as Collection <AttachmentSet>, this.runRequestTimeTracker.Elapsed); // Ignore the time sent (runCompleteArgs.ElapsedTimeInRunningTests) // by either engines - as both calculate at different points // If we use them, it would be an incorrect comparison between TAEF and Rocksteady this.OnRunCompletion.SafeInvoke(this, runCompletedEvent, "TestRun.TestRunComplete"); } finally { if (isCanceled) { this.State = TestRunState.Canceled; } else if (isAborted) { this.State = TestRunState.Aborted; } else { this.State = TestRunState.Completed; } // Notify the waiting handle that run is complete this.runCompletionEvent.Set(); } EqtTrace.Info("TestRunRequest:TestRunComplete: Completed."); } }
/// <inheritdoc /> public void CheckVersionWithTestHost() { // Negotiation follows these steps: // Runner sends highest supported version to Test host // Test host sends the version it can support (must be less than highest) to runner // Error case: test host can send a protocol error if it cannot find a supported version var protocolNegotiated = new ManualResetEvent(false); this.onMessageReceived = (sender, args) => { var message = this.dataSerializer.DeserializeMessage(args.Data); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("TestRequestSender.CheckVersionWithTestHost: onMessageReceived received message: {0}", message); } if (message.MessageType == MessageType.VersionCheck) { this.protocolVersion = this.dataSerializer.DeserializePayload <int>(message); } // TRH can also send TestMessage if tracing is enabled, so log it at runner end else if (message.MessageType == MessageType.TestMessage) { // Ignore test messages. Currently we don't have handler(which sends messages to client/console.) here. // Above we are logging it to EqtTrace. } else if (message.MessageType == MessageType.ProtocolError) { throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.VersionCheckFailed)); } else { throw new TestPlatformException(string.Format( CultureInfo.CurrentUICulture, CommonResources.UnexpectedMessage, MessageType.VersionCheck, message.MessageType)); } protocolNegotiated.Set(); }; this.channel.MessageReceived += this.onMessageReceived; try { // Send the protocol negotiation request. Note that we always serialize this data // without any versioning in the message itself. var data = this.dataSerializer.SerializePayload(MessageType.VersionCheck, this.highestSupportedVersion); this.channel.Send(data); // Wait for negotiation response var timeout = EnvironmentHelper.GetConnectionTimeout(); if (!protocolNegotiated.WaitOne(timeout * 1000)) { throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.VersionCheckTimedout, timeout, EnvironmentHelper.VstestConnectionTimeout)); } } finally { this.channel.MessageReceived -= this.onMessageReceived; this.onMessageReceived = null; } }
/// <inheritdoc /> public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 discoveryEventsHandler) { this.messageEventHandler = discoveryEventsHandler; this.onDisconnected = (disconnectedEventArgs) => { this.OnDiscoveryAbort(discoveryEventsHandler, disconnectedEventArgs.Error, true); }; this.onMessageReceived = (sender, args) => { try { var rawMessage = args.Data; // Currently each of the operations are not separate tasks since they should not each take much time. This is just a notification. if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("TestRequestSender: Received message: {0}", rawMessage); } // Send raw message first to unblock handlers waiting to send message to IDEs discoveryEventsHandler.HandleRawMessage(rawMessage); var data = this.dataSerializer.DeserializeMessage(rawMessage); switch (data.MessageType) { case MessageType.TestCasesFound: var testCases = this.dataSerializer.DeserializePayload <IEnumerable <TestCase> >(data); discoveryEventsHandler.HandleDiscoveredTests(testCases); break; case MessageType.DiscoveryComplete: var discoveryCompletePayload = this.dataSerializer.DeserializePayload <DiscoveryCompletePayload>(data); var discoveryCompleteEventsArgs = new DiscoveryCompleteEventArgs(discoveryCompletePayload.TotalTests, discoveryCompletePayload.IsAborted, discoveryCompletePayload.Metrics); discoveryEventsHandler.HandleDiscoveryComplete( discoveryCompleteEventsArgs, discoveryCompletePayload.LastDiscoveredTests); this.SetOperationComplete(); break; case MessageType.TestMessage: var testMessagePayload = this.dataSerializer.DeserializePayload <TestMessagePayload>( data); discoveryEventsHandler.HandleLogMessage( testMessagePayload.MessageLevel, testMessagePayload.Message); break; } } catch (Exception ex) { this.OnDiscoveryAbort(discoveryEventsHandler, ex, false); } }; this.channel.MessageReceived += this.onMessageReceived; var message = this.dataSerializer.SerializePayload( MessageType.StartDiscovery, discoveryCriteria, this.protocolVersion); this.channel.Send(message); }
public void Invoke(IDictionary <string, string> argsDictionary) { // Setup logging if enabled string logFile; if (argsDictionary.TryGetValue(LogFileArgument, out logFile)) { EqtTrace.InitializeVerboseTrace(logFile); } #if NET46 if (EqtTrace.IsInfoEnabled) { var appConfigText = System.IO.File.ReadAllText(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); EqtTrace.Info("DefaultEngineInvoker: Using Application Configuration: '{0}'", appConfigText); } #endif // Get port number and initialize communication var portNumber = GetIntArgFromDict(argsDictionary, PortArgument); // Start Processing of requests using (var requestHandler = new TestRequestHandler()) { // Attach to exit of parent process var parentProcessId = GetIntArgFromDict(argsDictionary, ParentProcessIdArgument); EqtTrace.Info("DefaultEngineInvoker: Monitoring parent process with id: '{0}'", parentProcessId); var parentProcessMonitoringTask = WaitForParentProcessExitAsync(parentProcessId); // Initialize Communication EqtTrace.Info("DefaultEngineInvoker: Initialize communication on port number: '{0}'", portNumber); requestHandler.InitializeCommunication(portNumber); // Can only do this after InitializeCommunication because TestHost cannot "Send Log" unless communications are initialized if (!string.IsNullOrEmpty(EqtTrace.LogFile)) { requestHandler.SendLog(TestMessageLevel.Informational, string.Format("Logging TestHost Diagnostics in file: {0}", EqtTrace.LogFile)); } // Initialize DataCollection Communication if data collection port is provided. var dcPort = GetIntArgFromDict(argsDictionary, DataCollectionPortArgument); if (dcPort > 0) { var dataCollectionTestCaseEventSender = DataCollectionTestCaseEventSender.Create(); dataCollectionTestCaseEventSender.InitializeCommunication(dcPort); dataCollectionTestCaseEventSender.WaitForRequestSenderConnection(ClientListenTimeOut); } // Start processing async in a different task EqtTrace.Info("DefaultEngineInvoker: Start Request Processing."); var processingTask = this.StartProcessingAsync(requestHandler, new TestHostManagerFactory()); // Wait for either processing to complete or parent process exit Task.WaitAny(processingTask, parentProcessMonitoringTask); if (dcPort > 0) { // Close socket communication connection. DataCollectionTestCaseEventSender.Instance.Close(); } } }
/// <summary> /// Loads and initializes data collector using data collector settings. /// </summary> /// <param name="dataCollectorSettings"> /// The data collector settings. /// </param> /// <param name="settingsXml"> runsettings Xml</param> private void LoadAndInitialize(DataCollectorSettings dataCollectorSettings, string settingsXml) { DataCollectorInformation dataCollectorInfo; DataCollectorConfig dataCollectorConfig; try { // Look up the extension and initialize it if one is found. var extensionManager = this.DataCollectorExtensionManager; var dataCollectorUri = string.Empty; this.TryGetUriFromFriendlyName(dataCollectorSettings.FriendlyName, out dataCollectorUri); DataCollector dataCollector = null; if (!string.IsNullOrWhiteSpace(dataCollectorUri)) { dataCollector = this.TryGetTestExtension(dataCollectorUri); } if (dataCollector == null) { this.LogWarning(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.DataCollectorNotFound, dataCollectorSettings.FriendlyName)); return; } if (this.RunDataCollectors.ContainsKey(dataCollector.GetType())) { // Collector is already loaded (may be configured twice). Ignore duplicates and return. return; } dataCollectorConfig = new DataCollectorConfig(dataCollector.GetType()); // Attempt to get the data collector information verifying that all of the required metadata for the collector is available. dataCollectorInfo = new DataCollectorInformation( dataCollector, dataCollectorSettings.Configuration, dataCollectorConfig, this.dataCollectionEnvironmentContext, this.attachmentManager, this.events, this.messageSink, settingsXml); } catch (Exception ex) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error("DataCollectionManager.LoadAndInitialize: exception while creating data collector {0} : {1}", dataCollectorSettings.FriendlyName, ex); } // No data collector info, so send the error with no direct association to the collector. this.LogWarning(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.DataCollectorInitializationError, dataCollectorSettings.FriendlyName, ex)); return; } try { dataCollectorInfo.InitializeDataCollector(); lock (this.RunDataCollectors) { // Add data collectors to run cache. this.RunDataCollectors[dataCollectorConfig.DataCollectorType] = dataCollectorInfo; } } catch (Exception ex) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error("DataCollectionManager.LoadAndInitialize: exception while initializing data collector {0} : {1}", dataCollectorSettings.FriendlyName, ex); } // Log error. dataCollectorInfo.Logger.LogError(this.dataCollectionEnvironmentContext.SessionDataCollectionContext, string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollectorInitializationError, dataCollectorConfig.FriendlyName, ex.Message)); // Dispose datacollector. dataCollectorInfo.DisposeDataCollector(); } }
/// <summary> /// Handle discovery complete. /// </summary> /// <param name="totalTests"> The total tests. </param> /// <param name="lastChunk"> The last chunk. </param> /// <param name="isAborted"> The is aborted. </param> public void HandleDiscoveryComplete(long totalTests, IEnumerable <TestCase> lastChunk, bool isAborted) { EqtTrace.Info(isAborted ? "Discover Aborted." : "Discover Finished."); this.requestHandler.DiscoveryComplete(totalTests, lastChunk, isAborted); }
private Assembly SearchAndLoadAssembly(string assemblyPath, string assemblyName, AssemblyName requestedName, bool isReflectionOnly) { try { if (!this.DoesFileExist(assemblyPath)) { return(null); } var foundName = AssemblyName.GetAssemblyName(assemblyPath); if (!RequestedAssemblyNameMatchesFound(requestedName, foundName)) { return(null); // File exists but version/public key is wrong. Try next extension. } Assembly assembly; if (isReflectionOnly) { assembly = this.ReflectionOnlyLoadAssemblyFrom(assemblyPath); this.reflectionOnlyResolvedAssemblies[assemblyName] = assembly; } else { assembly = this.LoadAssemblyFrom(assemblyPath); this.resolvedAssemblies[assemblyName] = assembly; } this.SafeLog( assemblyName, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("AssemblyResolver: Resolved assembly: {0}. ", assemblyName); } }); return(assembly); } catch (FileLoadException ex) { this.SafeLog( assemblyName, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("AssemblyResolver: Failed to load assembly: {0}. Reason:{1} ", assemblyName, ex); } }); // Re-throw FileLoadException, because this exception means that the assembly // was found, but could not be loaded. This will allow us to report a more // specific error message to the user for things like access denied. throw; } catch (Exception ex) { // For all other exceptions, try the next extension. this.SafeLog( assemblyName, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("AssemblyResolver: Failed to load assembly: {0}. Reason:{1} ", assemblyName, ex); } }); } return(null); }
/// <summary> /// Add a new file transfer (either copy/move) request. /// </summary> /// <param name="fileTransferInfo"> /// The file Transfer Info. /// </param> /// <param name="sendFileCompletedCallback"> /// The send File Completed Callback. /// </param> /// <param name="uri"> /// The uri. /// </param> /// <param name="friendlyName"> /// The friendly Name. /// </param> private void AddNewFileTransfer(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName) { var context = fileTransferInfo.Context; Debug.Assert( context != null, "DataCollectionManager.AddNewFileTransfer: FileDataHeaderMessage with null context."); var testCaseId = fileTransferInfo.Context.HasTestCase ? fileTransferInfo.Context.TestExecId.Id.ToString() : string.Empty; var directoryPath = Path.Combine( this.SessionOutputDirectory, testCaseId); var localFilePath = Path.Combine(directoryPath, Path.GetFileName(fileTransferInfo.FileName)); var task = Task.Factory.StartNew( () => { Validate(fileTransferInfo, localFilePath); if (this.cancellationTokenSource.Token.IsCancellationRequested) { this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); } try { if (fileTransferInfo.PerformCleanup) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moving file {0} to {1}", fileTransferInfo.FileName, localFilePath); } File.Move(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moved file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } else { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copying file {0} to {1}", fileTransferInfo.FileName, localFilePath); } File.Copy(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copied file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } } catch (Exception ex) { this.LogError( ex.Message, uri, friendlyName, Guid.Parse(testCaseId)); throw; } }, this.cancellationTokenSource.Token); var continuationTask = task.ContinueWith( (t) => { try { if (t.Exception == null) { this.AttachmentSets[uri].Attachments.Add(new UriDataAttachment(new Uri(localFilePath), fileTransferInfo.Description)); } if (sendFileCompletedCallback != null) { sendFileCompletedCallback(this, new AsyncCompletedEventArgs(t.Exception, false, fileTransferInfo.UserToken)); } } catch (Exception e) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error( "DataCollectionAttachmentManager.TriggerCallBack: Error occurred while raising the file transfer completed callback for {0}. Error: {1}", localFilePath, e.ToString()); } } }, this.cancellationTokenSource.Token); this.attachmentTasks.Add(continuationTask); }
/// <summary> /// It will search for a particular assembly in the given list of directory. /// </summary> /// <param name="searchDirectorypaths"> The search Directorypaths. </param> /// <param name="name"> The name. </param> /// <param name="isReflectionOnly"> Indicates whether this is called under a Reflection Only Load context. </param> /// <returns> The <see cref="Assembly"/>. </returns> protected virtual Assembly SearchAssembly(List <string> searchDirectorypaths, string name, bool isReflectionOnly) { if (searchDirectorypaths == null || searchDirectorypaths.Count == 0) { return(null); } // args.Name is like: "Microsoft.VisualStudio.TestTools.Common, Version=[VersionMajor].0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". AssemblyName requestedName = null; try { // Can throw ArgumentException, FileLoadException if arg is empty/wrong format, etc. Should not return null. requestedName = new AssemblyName(name); } catch (Exception ex) { this.SafeLog( name, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info( "AssemblyResolver: {0}: Failed to create assemblyName. Reason:{1} ", name, ex); } }); return(null); } Debug.Assert(requestedName != null && !string.IsNullOrEmpty(requestedName.Name), "AssemblyResolver.OnResolve: requested is null or name is empty!"); foreach (var dir in searchDirectorypaths) { if (string.IsNullOrEmpty(dir)) { continue; } this.SafeLog( name, () => { if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("AssemblyResolver: Searching assembly: {0} in the directory: {1}", requestedName.Name, dir); } }); foreach (var extension in new string[] { ".dll", ".exe" }) { var assemblyPath = Path.Combine(dir, requestedName.Name + extension); var assembly = this.SearchAndLoadAssembly(assemblyPath, name, requestedName, isReflectionOnly); if (assembly != null) { return(assembly); } } } return(null); }
private Assembly OnResolveInternal(object senderAppDomain, ResolveEventArgs args, bool isReflectionOnly) { if (string.IsNullOrEmpty(args?.Name)) { Debug.Assert(false, "AssemblyResolver.OnResolve: args.Name is null or empty."); return(null); } this.SafeLog( args.Name, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("AssemblyResolver: Resolving assembly: {0}.", args.Name); } }); string assemblyNameToLoad = AppDomain.CurrentDomain.ApplyPolicy(args.Name); this.SafeLog( assemblyNameToLoad, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("AssemblyResolver: Resolving assembly after applying policy: {0}.", assemblyNameToLoad); } }); lock (this.syncLock) { // Since both normal and reflection only cache are accessed in same block, putting only one lock should be sufficient. Assembly assembly = null; if (this.TryLoadFromCache(assemblyNameToLoad, isReflectionOnly, out assembly)) { return(assembly); } assembly = this.SearchAssembly(this.searchDirectories, assemblyNameToLoad, isReflectionOnly); if (assembly != null) { return(assembly); } if (this.directoryList != null && this.directoryList.Any()) { // required assembly is not present in searchDirectories?? // see, if we can find it in user specified search directories. while (assembly == null && this.directoryList.Count > 0) { // instead of loading whole search directory in one time, we are adding directory on the basis of need var currentNode = this.directoryList.Dequeue(); List <string> increamentalSearchDirectory = new List <string>(); if (this.DoesDirectoryExist(currentNode.DirectoryPath)) { increamentalSearchDirectory.Add(currentNode.DirectoryPath); if (currentNode.IncludeSubDirectories) { // Add all its sub-directory in depth first search order. this.AddSubdirectories(currentNode.DirectoryPath, increamentalSearchDirectory); } // Add this directory list in this.searchDirectories so that when we will try to resolve some other // assembly, then it will look in this whole directory first. this.searchDirectories.AddRange(increamentalSearchDirectory); assembly = this.SearchAssembly(increamentalSearchDirectory, assemblyNameToLoad, isReflectionOnly); } else { // generate warning that path does not exist. this.SafeLog( assemblyNameToLoad, () => { if (EqtTrace.IsWarningEnabled) { EqtTrace.Warning( "The Directory: {0}, does not exist", currentNode.DirectoryPath); } }); } } if (assembly != null) { return(assembly); } } // Try for default load for System dlls that can't be found in search paths. Needs to loaded just by name. try { if (isReflectionOnly) { // Put it in the resolved assembly cache so that if the Load call below // triggers another assembly resolution, then we don't end up in stack overflow. this.reflectionOnlyResolvedAssemblies[assemblyNameToLoad] = null; assembly = Assembly.ReflectionOnlyLoad(assemblyNameToLoad); if (assembly != null) { this.reflectionOnlyResolvedAssemblies[assemblyNameToLoad] = assembly; } } else { // Put it in the resolved assembly cache so that if the Load call below // triggers another assembly resolution, then we don't end up in stack overflow. this.resolvedAssemblies[assemblyNameToLoad] = null; assembly = Assembly.Load(assemblyNameToLoad); if (assembly != null) { this.resolvedAssemblies[assemblyNameToLoad] = assembly; } } return(assembly); } catch (Exception ex) { this.SafeLog( args?.Name, () => { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info( "AssemblyResolver: {0}: Failed to load assembly. Reason:{1} ", assemblyNameToLoad, ex); } }); } return(assembly); } }
private IEnumerable <DeploymentItem> GetSatellites(IEnumerable <DeploymentItem> deploymentItems, string testSource, IList <string> warnings) { List <DeploymentItem> satellites = new List <DeploymentItem>(); foreach (DeploymentItem item in deploymentItems) { // We do not care about deployment items which are directories because in that case we deploy all files underneath anyway. string path = null; try { path = this.GetFullPathToDeploymentItemSource(item.SourcePath, testSource); path = Path.GetFullPath(path); if (string.IsNullOrEmpty(path) || !this.assemblyUtility.IsAssemblyExtension(Path.GetExtension(path)) || !this.fileUtility.DoesFileExist(path) || !this.assemblyUtility.IsAssembly(path)) { continue; } } catch (ArgumentException ex) { EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); } catch (SecurityException ex) { EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); } catch (IOException ex) { // This covers PathTooLongException. EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); } catch (NotSupportedException ex) { EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); } // Note: now Path operations with itemPath should not result in any exceptions. // path is already canonicalized. // If we cannot access satellite due to security, etc, we report warning. try { string itemDir = Path.GetDirectoryName(path).TrimEnd( new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); List <string> itemSatellites = this.assemblyUtility.GetSatelliteAssemblies(path); foreach (string satellite in itemSatellites) { Debug.Assert(!string.IsNullOrEmpty(satellite), "DeploymentManager.DoDeployment: got empty satellite!"); Debug.Assert( satellite.IndexOf(itemDir, StringComparison.OrdinalIgnoreCase) == 0, "DeploymentManager.DoDeployment: Got satellite that does not start with original item path"); string satelliteDir = Path.GetDirectoryName(satellite).TrimEnd( new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); Debug.Assert(!string.IsNullOrEmpty(satelliteDir), "DeploymentManager.DoDeployment: got empty satellite dir!"); Debug.Assert(satelliteDir.Length > itemDir.Length + 1, "DeploymentManager.DoDeployment: wrong satellite dir lenght!"); string localeDir = satelliteDir.Substring(itemDir.Length + 1); Debug.Assert(!string.IsNullOrEmpty(localeDir), "DeploymentManager.DoDeployment: got empty dir name for satellite dir!"); string relativeOutputDir = Path.Combine(item.RelativeOutputDirectory, localeDir); // Now finally add the item! DeploymentItem satelliteItem = new DeploymentItem(satellite, relativeOutputDir, DeploymentItemOriginType.Satellite); this.deploymentItemUtility.AddDeploymentItem(satellites, satelliteItem); } } catch (ArgumentException ex) { EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); string warning = string.Format(CultureInfo.CurrentCulture, Resource.DeploymentErrorGettingSatellite, item, ex.GetType(), ex.GetExceptionMessage()); warnings.Add(warning); } catch (SecurityException ex) { EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); string warning = string.Format(CultureInfo.CurrentCulture, Resource.DeploymentErrorGettingSatellite, item, ex.GetType(), ex.GetExceptionMessage()); warnings.Add(warning); } catch (IOException ex) { // This covers PathTooLongException. EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DeploymentManager.GetSatellites: {0}", ex); string warning = string.Format(CultureInfo.CurrentCulture, Resource.DeploymentErrorGettingSatellite, item, ex.GetType(), ex.GetExceptionMessage()); warnings.Add(warning); } } return(satellites); }
private IEnumerable <string> Deploy(IList <DeploymentItem> deploymentItems, string testSource, string deploymentDirectory, string resultsDirectory) { Validate.IsFalse(string.IsNullOrWhiteSpace(deploymentDirectory), "Deployment directory is null or empty"); Validate.IsTrue(this.fileUtility.DoesDirectoryExist(deploymentDirectory), $"Deployment directory {deploymentDirectory} does not exist"); Validate.IsFalse(string.IsNullOrWhiteSpace(testSource), "TestSource directory is null/empty"); Validate.IsTrue(this.fileUtility.DoesFileExist(testSource), $"TestSource {testSource} does not exist."); testSource = Path.GetFullPath(testSource); var warnings = new List <string>(); if (MSTestSettingsProvider.Settings.DeployTestSourceDependencies) { EqtTrace.Info("Adding the references and satellite assemblies to the deploymentitems list"); // Get the referenced assemblies. this.ProcessNewStorage(testSource, deploymentItems, warnings); // Get the satellite assemblies var satelliteItems = this.GetSatellites(deploymentItems, testSource, warnings); foreach (var satelliteItem in satelliteItems) { this.deploymentItemUtility.AddDeploymentItem(deploymentItems, satelliteItem); } } else { EqtTrace.Info("Adding the test source directory to the deploymentitems list"); this.deploymentItemUtility.AddDeploymentItem(deploymentItems, new DeploymentItem(Path.GetDirectoryName(testSource))); } // Maps relative to Out dir destination -> source and used to determine if there are conflicted items. var destToSource = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); // Copy the deployment items. (As deployment item can correspond to directories as well, so each deployment item may map to n files) foreach (var deploymentItem in deploymentItems) { ValidateArg.NotNull(deploymentItem, "deploymentItem should not be null."); // Validate the output directory. if (!this.IsOutputDirectoryValid(deploymentItem, deploymentDirectory, warnings)) { continue; } // Get the files corresponding to this deployment item var deploymentItemFiles = this.GetFullPathToFilesCorrespondingToDeploymentItem(deploymentItem, testSource, resultsDirectory, warnings, out bool itemIsDirectory); if (deploymentItemFiles == null) { continue; } var fullPathToDeploymentItemSource = this.GetFullPathToDeploymentItemSource(deploymentItem.SourcePath, testSource); // Note: source is already rooted. foreach (var deploymentItemFile in deploymentItemFiles) { Debug.Assert(Path.IsPathRooted(deploymentItemFile), "File " + deploymentItemFile + " is not rooted"); // List of files to deploy, by default, just itemFile. var filesToDeploy = new List <string>(1); filesToDeploy.Add(deploymentItemFile); // Find dependencies of test deployment items and deploy them at the same time as master file. if (deploymentItem.OriginType == DeploymentItemOriginType.PerTestDeployment && this.assemblyUtility.IsAssemblyExtension(Path.GetExtension(deploymentItemFile))) { this.AddDependenciesOfDeploymentItem(deploymentItemFile, filesToDeploy, warnings); } foreach (var fileToDeploy in filesToDeploy) { Debug.Assert(Path.IsPathRooted(fileToDeploy), "File " + fileToDeploy + " is not rooted"); // Ignore the test platform files. var tempFile = Path.GetFileName(fileToDeploy); var assemblyName = Path.GetFileName(Assembly.GetExecutingAssembly().Location); if (tempFile.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) { continue; } string relativeDestination; if (itemIsDirectory) { // Deploy into subdirectory of deployment (Out) dir. Debug.Assert(fileToDeploy.StartsWith(fullPathToDeploymentItemSource, StringComparison.Ordinal), "Somehow source is outside original dir."); relativeDestination = this.fileUtility.TryConvertPathToRelative(fileToDeploy, fullPathToDeploymentItemSource); } else { // Deploy just to the deployment (Out) dir. relativeDestination = Path.GetFileName(fileToDeploy); } relativeDestination = Path.Combine(deploymentItem.RelativeOutputDirectory, relativeDestination); // Ignores empty arg1. var destination = Path.Combine(deploymentDirectory, relativeDestination); try { destination = Path.GetFullPath(destination); } catch (Exception e) { var warning = string.Format(CultureInfo.CurrentCulture, Resource.DeploymentErrorFailedToAccessFile, destination, e.GetType(), e.Message); warnings.Add(warning); continue; } if (!destToSource.ContainsKey(relativeDestination)) { destToSource.Add(relativeDestination, fileToDeploy); // Now, finally we can copy the file... destination = this.fileUtility.CopyFileOverwrite(fileToDeploy, destination, out string warning); if (!string.IsNullOrEmpty(warning)) { warnings.Add(warning); } if (string.IsNullOrEmpty(destination)) { continue; } // We clear the attributes so that e.g. you can write to the copies of files originally under SCC. this.fileUtility.SetAttributes(destination, FileAttributes.Normal); // Deploy PDB for line number info in stack trace. this.fileUtility.FindAndDeployPdb(destination, relativeDestination, fileToDeploy, destToSource); } else if ( !string.Equals( fileToDeploy, destToSource[relativeDestination], StringComparison.OrdinalIgnoreCase)) { EqtTrace.WarningIf( EqtTrace.IsWarningEnabled, "Conflict during copiyng file: '{0}' and '{1}' are from different origins although they might be the same.", fileToDeploy, destToSource[relativeDestination]); } } // foreach fileToDeploy. } // foreach itemFile. } return(warnings); }
private void SendData(string data) { EqtTrace.Verbose("TestRequestHandler.SendData: sending data from testhost: {0}", data); this.channel.Send(data); }
/// <summary> /// Triggers the execution for the next data object on the concurrent executor /// Each concurrent executor calls this method, once its completed working on previous data /// </summary> /// <param name="proxyExecutionManager">Proxy execution manager instance.</param> /// <returns>True, if execution triggered</returns> private void StartTestRunOnConcurrentManager(IProxyExecutionManager proxyExecutionManager) { TestRunCriteria testRunCriteria = null; if (!this.hasSpecificTestsRun) { if (this.TryFetchNextSource(this.sourceEnumerator, out string nextSource)) { EqtTrace.Info("ProxyParallelExecutionManager: Triggering test run for next source: {0}", nextSource); testRunCriteria = new TestRunCriteria( new[] { nextSource }, this.actualTestRunCriteria.FrequencyOfRunStatsChangeEvent, this.actualTestRunCriteria.KeepAlive, this.actualTestRunCriteria.TestRunSettings, this.actualTestRunCriteria.RunStatsChangeEventTimeout, this.actualTestRunCriteria.TestHostLauncher) { TestCaseFilter = this.actualTestRunCriteria.TestCaseFilter }; } } else { if (this.TryFetchNextSource(this.testCaseListEnumerator, out List <TestCase> nextSetOfTests)) { EqtTrace.Info("ProxyParallelExecutionManager: Triggering test run for next source: {0}", nextSetOfTests?.FirstOrDefault()?.Source); testRunCriteria = new TestRunCriteria( nextSetOfTests, this.actualTestRunCriteria.FrequencyOfRunStatsChangeEvent, this.actualTestRunCriteria.KeepAlive, this.actualTestRunCriteria.TestRunSettings, this.actualTestRunCriteria.RunStatsChangeEventTimeout, this.actualTestRunCriteria.TestHostLauncher); } } if (testRunCriteria != null) { if (!proxyExecutionManager.IsInitialized) { proxyExecutionManager.Initialize(); } Task.Run(() => { Interlocked.Increment(ref this.runStartedClients); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("ParallelProxyExecutionManager: Execution started. Started clients: " + this.runStartedClients); } proxyExecutionManager.StartTestRun(testRunCriteria, this.GetHandlerForGivenManager(proxyExecutionManager)); }) .ContinueWith(t => { // Just in case, the actual execution couldn't start for an instance. Ensure that // we call execution complete since we have already fetched a source. Otherwise // execution will not terminate if (EqtTrace.IsWarningEnabled) { EqtTrace.Warning("ParallelProxyExecutionManager: Failed to trigger execution. Exception: " + t.Exception); } // Send a run complete to caller. Similar logic is also used in ProxyExecutionManager.StartTestRun // Differences: // Aborted is sent to allow the current execution manager replaced with another instance // Ensure that the test run aggregator in parallel run events handler doesn't add these statistics // (since the test run didn't even start) var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection <AttachmentSet>(), TimeSpan.Zero); this.GetHandlerForGivenManager(proxyExecutionManager).HandleTestRunComplete(completeArgs, null, null, null); }, TaskContinuationOptions.OnlyOnFaulted); } if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("ProxyParallelExecutionManager: No sources available for execution."); } }
/// <summary> /// Validates the collectors in runsettings when an in-lined testsettings is specified /// </summary> /// <param name="runsettings">RunSettings used for the run</param> /// <returns>True if an incompatible collector is found</returns> public static bool AreRunSettingsCollectorsInCompatibleWithTestSettings(string runsettings) { // If there's no embedded testsettings.. bail out if (!IsTestSettingsEnabled(runsettings)) { return(false); } // Explicitly blocking usage of data collectors through modes runsettings and testsettings except // for couple of scenarios where the IDE generates the collector settings in the runsettings file even when // it has an embedded testsettings file. Longterm runsettings will be the single run configuration source // In-proc collectors are incompatible with testsettings var inprocDataCollectionSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(runsettings); if (inprocDataCollectionSettings != null && inprocDataCollectionSettings.IsCollectionEnabled && inprocDataCollectionSettings.DataCollectorSettingsList != null) { foreach (var collectorSettings in inprocDataCollectionSettings.DataCollectorSettingsList) { if (collectorSettings.IsEnabled) { EqtTrace.Warning($"Incompatible collector found. {collectorSettings.FriendlyName} : {collectorSettings.Uri}"); return(true); } } } // TestSettings and collection is enabled in runsetttings.. the only allowed collectors are code coverage and fakes var datacollectionSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(runsettings); if (datacollectionSettings != null && datacollectionSettings.IsCollectionEnabled && datacollectionSettings.DataCollectorSettingsList != null) { foreach (var collectorRef in datacollectionSettings.DataCollectorSettingsList) { // Ignore disabled collector if (!collectorRef.IsEnabled) { continue; } // If the configured collector is code coverage or fakes.. ignore if (!string.IsNullOrWhiteSpace(collectorRef.FriendlyName) && (FakesFriendlyName.Equals(collectorRef.FriendlyName, StringComparison.OrdinalIgnoreCase) || CodeCoverageFriendlyName.Equals(collectorRef.FriendlyName, StringComparison.OrdinalIgnoreCase))) { continue; } // If the configured collector is code coverage or fakes.. ignore if (collectorRef.Uri != null && (CodeCoverageCollectorUri.Equals(collectorRef.Uri.ToString(), StringComparison.OrdinalIgnoreCase) || FakesCollectorUri.Equals(collectorRef.Uri.ToString(), StringComparison.OrdinalIgnoreCase))) { continue; } EqtTrace.Warning($"Incompatible collector found. {collectorRef.FriendlyName} : {collectorRef.Uri}"); return(true); } } return(false); }
/// <summary> /// Starts the test run /// </summary> /// <param name="testRunCriteria"> The settings/options for the test run. </param> /// <param name="eventHandler"> EventHandler for handling execution events from Engine. </param> /// <returns> The process id of the runner executing tests. </returns> public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsHandler eventHandler) { try { if (!this.testHostManager.Shared) { // Non shared test host requires test source information to launch. Provide the sources // information and create the channel. EqtTrace.Verbose("ProxyExecutionManager: Test host is non shared. Lazy initialize."); var testSources = testRunCriteria.Sources; // If the test execution is with a test filter, group them by sources if (testRunCriteria.HasSpecificTests) { testSources = testRunCriteria.Tests.GroupBy(tc => tc.Source).Select(g => g.Key); } this.InitializeExtensions(testSources); } this.SetupChannel(testRunCriteria.Sources); var executionContext = new TestExecutionContext( testRunCriteria.FrequencyOfRunStatsChangeEvent, testRunCriteria.RunStatsChangeEventTimeout, inIsolation: false, keepAlive: testRunCriteria.KeepAlive, isDataCollectionEnabled: false, areTestCaseLevelEventsRequired: false, hasTestRun: true, isDebug: (testRunCriteria.TestHostLauncher != null && testRunCriteria.TestHostLauncher.IsDebug), testCaseFilter: testRunCriteria.TestCaseFilter); if (testRunCriteria.HasSpecificSources) { var runRequest = new TestRunCriteriaWithSources( testRunCriteria.AdapterSourceMap, testRunCriteria.TestRunSettings, executionContext); this.RequestSender.StartTestRun(runRequest, eventHandler); } else { var runRequest = new TestRunCriteriaWithTests( testRunCriteria.Tests, testRunCriteria.TestRunSettings, executionContext); this.RequestSender.StartTestRun(runRequest, eventHandler); } } catch (Exception exception) { EqtTrace.Error("ProxyExecutionManager.StartTestRun: Failed to start test run: {0}", exception); var completeArgs = new TestRunCompleteEventArgs(null, false, false, exception, new Collection <AttachmentSet>(), TimeSpan.Zero); eventHandler.HandleLogMessage(TestMessageLevel.Error, exception.Message); eventHandler.HandleTestRunComplete(completeArgs, null, null, null); } return(0); }
/// <summary> /// Returns true if legacy settings node is present in runsettings /// </summary> /// <param name="runsettingsXml">The run settings xml string</param> /// <param name="legacySettingsTelemetry">The telemetry data that needs to be captured</param> /// <returns></returns> public static bool TryGetLegacySettingElements(string runsettingsXml, out Dictionary <string, string> legacySettingsTelemetry) { legacySettingsTelemetry = new Dictionary <string, string>(); try { using (var stream = new StringReader(runsettingsXml)) using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings)) { var document = new XmlDocument(); document.Load(reader); var runSettingsNavigator = document.CreateNavigator(); var node = runSettingsNavigator.SelectSingleNode(@"/RunSettings/LegacySettings"); if (node == null) { return(false); } var childNodes = node.SelectChildren(XPathNodeType.Element); var legacySettingElements = new List <string>(); while (childNodes.MoveNext()) { legacySettingElements.Add(childNodes.Current.Name); } foreach (var executionNodePath in ExecutionNodesPaths) { var executionNode = runSettingsNavigator.SelectSingleNode(executionNodePath); if (executionNode != null) { legacySettingElements.Add(executionNode.Name); } } if (legacySettingElements.Count > 0) { legacySettingsTelemetry.Add(LegacyElementsString, string.Join(", ", legacySettingElements)); } var deploymentNode = runSettingsNavigator.SelectSingleNode(@"/RunSettings/LegacySettings/Deployment"); var deploymentAttributes = GetNodeAttributes(deploymentNode); if (deploymentAttributes != null) { legacySettingsTelemetry.Add(DeploymentAttributesString, string.Join(", ", deploymentAttributes)); } var executiontNode = runSettingsNavigator.SelectSingleNode(@"/RunSettings/LegacySettings/Execution"); var executiontAttributes = GetNodeAttributes(executiontNode); if (executiontAttributes != null) { legacySettingsTelemetry.Add(ExecutionAttributesString, string.Join(", ", executiontAttributes)); } } } catch (Exception ex) { EqtTrace.Error("Error while trying to read legacy settings. Message: {0}", ex.ToString()); return(false); } return(true); }
/// <summary> /// Handles discovered tests /// </summary> /// <param name="discoveredTestCases">List of test cases</param> public void HandleDiscoveredTests(IEnumerable <TestCase> discoveredTestCases) { EqtTrace.Info("Test Cases found "); this.requestHandler.SendTestCases(discoveredTestCases); }
/// <summary> /// Make runsettings compatible with testhost of version 15.0.0-preview /// Due to bug https://github.com/Microsoft/vstest/issues/970 we need this function /// </summary> /// <param name="runsettingsXml">string content of runsettings </param> /// <returns>compatible runsettings</returns> public static string MakeRunsettingsCompatible(string runsettingsXml) { var updatedRunSettingsXml = runsettingsXml; if (!string.IsNullOrWhiteSpace(runsettingsXml)) { using (var stream = new StringReader(runsettingsXml)) using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings)) { var document = new XmlDocument(); document.Load(reader); var runSettingsNavigator = document.CreateNavigator(); // Move navigator to RunConfiguration node if (!runSettingsNavigator.MoveToChild(RunSettingsNodeName, string.Empty) || !runSettingsNavigator.MoveToChild(RunConfigurationNodeName, string.Empty)) { EqtTrace.Error("InferRunSettingsHelper.MakeRunsettingsCompatible: Unable to navigate to RunConfiguration. Current node: " + runSettingsNavigator.LocalName); } else if (runSettingsNavigator.HasChildren) { var listOfInValidRunConfigurationSettings = new List <string>(); // These are the list of valid RunConfiguration setting name which old testhost understand. var listOfValidRunConfigurationSettings = new HashSet <string> { "TargetPlatform", "TargetFrameworkVersion", "TestAdaptersPaths", "ResultsDirectory", "SolutionDirectory", "MaxCpuCount", "DisableParallelization", "DisableAppDomain" }; // Find all invalid RunConfiguration Settings runSettingsNavigator.MoveToFirstChild(); do { if (!listOfValidRunConfigurationSettings.Contains(runSettingsNavigator.LocalName)) { listOfInValidRunConfigurationSettings.Add(runSettingsNavigator.LocalName); } } while (runSettingsNavigator.MoveToNext()); // Delete all invalid RunConfiguration Settings if (listOfInValidRunConfigurationSettings.Count > 0) { if (EqtTrace.IsWarningEnabled) { string settingsName = string.Join(", ", listOfInValidRunConfigurationSettings); EqtTrace.Warning(string.Format("InferRunSettingsHelper.MakeRunsettingsCompatible: Removing the following settings: {0} from RunSettings file. To use those settings please move to latest version of Microsoft.NET.Test.Sdk", settingsName)); } // move navigator to RunConfiguration node runSettingsNavigator.MoveToParent(); foreach (var s in listOfInValidRunConfigurationSettings) { var nodePath = RunConfigurationNodePath + "/" + s; XmlUtilities.RemoveChildNode(runSettingsNavigator, nodePath, s); } runSettingsNavigator.MoveToRoot(); updatedRunSettingsXml = runSettingsNavigator.OuterXml; } } } } return(updatedRunSettingsXml); }
/// <summary> /// Determines Architecture from sources. /// </summary> public Architecture AutoDetectArchitecture(List <string> sources, IDictionary <string, Architecture> sourcePlatforms) { Architecture architecture = Constants.DefaultPlatform; try { if (sources != null && sources.Count > 0) { Architecture?finalArch = null; foreach (string source in sources) { Architecture arch; if (IsDotNETAssembly(source)) { arch = assemblyMetadataProvider.GetArchitecture(source); } else { // Set AnyCPU for non dotnet test sources (js, py and other). Otherwise warning will // show up if there is mismatch with user provided platform. arch = Architecture.AnyCPU; } sourcePlatforms[source] = (Architecture)arch; if (Architecture.AnyCPU.Equals(arch)) { // If arch is AnyCPU ignore it. continue; } if (finalArch == null) { finalArch = arch; continue; } if (!finalArch.Equals(arch)) { finalArch = Constants.DefaultPlatform; EqtTrace.Info("Conflict in platform architecture, using default platform:{0}", finalArch); } } if (finalArch != null) { architecture = (Architecture)finalArch; } } } catch (Exception ex) { EqtTrace.Error("Failed to determine platform: {0}, using default: {1}", ex, architecture); } if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Determined platform for all sources: {0}", architecture); } return(architecture); }
/// <inheritdoc/> public virtual TestProcessStartInfo GetTestHostProcessStartInfo( IEnumerable <string> sources, IDictionary <string, string> environmentVariables, TestRunnerConnectionInfo connectionInfo) { var startInfo = new TestProcessStartInfo(); var currentProcessPath = this.processHelper.GetCurrentProcessFileName(); // This host manager can create process start info for dotnet core targets only. // If already running with the dotnet executable, use it; otherwise pick up the dotnet available on path. // Wrap the paths with quotes in case dotnet executable is installed on a path with whitespace. if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase) || currentProcessPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase)) { startInfo.FileName = currentProcessPath; } else { startInfo.FileName = this.dotnetHostHelper.GetDotnetPath(); } EqtTrace.Verbose("DotnetTestHostmanager: Full path of dotnet.exe is {0}", startInfo.FileName); // .NET core host manager is not a shared host. It will expect a single test source to be provided. var args = "exec"; var sourcePath = sources.Single(); var sourceFile = Path.GetFileNameWithoutExtension(sourcePath); var sourceDirectory = Path.GetDirectoryName(sourcePath); // Probe for runtimeconfig and deps file for the test source var runtimeConfigPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.json")); if (this.fileHelper.Exists(runtimeConfigPath)) { string argsToAdd = " --runtimeconfig " + runtimeConfigPath.AddDoubleQuote(); args += argsToAdd; EqtTrace.Verbose("DotnetTestHostmanager: Adding {0} in args", argsToAdd); } else { EqtTrace.Verbose("DotnetTestHostmanager: File {0}, doesnot exist", runtimeConfigPath); } // Use the deps.json for test source var depsFilePath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".deps.json")); if (this.fileHelper.Exists(depsFilePath)) { string argsToAdd = " --depsfile " + depsFilePath.AddDoubleQuote(); args += argsToAdd; EqtTrace.Verbose("DotnetTestHostmanager: Adding {0} in args", argsToAdd); } else { EqtTrace.Verbose("DotnetTestHostmanager: File {0}, doesnot exist", depsFilePath); } var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json")); var testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory); if (this.fileHelper.Exists(testHostPath)) { EqtTrace.Verbose("DotnetTestHostmanager: Full path of testhost.dll is {0}", testHostPath); args += " " + testHostPath.AddDoubleQuote() + " " + connectionInfo.ToCommandLineOptions(); } else { string message = string.Format(CultureInfo.CurrentCulture, Resources.NoTestHostFileExist, sourcePath); EqtTrace.Verbose("DotnetTestHostmanager: " + message); throw new FileNotFoundException(message); } // Create a additional probing path args with Nuget.Client // args += "--additionalprobingpath xxx" // TODO this may be required in ASP.net, requires validation // Sample command line for the spawned test host // "D:\dd\gh\Microsoft\vstest\tools\dotnet\dotnet.exe" exec // --runtimeconfig G:\tmp\netcore-test\bin\Debug\netcoreapp1.0\netcore-test.runtimeconfig.json // --depsfile G:\tmp\netcore-test\bin\Debug\netcoreapp1.0\netcore-test.deps.json // --additionalprobingpath C:\Users\username\.nuget\packages\ // G:\nuget-package-path\microsoft.testplatform.testhost\version\**\testhost.dll // G:\tmp\netcore-test\bin\Debug\netcoreapp1.0\netcore-test.dll startInfo.Arguments = args; startInfo.EnvironmentVariables = environmentVariables ?? new Dictionary <string, string>(); startInfo.WorkingDirectory = sourceDirectory; return(startInfo); }
private void OnExecutionMessageReceived(object sender, MessageReceivedEventArgs messageReceived, ITestRunEventsHandler testRunEventsHandler) { try { var rawMessage = messageReceived.Data; if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("TestRequestSender.OnExecutionMessageReceived: Received message: {0}", rawMessage); } // Send raw message first to unblock handlers waiting to send message to IDEs testRunEventsHandler.HandleRawMessage(rawMessage); var message = this.dataSerializer.DeserializeMessage(rawMessage); switch (message.MessageType) { case MessageType.TestRunStatsChange: var testRunChangedArgs = this.dataSerializer.DeserializePayload <TestRunChangedEventArgs>(message); testRunEventsHandler.HandleTestRunStatsChange(testRunChangedArgs); break; case MessageType.ExecutionComplete: var testRunCompletePayload = this.dataSerializer.DeserializePayload <TestRunCompletePayload>(message); testRunEventsHandler.HandleTestRunComplete( testRunCompletePayload.TestRunCompleteArgs, testRunCompletePayload.LastRunTests, testRunCompletePayload.RunAttachments, testRunCompletePayload.ExecutorUris); this.SetOperationComplete(); break; case MessageType.TestMessage: var testMessagePayload = this.dataSerializer.DeserializePayload <TestMessagePayload>(message); testRunEventsHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); break; case MessageType.LaunchAdapterProcessWithDebuggerAttached: var testProcessStartInfo = this.dataSerializer.DeserializePayload <TestProcessStartInfo>(message); int processId = testRunEventsHandler.LaunchProcessWithDebuggerAttached(testProcessStartInfo); var data = this.dataSerializer.SerializePayload( MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, processId, this.protocolVersion); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("TestRequestSender.OnExecutionMessageReceived: Sending LaunchAdapterProcessWithDebuggerAttachedCallback message: {0}", data); } this.channel.Send(data); break; case MessageType.AttachDebugger: var testProcessPid = this.dataSerializer.DeserializePayload <TestProcessAttachDebuggerPayload>(message); bool result = ((ITestRunEventsHandler2)testRunEventsHandler).AttachDebuggerToProcess(testProcessPid.ProcessID); var resultMessage = this.dataSerializer.SerializePayload( MessageType.AttachDebuggerCallback, result, this.protocolVersion); this.channel.Send(resultMessage); break; } } catch (Exception exception) { this.OnTestRunAbort(testRunEventsHandler, exception, false); } }
private string GetTestHostPath(string runtimeConfigDevPath, string depsFilePath, string sourceDirectory) { string testHostPackageName = "microsoft.testplatform.testhost"; string testHostPath = string.Empty; if (this.fileHelper.Exists(runtimeConfigDevPath) && this.fileHelper.Exists(depsFilePath)) { EqtTrace.Verbose("DotnetTestHostmanager: Reading file {0} to get path of testhost.dll", depsFilePath); // Get testhost relative path using (var stream = this.fileHelper.GetStream(depsFilePath, FileMode.Open)) { var context = new DependencyContextJsonReader().Read(stream); var testhostPackage = context.RuntimeLibraries.Where(lib => lib.Name.Equals(testHostPackageName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (testhostPackage != null) { foreach (var runtimeAssemblyGroup in testhostPackage.RuntimeAssemblyGroups) { foreach (var path in runtimeAssemblyGroup.AssetPaths) { if (path.EndsWith("testhost.dll", StringComparison.OrdinalIgnoreCase)) { testHostPath = path; break; } } } testHostPath = Path.Combine(testhostPackage.Path, testHostPath); this.hostPackageVersion = testhostPackage.Version; EqtTrace.Verbose("DotnetTestHostmanager: Relative path of testhost.dll with respect to package folder is {0}", testHostPath); } } // Get probing path using (StreamReader file = new StreamReader(this.fileHelper.GetStream(runtimeConfigDevPath, FileMode.Open))) using (JsonTextReader reader = new JsonTextReader(file)) { JObject context = (JObject)JToken.ReadFrom(reader); JObject runtimeOptions = (JObject)context.GetValue("runtimeOptions"); JToken additionalProbingPaths = runtimeOptions.GetValue("additionalProbingPaths"); foreach (var x in additionalProbingPaths) { EqtTrace.Verbose("DotnetTestHostmanager: Looking for path {0} in folder {1}", testHostPath, x.ToString()); string testHostFullPath; try { testHostFullPath = Path.Combine(x.ToString(), testHostPath); } catch (ArgumentException) { // https://github.com/Microsoft/vstest/issues/847 // skip any invalid paths and continue checking the others continue; } if (this.fileHelper.Exists(testHostFullPath)) { return(testHostFullPath); } } } } // If we are here it means it couldnt resolve testhost.dll from nuget chache. // Try resolving testhost from output directory of test project. This is required if user has published the test project // and is running tests in an isolated machine. A second scenario is self test: test platform unit tests take a project // dependency on testhost (instead of nuget dependency), this drops testhost to output path. testHostPath = Path.Combine(sourceDirectory, "testhost.dll"); EqtTrace.Verbose("DotnetTestHostManager: Assume published test project, with test host path = {0}.", testHostPath); return(testHostPath); }
public static bool SplitCommandLineIntoArguments(string args, out string[] arguments) { bool hadError = false; var argArray = new List <string>(); var currentArg = new StringBuilder(); bool inQuotes = false; int index = 0; try { while (true) { // skip whitespace while (char.IsWhiteSpace(args[index])) { index++; } // # - comment to end of line if (args[index] == '#') { index++; while (args[index] != '\n') { index++; } continue; } // do one argument do { if (args[index] == '\\') { int cSlashes = 1; index++; while (index == args.Length && args[index] == '\\') { cSlashes++; } if (index == args.Length || args[index] != '"') { currentArg.Append('\\', cSlashes); } else { currentArg.Append('\\', (cSlashes >> 1)); if (0 != (cSlashes & 1)) { currentArg.Append('"'); } else { inQuotes = !inQuotes; } } } else if (args[index] == '"') { inQuotes = !inQuotes; index++; } else { currentArg.Append(args[index]); index++; } } while (!char.IsWhiteSpace(args[index]) || inQuotes); argArray.Add(currentArg.ToString()); currentArg.Clear(); } } catch (IndexOutOfRangeException) { // got EOF if (inQuotes) { EqtTrace.Verbose("Executor.Execute: Exiting with exit code of {0}", 1); EqtTrace.Error(string.Format(CultureInfo.InvariantCulture, "Error: Unbalanced '\"' in command line argument file")); hadError = true; } else if (currentArg.Length > 0) { // valid argument can be terminated by EOF argArray.Add(currentArg.ToString()); } } arguments = argArray.ToArray(); return(hadError); }
public override List <string> GetDataTablesAndViews() { WriteDiagnostics("GetDataTablesAndViews"); List <string> tableNames = new List <string>(); try { string defaultSchema = this.GetDefaultSchema(); WriteDiagnostics("Default schema is {0}", defaultSchema); SchemaMetaData[] metadatas = this.GetSchemaMetaData(); // TODO: may be find better way to enumerate tables/views. foreach (SchemaMetaData metadata in metadatas) { DataTable dataTable = null; try { WriteDiagnostics("Getting schema table {0}", metadata.SchemaTable); dataTable = this.Connection.GetSchema(metadata.SchemaTable); } catch (Exception ex) { WriteDiagnostics("Failed to get schema table"); // This can be normal case as some providers do not support views. EqtTrace.WarningIf(EqtTrace.IsWarningEnabled, "DataUtil.GetDataTablesAndViews: exception (can be normal case as some providers do not support views): " + ex); continue; } Debug.Assert(dataTable != null, "Failed to get data table that contains metadata about tables!"); foreach (DataRow row in dataTable.Rows) { WriteDiagnostics("Row: {0}", row); string tableSchema = null; bool isDefaultSchema = false; // Check the table type for validity if (metadata.TableTypeColumn != null) { if (row[metadata.TableTypeColumn] != DBNull.Value) { string tableType = row[metadata.TableTypeColumn] as string; if (!IsInArray(tableType, metadata.ValidTableTypes)) { WriteDiagnostics("Table type {0} is not acceptable", tableType); // Not a valid table type, get the next row continue; } } } // Get the schema name, and filter bad schemas if (row[metadata.SchemaColumn] != DBNull.Value) { tableSchema = row[metadata.SchemaColumn] as string; if (IsInArray(tableSchema, metadata.InvalidSchemas)) { WriteDiagnostics("Schema {0} is not acceptable", tableSchema); // A table in a schema we do not want to see, get the next row continue; } isDefaultSchema = string.Equals(tableSchema, defaultSchema, StringComparison.OrdinalIgnoreCase); } string tableName = row[metadata.NameColumn] as string; WriteDiagnostics("Table {0}{1} found", tableSchema != null ? tableSchema + "." : string.Empty, tableName); // If schema is defined and is not equal to default, prepend table schema in front of the table. string qualifiedTableName = tableName; if (isDefaultSchema) { qualifiedTableName = this.FormatTableNameForDisplay(null, tableName); } else { qualifiedTableName = this.FormatTableNameForDisplay(tableSchema, tableName); } WriteDiagnostics("Adding Table {0}", qualifiedTableName); tableNames.Add(qualifiedTableName); } tableNames.Sort(StringComparer.OrdinalIgnoreCase); } } catch (Exception e) { WriteDiagnostics("Failed to fetch tables for {0}, exception: {1}", this.Connection.ConnectionString, e); // OK to fall through and return whatever we do have... } return(tableNames); }
/// <inheritdoc/> public void HandleDiscoveryComplete(DiscoveryCompleteEventArgs discoveryCompleteEventArgs, IEnumerable <TestCase> lastChunk) { if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("DiscoveryRequest.DiscoveryComplete: Starting. Aborted:{0}, TotalTests:{1}", discoveryCompleteEventArgs.IsAborted, discoveryCompleteEventArgs.TotalCount); } lock (this.syncObject) { if (this.disposed) { if (EqtTrace.IsWarningEnabled) { EqtTrace.Warning("DiscoveryRequest.DiscoveryComplete: Ignoring as the object is disposed."); } return; } // If discovery event is already raised, ignore current one. if (this.discoveryCompleted.WaitOne(0)) { if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("DiscoveryRequest.DiscoveryComplete:Ignoring duplicate DiscoveryComplete. Aborted:{0}, TotalTests:{1}", discoveryCompleteEventArgs.IsAborted, discoveryCompleteEventArgs.TotalCount); } return; } // Close the discovery session and terminate any test host processes. This operation should never // throw. this.DiscoveryManager?.Close(); try { // Raise onDiscoveredTests event if there are some tests in the last chunk. // (We don't want to send the tests in the discovery complete event so that programming on top of // RS client is easier i.e. user does not have to listen on discovery complete event.) if (lastChunk != null && lastChunk.Any()) { var discoveredTestsEvent = new DiscoveredTestsEventArgs(lastChunk); this.LoggerManager.HandleDiscoveredTests(discoveredTestsEvent); this.OnDiscoveredTests.SafeInvoke(this, discoveredTestsEvent, "DiscoveryRequest.DiscoveryComplete"); } this.LoggerManager.HandleDiscoveryComplete(discoveryCompleteEventArgs); this.OnDiscoveryComplete.SafeInvoke(this, discoveryCompleteEventArgs, "DiscoveryRequest.DiscoveryComplete"); } finally { // Notify the waiting handle that discovery is complete if (this.discoveryCompleted != null) { this.discoveryCompleted.Set(); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("DiscoveryRequest.DiscoveryComplete: Notified the discovery complete event."); } } else { if (EqtTrace.IsWarningEnabled) { EqtTrace.Warning("DiscoveryRequest.DiscoveryComplete: Discovery complete event was null."); } } this.discoveryInProgress = false; var discoveryFinalTimeTaken = DateTime.UtcNow - this.discoveryStartTime; // Fill in the Metrics From Test Host Process var metrics = discoveryCompleteEventArgs.Metrics; if (metrics != null && metrics.Count != 0) { foreach (var metric in metrics) { this.requestData.MetricsCollection.Add(metric.Key, metric.Value); } } // Collecting Total Time Taken this.requestData.MetricsCollection.Add( TelemetryDataConstants.TimeTakenInSecForDiscovery, discoveryFinalTimeTaken.TotalSeconds); } } if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DiscoveryRequest.DiscoveryComplete: Completed."); } }
/// <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; lock (this.executionStatusLockObject) { // Each concurrent Executor calls this method // So, we need to keep track of total runcomplete calls this.runCompletedClients++; if (testRunCompleteArgs.IsCanceled) { allRunsCompleted = this.runCompletedClients == this.runStartedClients; } else { allRunsCompleted = this.runCompletedClients == this.availableTestSources; } if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Total completed clients = {0}, Run complete = {1}, Run canceled: {2}.", this.runCompletedClients, allRunsCompleted, testRunCompleteArgs.IsCanceled); } } // 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(true); } // In case of DataCollection we only start dc.exe on initialize, & close once the TestRun is complete, // So instead of resuing ProxyExecutionManager, we will close it here, & create new PEMWDC // In Case of Abort, clean old one and create new proxyExecutionManager in place of old one. if (!this.SharedHosts || testRunCompleteArgs.IsAborted || (proxyExecutionManager is ProxyExecutionManagerWithDataCollection)) { if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Replace execution manager. Shared: {0}, Aborted: {1}.", this.SharedHosts, testRunCompleteArgs.IsAborted); } this.RemoveManager(proxyExecutionManager); proxyExecutionManager = CreateNewConcurrentManager(); var parallelEventsHandler = this.GetEventsHandler(proxyExecutionManager); this.AddManager(proxyExecutionManager, parallelEventsHandler); } // If cancel is triggered for any one run, there is no reason to fetch next source // and queue another test run if (!testRunCompleteArgs.IsCanceled) { this.StartTestRunOnConcurrentManager(proxyExecutionManager); } return(false); }
/// <inheritdoc /> public void Close() { this.Dispose(); EqtTrace.Info("Closing the connection"); }
public void Invoke(IDictionary <string, string> argsDictionary) { // Setup logging if enabled string logFile; if (argsDictionary.TryGetValue(LogFileArgument, out logFile)) { EqtTrace.InitializeVerboseTrace(logFile); } #if NET451 if (EqtTrace.IsInfoEnabled) { var appConfigText = System.IO.File.ReadAllText(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); EqtTrace.Info("DefaultEngineInvoker: Using Application Configuration: '{0}'", appConfigText); } #endif // vstest.console < 15.5 won't send endpoint and role arguments. // So derive endpoint from port argument and Make connectionRole as Client. string endpoint = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, EndpointArgument); if (string.IsNullOrWhiteSpace(endpoint)) { var port = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, "--port"); endpoint = IPAddress.Loopback + ":" + port; } var connectionRole = ConnectionRole.Client; string role = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, RoleArgument); if (!string.IsNullOrWhiteSpace(role) && string.Equals(role, "host", StringComparison.OrdinalIgnoreCase)) { connectionRole = ConnectionRole.Host; } // Start Processing of requests using (var requestHandler = new TestRequestHandler(new TestHostConnectionInfo { Endpoint = endpoint, Role = connectionRole, Transport = Transport.Sockets })) { // Attach to exit of parent process var parentProcessId = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, ParentProcessIdArgument); EqtTrace.Info("DefaultEngineInvoker: Monitoring parent process with id: '{0}'", parentProcessId); // In remote scenario we cannot monitor parent process, so we expect user to pass parentProcessId as -1 if (parentProcessId != -1) { var processHelper = new ProcessHelper(); processHelper.SetExitCallback( parentProcessId, () => { EqtTrace.Info("DefaultEngineInvoker: ParentProcess '{0}' Exited.", parentProcessId); new PlatformEnvironment().Exit(1); }); } // Initialize Communication EqtTrace.Info("DefaultEngineInvoker: Initialize communication on endpoint address: '{0}'", endpoint); requestHandler.InitializeCommunication(); // Initialize DataCollection Communication if data collection port is provided. var dcPort = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, DataCollectionPortArgument); if (dcPort > 0) { var dataCollectionTestCaseEventSender = DataCollectionTestCaseEventSender.Create(); dataCollectionTestCaseEventSender.InitializeCommunication(dcPort); dataCollectionTestCaseEventSender.WaitForRequestSenderConnection(ClientListenTimeOut); } // Start processing async in a different task EqtTrace.Info("DefaultEngineInvoker: Start Request Processing."); var requestData = new RequestData(new MetricsCollection()); var processingTask = this.StartProcessingAsync(requestHandler, new TestHostManagerFactory(requestData)); // Wait for processing to complete. Task.WaitAny(processingTask); if (dcPort > 0) { // Close socket communication connection. DataCollectionTestCaseEventSender.Instance.Close(); } } }