private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync(IEnumerable <AttachmentSet> attachments, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler eventHandler, CancellationToken cancellationToken) { try { var payload = new TestRunAttachmentsProcessingPayload { Attachments = attachments, CollectMetrics = collectMetrics }; this.communicationManager.SendMessage(MessageType.TestRunAttachmentsProcessingStart, payload); var isTestRunAttachmentsProcessingComplete = false; using (cancellationToken.Register(() => this.communicationManager.SendMessage(MessageType.TestRunAttachmentsProcessingCancel))) { // Cycle through the messages that the vstest.console sends. // Currently each of the operations are not separate tasks since they should not each take much time. // This is just a notification. while (!isTestRunAttachmentsProcessingComplete) { var message = await this.TryReceiveMessageAsync().ConfigureAwait(false); if (string.Equals(MessageType.TestRunAttachmentsProcessingComplete, message.MessageType)) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Process complete."); } var testRunAttachmentsProcessingCompletePayload = this.dataSerializer.DeserializePayload <TestRunAttachmentsProcessingCompletePayload>(message); eventHandler.HandleTestRunAttachmentsProcessingComplete(testRunAttachmentsProcessingCompletePayload.AttachmentsProcessingCompleteEventArgs, testRunAttachmentsProcessingCompletePayload.Attachments); isTestRunAttachmentsProcessingComplete = true; } else if (string.Equals(MessageType.TestRunAttachmentsProcessingProgress, message.MessageType)) { var testRunAttachmentsProcessingProgressPayload = this.dataSerializer.DeserializePayload <TestRunAttachmentsProcessingProgressPayload>(message); eventHandler.HandleTestRunAttachmentsProcessingProgress(testRunAttachmentsProcessingProgressPayload.AttachmentsProcessingProgressEventArgs); } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { var testMessagePayload = this.dataSerializer.DeserializePayload <TestMessagePayload>(message); eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); } else { EqtTrace.Warning($"VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Unexpected message received {message.MessageType}."); } } } } catch (Exception exception) { EqtTrace.Error("Aborting Test Session End Operation: {0}", exception); eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestRunAttachmentsProcessing); eventHandler.HandleTestRunAttachmentsProcessingComplete(new TestRunAttachmentsProcessingCompleteEventArgs(false, exception), null); // Earlier we were closing the connection with vstest.console in case of exceptions // Removing that code because vstest.console might be in a healthy state and letting the client // know of the error, so that the TL can wait for the next instruction from the client itself. // Also, connection termination might not kill the process which could result in files being locked by testhost. } finally { this.testPlatformEventSource.TranslationLayerTestRunAttachmentsProcessingStop(); } }
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); // choose the highest version that we both support var negotiatedVersion = Math.Min(version, highestSupportedVersion); // BUT don't choose 3, because protocol version 3 has performance problems in 16.7.1-16.8. Those problems are caused // by choosing payloadSerializer instead of payloadSerializer2 for protocol version 3. // // We cannot just update the code to choose the new serializer, because then that change would apply only to testhost. // Testhost is is delivered by Microsoft.NET.Test.SDK nuget package, and can be used with an older vstest.console. // An older vstest.console, that supports protocol version 3, would serialize its messages using payloadSerializer, // but the fixed testhost would serialize it using payloadSerializer2, resulting in incompatible messages. // // Instead we must downgrade to protocol version 2 when 3 would be negotiated. Or higher when higher version // would be negotiated. if (negotiatedVersion != 3) { this.protocolVersion = negotiatedVersion; } else { var flag = Environment.GetEnvironmentVariable("VSTEST_DISABLE_PROTOCOL_3_VERSION_DOWNGRADE"); var flagIsEnabled = flag != null && flag != "0"; var dowgradeIsDisabled = flagIsEnabled; if (dowgradeIsDisabled) { this.protocolVersion = negotiatedVersion; } else { this.protocolVersion = 2; } } // 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: { //System.Diagnostics.Debugger.Launch(); //System.Diagnostics.Debugger.Break(); 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: { //System.Diagnostics.Debugger.Launch(); //System.Diagnostics.Debugger.Break(); 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.onLaunchAdapterProcessWithDebuggerAttachedAckReceived?.Invoke(message); break; case MessageType.AttachDebuggerCallback: this.onAttachDebuggerAckRecieved?.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: { // Don't do anything for now. break; } default: { EqtTrace.Info("Invalid Message types"); break; } } }
/// <summary> /// Run Tests with given a set of test cases. /// </summary> /// <param name="testRunRequestPayload">TestRun request Payload</param> /// <param name="testHostLauncher">TestHost Launcher for the run</param> /// <param name="testRunEventsRegistrar">event registrar for run events</param> /// <param name="protocolConfig">Protocol related information</param> /// <returns>True, if successful</returns> public bool RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLauncher testHostLauncher, ITestRunEventsRegistrar testRunEventsRegistrar, ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.RunTests: run tests started."); TestRunCriteria runCriteria = null; var runsettings = testRunRequestPayload.RunSettings; if (testRunRequestPayload.TestPlatformOptions != null) { this.telemetryOptedIn = testRunRequestPayload.TestPlatformOptions.CollectMetrics; } var requestData = this.GetRequestData(protocolConfig); // Get sources to auto detect fx and arch for both run selected or run all scenario. var sources = GetSources(testRunRequestPayload); if (this.UpdateRunSettingsIfRequired(runsettings, sources, out string updatedRunsettings)) { runsettings = updatedRunsettings; } if (InferRunSettingsHelper.IsTestSettingsEnabled(runsettings)) { bool throwException = false; if (this.commandLineOptions.EnableCodeCoverage) { var dataCollectorsFriendlyNames = XmlRunSettingsUtilities.GetDataCollectorsFriendlyName(runsettings); if (dataCollectorsFriendlyNames.Count >= 2) { throwException = true; } } else if (XmlRunSettingsUtilities.IsDataCollectionEnabled(runsettings)) { throwException = true; } if (throwException) { throw new SettingsException(string.Format(Resources.RunsettingsWithDCErrorMessage, runsettings)); } } var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings); var batchSize = runConfiguration.BatchSize; if (requestData.IsTelemetryOptedIn) { // Collect Metrics this.CollectMetrics(requestData, runConfiguration); // Collect Commands this.LogCommandsTelemetryPoints(requestData); } if (!commandLineOptions.IsDesignMode) { // Generate fakes settings only for command line scenarios. In case of // Editors/IDEs, this responsibility is with the caller. GenerateFakesUtilities.GenerateFakesSettings(this.commandLineOptions, this.commandLineOptions.Sources.ToList(), ref runsettings); } if (testRunRequestPayload.Sources != null && testRunRequestPayload.Sources.Any()) { runCriteria = new TestRunCriteria( testRunRequestPayload.Sources, batchSize, testRunRequestPayload.KeepAlive, runsettings, this.commandLineOptions.TestStatsEventTimeout, testHostLauncher); runCriteria.TestCaseFilter = testRunRequestPayload.TestPlatformOptions?.TestCaseFilter; runCriteria.FilterOptions = testRunRequestPayload.TestPlatformOptions?.FilterOptions; } else { runCriteria = new TestRunCriteria( testRunRequestPayload.TestCases, batchSize, testRunRequestPayload.KeepAlive, runsettings, this.commandLineOptions.TestStatsEventTimeout, testHostLauncher); } var success = this.RunTests(requestData, runCriteria, testRunEventsRegistrar); EqtTrace.Info("TestRequestManager.RunTests: run tests completed, sucessful: {0}.", success); this.testPlatformEventSource.ExecutionRequestStop(); // Post the run complete event this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestExecutionCompleteEvent, requestData.MetricsCollection.Metrics); return(success); }
/// <summary> /// Cancel the test discovery. /// </summary> public void CancelDiscovery() { EqtTrace.Info("TestRequestManager.CancelTestDiscovery: Sending cancel request."); this.currentDiscoveryRequest?.Abort(); }
/// <inheritdoc/> public void CancelTestRunAttachmentsProcessing() { EqtTrace.Info("TestRequestManager.CancelTestRunAttachmentsProcessing: Sending cancel request."); this.currentAttachmentsProcessingCancellationTokenSource?.Cancel(); }
/// <summary> /// Discover Tests given a list of sources, run settings. /// </summary> /// <param name="discoveryPayload">Discovery payload</param> /// <param name="discoveryEventsRegistrar">EventHandler for discovered tests</param> /// <param name="protocolConfig">Protocol related information</param> /// <returns>True, if successful</returns> public bool DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests started."); bool success = false; var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(discoveryPayload.RunSettings); var batchSize = runConfiguration.BatchSize; var runsettings = discoveryPayload.RunSettings; if (this.UpdateRunSettingsIfRequired(runsettings, out string updatedRunsettings)) { runsettings = updatedRunsettings; } runsettings = UpdateExtensionsFolderInRunSettings(runsettings); // create discovery request var criteria = new DiscoveryCriteria(discoveryPayload.Sources, batchSize, this.commandLineOptions.TestStatsEventTimeout, runsettings); using (IDiscoveryRequest discoveryRequest = this.testPlatform.CreateDiscoveryRequest(criteria, protocolConfig)) { try { this.testLoggerManager?.RegisterDiscoveryEvents(discoveryRequest); discoveryEventsRegistrar?.RegisterDiscoveryEvents(discoveryRequest); this.testPlatformEventSource.DiscoveryRequestStart(); discoveryRequest.DiscoverAsync(); discoveryRequest.WaitForCompletion(); success = true; } catch (Exception ex) { if (ex is TestPlatformException || ex is SettingsException || ex is InvalidOperationException) { #if TODO Utilities.RaiseTestRunError(testLoggerManager, null, ex); #endif success = false; } else { throw; } } finally { this.testLoggerManager?.UnregisterDiscoveryEvents(discoveryRequest); discoveryEventsRegistrar?.UnregisterDiscoveryEvents(discoveryRequest); } } EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests completed, successful: {0}.", success); this.testPlatformEventSource.DiscoveryRequestStop(); return(success); }
/// <summary> /// Discover Tests given a list of sources, run settings. /// </summary> /// <param name="discoveryPayload">Discovery payload</param> /// <param name="discoveryEventsRegistrar">EventHandler for discovered tests</param> /// <param name="protocolConfig">Protocol related information</param> /// <returns>True, if successful</returns> public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests started."); var runsettings = discoveryPayload.RunSettings; if (discoveryPayload.TestPlatformOptions != null) { this.telemetryOptedIn = discoveryPayload.TestPlatformOptions.CollectMetrics; } var requestData = this.GetRequestData(protocolConfig); if (this.UpdateRunSettingsIfRequired(runsettings, discoveryPayload.Sources?.ToList(), discoveryEventsRegistrar, out string updatedRunsettings)) { runsettings = updatedRunsettings; } var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings); var batchSize = runConfiguration.BatchSize; var testCaseFilterFromRunsettings = runConfiguration.TestCaseFilter; if (requestData.IsTelemetryOptedIn) { // Collect Metrics this.CollectMetrics(requestData, runConfiguration); // Collect Commands this.LogCommandsTelemetryPoints(requestData); } // create discovery request var criteria = new DiscoveryCriteria(discoveryPayload.Sources, batchSize, this.commandLineOptions.TestStatsEventTimeout, runsettings) { TestCaseFilter = this.commandLineOptions.TestCaseFilterValue ?? testCaseFilterFromRunsettings }; // Make sure to run the run request inside a lock as the below section is not thread-safe // There can be only one discovery or execution request at a given point in time lock (this.syncObject) { try { EqtTrace.Info("TestRequestManager.DiscoverTests: Synchronization context taken"); this.currentDiscoveryRequest = this.testPlatform.CreateDiscoveryRequest(requestData, criteria, discoveryPayload.TestPlatformOptions); discoveryEventsRegistrar?.RegisterDiscoveryEvents(this.currentDiscoveryRequest); // Notify start of discovery start this.testPlatformEventSource.DiscoveryRequestStart(); // Start the discovery of tests and wait for completion this.currentDiscoveryRequest.DiscoverAsync(); this.currentDiscoveryRequest.WaitForCompletion(); } finally { if (this.currentDiscoveryRequest != null) { // Dispose the discovery request and unregister for events discoveryEventsRegistrar?.UnregisterDiscoveryEvents(currentDiscoveryRequest); this.currentDiscoveryRequest.Dispose(); this.currentDiscoveryRequest = null; } EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests completed."); this.testPlatformEventSource.DiscoveryRequestStop(); // Posts the Discovery Complete event. this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestDiscoveryCompleteEvent, requestData.MetricsCollection.Metrics); } } }
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); }
public void Invoke(IDictionary <string, string> argsDictionary) { DefaultEngineInvoker.InitializeEqtTrace(argsDictionary); if (EqtTrace.IsVerboseEnabled) { var version = typeof(DefaultEngineInvoker) .GetTypeInfo() .Assembly .GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion; EqtTrace.Verbose($"Version: { version }"); } if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DefaultEngineInvoker.Invoke: Testhost process started with args :{0}", string.Join(",", argsDictionary)); #if NETFRAMEWORK var appConfigText = System.IO.File.ReadAllText(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); EqtTrace.Info("DefaultEngineInvoker: Using Application Configuration: '{0}'", appConfigText); #endif } #if NETCOREAPP TestHostTraceListener.Setup(); #endif this.SetParentProcessExitCallback(argsDictionary); this.requestHandler.ConnectionInfo = DefaultEngineInvoker.GetConnectionInfo(argsDictionary); // Initialize Communication with vstest.console this.requestHandler.InitializeCommunication(); // skipping because 0 is the default value, and also the value the the callers use when they // call with the parameter specified, but without providing an actual port var dcPort = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, DataCollectionPortArgument); if (dcPort > 0) { this.ConnectToDatacollector(dcPort); } var requestData = DefaultEngineInvoker.GetRequestData(argsDictionary); // Start processing async in a different task EqtTrace.Info("DefaultEngineInvoker.Invoke: Start Request Processing."); try { this.StartProcessingAsync(requestHandler, new TestHostManagerFactory(requestData)).Wait(); } finally { if (dcPort > 0) { // Close datacollector communication. this.dataCollectionTestCaseEventSender.Close(); } this.requestHandler.Dispose(); } }
/// <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.Fail("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. if (this.TryLoadFromCache(assemblyNameToLoad, isReflectionOnly, out var 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); } }
/// <summary> /// Launches a process with a given process info under debugger /// Adapter get to call into this to launch any additional processes under debugger /// </summary> /// <param name="testProcessStartInfo">Process start info</param> /// <returns>ProcessId of the launched process</returns> public int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessStartInfo) { EqtTrace.Info("Sending LaunchProcessWithDebuggerAttached on additional test process: {0}", testProcessStartInfo?.FileName); return(this.requestHandler.LaunchProcessWithDebuggerAttached(testProcessStartInfo)); }
/// <summary> /// Handle test run complete. /// </summary> /// <param name="testRunCompleteArgs"> The test run complete args. </param> /// <param name="lastChunkArgs"> The last chunk args. </param> /// <param name="runContextAttachments"> The run context attachments. </param> /// <param name="executorUris"> The executor uris. </param> public void HandleTestRunComplete(TestRunCompleteEventArgs testRunCompleteArgs, TestRunChangedEventArgs lastChunkArgs, ICollection <AttachmentSet> runContextAttachments, ICollection <string> executorUris) { EqtTrace.Info("Sending test run complete"); this.requestHandler.SendExecutionComplete(testRunCompleteArgs, lastChunkArgs, runContextAttachments, executorUris); }
/// <summary> /// Handle test run stats change. /// </summary> /// <param name="testRunChangedArgs"> The test run changed args. </param> public void HandleTestRunStatsChange(TestRunChangedEventArgs testRunChangedArgs) { EqtTrace.Info("Sending test run statistics"); this.requestHandler.SendTestRunStatistics(testRunChangedArgs); }
/// <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, don't 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.LoggerManager.HandleTestRunStatsChange(lastChunkArgs); this.OnRunStatsChange.SafeInvoke(this, lastChunkArgs, "TestRun.RunStatsChanged"); } TestRunCompleteEventArgs runCompletedEvent = new TestRunCompleteEventArgs( runCompleteArgs.TestRunStatistics, runCompleteArgs.IsCanceled, runCompleteArgs.IsAborted, runCompleteArgs.Error, // This is required as TMI adapter is sending attachments as List which cannot be type casted to Collection. runContextAttachments != null ? new Collection <AttachmentSet>(runContextAttachments.ToList()) : null, 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.LoggerManager.HandleTestRunComplete(runCompletedEvent); 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(); var executionTotalTimeTaken = DateTime.UtcNow - this.executionStartTime; // Fill in the time taken to complete the run this.requestData.MetricsCollection.Add(TelemetryDataConstants.TimeTakenInSecForRun, executionTotalTimeTaken.TotalSeconds); // Fill in the Metrics From Test Host Process var metrics = runCompleteArgs.Metrics; if (metrics != null && metrics.Count != 0) { foreach (var metric in metrics) { this.requestData.MetricsCollection.Add(metric.Key, metric.Value); } } } EqtTrace.Info("TestRunRequest:TestRunComplete: Completed."); } }
/// <summary> /// Process Requests from the IDE /// </summary> /// <param name="testRequestManager"> /// The test Request Manager. /// </param> private void ProcessRequests(ITestRequestManager testRequestManager) { var isSessionEnd = false; do { try { var message = this.communicationManager.ReceiveMessage(); EqtTrace.Info("DesignModeClient: Processing Message of message type: {0}", message.MessageType); switch (message.MessageType) { case MessageType.VersionCheck: { var version = this.dataSerializer.DeserializePayload <int>(message); this.protocolConfig.Version = Math.Min(version, this.protocolConfig.Version); this.communicationManager.SendMessage(MessageType.VersionCheck, this.protocolConfig.Version); break; } case MessageType.ExtensionsInitialize: { var extensionPaths = this.communicationManager.DeserializePayload <IEnumerable <string> >(message); testRequestManager.InitializeExtensions(extensionPaths); break; } case MessageType.StartDiscovery: { var discoveryPayload = this.dataSerializer.DeserializePayload <DiscoveryRequestPayload>(message); this.StartDiscovery(discoveryPayload, testRequestManager); break; } case MessageType.GetTestRunnerProcessStartInfoForRunAll: case MessageType.GetTestRunnerProcessStartInfoForRunSelected: { var testRunPayload = this.communicationManager.DeserializePayload <TestRunRequestPayload>( message); this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: true); break; } case MessageType.TestRunAllSourcesWithDefaultHost: case MessageType.TestRunSelectedTestCasesDefaultHost: { var testRunPayload = this.communicationManager.DeserializePayload <TestRunRequestPayload>( message); this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: false); break; } case MessageType.CancelTestRun: { testRequestManager.CancelTestRun(); break; } case MessageType.AbortTestRun: { testRequestManager.AbortTestRun(); break; } case MessageType.CustomTestHostLaunchCallback: { this.onAckMessageReceived?.Invoke(message); break; } case MessageType.SessionEnd: { EqtTrace.Info("DesignModeClient: Session End message received from server. Closing the connection."); isSessionEnd = true; this.Dispose(); break; } default: { EqtTrace.Info("DesignModeClient: Invalid Message received: {0}", message); break; } } } catch (Exception ex) { EqtTrace.Error("DesignModeClient: Error processing request: {0}", ex); isSessionEnd = true; this.Dispose(); } }while (!isSessionEnd); }
/// <summary> /// Initializes the extensions while probing additional paths. /// </summary> /// <param name="pathToAdditionalExtensions">Paths to Additional extensions</param> public void InitializeExtensions(IEnumerable <string> pathToAdditionalExtensions) { EqtTrace.Info("TestRequestManager.InitializeExtensions: Initialize extensions started."); this.testPlatform.UpdateExtensions(pathToAdditionalExtensions, false); EqtTrace.Info("TestRequestManager.InitializeExtensions: Initialize extensions completed."); }
/// <summary> /// Called when Session End event is invoked /// </summary> /// <param name="sender">Sender</param> /// <param name="args">SessionEndEventArgs</param> private void SessionEndedHandler(object sender, SessionEndEventArgs args) { this.ResetInactivityTimer(); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Blame Collector : Session End"); } try { // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment if (this.testStartCount > this.testEndCount) { var filepath = Path.Combine(this.GetResultsDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } if (this.collectProcessDumpOnTrigger) { // If there was a test case crash or if we need to collect dump on process exit. if (this.testStartCount > this.testEndCount || this.collectDumpAlways) { try { var dumpFile = this.processDumpUtility.GetDumpFile(); if (!string.IsNullOrEmpty(dumpFile)) { var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } else { EqtTrace.Warning("BlameCollector.SessionEndedHandler: blame:CollectDump was enabled but dump file was not generated."); this.logger.LogWarning(args.Context, Resources.Resources.ProcDumpNotGenerated); } } catch (FileNotFoundException ex) { EqtTrace.Warning(ex.ToString()); this.logger.LogWarning(args.Context, ex.ToString()); } } } } finally { // Attempt to terminate the proc dump process if proc dump was enabled if (this.collectProcessDumpOnTrigger) { this.processDumpUtility.DetachFromTargetProcess(this.testHostProcessId); this.processDumpUtility.TerminateProcess(); } this.DeregisterEvents(); } }
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 pathToAdditionalExtensions = message.Payload.ToObject <IEnumerable <string> >(); jobQueue.QueueJob( () => testHostManagerFactory.GetDiscoveryManager().Initialize(pathToAdditionalExtensions), 0); break; } case MessageType.StartDiscovery: { EqtTrace.Info("Discovery started."); this.testHostManagerFactoryReady.Wait(); var discoveryEventsHandler = new TestDiscoveryEventHandler(this); var discoveryCriteria = message.Payload.ToObject <DiscoveryCriteria>(); jobQueue.QueueJob( () => testHostManagerFactory.GetDiscoveryManager() .DiscoverTests(discoveryCriteria, discoveryEventsHandler), 0); break; } case MessageType.ExecutionInitialize: { EqtTrace.Info("Discovery Session Initialize."); this.testHostManagerFactoryReady.Wait(); var pathToAdditionalExtensions = message.Payload.ToObject <IEnumerable <string> >(); jobQueue.QueueJob( () => testHostManagerFactory.GetExecutionManager().Initialize(pathToAdditionalExtensions), 0); break; } case MessageType.StartTestExecutionWithSources: { EqtTrace.Info("Execution started."); var testRunEventsHandler = new TestRunEventsHandler(this); this.testHostManagerFactoryReady.Wait(); var testRunCriteriaWithSources = message.Payload.ToObject <TestRunCriteriaWithSources>(); 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(); break; case MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback: this.onAckMessageRecieved?.Invoke(message); break; case MessageType.AbortTestRun: jobQueue.Pause(); this.testHostManagerFactoryReady.Wait(); testHostManagerFactory.GetExecutionManager().Abort(); 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; } } }
/// <inheritDoc /> public void ProcessRequests() { var isSessionEnd = false; do { var message = this.communicationManager.ReceiveMessage(); switch (message.MessageType) { case MessageType.DataCollectionTestStart: if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler: Test case starting."); } var testCaseStartEventArgs = message.Payload.ToObject <TestCaseStartEventArgs>(); this.dataCollectionManager.TestCaseStarted(testCaseStartEventArgs); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler: Test case started."); } break; case MessageType.DataCollectionTestEnd: if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler : Test case completing."); } var testCaseEndEventArgs = message.Payload.ToObject <TestCaseEndEventArgs>(); var attachmentSets = this.dataCollectionManager.TestCaseEnded(testCaseEndEventArgs); this.communicationManager.SendMessage(MessageType.DataCollectionTestEndResult, attachmentSets); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler: Test case completed"); } break; case MessageType.SessionEnd: isSessionEnd = true; if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler: Test session ended"); } this.Close(); break; default: if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionTestCaseEventHandler: Invalid Message types"); } break; } }while (!isSessionEnd); }
/// <summary> /// Cancel the test run. /// </summary> public void CancelTestRun() { EqtTrace.Info("TestRequestManager.CancelTestRun: Sending cancel request."); this.currentTestRunRequest?.CancelAsync(); }
/// <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> /// Aborts the test run. /// </summary> public void AbortTestRun() { EqtTrace.Info("TestRequestManager.AbortTestRun: Sending abort request."); this.currentTestRunRequest?.Abort(); }
/// <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); } this.fileHelper.MoveFile(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); } this.fileHelper.CopyFile(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copied file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } } catch (Exception ex) { this.LogError( ex.ToString(), uri, friendlyName, Guid.Parse(testCaseId)); throw; } }, this.cancellationTokenSource.Token); var continuationTask = task.ContinueWith( (t) => { try { if (t.Exception == null) { // Uri doesn't recognize file paths in unix. See https://github.com/dotnet/corefx/issues/1745 var attachmentUri = new UriBuilder() { Scheme = "file", Host = "", Path = localFilePath }.Uri; lock (attachmentTaskLock) { this.AttachmentSets[fileTransferInfo.Context][uri].Attachments.Add(new UriDataAttachment(attachmentUri, 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[fileTransferInfo.Context].Add(continuationTask); }
/// <inheritdoc /> public void Close() { this.Dispose(); EqtTrace.Info("Closing the connection !"); }
/// <summary> /// Called when a test run is completed. /// </summary> private void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e) { Output.WriteLine(string.Empty, OutputLevel.Information); // Printing Run-level Attachments var runLevelAttachementCount = (e.AttachmentSets == null) ? 0 : e.AttachmentSets.Sum(attachmentSet => attachmentSet.Attachments.Count); if (runLevelAttachementCount > 0) { Output.Information(false, CommandLineResources.AttachmentsBanner); foreach (var attachmentSet in e.AttachmentSets) { foreach (var uriDataAttachment in attachmentSet.Attachments) { var attachmentOutput = string.Format(CultureInfo.CurrentCulture, CommandLineResources.AttachmentOutputFormat, uriDataAttachment.Uri.LocalPath); Output.Information(false, attachmentOutput); } } Output.WriteLine(String.Empty, OutputLevel.Information); } // Output a summary. if (this.testsTotal > 0) { string testCountDetails; if (e.IsAborted || e.IsCanceled) { testCountDetails = string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestRunSummaryForCanceledOrAbortedRun, testsPassed, testsFailed, testsSkipped); } else { testCountDetails = string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestRunSummary, testsTotal, testsPassed, testsFailed, testsSkipped); } Output.Information(false, testCountDetails); } if (e.IsCanceled) { Output.Error(false, CommandLineResources.TestRunCanceled); } else if (e.IsAborted) { Output.Error(false, CommandLineResources.TestRunAborted); } else if (this.testOutcome == TestOutcome.Failed && this.testsTotal > 0) { Output.Error(false, CommandLineResources.TestRunFailed); } else if (this.testsTotal > 0) { Output.Information(false, ConsoleColor.Green, CommandLineResources.TestRunSuccessful); } if (this.testsTotal > 0) { if (!e.ElapsedTimeInRunningTests.Equals(TimeSpan.Zero)) { PrintTimeSpan(e.ElapsedTimeInRunningTests); } else { EqtTrace.Info("Skipped printing test execution time on console because it looks like the test run had faced some errors"); } } }
/// <summary> /// Discover Tests given a list of sources, run settings. /// </summary> /// <param name="discoveryPayload">Discovery payload</param> /// <param name="discoveryEventsRegistrar">EventHandler for discovered tests</param> /// <param name="protocolConfig">Protocol related information</param> /// <returns>True, if successful</returns> public bool DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests started."); bool success = false; var runsettings = discoveryPayload.RunSettings; if (discoveryPayload.TestPlatformOptions != null) { this.telemetryOptedIn = discoveryPayload.TestPlatformOptions.CollectMetrics; } var requestData = this.GetRequestData(protocolConfig); if (this.UpdateRunSettingsIfRequired(runsettings, discoveryPayload.Sources?.ToList(), out string updatedRunsettings)) { runsettings = updatedRunsettings; } var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings); var batchSize = runConfiguration.BatchSize; if (requestData.IsTelemetryOptedIn) { // Collect Metrics this.CollectMetrics(requestData, runConfiguration); // Collect Commands this.LogCommandsTelemetryPoints(requestData); } // create discovery request var criteria = new DiscoveryCriteria(discoveryPayload.Sources, batchSize, this.commandLineOptions.TestStatsEventTimeout, runsettings); criteria.TestCaseFilter = this.commandLineOptions.TestCaseFilterValue; try { using (IDiscoveryRequest discoveryRequest = this.testPlatform.CreateDiscoveryRequest(requestData, criteria)) { try { this.testLoggerManager?.RegisterDiscoveryEvents(discoveryRequest); discoveryEventsRegistrar?.RegisterDiscoveryEvents(discoveryRequest); this.testPlatformEventSource.DiscoveryRequestStart(); discoveryRequest.DiscoverAsync(); discoveryRequest.WaitForCompletion(); success = true; } finally { this.testLoggerManager?.UnregisterDiscoveryEvents(discoveryRequest); discoveryEventsRegistrar?.UnregisterDiscoveryEvents(discoveryRequest); } } } catch (Exception ex) { if (ex is TestPlatformException || ex is SettingsException || ex is InvalidOperationException) { LoggerUtilities.RaiseTestRunError(testLoggerManager, null, ex); success = false; } else { throw; } } EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests completed, successful: {0}.", success); this.testPlatformEventSource.DiscoveryRequestStop(); // Posts the Discovery Complete event. this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestDiscoveryCompleteEvent, requestData.MetricsCollection.Metrics); return(success); }
/// <summary> /// Execute the test run asynchronously /// </summary> /// <returns>The process id of test host.</returns> public int ExecuteAsync() { EqtTrace.Verbose("TestRunRequest.ExecuteAsync: Starting."); lock (this.syncObject) { if (this.disposed) { throw new ObjectDisposedException("testRunRequest"); } if (this.State != TestRunState.Pending) { throw new InvalidOperationException(ClientResources.InvalidStateForExecution); } this.executionStartTime = DateTime.UtcNow; // Collecting Number of sources Sent For Execution var numberOfSources = (uint)(testRunCriteria.Sources != null ? testRunCriteria.Sources.Count <string>() : 0); this.requestData.MetricsCollection.Add(TelemetryDataConstants.NumberOfSourcesSentForRun, numberOfSources); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("TestRunRequest.ExecuteAsync: Starting run with settings:{0}", this.testRunCriteria); } if (EqtTrace.IsVerboseEnabled) { // Waiting for warm up to be over. EqtTrace.Verbose("TestRunRequest.ExecuteAsync: Wait for the first run request is over."); } this.State = TestRunState.InProgress; // Reset the run completion event // (This needs to be done before queuing the test run because if the test run finishes fast then runCompletion event can // remain in non-signaled state even though run is actually complete. this.runCompletionEvent.Reset(); try { var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(this.TestRunCriteria.TestRunSettings); this.testSessionTimeout = runConfiguration.TestSessionTimeout; if (testSessionTimeout > 0) { if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose(String.Format("TestRunRequest.ExecuteAsync: TestSessionTimeout is {0} milliseconds.", testSessionTimeout)); } this.timer = new Timer(this.OnTestSessionTimeout, null, TimeSpan.FromMilliseconds(testSessionTimeout), TimeSpan.FromMilliseconds(0)); } this.runRequestTimeTracker = new Stopwatch(); // Start the stop watch for calculating the test run time taken overall this.runRequestTimeTracker.Start(); var testRunStartEvent = new TestRunStartEventArgs(this.testRunCriteria); this.LoggerManager.HandleTestRunStart(testRunStartEvent); this.OnRunStart.SafeInvoke(this, testRunStartEvent, "TestRun.TestRunStart"); int processId = this.ExecutionManager.StartTestRun(this.testRunCriteria, this); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("TestRunRequest.ExecuteAsync: Started."); } return(processId); } catch { this.State = TestRunState.Pending; throw; } } }
private bool UpdateRunSettingsIfRequired(string runsettingsXml, List <string> sources, out string updatedRunSettingsXml) { bool settingsUpdated = false; updatedRunSettingsXml = runsettingsXml; IDictionary <string, Architecture> sourcePlatforms = new Dictionary <string, Architecture>(); IDictionary <string, Framework> sourceFrameworks = new Dictionary <string, Framework>(); if (!string.IsNullOrEmpty(runsettingsXml)) { // TargetFramework is full CLR. Set DesignMode based on current context. using (var stream = new StringReader(runsettingsXml)) using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings)) { var document = new XmlDocument(); document.Load(reader); var navigator = document.CreateNavigator(); var inferedFramework = inferHelper.AutoDetectFramework(sources, sourceFrameworks); Framework chosenFramework; var inferedPlatform = inferHelper.AutoDetectArchitecture(sources, sourcePlatforms); Architecture chosenPlatform; // Update frmaework and platform if required. For commandline scenario update happens in ArgumentProcessor. bool updateFramework = IsAutoFrameworkDetectRequired(navigator, out chosenFramework); bool updatePlatform = IsAutoPlatformDetectRequired(navigator, out chosenPlatform); if (updateFramework) { InferRunSettingsHelper.UpdateTargetFramework(document, inferedFramework?.ToString(), overwrite: true); chosenFramework = inferedFramework; settingsUpdated = true; } if (updatePlatform) { InferRunSettingsHelper.UpdateTargetPlatform(document, inferedPlatform.ToString(), overwrite: true); chosenPlatform = inferedPlatform; settingsUpdated = true; } var compatibleSources = InferRunSettingsHelper.FilterCompatibleSources(chosenPlatform, chosenFramework, sourcePlatforms, sourceFrameworks, out var incompatibleSettingWarning); if (!string.IsNullOrEmpty(incompatibleSettingWarning)) { EqtTrace.Info(incompatibleSettingWarning); LoggerUtilities.RaiseTestRunWarning(this.testLoggerManager, this.testRunResultAggregator, incompatibleSettingWarning); } if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Compatible sources list : "); EqtTrace.Info(string.Join("\n", compatibleSources.ToArray())); } // If user is already setting DesignMode via runsettings or CLI args; we skip. var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml); if (!runConfiguration.DesignModeSet) { InferRunSettingsHelper.UpdateDesignMode(document, this.commandLineOptions.IsDesignMode); settingsUpdated = true; } if (!runConfiguration.CollectSourceInformationSet) { InferRunSettingsHelper.UpdateCollectSourceInformation(document, this.commandLineOptions.ShouldCollectSourceInformation); settingsUpdated = true; } if (InferRunSettingsHelper.TryGetDeviceXml(navigator, out string deviceXml)) { InferRunSettingsHelper.UpdateTargetDevice(document, deviceXml); settingsUpdated = true; } updatedRunSettingsXml = navigator.OuterXml; } } return(settingsUpdated); }
private async Task SendMessageAndListenAndReportTestResultsAsync(string messageType, object payload, ITestRunEventsHandler eventHandler, ITestHostLauncher customHostLauncher) { try { this.communicationManager.SendMessage(messageType, payload, this.protocolVersion); var isTestRunComplete = false; // Cycle through the messages that the testhost sends. // Currently each of the operations are not separate tasks since they should not each take much time. This is just a notification. while (!isTestRunComplete) { var message = await this.TryReceiveMessageAsync(); if (string.Equals(MessageType.TestRunStatsChange, message.MessageType)) { var testRunChangedArgs = this.dataSerializer.DeserializePayload <TestRunChangedEventArgs>( message); eventHandler.HandleTestRunStatsChange(testRunChangedArgs); } else if (string.Equals(MessageType.ExecutionComplete, message.MessageType)) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportTestResultsAsync: Execution complete."); } var testRunCompletePayload = this.dataSerializer.DeserializePayload <TestRunCompletePayload>(message); eventHandler.HandleTestRunComplete( testRunCompletePayload.TestRunCompleteArgs, testRunCompletePayload.LastRunTests, testRunCompletePayload.RunAttachments, testRunCompletePayload.ExecutorUris); isTestRunComplete = true; } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { var testMessagePayload = this.dataSerializer.DeserializePayload <TestMessagePayload>(message); eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); } else if (string.Equals(MessageType.CustomTestHostLaunch, message.MessageType)) { HandleCustomHostLaunch(customHostLauncher, message); } else if (string.Equals(MessageType.EditorAttachDebugger, message.MessageType)) { AttachDebuggerToProcess(customHostLauncher, message); } } } catch (Exception exception) { EqtTrace.Error("Aborting Test Run Operation: {0}", exception); eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestsRun); var completeArgs = new TestRunCompleteEventArgs(null, false, true, exception, null, TimeSpan.Zero); eventHandler.HandleTestRunComplete(completeArgs, null, null, null); // Earlier we were closing the connection with vstest.console in case of exceptions // Removing that code because vstest.console might be in a healthy state and letting the client // know of the error, so that the TL can wait for the next instruction from the client itself. // Also, connection termination might not kill the process which could result in files being locked by testhost. } this.testPlatformEventSource.TranslationLayerExecutionStop(); }