diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/CommunicationEndpointFactory.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/CommunicationEndpointFactory.cs new file mode 100644 index 0000000000..99b2621f38 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/CommunicationEndpointFactory.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities +{ + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + + /// + /// Implements ICommunicationEndpointFactory. + /// + public class CommunicationEndpointFactory : ICommunicationEndpointFactory + { + /// + public ICommunicationEndPoint Create(ConnectionRole role) + { + ICommunicationEndPoint endPoint; + if (role == ConnectionRole.Host) + { + endPoint = new SocketServer(); + } + else + { + endPoint = new SocketClient(); + } + + return endPoint; + } + } +} diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs index ba4aa8c356..d9102a7665 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs @@ -5,11 +5,12 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollect { using System; using System.Collections.Generic; + using System.Globalization; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; - + using CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.DataCollection; using Microsoft.VisualStudio.TestPlatform.Common.DataCollector; @@ -25,15 +26,14 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollect using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + /// /// Handles test session events received from vstest console process. /// internal class DataCollectionRequestHandler : IDataCollectionRequestHandler, IDisposable { - // On Slower Machines(hosted agents) with Profiling enabled 15secs is not enough for testhost to get started(weird right!!), - // hence increasing this timeout - private const int DataCollectionCommTimeOut = 60 * 1000; - private static readonly object SyncObject = new object(); private readonly ICommunicationManager communicationManager; @@ -294,21 +294,30 @@ private void HandleBeforeTestRunStart(Message message) { try { + var timeout = EnvironmentHelper.GetConnectionTimeout(); if (this.dataCollectionTestCaseEventHandler.WaitForRequestHandlerConnection( - DataCollectionCommTimeOut)) + timeout * 1000)) { this.dataCollectionTestCaseEventHandler.ProcessRequests(); } else { - EqtTrace.Error("DataCollectionRequestHandler.ProcessRequests: TestCaseEventHandler timed out while connecting to the Sender."); + EqtTrace.Error( + "DataCollectionRequestHandler.HandleBeforeTestRunStart: TestCaseEventHandler timed out while connecting to the Sender."); this.dataCollectionTestCaseEventHandler.Close(); - throw new TimeoutException(); + throw new TestPlatformException( + string.Format( + CultureInfo.CurrentUICulture, + CommunicationUtilitiesResources.ConnectionTimeoutErrorMessage, + CoreUtilitiesConstants.DatacollectorProcessName, + CoreUtilitiesConstants.TesthostProcessName, + timeout, + EnvironmentHelper.VstestConnectionTimeout)); } } catch (Exception e) { - EqtTrace.Error("DataCollectionRequestHandler.ProcessRequests : Error occured during initialization of TestHost : {0}", e); + EqtTrace.Error("DataCollectionRequestHandler.HandleBeforeTestRunStart : Error occured during initialization of TestHost : {0}", e); } }, this.cancellationTokenSource.Token); @@ -337,7 +346,7 @@ private void HandleAfterTestRunEnd(Message message) } catch (Exception ex) { - EqtTrace.Error("DataCollectionRequestHandler.ProcessRequests : {0}", ex.ToString()); + EqtTrace.Error("DataCollectionRequestHandler.HandleAfterTestRunEnd : Error while processing event from testhost: {0}", ex.ToString()); } var attachmentsets = this.dataCollectionManager.SessionEnded(isCancelled); diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs index 0e55268a01..bdd70c6c18 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs @@ -11,4 +11,5 @@ [assembly: InternalsVisibleTo("datacollector, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("datacollector.PlatformTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] +[assembly: InternalsVisibleTo("datacollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationEndpointFactory.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationEndpointFactory.cs new file mode 100644 index 0000000000..4fc2630b12 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationEndpointFactory.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces +{ + using TestPlatform.ObjectModel; + + public interface ICommunicationEndpointFactory + { + /// + /// Create communication endpoint. + /// + /// Endpoint role. + /// Return communication endpoint object. + ICommunicationEndPoint Create(ConnectionRole role); + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionTestCaseEventSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionTestCaseEventSender.cs index ba51d1b556..e73d69ef8e 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionTestCaseEventSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionTestCaseEventSender.cs @@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces /// /// Interface for sending test case events from test execution process to data collection process /// - internal interface IDataCollectionTestCaseEventSender + public interface IDataCollectionTestCaseEventSender { /// /// Setups client based on port diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestHandler.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestHandler.cs index f8a2f146ad..e15bb9a203 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestHandler.cs @@ -3,6 +3,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces { + using System; using System.Collections.Generic; using Microsoft.VisualStudio.TestPlatform.ObjectModel; @@ -13,8 +14,13 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces /// /// Defines the contract for handling test platform requests /// - public interface ITestRequestHandler + public interface ITestRequestHandler : IDisposable { + /// + /// Gets or sets connection info for to start server/client. + /// + TestHostConnectionInfo ConnectionInfo { get; set; } + /// /// Setups client based on port /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Microsoft.TestPlatform.CommunicationUtilities.csproj b/src/Microsoft.TestPlatform.CommunicationUtilities/Microsoft.TestPlatform.CommunicationUtilities.csproj index d628ab72d1..2e7ec2d4d4 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Microsoft.TestPlatform.CommunicationUtilities.csproj +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Microsoft.TestPlatform.CommunicationUtilities.csproj @@ -39,10 +39,16 @@ - ResXFileCodeGenerator + PublicResXFileCodeGenerator Resources.Designer.cs + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + 1621415e-7723-4f46-a589-4c4620c0751a diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs index 51df712ef3..a2f1fef914 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs @@ -20,10 +20,10 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { + public class Resources { private static global::System.Resources.ResourceManager resourceMan; @@ -37,7 +37,7 @@ internal Resources() { /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources", typeof(Resources).GetTypeInfo().Assembly); @@ -52,7 +52,7 @@ internal Resources() { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { + public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -62,18 +62,18 @@ internal Resources() { } /// - /// Looks up a localized string similar to The active Test Discovery was aborted. Due to {0}. + /// Looks up a localized string similar to The active test discovery was aborted. Reason: {0}. /// - internal static string AbortedTestDiscovery { + public static string AbortedTestDiscovery { get { return ResourceManager.GetString("AbortedTestDiscovery", resourceCulture); } } /// - /// Looks up a localized string similar to The active Test Run was aborted. Due to {0}. + /// Looks up a localized string similar to The active test run was aborted. Reason: {0}. /// - internal static string AbortedTestRun { + public static string AbortedTestRun { get { return ResourceManager.GetString("AbortedTestRun", resourceCulture); } @@ -82,16 +82,25 @@ internal static string AbortedTestRun { /// /// Looks up a localized string similar to An existing connection was forcibly closed by the remote host.. /// - internal static string ConnectionClosed { + public static string ConnectionClosed { get { return ResourceManager.GetString("ConnectionClosed", resourceCulture); } } /// - /// Looks up a localized string similar to Unable to communicate with test execution process.. + /// Looks up a localized string similar to {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout.. /// - internal static string UnableToCommunicateToTestHost { + public static string ConnectionTimeoutErrorMessage { + get { + return ResourceManager.GetString("ConnectionTimeoutErrorMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to communicate with test host process.. + /// + public static string UnableToCommunicateToTestHost { get { return ResourceManager.GetString("UnableToCommunicateToTestHost", resourceCulture); } @@ -100,32 +109,26 @@ internal static string UnableToCommunicateToTestHost { /// /// Looks up a localized string similar to Unexpected message received. Expected MessageType : {0} Actual MessageType: {1}. /// - internal static string UnexpectedMessage - { - get - { + public static string UnexpectedMessage { + get { return ResourceManager.GetString("UnexpectedMessage", resourceCulture); } } - + /// /// Looks up a localized string similar to Protocol version check failed. Make sure test runner and host are compatible.. /// - internal static string VersionCheckFailed - { - get - { + public static string VersionCheckFailed { + get { return ResourceManager.GetString("VersionCheckFailed", resourceCulture); } } - + /// - /// Looks up a localized string similar to Failed to negotiate protocol. Wait for response timed out. + /// Looks up a localized string similar to Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout.. /// - internal static string VersionCheckTimedout - { - get - { + public static string VersionCheckTimedout { + get { return ResourceManager.GetString("VersionCheckTimedout", resourceCulture); } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx index 1defecfd8c..48f90d1d97 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx @@ -136,6 +136,9 @@ Protocol version check failed. Make sure test runner and host are compatible. - Failed to negotiate protocol. Wait for response timed out. + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.cs.xlf index bed798d669..7baa1c0063 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.cs.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Nepovedlo se vyjednat protokol. Při čekání na odpověď vypršel časový limit. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Nepovedlo se vyjednat protokol. Při čekání na odpověď vypršel časový limit. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.de.xlf index 51f1e70a7b..5370b85b07 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.de.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Fehler beim Verhandeln des Protokolls. Timeout beim Warten auf Antwort. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Fehler beim Verhandeln des Protokolls. Timeout beim Warten auf Antwort. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.es.xlf index 6015ae9bc2..a4fc6aa154 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.es.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - No se pudo negociar el protocolo. Se agotó el tiempo de espera para la respuesta. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + No se pudo negociar el protocolo. Se agotó el tiempo de espera para la respuesta. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.fr.xlf index ea8536bac7..c6ecaf60d0 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.fr.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Échec de la négociation du protocole. Expiration du délai d'attente de la réponse. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Échec de la négociation du protocole. Expiration du délai d'attente de la réponse. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.it.xlf index 060c9015cb..fdd33e07e0 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.it.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Non è stato possibile negoziare il protocollo. Si è verificato un timeout durante l'attesa della risposta. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Non è stato possibile negoziare il protocollo. Si è verificato un timeout durante l'attesa della risposta. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ja.xlf index f05403c1af..f72c2532b2 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ja.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - プロトコルをネゴシエートできませんでした。応答がタイムアウトするまでしばらくお待ちください。 - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + プロトコルをネゴシエートできませんでした。応答がタイムアウトするまでしばらくお待ちください。 + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ko.xlf index d9a13a981b..84856923c2 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ko.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - 프로토콜을 협상하지 못했습니다. 응답 시간이 초과될 때까지 기다려 주세요. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + 프로토콜을 협상하지 못했습니다. 응답 시간이 초과될 때까지 기다려 주세요. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pl.xlf index 310bff4932..06e1bc3b1e 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pl.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Nie można negocjować protokołu. Zaczekaj na przekroczenie limitu czasu odpowiedzi. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Nie można negocjować protokołu. Zaczekaj na przekroczenie limitu czasu odpowiedzi. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pt-BR.xlf index 552be7fd49..70ab80a888 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.pt-BR.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Falha ao negociar o protocolo. Aguarde a resposta atingir o tempo limite. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Falha ao negociar o protocolo. Aguarde a resposta atingir o tempo limite. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ru.xlf index 1ef3e063fe..84d0c39a99 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.ru.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Не удалось согласовать протокол. Подождите, пока истечет время ожидания ответа. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Не удалось согласовать протокол. Подождите, пока истечет время ожидания ответа. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.tr.xlf index 209ebf854b..bc704988c0 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.tr.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - Protokol üzerinde anlaşmaya varılamadı. Yanıt beklenirken zaman aşımı gerçekleşti. - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + Protokol üzerinde anlaşmaya varılamadı. Yanıt beklenirken zaman aşımı gerçekleşti. + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.xlf index 1c97df34a8..c74f5aa81e 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.xlf @@ -29,10 +29,15 @@ - Failed to negotiate protocol. Wait for response timed out. + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. Failed to negotiate protocol. Wait for response timed out. + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hans.xlf index fd11b59dca..d2a47ba695 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hans.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - 未能协商协议。等待响应超时。 - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + 未能协商协议。等待响应超时。 + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hant.xlf index f1ed3e4784..8d14d594b6 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/xlf/Resources.zh-Hant.xlf @@ -67,9 +67,14 @@ - Failed to negotiate protocol. Wait for response timed out. - 無法交涉通訊協定。請等候回應逾時。 - + Failed to negotiate protocol, waiting for response timed out after {0} seconds. This may occur due to machine slowness, please set environment variable {1} to increase timeout. + 無法交涉通訊協定。請等候回應逾時。 + + + + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + {0} process failed to connect to {1} process after {2} seconds. This may occur due to machine slowness, please set environment variable {3} to increase timeout. + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs index 874bdd3b2e..cb16127f5c 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs @@ -7,13 +7,13 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities using System.Collections.Generic; using System.Globalization; using System.Threading; - + using CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using CommonResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; /// @@ -96,11 +96,11 @@ internal TestRequestSender( /// Protocol configuration. /// Time to wait for client process exit. internal TestRequestSender( - ICommunicationEndPoint communicationEndPoint, - TestHostConnectionInfo connectionInfo, - IDataSerializer serializer, - ProtocolConfig protocolConfig, - int clientExitedWaitTime) + ICommunicationEndPoint communicationEndPoint, + TestHostConnectionInfo connectionInfo, + IDataSerializer serializer, + ProtocolConfig protocolConfig, + int clientExitedWaitTime) : this(connectionInfo, serializer, protocolConfig, clientExitedWaitTime) { this.communicationEndpoint = communicationEndPoint; @@ -198,9 +198,10 @@ public void CheckVersionWithTestHost() this.channel.Send(data); // Wait for negotiation response - if (!protocolNegotiated.WaitOne(60 * 1000)) + var timeout = EnvironmentHelper.GetConnectionTimeout(); + if (!protocolNegotiated.WaitOne(timeout * 1000)) { - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.VersionCheckTimedout)); + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.VersionCheckTimedout, timeout, EnvironmentHelper.VstestConnectionTimeout)); } } finally diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Constants.cs b/src/Microsoft.TestPlatform.CoreUtilities/Constants.cs new file mode 100644 index 0000000000..d9856906a0 --- /dev/null +++ b/src/Microsoft.TestPlatform.CoreUtilities/Constants.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CoreUtilities +{ + /// + /// The set of constants required for across various(Communication, CrossPlatform, etc.) modules. + /// + public class Constants + { + /// + /// Vstest.console process name, without file extension(.exe/.dll) + /// + public const string VstestConsoleProcessName = "vstest.console"; + + /// + /// Testhost process name, without file extension(.exe/.dll) and architecture type(x86). + /// + public const string TesthostProcessName = "testhost"; + + /// + /// Datacollector process name, without file extension(.exe/.dll) + /// + public const string DatacollectorProcessName = "datacollector"; + } +} diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Helpers/EnvironmentHelper.cs b/src/Microsoft.TestPlatform.CoreUtilities/Helpers/EnvironmentHelper.cs new file mode 100644 index 0000000000..23f9f6e502 --- /dev/null +++ b/src/Microsoft.TestPlatform.CoreUtilities/Helpers/EnvironmentHelper.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers +{ + using System; + using ObjectModel; + + public class EnvironmentHelper + { + public const string VstestConnectionTimeout = "VSTEST_CONNECTION_TIMEOUT"; + public const int DefaultConnectionTimeout = 90; // seconds + + /// + /// Get timeout based on environment variable VSTEST_CONNECTION_TIMEOUT. + /// + public static int GetConnectionTimeout() + { + var envVarValue = Environment.GetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout); + if (!string.IsNullOrEmpty(envVarValue) && int.TryParse(envVarValue, out int value) && value >= 0) + { + EqtTrace.Info("EnvironmentHelper.GetConnectionTimeout: {0} value set to {1}.", EnvironmentHelper.VstestConnectionTimeout, value); + } + else + { + value = EnvironmentHelper.DefaultConnectionTimeout; + } + + return value; + } + } +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index 61b87c7a1b..4d735df490 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -42,7 +42,7 @@ public class ProxyDiscoveryManager : ProxyOperationManager, IProxyDiscoveryManag /// Test request sender instance. /// Test host manager instance. public ProxyDiscoveryManager(IRequestData requestData, ITestRequestSender testRequestSender, ITestRuntimeProvider testHostManager) - : this(requestData, testRequestSender, testHostManager, JsonDataSerializer.Instance, CrossPlatEngine.Constants.ClientConnectionTimeout) + : this(requestData, testRequestSender, testHostManager, JsonDataSerializer.Instance) { this.testHostManager = testHostManager; } @@ -51,23 +51,19 @@ public ProxyDiscoveryManager(IRequestData requestData, ITestRequestSender testRe /// Initializes a new instance of the class. /// Constructor with Dependency injection. Used for unit testing. /// + /// /// - /// The request Sender. + /// The request Sender. /// /// - /// Test host Manager instance + /// Test host Manager instance /// /// - /// - /// The client Connection Timeout - /// - internal ProxyDiscoveryManager( - IRequestData requestData, + internal ProxyDiscoveryManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager, - IDataSerializer dataSerializer, - int clientConnectionTimeout) - : base(requestData, requestSender, testHostManager, clientConnectionTimeout) + IDataSerializer dataSerializer) + : base(requestData, requestSender, testHostManager) { this.dataSerializer = dataSerializer; this.testHostManager = testHostManager; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index bf979588e4..3bb1963620 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -22,8 +22,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - using Constants = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Constants; - /// /// Orchestrates test execution operations for the engine communicating with the client. /// @@ -49,7 +47,7 @@ internal class ProxyExecutionManager : ProxyOperationManager, IProxyExecutionMan /// Test request sender instance. /// Test host manager for this proxy. public ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) : - this(requestData, requestSender, testHostManager, JsonDataSerializer.Instance, Constants.ClientConnectionTimeout) + this(requestData, requestSender, testHostManager, JsonDataSerializer.Instance) { } @@ -61,9 +59,9 @@ public ProxyExecutionManager(IRequestData requestData, ITestRequestSender reques /// Request Sender instance /// Test host manager instance /// - /// The client Connection Timeout - internal ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager, IDataSerializer dataSerializer, int clientConnectionTimeout) - : base(requestData, requestSender, testHostManager, clientConnectionTimeout) + internal ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager, IDataSerializer dataSerializer) + : base(requestData, requestSender, testHostManager) { this.testHostManager = testHostManager; this.dataSerializer = dataSerializer; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs index aa6c886d12..912a896cfa 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using System.Linq; using System.Reflection; using System.Threading; - + using CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Extensions; using Microsoft.VisualStudio.TestPlatform.ObjectModel; @@ -22,6 +22,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.Utilities; using CrossPlatEngineResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; /// /// Base class for any operations that the client needs to drive through the engine. @@ -30,7 +32,6 @@ public abstract class ProxyOperationManager { private readonly ITestRuntimeProvider testHostManager; private readonly IProcessHelper processHelper; - private readonly int connectionTimeout; private readonly string versionCheckPropertyName = "IsVersionCheckRequired"; private readonly string makeRunsettingsCompatiblePropertyName = "MakeRunsettingsCompatible"; private bool versionCheckRequired = true; @@ -49,13 +50,12 @@ public abstract class ProxyOperationManager /// /// Initializes a new instance of the class. /// + /// /// Request Sender instance. /// Test host manager instance. - /// Client Connection Timeout. - protected ProxyOperationManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager, int clientConnectionTimeout) + protected ProxyOperationManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) { this.RequestSender = requestSender; - this.connectionTimeout = clientConnectionTimeout; this.testHostManager = testHostManager; this.processHelper = new ProcessHelper(); this.initialized = false; @@ -93,14 +93,8 @@ protected ProxyOperationManager(IRequestData requestData, ITestRequestSender req /// public virtual bool SetupChannel(IEnumerable sources, CancellationToken cancellationToken) { - var connTimeout = this.connectionTimeout; + var connTimeout = EnvironmentHelper.GetConnectionTimeout(); - var userSpecifiedTimeout = Environment.GetEnvironmentVariable("VSTEST_CONNECTION_TIMEOUT"); - if(!string.IsNullOrEmpty(userSpecifiedTimeout) && Int32.TryParse(userSpecifiedTimeout, out int result)) - { - connTimeout = result * 1000; - } - if (!this.initialized) { this.testHostProcessStdError = string.Empty; @@ -151,21 +145,14 @@ public virtual bool SetupChannel(IEnumerable sources, CancellationToken OutputLevel.Information); // Increase connection timeout when debugging is enabled. - connTimeout = 5 * this.connectionTimeout; + connTimeout *= 5; } // Wait for a timeout for the client to connect. - if (!this.testHostLaunched || !this.RequestSender.WaitForRequestHandlerConnection(connTimeout)) + if (!this.testHostLaunched || + !this.RequestSender.WaitForRequestHandlerConnection(connTimeout * 1000)) { - var errorMsg = CrossPlatEngineResources.InitializationFailed; - - if (!string.IsNullOrWhiteSpace(this.testHostProcessStdError)) - { - // Testhost failed with error - errorMsg = string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError); - } - - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, errorMsg)); + this.ThrowExceptionOnConnectionFailure(connTimeout); } // Handling special case for dotnet core projects with older test hosts @@ -310,5 +297,31 @@ private void TestHostManagerHostExited(object sender, HostProviderEventArgs e) this.testHostExited.Set(); } + + private void ThrowExceptionOnConnectionFailure(int connTimeout) + { + // Failed to launch testhost process. + var errorMsg = CrossPlatEngineResources.InitializationFailed; + + // Testhost launched but Timeout occured due to machine slowness. + if (this.testHostLaunched) + { + errorMsg = string.Format( + CommunicationUtilitiesResources.ConnectionTimeoutErrorMessage, + CoreUtilitiesConstants.VstestConsoleProcessName, + CoreUtilitiesConstants.TesthostProcessName, + connTimeout, + EnvironmentHelper.VstestConnectionTimeout); + } + + // After testhost process launched failed with error. + if (!string.IsNullOrWhiteSpace(this.testHostProcessStdError)) + { + // Testhost failed with error + errorMsg = string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError); + } + + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, errorMsg)); + } } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Constants.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Constants.cs deleted file mode 100644 index a49871364b..0000000000 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Constants.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine -{ - using System.Runtime.InteropServices; - - /// - /// The set of constants used throughout this project. - /// - public class Constants - { - /// - /// The port option to be specified to the test host process. - /// - internal const string PortOption = "--port"; - - internal const string ParentProcessIdOption = "--parentprocessid"; - - /// - /// The connection timeout for clients in milliseconds. - /// - internal const int ClientConnectionTimeout = 60 * 1000; - } -} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs index e694b79678..1fb1745a19 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs @@ -59,13 +59,17 @@ public DataCollectionLauncher(IProcessHelper processHelper, IMessageLogger messa if (exitCode != 0) { - EqtTrace.Error("Data collector exited with error: '{0}'", processStdErrorStr); + EqtTrace.Error("DataCollectionLauncher.ExitCallBack: Data collector exited with exitcode:{0} error: '{1}'", exitCode, processStdErrorStr); if (!string.IsNullOrWhiteSpace(processStdErrorStr)) { this.messageLogger.SendMessage(TestMessageLevel.Error, processStdErrorStr); } } + else + { + EqtTrace.Info("DataCollectionLauncher.ExitCallBack: Data collector exited with exitcode: 0 error: '{0}'", processStdErrorStr); + } }; /// @@ -77,7 +81,7 @@ public DataCollectionLauncher(IProcessHelper processHelper, IMessageLogger messa { // Log all standard error message because on too much data we ignore starting part. // This is helpful in abnormal failure of process. - EqtTrace.Warning("Data collector standard error line: {0}", data); + EqtTrace.Warning("DataCollectionLauncher.ErrorReceivedCallback: Data collector standard error line: {0}", data); // Add newline for readbility. data += Environment.NewLine; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs index 6dbb07ad9f..c8f5cdf63c 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs @@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection using System.Linq; using System.Reflection; using System.Xml; - + using CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; @@ -27,6 +27,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection using Microsoft.VisualStudio.TestPlatform.Utilities; using CrossPlatEngineResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; /// /// Managed datacollector interaction from runner process. @@ -36,15 +38,12 @@ internal class ProxyDataCollectionManager : IProxyDataCollectionManager private const string PortOption = "--port"; private const string DiagOption = "--diag"; private const string ParentProcessIdOption = "--parentprocessid"; - public const int DataCollectorConnectionTimeout = 30 * 1000; // In milliseconds. - public const string TimeoutEnvironmentVaribleName = "VSTEST_DATACOLLECTOR_CONNECTION_TIMEOUT"; public const string DebugEnvironmentVaribleName = "VSTEST_DATACOLLECTOR_DEBUG"; private IDataCollectionRequestSender dataCollectionRequestSender; private IDataCollectionLauncher dataCollectionLauncher; private IProcessHelper processHelper; private string settingsXml; - private int connectionTimeout; private IRequestData requestData; private int dataCollectionPort; private int dataCollectionProcessId; @@ -67,13 +66,13 @@ public ProxyDataCollectionManager(IRequestData requestData, string settingsXml) /// Initializes a new instance of the class. /// /// - /// Request Data providing common execution/discovery services. + /// Request Data providing common execution/discovery services. /// /// - /// The settings xml. + /// The settings xml. /// /// - /// The process helper. + /// The process helper. /// internal ProxyDataCollectionManager(IRequestData requestData, string settingsXml, IProcessHelper processHelper) : this(requestData, settingsXml, new DataCollectionRequestSender(), processHelper, DataCollectionLauncherFactory.GetDataCollectorLauncher(processHelper, settingsXml)) { @@ -83,21 +82,23 @@ public ProxyDataCollectionManager(IRequestData requestData, string settingsXml) /// Initializes a new instance of the class. /// /// - /// Request Data providing common execution/discovery services. + /// Request Data providing common execution/discovery services. /// /// - /// Runsettings that contains the datacollector related configuration. + /// Runsettings that contains the datacollector related configuration. /// /// - /// Handles communication with datacollector process. + /// Handles communication with datacollector process. /// /// - /// The process Helper. + /// The process Helper. /// /// - /// Launches datacollector process. + /// Launches datacollector process. /// - internal ProxyDataCollectionManager(IRequestData requestData, string settingsXml, IDataCollectionRequestSender dataCollectionRequestSender, IProcessHelper processHelper, IDataCollectionLauncher dataCollectionLauncher) + internal ProxyDataCollectionManager(IRequestData requestData, string settingsXml, + IDataCollectionRequestSender dataCollectionRequestSender, IProcessHelper processHelper, + IDataCollectionLauncher dataCollectionLauncher) { // DataCollector process needs the information of the Extensions folder // Add the Extensions folder path to runsettings. @@ -107,8 +108,8 @@ internal ProxyDataCollectionManager(IRequestData requestData, string settingsXml this.dataCollectionRequestSender = dataCollectionRequestSender; this.dataCollectionLauncher = dataCollectionLauncher; this.processHelper = processHelper; - this.connectionTimeout = ProxyDataCollectionManager.DataCollectorConnectionTimeout; this.LogEnabledDataCollectors(); + } /// @@ -207,20 +208,30 @@ public void Initialize() this.dataCollectionProcessId = this.dataCollectionLauncher.LaunchDataCollector(null, this.GetCommandLineArguments(this.dataCollectionPort)); EqtTrace.Info("ProxyDataCollectionManager.Initialize: Launched datacollector processId: {0} port: {1}", this.dataCollectionProcessId, this.dataCollectionPort); - ChangeConnectionTimeoutIfRequired(dataCollectionProcessId); + var connectionTimeout = this.GetConnectionTimeout(dataCollectionProcessId); - EqtTrace.Info("ProxyDataCollectionManager.Initialize: waiting for connection with timeout: {0}", this.connectionTimeout); + EqtTrace.Info("ProxyDataCollectionManager.Initialize: waiting for connection with timeout: {0} seconds", connectionTimeout); - var connected = this.dataCollectionRequestSender.WaitForRequestHandlerConnection(this.connectionTimeout); + var connected = this.dataCollectionRequestSender.WaitForRequestHandlerConnection(connectionTimeout * 1000); if (connected == false) { EqtTrace.Error("ProxyDataCollectionManager.Initialize: failed to connect to datacollector process, processId: {0} port: {1}", this.dataCollectionProcessId, this.dataCollectionPort); - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CrossPlatEngineResources.FailedToConnectDataCollector)); + throw new TestPlatformException( + string.Format( + CultureInfo.CurrentUICulture, + CommunicationUtilitiesResources.ConnectionTimeoutErrorMessage, + CoreUtilitiesConstants.VstestConsoleProcessName, + CoreUtilitiesConstants.DatacollectorProcessName, + connectionTimeout, + EnvironmentHelper.VstestConnectionTimeout) + ); } } - private void ChangeConnectionTimeoutIfRequired(int processId) + private int GetConnectionTimeout(int processId) { + var connectionTimeout = EnvironmentHelper.GetConnectionTimeout(); + // Increase connection timeout when debugging is enabled. var dataCollectorDebugEnabled = Environment.GetEnvironmentVariable(DebugEnvironmentVaribleName); if (!string.IsNullOrEmpty(dataCollectorDebugEnabled) && @@ -230,15 +241,12 @@ private void ChangeConnectionTimeoutIfRequired(int processId) ConsoleOutput.Instance.WriteLine( string.Format("Process Id: {0}, Name: {1}", processId, this.processHelper.GetProcessName(processId)), OutputLevel.Information); - this.connectionTimeout = 5 * this.connectionTimeout; - } - // Change connection timeout if user specified environment variable VSTEST_DATACOLLECTOR_CONNECTION_TIMEOUT. - var userSpecifiedTimeout = Environment.GetEnvironmentVariable(TimeoutEnvironmentVaribleName); - if (!string.IsNullOrEmpty(userSpecifiedTimeout) && Int32.TryParse(userSpecifiedTimeout, out int result)) - { - this.connectionTimeout = result * 1000; + // Increase connection timeout when debugging is enabled. + connectionTimeout *= 5; } + + return connectionTimeout; } private void InvokeDataCollectionServiceAction(Action action, ITestMessageEventHandler runEventsHandler) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs index cbe9a27f5a..ab86de6ea0 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs @@ -20,14 +20,15 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities using Microsoft.VisualStudio.TestPlatform.Utilities; using CrossPlatResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; - public class TestRequestHandler : IDisposable, ITestRequestHandler + public class TestRequestHandler : ITestRequestHandler { private readonly IDataSerializer dataSerializer; private ITestHostManagerFactory testHostManagerFactory; private ICommunicationEndPoint communicationEndPoint; + private ICommunicationEndpointFactory communicationEndpointFactory; private int protocolVersion = 1; - private TestHostConnectionInfo connectionInfo; + public TestHostConnectionInfo ConnectionInfo { get; set; } private int highestSupportedVersion = 2; private JobQueue jobQueue; @@ -41,16 +42,16 @@ public class TestRequestHandler : IDisposable, ITestRequestHandler private Action onAckMessageRecieved; /// - /// Initializes a new instance of the . + /// Initializes a new instance of the . /// - public TestRequestHandler(TestHostConnectionInfo connectionInfo) : this(connectionInfo, JsonDataSerializer.Instance) + public TestRequestHandler() : this(JsonDataSerializer.Instance, new CommunicationEndpointFactory()) { } - protected TestRequestHandler(TestHostConnectionInfo connectionInfo, ICommunicationEndPoint communicationEndpoint, IDataSerializer dataSerializer, JobQueue jobQueue, Action onAckMessageRecieved) + protected TestRequestHandler(TestHostConnectionInfo connectionInfo, ICommunicationEndpointFactory communicationEndpointFactory, IDataSerializer dataSerializer, JobQueue jobQueue, Action onAckMessageRecieved) { - this.communicationEndPoint = communicationEndpoint; - this.connectionInfo = connectionInfo; + this.communicationEndpointFactory = communicationEndpointFactory; + this.ConnectionInfo = connectionInfo; this.dataSerializer = dataSerializer; this.requestSenderConnected = new ManualResetEventSlim(false); this.testHostManagerFactoryReady = new ManualResetEventSlim(false); @@ -59,17 +60,15 @@ protected TestRequestHandler(TestHostConnectionInfo connectionInfo, ICommunicati this.jobQueue = jobQueue; } - protected TestRequestHandler(TestHostConnectionInfo connectionInfo, IDataSerializer dataSerializer) + protected TestRequestHandler(IDataSerializer dataSerializer, ICommunicationEndpointFactory communicationEndpointFactory) { - this.connectionInfo = connectionInfo; this.dataSerializer = dataSerializer; + this.communicationEndpointFactory = communicationEndpointFactory; this.requestSenderConnected = new ManualResetEventSlim(false); this.sessionCompleted = new ManualResetEventSlim(false); this.testHostManagerFactoryReady = new ManualResetEventSlim(false); this.onAckMessageRecieved = (message) => { throw new NotImplementedException(); }; - this.SetCommunicationEndPoint(); - this.jobQueue = new JobQueue( (action) => { action(); }, "TestHostOperationQueue", @@ -82,6 +81,7 @@ protected TestRequestHandler(TestHostConnectionInfo connectionInfo, IDataSeriali /// public virtual void InitializeCommunication() { + this.communicationEndPoint = this.communicationEndpointFactory.Create(this.ConnectionInfo.Role); this.communicationEndPoint.Connected += (sender, connectedArgs) => { if (!connectedArgs.Connected) @@ -94,7 +94,7 @@ public virtual void InitializeCommunication() requestSenderConnected.Set(); }; - this.communicationEndPoint.Start(connectionInfo.Endpoint); + this.communicationEndPoint.Start(this.ConnectionInfo.Endpoint); } /// @@ -367,26 +367,6 @@ private ITestCaseEventsHandler GetTestCaseEventsHandler(string runSettings) return testCaseEventsHandler; } - private void SetCommunicationEndPoint() - { - if (this.connectionInfo.Role == ConnectionRole.Host) - { - this.communicationEndPoint = new SocketServer(); - if (EqtTrace.IsVerboseEnabled) - { - EqtTrace.Verbose("TestRequestHanlder is acting as server"); - } - } - else - { - this.communicationEndPoint = new SocketClient(); - if (EqtTrace.IsVerboseEnabled) - { - EqtTrace.Verbose("TestRequestHanlder is acting as client"); - } - } - } - private void SendData(string data) { EqtTrace.Verbose("TestRequestHandler.SendData: sending data from testhost: {0}", data); diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs index 9f220667af..7ede748973 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs @@ -133,15 +133,6 @@ internal static string ExecutionThreadApartmentStateNotSupportedForFramework { } } - /// - /// Looks up a localized string similar to Failed to connect to datacollector process.. - /// - internal static string FailedToConnectDataCollector { - get { - return ResourceManager.GetString("FailedToConnectDataCollector", resourceCulture); - } - } - /// /// Looks up a localized string similar to Failed to launch testhost with error: {0}. /// diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx index 9c5444edee..d757b30a89 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx @@ -189,7 +189,4 @@ You are using an older version of Microsoft.NET.Test.Sdk. Kindly move to a version equal or greater than 15.3.0. - - Failed to connect to datacollector process. - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf index b72842888b..104ada7f58 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf @@ -191,11 +191,6 @@ Používáte starší verzi sady Microsoft.NET.Test.Sdk. Přejděte prosím na verzi 15.3.0 nebo vyšší. - - Failed to connect to datacollector process. - Připojení k procesu kolekce dat bylo neúspěšné. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf index 5d6b8b9a98..c247e4c5cc 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf @@ -191,11 +191,6 @@ Sie verwenden eine ältere Version von Microsoft.NET.Test.Sdk. Wechseln Sie zu Version 15.3.0 oder höher. - - Failed to connect to datacollector process. - Fehler bei der Verbindungsherstellung mit dem Datensammlerprozess. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf index e85da7f235..46b32b70f0 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf @@ -191,11 +191,6 @@ Está utilizando una versión anterior de Microsoft.NET.Test.Sdk. Cámbiese a una versión igual o superior a 15.3.0. - - Failed to connect to datacollector process. - No se pudo conectar con el proceso del recopilador de datos. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf index 58c0bd6373..ee9793bac9 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf @@ -191,11 +191,6 @@ Vous utilisez une ancienne version de Microsoft.NET.Test.Sdk. Passez à une version égale ou supérieure à la version 15.3.0. - - Failed to connect to datacollector process. - Échec de la connexion au processus du collecteur de données. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf index b8dcd97001..1908b74868 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf @@ -191,11 +191,6 @@ La versione di Microsoft.NET.Test.Sdk è obsoleta. Passare alla versione 15.3.0 o a una versione successiva. - - Failed to connect to datacollector process. - Non è stato possibile connettere l'agente di raccolta dati. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf index 087092b712..8d83d22a9c 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf @@ -191,11 +191,6 @@ Microsoft.NET.Test.Sdk の古いバージョンを使用しています。15.3.0 以降のバージョンに移行することをお勧めします。 - - Failed to connect to datacollector process. - datacollector プロセスに接続できませんでした。 - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf index 71b7078908..3fb05928dd 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf @@ -191,11 +191,6 @@ 이전 버전의 Microsoft.NET.Test.Sdk를 사용하고 있습니다. 15.3.0 이상 버전으로 이동하세요. - - Failed to connect to datacollector process. - datacollector 프로세스에 연결하지 못했습니다. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf index 1c4714cc94..7361d052f9 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf @@ -191,11 +191,6 @@ Używamy starszej wersji zestawu Microsoft.NET.Test.Sdk. Przejdź na wersję 15.3.0 lub nowszą. - - Failed to connect to datacollector process. - Nie można połączyć z procesem modułu zbierającego dane. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf index 7ca2a5e93a..6db7c06bee 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf @@ -191,11 +191,6 @@ Você está usando uma versão mais antiga do Microsoft.NET.Test.Sdk. Mude para uma versão igual ou maior que 15.3.0. - - Failed to connect to datacollector process. - Falha ao conectar ao processo datacollector. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf index fe7d583fdf..7979b5fd88 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf @@ -191,11 +191,6 @@ Вы используете более старую версию Microsoft.NET.Test.Sdk. Перейдите на версию 15.3.0 или более позднюю. - - Failed to connect to datacollector process. - Не удалось подключиться к процессу сборщика данных. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf index 6f19f36f1d..640c0ec0e7 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf @@ -191,11 +191,6 @@ Eski bir Microsoft.NET.Test.Sdk sürümü kullanıyorsunuz. Lütfen 15.3.0 veya daha yeni bir sürüme geçin. - - Failed to connect to datacollector process. - Datacollector işlemine bağlanılamadı. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf index ff42d08ab4..9065983d4e 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf @@ -102,11 +102,6 @@ You are using an older version of Microsoft.NET.Test.Sdk. Kindly move to a version equal or greater than 15.3.0 - - Failed to connect to datacollector process. - Failed to connect datacollector. - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf index f1d9380809..da310af07e 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf @@ -191,11 +191,6 @@ 你使用的是旧版 Microsoft.NET.Test.Sdk。请迁移到 15.3.0 及更高版本。 - - Failed to connect to datacollector process. - 未能连接到 datacollector 进程。 - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf index f7c6fb96d9..8ce649fa6d 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf @@ -191,11 +191,6 @@ 您正使用較舊版的 Microsoft.NET.Test.Sdk。請移到等於或大於 15.3.0 的版本。 - - Failed to connect to datacollector process. - 無法連線到資料收集器處理序。 - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/TestHostManagerCallbacks.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/TestHostManagerCallbacks.cs index 05ff0b1933..5a4082efe6 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/TestHostManagerCallbacks.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/TestHostManagerCallbacks.cs @@ -8,7 +8,6 @@ namespace Microsoft.TestPlatform.TestHostProvider.Hosting using System.Text; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; - using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; internal class TestHostManagerCallbacks @@ -19,7 +18,7 @@ public static void ErrorReceivedCallback(StringBuilder testHostProcessStdError, { // Log all standard error message because on too much data we ignore starting part. // This is helpful in abnormal failure of testhost. - EqtTrace.Warning("Test host standard error line: {0}", data); + EqtTrace.Warning("TestHostManagerCallbacks.ErrorReceivedCallback Test host standard error line: {0}", data); // Add newline for readbility. data += Environment.NewLine; @@ -56,11 +55,6 @@ public static void ExitCallBack( processHelper.TryGetExitCode(process, out exitCode); - if (exitCode != 0) - { - EqtTrace.Error("Test host exited with error: '{0}'", testHostProcessStdErrorStr); - } - int procId = -1; try { @@ -70,6 +64,15 @@ public static void ExitCallBack( { } + if (exitCode != 0) + { + EqtTrace.Error("TestHostManagerCallbacks.ExitCallBack: Testhost processId: {0} exited with exitcode: {1} error: '{2}'", procId, exitCode, testHostProcessStdErrorStr); + } + else + { + EqtTrace.Info("TestHostManagerCallbacks.ExitCallBack: Testhost processId: {0} exited with exitcode: 0 error: '{1}'", procId, testHostProcessStdErrorStr); + } + onHostExited(new HostProviderEventArgs(testHostProcessStdErrorStr, exitCode, procId)); } } diff --git a/src/datacollector/DataCollectorMain.cs b/src/datacollector/DataCollectorMain.cs new file mode 100644 index 0000000000..e57f914da6 --- /dev/null +++ b/src/datacollector/DataCollectorMain.cs @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.DataCollector +{ + using System; + using System.Diagnostics; + using System.Globalization; + + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; + using PlatformAbstractions.Interfaces; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + + public class DataCollectorMain + { + /// + /// Port number used to communicate with test runner process. + /// + private const string PortArgument = "--port"; + + /// + /// Parent process Id argument to monitor parent process. + /// + private const string ParentProcessArgument = "--parentprocessid"; + + /// + /// Log file for writing eqt trace logs. + /// + private const string LogFileArgument = "--diag"; + + private IProcessHelper processHelper; + + private IEnvironment environment; + private IDataCollectionRequestHandler requestHandler; + + public DataCollectorMain(): + this( + new ProcessHelper(), + new PlatformEnvironment(), + DataCollectionRequestHandler.Create(new SocketCommunicationManager(), new MessageSink()) + ) + { + } + + internal DataCollectorMain(IProcessHelper processHelper, IEnvironment environment, IDataCollectionRequestHandler requestHandler) + { + this.processHelper = processHelper; + this.environment = environment; + this.requestHandler = requestHandler; + } + + public void Run(string[] args) + { + WaitForDebuggerIfEnabled(); + var argsDictionary = CommandLineArgumentsHelper.GetArgumentsDictionary(args); + + // Setup logging if enabled + string logFile; + if (argsDictionary.TryGetValue(LogFileArgument, out logFile)) + { + EqtTrace.InitializeVerboseTrace(logFile); + } + else + { + EqtTrace.DoNotInitailize = true; + } + + EqtTrace.Info("DataCollectorMain.Run: Starting data collector run with args: {0}", string.Join(",", args)); + + // Attach to exit of parent process + var parentProcessId = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, ParentProcessArgument); + EqtTrace.Info("DataCollector: Monitoring parent process with id: '{0}'", parentProcessId); + + this.processHelper.SetExitCallback( + parentProcessId, + (obj) => + { + EqtTrace.Info("DataCollector: ParentProcess '{0}' Exited.", parentProcessId); + this.environment.Exit(1); + }); + + // Get server port and initialize communication. + string portValue; + int port = argsDictionary.TryGetValue(PortArgument, out portValue) ? int.Parse(portValue) : 0; + + if (port <= 0) + { + throw new ArgumentException("Incorrect/No Port number"); + } + + this.requestHandler.InitializeCommunication(port); + + // Can only do this after InitializeCommunication because datacollector cannot "Send Log" unless communications are initialized + if (!string.IsNullOrEmpty(EqtTrace.LogFile)) + { + ((DataCollectionRequestHandler)this.requestHandler).SendDataCollectionMessage(new DataCollectionMessageEventArgs(TestMessageLevel.Informational, string.Format("Logging DataCollector Diagnostics in file: {0}", EqtTrace.LogFile))); + } + + // Start processing async in a different task + EqtTrace.Info("DataCollector: Start Request Processing."); + StartProcessing(); + } + + private void WaitForDebuggerIfEnabled() + { + var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_DATACOLLECTOR_DEBUG"); + if (!string.IsNullOrEmpty(debugEnabled) && debugEnabled.Equals("1", StringComparison.Ordinal)) + { + while (!Debugger.IsAttached) + { + System.Threading.Thread.Sleep(1000); + } + + Debugger.Break(); + } + } + + private void StartProcessing() + { + var timeout = EnvironmentHelper.GetConnectionTimeout(); + + // Wait for the connection to the sender and start processing requests from sender + if (this.requestHandler.WaitForRequestSenderConnection(timeout * 1000)) + { + this.requestHandler.ProcessRequests(); + } + else + { + EqtTrace.Error( + "DataCollectorMain.StartProcessing: RequestHandler timed out while connecting to the Sender, timeout: {0} seconds.", + timeout); + + this.requestHandler.Close(); + + throw new TestPlatformException( + string.Format( + CultureInfo.CurrentUICulture, + CommunicationUtilitiesResources.ConnectionTimeoutErrorMessage, + CoreUtilitiesConstants.DatacollectorProcessName, + CoreUtilitiesConstants.VstestConsoleProcessName, + timeout, + EnvironmentHelper.VstestConnectionTimeout) + ); + } + } + } +} \ No newline at end of file diff --git a/src/datacollector/Program.cs b/src/datacollector/Program.cs index 1ef33abda3..4551989e1f 100644 --- a/src/datacollector/Program.cs +++ b/src/datacollector/Program.cs @@ -4,44 +4,13 @@ namespace Microsoft.VisualStudio.TestPlatform.DataCollector { using System; - using System.Diagnostics; - using System.Net.Sockets; - using System.Threading.Tasks; - - using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; - using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; - using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces; - using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.ObjectModel; - using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; - using Microsoft.VisualStudio.TestPlatform.Utilities; /// /// The program. /// public class Program { - /// - /// The timeout for the client to connect to the server. - /// - private const int ClientListenTimeOut = 5 * 1000; - - /// - /// Port number used to communicate with test runner process. - /// - private const string PortArgument = "--port"; - - /// - /// Parent process Id argument to monitor parent process. - /// - private const string ParentProcessArgument = "--parentprocessid"; - - /// - /// Log file for writing eqt trace logs. - /// - private const string LogFileArgument = "--diag"; - /// /// The main. /// @@ -52,107 +21,17 @@ public static void Main(string[] args) { try { - WaitForDebuggerIfEnabled(); - Run(args); + new DataCollectorMain().Run(args); } catch (Exception ex) { - EqtTrace.Error("DataCollector: Error occured during initialization of Datacollector : {0}", ex); + EqtTrace.Error("Program.Main: Error occured during initialization of Datacollector : {0}", ex); throw; } - } - - private static void Run(string[] args) - { - var argsDictionary = CommandLineArgumentsHelper.GetArgumentsDictionary(args); - - // Setup logging if enabled - string logFile; - if (argsDictionary.TryGetValue(LogFileArgument, out logFile)) + finally { - EqtTrace.InitializeVerboseTrace(logFile); + EqtTrace.Info("Program.Main: exiting datacollector process."); } - else - { - EqtTrace.DoNotInitailize = true; - } - - // Attach to exit of parent process - var parentProcessId = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, ParentProcessArgument); - EqtTrace.Info("DataCollector: Monitoring parent process with id: '{0}'", parentProcessId); - - var processHelper = new ProcessHelper(); - processHelper.SetExitCallback( - parentProcessId, - (obj) => - { - EqtTrace.Info("DataCollector: ParentProcess '{0}' Exited.", parentProcessId); - Environment.Exit(1); - }); - - // Get server port and initialize communication. - string portValue; - int port = argsDictionary.TryGetValue(PortArgument, out portValue) ? int.Parse(portValue) : 0; - - if (port <= 0) - { - throw new ArgumentException("Incorrect/No Port number"); - } - - var requestHandler = DataCollectionRequestHandler.Create(new SocketCommunicationManager(), new MessageSink()); - requestHandler.InitializeCommunication(port); - - // Can only do this after InitializeCommunication because datacollector cannot "Send Log" unless communications are initialized - if (!string.IsNullOrEmpty(EqtTrace.LogFile)) - { - requestHandler.SendDataCollectionMessage(new DataCollectionMessageEventArgs(TestMessageLevel.Informational, string.Format("Logging DataCollector Diagnostics in file: {0}", EqtTrace.LogFile))); - } - - // Start processing async in a different task - EqtTrace.Info("DataCollector: Start Request Processing."); - var processingTask = StartProcessingAsync(requestHandler); - - // Wait for processing to complete. - Task.WaitAny(processingTask); - } - - private static void WaitForDebuggerIfEnabled() - { - var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_DATACOLLECTOR_DEBUG"); - if (!string.IsNullOrEmpty(debugEnabled) && debugEnabled.Equals("1", StringComparison.Ordinal)) - { - ConsoleOutput.Instance.WriteLine("Waiting for debugger attach...", OutputLevel.Information); - - var currentProcess = Process.GetCurrentProcess(); - ConsoleOutput.Instance.WriteLine( - string.Format("Process Id: {0}, Name: {1}", currentProcess.Id, currentProcess.ProcessName), - OutputLevel.Information); - - while (!Debugger.IsAttached) - { - System.Threading.Thread.Sleep(1000); - } - - Debugger.Break(); - } - } - - private static Task StartProcessingAsync(IDataCollectionRequestHandler requestHandler) - { - return Task.Run(() => - { - // Wait for the connection to the sender and start processing requests from sender - if (requestHandler.WaitForRequestSenderConnection(ClientListenTimeOut)) - { - requestHandler.ProcessRequests(); - } - else - { - EqtTrace.Info("DataCollector: RequestHandler timed out while connecting to the Sender."); - requestHandler.Close(); - throw new TimeoutException(); - } - }); } } } \ No newline at end of file diff --git a/src/testhost.x86/DefaultEngineInvoker.cs b/src/testhost.x86/DefaultEngineInvoker.cs index 0aaf0148b6..12acfc0d44 100644 --- a/src/testhost.x86/DefaultEngineInvoker.cs +++ b/src/testhost.x86/DefaultEngineInvoker.cs @@ -5,10 +5,10 @@ namespace Microsoft.VisualStudio.TestPlatform.TestHost { using System; using System.Collections.Generic; + using System.Globalization; using System.Net; using System.Threading; using System.Threading.Tasks; - using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; @@ -19,6 +19,10 @@ namespace Microsoft.VisualStudio.TestPlatform.TestHost using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.TesthostProtocol; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; + using PlatformAbstractions.Interfaces; + using CommunicationUtilitiesResources = + Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; internal class DefaultEngineInvoker : #if NET451 @@ -32,8 +36,6 @@ internal class DefaultEngineInvoker : /// private const int ClientListenTimeOut = Timeout.Infinite; - private const int DataConnectionClientListenTimeOut = 60 * 1000; - private const string EndpointArgument = "--endpoint"; private const string RoleArgument = "--role"; @@ -46,34 +48,163 @@ internal class DefaultEngineInvoker : private const string TelemetryOptedIn = "--telemetryoptedin"; + private ITestRequestHandler requestHandler; + + private IDataCollectionTestCaseEventSender dataCollectionTestCaseEventSender; + + private IProcessHelper processHelper; + + + public DefaultEngineInvoker() : this(new TestRequestHandler(), DataCollectionTestCaseEventSender.Create(), new ProcessHelper()) + { + } + + internal DefaultEngineInvoker(ITestRequestHandler requestHandler, + IDataCollectionTestCaseEventSender dataCollectionTestCaseEventSender, IProcessHelper processHelper) + { + this.processHelper = processHelper; + this.requestHandler = requestHandler; + this.dataCollectionTestCaseEventSender = dataCollectionTestCaseEventSender; + } + public void Invoke(IDictionary argsDictionary) { - // Setup logging if enabled - if (argsDictionary.TryGetValue(LogFileArgument, out string logFile)) + DefaultEngineInvoker.InitializeEqtTrace(argsDictionary); + + if (EqtTrace.IsInfoEnabled) { - EqtTrace.InitializeVerboseTrace(logFile); + EqtTrace.Info("DefaultEngineInvoker.Invoke: Testhost process started with args :{0}", + string.Join(",", argsDictionary)); +#if NET451 + var appConfigText = + System.IO.File.ReadAllText(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); + EqtTrace.Info("DefaultEngineInvoker: Using Application Configuration: '{0}'", appConfigText); +#endif } - else + + this.SetParentProcessExitCallback(argsDictionary); + + this.requestHandler.ConnectionInfo = + DefaultEngineInvoker.GetConnectionInfo(argsDictionary); + + // Initialize Communication with vstest.console + this.requestHandler.InitializeCommunication(); + + // Initialize DataCollection Communication if data collection port is provided. + var dcPort = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, DataCollectionPortArgument); + if (dcPort > 0) { - EqtTrace.DoNotInitailize = true; + this.ConnectToDatacollector(dcPort); } -#if NET451 - if (EqtTrace.IsInfoEnabled) + + var requestData = DefaultEngineInvoker.GetRequestData(argsDictionary); + + // Start processing async in a different task + EqtTrace.Info("DefaultEngineInvoker.Invoke: Start Request Processing."); + try { - var appConfigText = System.IO.File.ReadAllText(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); - EqtTrace.Info("DefaultEngineInvoker: Using Application Configuration: '{0}'", appConfigText); + this.StartProcessingAsync(requestHandler, new TestHostManagerFactory(requestData)).Wait(); } -#endif + finally + { + if (dcPort > 0) + { + // Close datacollector communication. + this.dataCollectionTestCaseEventSender.Close(); + } + + this.requestHandler.Dispose(); + } + } + + private static RequestData GetRequestData(IDictionary argsDictionary) + { + // Checks for Telemetry Opted in or not from Command line Arguments. + // By Default opting out in Test Host to handle scenario when user running old version of vstest.console + var telemetryStatus = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, TelemetryOptedIn); + var telemetryOptedIn = false; + if (!string.IsNullOrWhiteSpace(telemetryStatus)) + { + if (telemetryStatus.Equals("true", StringComparison.Ordinal)) + { + telemetryOptedIn = true; + } + } + + var requestData = new RequestData + { + MetricsCollection = + telemetryOptedIn + ? (IMetricsCollection) new MetricsCollection() + : new NoOpMetricsCollection(), + IsTelemetryOptedIn = telemetryOptedIn + }; + return requestData; + } + + private void ConnectToDatacollector(int dcPort) + { + EqtTrace.Info("DefaultEngineInvoker.ConnectToDatacollector: Connecting to datacollector, port: {0}", + dcPort); + this.dataCollectionTestCaseEventSender.InitializeCommunication(dcPort); + // It's possible that connection to vstest.console happens, but to datacollector fails, why? + // DataCollector keeps the server alive for testhost only for 15secs(increased to 90 now), + // if somehow(on slower machines, with Profiler Enabled) testhost can take considerable time to launch, + // in such scenario dc.exe would have killed the server, but testhost will wait infinitely to connect to it, + // hence do not wait to connect to datacollector process infinitely, as it will cause process hang. + var timeout = EnvironmentHelper.GetConnectionTimeout(); + if (!this.dataCollectionTestCaseEventSender.WaitForRequestSenderConnection(timeout * 1000)) + { + EqtTrace.Error( + "DefaultEngineInvoker.ConnectToDatacollector: Connection to DataCollector failed: '{0}', DataCollection will not happen in this session", + dcPort); + throw new TestPlatformException( + string.Format( + CultureInfo.CurrentUICulture, + CommunicationUtilitiesResources.ConnectionTimeoutErrorMessage, + CoreUtilitiesConstants.TesthostProcessName, + CoreUtilitiesConstants.DatacollectorProcessName, + timeout, + EnvironmentHelper.VstestConnectionTimeout) + ); + } + } + + private void SetParentProcessExitCallback(IDictionary argsDictionary) + { + // Attach to exit of parent process + var parentProcessId = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, ParentProcessIdArgument); + EqtTrace.Info("DefaultEngineInvoker.SetParentProcessExitCallback: 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) + { + this.processHelper.SetExitCallback( + parentProcessId, + (obj) => + { + EqtTrace.Info("DefaultEngineInvoker.SetParentProcessExitCallback: ParentProcess '{0}' Exited.", + parentProcessId); + new PlatformEnvironment().Exit(1); + }); + } + } + + private static TestHostConnectionInfo GetConnectionInfo(IDictionary argsDictionary) + { // 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); + var endpoint = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, EndpointArgument); if (string.IsNullOrWhiteSpace(endpoint)) { var port = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, "--port"); endpoint = IPAddress.Loopback + ":" + port; } + EqtTrace.Info("DefaultEngineInvoker.GetConnectionInfo: Initialize communication on endpoint address: '{0}'", endpoint); + var connectionRole = ConnectionRole.Client; string role = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, RoleArgument); if (!string.IsNullOrWhiteSpace(role) && string.Equals(role, "host", StringComparison.OrdinalIgnoreCase)) @@ -82,80 +213,26 @@ public void Invoke(IDictionary argsDictionary) } // Start Processing of requests - using (var requestHandler = new TestRequestHandler(new TestHostConnectionInfo { Endpoint = endpoint, Role = connectionRole, Transport = Transport.Sockets })) + var connectionInfo = new TestHostConnectionInfo { - // 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, - (obj) => - { - 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); - - // It's possible that connection to vstest.console happens, but to datacollector fails, why? - // DataCollector keeps the server alive for testhost only for 15secs(increased to 60 now), - // if somehow(on slower machines, with Profiler Enabled) testhost can take considerable time to launch, - // in such scenario dc.exe would have killed the server, but testhost will wait infinitely to connect to it, - // hence do not wait to connect to datacollector process infinitely, as it will cause process hang. - if(!dataCollectionTestCaseEventSender.WaitForRequestSenderConnection(DataConnectionClientListenTimeOut)) - { - EqtTrace.Info("DefaultEngineInvoker: Connection to DataCollector failed: '{0}', DataCollection will not happen in this session", dcPort); - } - } - - // Checks for Telemetry Opted in or not from Command line Arguments. - // By Default opting out in Test Host to handle scenario when user running old version of vstest.console - var telemetryStatus = CommandLineArgumentsHelper.GetStringArgFromDict(argsDictionary, TelemetryOptedIn); - var telemetryOptedIn = false; - if (!string.IsNullOrWhiteSpace(telemetryStatus)) - { - if (telemetryStatus.Equals("true", StringComparison.Ordinal)) - { - telemetryOptedIn = true; - } - } - - var requestData = new RequestData - { - MetricsCollection = - telemetryOptedIn - ? (IMetricsCollection)new MetricsCollection() - : new NoOpMetricsCollection(), - IsTelemetryOptedIn = telemetryOptedIn - }; + Endpoint = endpoint, + Role = connectionRole, + Transport = Transport.Sockets + }; - // Start processing async in a different task - EqtTrace.Info("DefaultEngineInvoker: Start Request Processing."); - var processingTask = this.StartProcessingAsync(requestHandler, new TestHostManagerFactory(requestData)); - - // Wait for processing to complete. - Task.WaitAny(processingTask); + return connectionInfo; + } - if (dcPort > 0) - { - // Close socket communication connection. - DataCollectionTestCaseEventSender.Instance.Close(); - } + private static void InitializeEqtTrace(IDictionary argsDictionary) + { + // Setup logging if enabled + if (argsDictionary.TryGetValue(LogFileArgument, out string logFile)) + { + EqtTrace.InitializeVerboseTrace(logFile); + } + else + { + EqtTrace.DoNotInitailize = true; } } @@ -163,29 +240,31 @@ private Task StartProcessingAsync(ITestRequestHandler requestHandler, ITestHostM { var task = new Task( () => - { - // Wait for the connection to the sender and start processing requests from sender - // Note that we are waiting here infinitely to connect to vstest.console, but at the same time vstest.console doesn't wait infinitely. - // It has a default timeout of 60secs(which is configurable), & then it kills testhost.exe - // The reason to wait infinitely, was remote debugging scenarios of UWP app, - // in such cases after the app gets launched, VS debugger takes control of it, & causes a lot of delay, which frequently causes timeout with vstest.console. - // One fix would be just double this timeout, but there is no telling how much time it can actually take. - // Hence we are waiting here indefinelty, to avoid such guessed timeouts, & letting user kill the debugging if they feel it is taking too much time. - // In other cases if vstest.console's timeout exceeds it will definitelty such down the app. - if (requestHandler.WaitForRequestSenderConnection(ClientListenTimeOut)) { - requestHandler.ProcessRequests(managerFactory); - } - else - { - EqtTrace.Info("DefaultEngineInvoker: RequestHandler timed out while connecting to the Sender."); - throw new TimeoutException(); - } - }, + // Wait for the connection to the sender and start processing requests from sender + // Note that we are waiting here infinitely to connect to vstest.console, but at the same time vstest.console doesn't wait infinitely. + // It has a default timeout of 60secs(which is configurable), & then it kills testhost.exe + // The reason to wait infinitely, was remote debugging scenarios of UWP app, + // in such cases after the app gets launched, VS debugger takes control of it, & causes a lot of delay, which frequently causes timeout with vstest.console. + // One fix would be just double this timeout, but there is no telling how much time it can actually take. + // Hence we are waiting here indefinelty, to avoid such guessed timeouts, & letting user kill the debugging if they feel it is taking too much time. + // In other cases if vstest.console's timeout exceeds it will definitelty such down the app. + if (requestHandler.WaitForRequestSenderConnection(ClientListenTimeOut)) + { + EqtTrace.Info("DefaultEngineInvoker.StartProcessingAsync: Connected to vstest.console, Starting process requests."); + requestHandler.ProcessRequests(managerFactory); + } + else + { + EqtTrace.Info( + "DefaultEngineInvoker.StartProcessingAsync: RequestHandler timed out while connecting to the Sender."); + throw new TimeoutException(); + } + }, TaskCreationOptions.LongRunning); task.Start(); return task; } } -} +} \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs index 1effc2d0b8..5fcfa1efc1 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs @@ -5,6 +5,7 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests { using System; using System.Collections.ObjectModel; + using System.Globalization; using System.Net; using Microsoft.TestPlatform.CommunicationUtilities.UnitTests.TestDoubles; @@ -21,6 +22,10 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests using Moq; using Newtonsoft.Json.Linq; + using VisualStudio.TestPlatform.CoreUtilities.Helpers; + + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; [TestClass] public class DataCollectionRequestHandlerTests @@ -31,6 +36,8 @@ public class DataCollectionRequestHandlerTests private Mock mockDataCollectionTestCaseEventHandler; private TestableDataCollectionRequestHandler requestHandler; private Mock mockDataSerializer; + private Message afterTestRunEnd = new Message() { MessageType = MessageType.AfterTestRunEnd, Payload = "false" }; + private Message beforeTestRunStart = new Message() { MessageType = MessageType.BeforeTestRunStart, Payload = "settingsXml" }; public DataCollectionRequestHandlerTests() { @@ -41,6 +48,16 @@ public DataCollectionRequestHandlerTests() this.mockDataCollectionTestCaseEventHandler = new Mock(); this.mockDataCollectionTestCaseEventHandler.Setup(x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(true); this.requestHandler = new TestableDataCollectionRequestHandler(this.mockCommunicationManager.Object, this.mockMessageSink.Object, this.mockDataCollectionManager.Object, this.mockDataCollectionTestCaseEventHandler.Object, this.mockDataSerializer.Object); + + this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(this.beforeTestRunStart).Returns(this.afterTestRunEnd); + + this.mockDataCollectionManager.Setup(x => x.SessionStarted()).Returns(true); + } + + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); } [TestMethod] @@ -159,16 +176,12 @@ public void DisposeShouldCloseCommunicationChannel() [TestMethod] public void ProcessRequestsShouldProcessRequests() { - var message = new Message(); - message.MessageType = MessageType.BeforeTestRunStart; - message.Payload = "settingsXml"; - var testHostLaunchedPayload = new TestHostLaunchedPayload(); testHostLaunchedPayload.ProcessId = 1234; - this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message) + this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(this.beforeTestRunStart) .Returns(new Message() { MessageType = MessageType.TestHostLaunched, Payload = JToken.FromObject(testHostLaunchedPayload) }) - .Returns(new Message() { MessageType = MessageType.AfterTestRunEnd, Payload = "false" }); + .Returns(this.afterTestRunEnd); this.mockDataCollectionManager.Setup(x => x.SessionStarted()).Returns(true); this.mockDataCollectionManager.Setup(x => x.TestHostLaunched(It.IsAny())); @@ -214,14 +227,6 @@ public void ProcessRequestsShouldThrowExceptionIfThrownByCommunicationManager() [TestMethod] public void ProcessRequestsShouldInitializeTestCaseEventHandlerIfTestCaseLevelEventsAreEnabled() { - var message = new Message(); - message.MessageType = MessageType.BeforeTestRunStart; - message.Payload = "settingsXml"; - - this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(new Message() { MessageType = MessageType.AfterTestRunEnd, Payload = "false" }); - - this.mockDataCollectionManager.Setup(x => x.SessionStarted()).Returns(true); - this.requestHandler.ProcessRequests(); this.mockDataCollectionTestCaseEventHandler.Verify(x => x.InitializeCommunication(), Times.Once); @@ -230,14 +235,27 @@ public void ProcessRequestsShouldInitializeTestCaseEventHandlerIfTestCaseLevelEv } [TestMethod] - public void ProcessRequestsShouldNotInitializeTestCaseEventHandlerIfTestCaseLevelEventsAreNotEnabled() + public void ProcessRequestsShouldSetDefaultTimeoutIfNoEnvVarialbeSet() { - var message = new Message(); - message.MessageType = MessageType.BeforeTestRunStart; - message.Payload = "settingsXml"; + this.requestHandler.ProcessRequests(); + + this.mockDataCollectionTestCaseEventHandler.Verify(h => h.WaitForRequestHandlerConnection(EnvironmentHelper.DefaultConnectionTimeout * 1000)); + } + + [TestMethod] + public void ProcessRequestsShouldSetTimeoutBasedOnEnvVariable() + { + var timeout = 10; + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, timeout.ToString()); - this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(new Message() { MessageType = MessageType.AfterTestRunEnd, Payload = "false" }); + this.requestHandler.ProcessRequests(); + + this.mockDataCollectionTestCaseEventHandler.Verify(h => h.WaitForRequestHandlerConnection(timeout * 1000)); + } + [TestMethod] + public void ProcessRequestsShouldNotInitializeTestCaseEventHandlerIfTestCaseLevelEventsAreNotEnabled() + { this.mockDataCollectionManager.Setup(x => x.SessionStarted()).Returns(false); this.requestHandler.ProcessRequests(); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs index bb0e9412fa..746d81e84a 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs @@ -5,6 +5,7 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests { using System; using System.Collections.Generic; + using System.Globalization; using System.Linq; using System.Net; using System.Threading; @@ -18,6 +19,7 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using VisualStudio.TestPlatform.CoreUtilities.Helpers; using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; [TestClass] @@ -26,7 +28,7 @@ public class TestRequestSenderTests private const int DUMMYPROTOCOLVERSION = 42; private const int DEFAULTPROTOCOLVERSION = 1; private const int DUMMYNEGOTIATEDPROTOCOLVERSION = 41; - private const int CLIENTPROCESSEXITWAIT = 10 * 1000; + private static readonly string TimoutErrorMessage = "Failed to negotiate protocol, waiting for response timed out after 0 seconds. This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; private readonly Mock mockServer; private readonly Mock mockDataSerializer; @@ -39,7 +41,6 @@ public class TestRequestSenderTests private readonly TestRunCriteriaWithSources testRunCriteriaWithSources; private TestHostConnectionInfo connectionInfo; private ITestRequestSender testRequestSender; - private ProtocolConfig protocolConfig = new ProtocolConfig { Version = 2 }; public TestRequestSenderTests() { @@ -60,6 +61,12 @@ public TestRequestSenderTests() this.testRunCriteriaWithSources = new TestRunCriteriaWithSources(new Dictionary>(), "runsettings", null, null); } + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); + } + [TestMethod] public void InitializeCommunicationShouldHostServerAndAcceptClient() { @@ -203,6 +210,18 @@ public void CheckVersionWithTestHostShouldThrowIfUnexpectedResponseIsReceived() Assert.ThrowsException(() => this.testRequestSender.CheckVersionWithTestHost()); } + [TestMethod] + public void CheckVersionWithTestHostShouldThrowIfProtocolNegotiationTimeouts() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "0"); + + this.SetupFakeCommunicationChannel(); + + var message = Assert.ThrowsException(() => this.testRequestSender.CheckVersionWithTestHost()).Message; + + Assert.AreEqual(message, TestRequestSenderTests.TimoutErrorMessage); + } + #endregion #region Discovery Protocol Tests diff --git a/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Helpers/EnvironmentHelperTests.cs b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Helpers/EnvironmentHelperTests.cs new file mode 100644 index 0000000000..c8f4f04117 --- /dev/null +++ b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Helpers/EnvironmentHelperTests.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.TestPlatform.CoreUtilities.UnitTests.Helpers +{ + using System; + using System.Collections.Generic; + + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class EnvironmentHelperTests + { + private static readonly int DefaultTimeout = 90; + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnDefaultValue() + { + Assert.AreEqual(EnvironmentHelperTests.DefaultTimeout, EnvironmentHelper.GetConnectionTimeout()); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnEnvVariableValueIfSet() + { + var val = 100; + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, val.ToString()); + Assert.AreEqual(val, EnvironmentHelper.GetConnectionTimeout()); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnDefaultOnNegativeValue() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "-1"); + Assert.AreEqual(EnvironmentHelperTests.DefaultTimeout, EnvironmentHelper.GetConnectionTimeout()); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnZeroOnEnvVariableValueZero() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "0"); + Assert.AreEqual(0, EnvironmentHelper.GetConnectionTimeout()); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnDefaultOnEnvVariableValueDecimal() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "10.4"); + Assert.AreEqual(EnvironmentHelperTests.DefaultTimeout, EnvironmentHelper.GetConnectionTimeout()); + } + + [TestMethod] + public void GetConnectionTimeoutShouldReturnDefaultOnInvalidValue() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "InvalidValue"); + Assert.AreEqual(EnvironmentHelperTests.DefaultTimeout, EnvironmentHelper.GetConnectionTimeout()); + } + } +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyBaseManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyBaseManagerTests.cs index bba1a233f0..ebc9d0ee62 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyBaseManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyBaseManagerTests.cs @@ -21,7 +21,6 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client public class ProxyBaseManagerTests { private const int CLIENTPROCESSEXITWAIT = 10 * 1000; - private int clientConnectionTimeout = 400; private Mock mockCommunicationEndpoint; private ITestRequestSender testRequestSender; @@ -104,8 +103,7 @@ protected ProxyDiscoveryManager GetProxyDiscoveryManager() mockRequestData.Object, testRequestSender, mockTestHostManager.Object, - mockDataSerializer.Object, - clientConnectionTimeout); + mockDataSerializer.Object); return testDiscoveryManager; } @@ -114,7 +112,7 @@ internal ProxyExecutionManager GetProxyExecutionManager() { this.SetupAndInitializeTestRequestSender(); var testExecutionManager = new ProxyExecutionManager(mockRequestData.Object, testRequestSender, - mockTestHostManager.Object, mockDataSerializer.Object, clientConnectionTimeout); + mockTestHostManager.Object, mockDataSerializer.Object); return testExecutionManager; } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs index 0ccf548050..27aaf4f427 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs @@ -41,10 +41,6 @@ public class ProxyDiscoveryManagerTests : ProxyBaseManagerTests private Mock mockMetricsCollection; - /// - /// The client connection timeout in milliseconds for unit tests. - /// - private int testableClientConnectionTimeout = 400; public ProxyDiscoveryManagerTests() { @@ -56,8 +52,7 @@ public ProxyDiscoveryManagerTests() this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, - this.mockDataSerializer.Object, - this.testableClientConnectionTimeout); + this.mockDataSerializer.Object); this.discoveryCriteria = new DiscoveryCriteria(new[] { "test.dll" }, 1, string.Empty); } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 29a3c50a44..3d0c6da61d 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -40,10 +40,6 @@ public class ProxyExecutionManagerTests : ProxyBaseManagerTests //private Mock mockDataSerializer; - /// - /// The client connection timeout in milliseconds for unit tests. - /// - private int clientConnectionTimeout = 400; public ProxyExecutionManagerTests() { this.mockRequestSender = new Mock(); @@ -53,7 +49,7 @@ public ProxyExecutionManagerTests() this.mockMetricsCollection = new Mock(); this.mockRequestData.Setup(rd => rd.MetricsCollection).Returns(this.mockMetricsCollection.Object); - this.testExecutionManager = new ProxyExecutionManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.mockDataSerializer.Object, this.clientConnectionTimeout); + this.testExecutionManager = new ProxyExecutionManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.mockDataSerializer.Object); //this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(null)).Returns(new Message()); //this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(string.Empty)).Returns(new Message()); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs index 924036224f..f3a8aecadf 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs @@ -42,11 +42,6 @@ public class ProxyExecutionManagerWithDataCollectionTests private Mock mockMetricsCollection; - /// - /// The client connection timeout in milliseconds for unit tests. - /// - private int testableClientConnectionTimeout = 400; - [TestInitialize] public void TestInit() { @@ -56,7 +51,7 @@ public void TestInit() this.mockRequestData = new Mock(); this.mockMetricsCollection = new Mock(); this.mockRequestData.Setup(rd => rd.MetricsCollection).Returns(this.mockMetricsCollection.Object); - this.testExecutionManager = new ProxyExecutionManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.mockDataSerializer.Object, this.testableClientConnectionTimeout); + this.testExecutionManager = new ProxyExecutionManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.mockDataSerializer.Object); this.mockDataCollectionManager = new Mock(); this.mockProcessHelper = new Mock(); this.proxyExecutionManager = new ProxyExecutionManagerWithDataCollection(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.mockDataCollectionManager.Object); @@ -100,7 +95,7 @@ public void InitializeShouldSaveExceptionMessagesIfThrownByDataCollectionProcess { var mockRequestSender = new Mock(); mockRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), It.IsAny())).Throws(new Exception("MyException")); - mockRequestSender.Setup(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout)).Returns(true); + mockRequestSender.Setup(x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(true); var mockDataCollectionLauncher = new Mock(); var proxyDataCollectonManager = new ProxyDataCollectionManager(this.mockRequestData.Object, string.Empty, mockRequestSender.Object, this.mockProcessHelper.Object, mockDataCollectionLauncher.Object); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs index 6e047c7b83..4e319f071e 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs @@ -6,6 +6,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using System; using System.Collections.Generic; using System.Diagnostics; + using System.Globalization; using System.Linq; using System.Net; using System.Threading; @@ -14,6 +15,8 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources; + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; @@ -25,6 +28,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using Constants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; [TestClass] public class ProxyOperationManagerTests : ProxyBaseManagerTests @@ -43,18 +47,24 @@ public class ProxyOperationManagerTests : ProxyBaseManagerTests private Mock mockRequestData; - /// - /// The client connection timeout in milliseconds for unit tests. - /// - private int connectionTimeout = 400; + private int connectionTimeout = EnvironmentHelper.DefaultConnectionTimeout * 1000; + + private static readonly string TimoutErrorMessage = + "vstest.console process failed to connect to testhost process after 90 seconds. This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; public ProxyOperationManagerTests() { this.mockRequestSender = new Mock(); - this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout)).Returns(true); + this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(connectionTimeout)).Returns(true); this.mockRequestData = new Mock(); this.mockRequestData.Setup(rd => rd.MetricsCollection).Returns(new Mock().Object); - this.testOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); + this.testOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); + } + + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); } [TestMethod] @@ -137,7 +147,7 @@ public void SetupChannelShouldCallHostServerIfRunnerIsServer() this.mockTestHostManager.Setup(thm => thm.GetTestHostConnectionInfo()).Returns(connectionInfo); - var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object, this.connectionTimeout); + var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object); localTestOperationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); @@ -168,7 +178,7 @@ public void SetupChannelShouldCallSetupClientIfRunnerIsClient() this.mockTestHostManager.Setup(thm => thm.GetTestHostConnectionInfo()).Returns(connectionInfo); - var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object, this.connectionTimeout); + var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object); localTestOperationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); @@ -204,24 +214,12 @@ public void SetupChannelShouldNotWaitForTestHostConnectionIfConnectionIsInitiali [TestMethod] public void SetupChannelShouldHonorTimeOutSetByUser() { - Environment.SetEnvironmentVariable("VSTEST_CONNECTION_TIMEOUT", "100"); + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "100"); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(100000)).Returns(true); this.testOperationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(100000), Times.Exactly(1)); - - this.connectionTimeout = 400; - } - - [TestMethod] - public void SetupChannelShouldNotHonorGarbageTimeOutSetByUser() - { - Environment.SetEnvironmentVariable("VSTEST_CONNECTION_TIMEOUT", "garbage"); - - this.testOperationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); - - this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout), Times.Exactly(1)); } [TestMethod] @@ -230,9 +228,10 @@ public void SetupChannelShouldThrowIfWaitForTestHostConnectionTimesOut() SetupTestHostLaunched(true); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout)).Returns(false); - var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); + var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); - Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None)); + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None)).Message; + Assert.AreEqual(message, ProxyOperationManagerTests.TimoutErrorMessage); } [TestMethod] @@ -241,9 +240,10 @@ public void SetupChannelShouldThrowIfLaunchTestHostFails() SetupTestHostLaunched(false); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout)).Returns(true); - var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); + var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); - Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None)); + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None)).Message; + Assert.AreEqual(message, string.Format(CultureInfo.CurrentUICulture, Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources.InitializationFailed)); } [TestMethod] @@ -266,7 +266,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShoul { this.SetUpMocksForDotNetTestHost(); var testHostManager = new TestableDotnetTestHostManager(false, this.mockProcessHelper.Object, this.mockFileHelper.Object, this.mockEnvironment.Object); - var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, testHostManager, this.connectionTimeout); + var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, testHostManager); operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); @@ -278,7 +278,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShould { this.SetUpMocksForDotNetTestHost(); var testHostManager = new TestableDotnetTestHostManager(true, this.mockProcessHelper.Object, this.mockFileHelper.Object, this.mockEnvironment.Object); - var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, testHostManager, this.connectionTimeout); + var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, testHostManager); operationManager.SetupChannel(Enumerable.Empty(), CancellationToken.None); @@ -368,7 +368,7 @@ public void UpdateTestProcessStartInfoShouldUpdateTelemetryOptedInArgTrueIfTelem mockRequestData.Setup(rd => rd.IsTelemetryOptedIn).Returns(true); - var testOperationManager = new TestableProxyOperationManager(mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); + var testOperationManager = new TestableProxyOperationManager(mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); this.mockTestHostManager .Setup(tm => tm.LaunchTestHostAsync(It.IsAny(), It.IsAny())) @@ -394,7 +394,7 @@ public void UpdateTestProcessStartInfoShouldUpdateTelemetryOptedInArgFalseIfTele mockRequestData.Setup(rd => rd.IsTelemetryOptedIn).Returns(false); - var testOperationManager = new TestableProxyOperationManager(mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); + var testOperationManager = new TestableProxyOperationManager(mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); this.mockTestHostManager .Setup(tm => tm.LaunchTestHostAsync(It.IsAny(), It.IsAny())) @@ -452,11 +452,9 @@ private void SetUpMocksForDotNetTestHost() private class TestableProxyOperationManager : ProxyOperationManager { - public TestableProxyOperationManager( - IRequestData requestData, + public TestableProxyOperationManager(IRequestData requestData, ITestRequestSender requestSender, - ITestRuntimeProvider testHostManager, - int clientConnectionTimeout) : base(requestData, requestSender, testHostManager, clientConnectionTimeout) + ITestRuntimeProvider testHostManager) : base(requestData, requestSender, testHostManager) { } } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs index 126349eb83..2388b21be7 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs @@ -7,6 +7,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; + using System.Globalization; using System.IO; using System.Reflection; @@ -14,6 +15,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel; @@ -22,6 +24,9 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + using Moq; [TestClass] @@ -33,6 +38,8 @@ public class ProxyDataCollectionManagerTests private Mock mockProcessHelper; private Mock mockRequestData; private Mock mockMetricsCollection; + private static readonly string TimoutErrorMessage = + "vstest.console process failed to connect to datacollector process after 90 seconds. This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; [TestInitialize] public void Initialize() @@ -46,34 +53,40 @@ public void Initialize() this.proxyDataCollectionManager = new ProxyDataCollectionManager(this.mockRequestData.Object, string.Empty, this.mockDataCollectionRequestSender.Object, this.mockProcessHelper.Object, this.mockDataCollectionLauncher.Object); } + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); + Environment.SetEnvironmentVariable(ProxyDataCollectionManager.DebugEnvironmentVaribleName, string.Empty); + } + [TestMethod] public void InitializeShouldInitializeCommunication() { - this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout)).Returns(true); + this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(EnvironmentHelper.DefaultConnectionTimeout * 1000)).Returns(true); this.proxyDataCollectionManager.Initialize(); this.mockDataCollectionLauncher.Verify(x => x.LaunchDataCollector(It.IsAny>(), It.IsAny>()), Times.Once); - this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout), Times.Once); + this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(EnvironmentHelper.DefaultConnectionTimeout * 1000), Times.Once); } [TestMethod] public void InitializeShouldThrowExceptionIfConnectionTimeouts() { - this.mockDataCollectionRequestSender.Setup( x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout)).Returns(false); + this.mockDataCollectionRequestSender.Setup( x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(false); - Assert.ThrowsException(() => this.proxyDataCollectionManager.Initialize()); + var message = Assert.ThrowsException(() => this.proxyDataCollectionManager.Initialize()).Message; + Assert.AreEqual(message, ProxyDataCollectionManagerTests.TimoutErrorMessage); } [TestMethod] public void InitializeShouldSetTimeoutBasedOnTimeoutEnvironmentVarible() { - var timeout = 10; - Environment.SetEnvironmentVariable(ProxyDataCollectionManager.TimeoutEnvironmentVaribleName, timeout.ToString()); + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, timeout.ToString()); this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(timeout * 1000)).Returns(true); this.proxyDataCollectionManager.Initialize(); - Environment.SetEnvironmentVariable(ProxyDataCollectionManager.TimeoutEnvironmentVaribleName, string.Empty); this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(timeout * 1000), Times.Once); } @@ -82,12 +95,12 @@ public void InitializeShouldSetTimeoutBasedOnTimeoutEnvironmentVarible() public void InitializeShouldSetTimeoutBasedOnDebugEnvironmentVaribleName() { Environment.SetEnvironmentVariable(ProxyDataCollectionManager.DebugEnvironmentVaribleName, "1"); - this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout * 5)).Returns(true); + var expectedTimeout = EnvironmentHelper.DefaultConnectionTimeout * 1000 * 5; + this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(expectedTimeout)).Returns(true); this.proxyDataCollectionManager.Initialize(); - Environment.SetEnvironmentVariable(ProxyDataCollectionManager.DebugEnvironmentVaribleName, string.Empty); - this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout * 5), Times.Once); + this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(expectedTimeout), Times.Once); } [TestMethod] @@ -106,7 +119,7 @@ public void InitializeShouldPassDiagArgumentsIfDiagIsEnabled() try { EqtTrace.InitializeVerboseTrace("mylog.txt"); - this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout)).Returns(true); + this.mockDataCollectionRequestSender.Setup(x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(true); this.proxyDataCollectionManager.Initialize(); @@ -116,7 +129,6 @@ public void InitializeShouldPassDiagArgumentsIfDiagIsEnabled() It.IsAny>(), It.Is>(list => list.Contains("--diag"))), Times.Once); - this.mockDataCollectionRequestSender.Verify(x => x.WaitForRequestHandlerConnection(ProxyDataCollectionManager.DataCollectorConnectionTimeout), Times.Once); } finally { diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/EventHandlers/TestRequestHandlerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/EventHandlers/TestRequestHandlerTests.cs index dbc611abad..d728a07d4e 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/EventHandlers/TestRequestHandlerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/EventHandlers/TestRequestHandlerTests.cs @@ -29,25 +29,27 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities public class TestRequestHandlerTests { private readonly Mock mockCommunicationClient; + private readonly Mock mockCommunicationEndpointFactory; private readonly Mock mockChannel; private readonly Mock mockTestHostManagerFactory; private readonly Mock mockDiscoveryManager; private readonly Mock mockExecutionManager; private readonly JsonDataSerializer dataSerializer; - private readonly ITestRequestHandler requestHandler; + private ITestRequestHandler requestHandler; private readonly TestHostConnectionInfo testHostConnectionInfo; private readonly JobQueue jobQueue; public TestRequestHandlerTests() { this.mockCommunicationClient = new Mock(); + this.mockCommunicationEndpointFactory = new Mock(); this.mockChannel = new Mock(); this.dataSerializer = JsonDataSerializer.Instance; this.testHostConnectionInfo = new TestHostConnectionInfo { Endpoint = IPAddress.Loopback + ":123", - Role = ConnectionRole.Host + Role = ConnectionRole.Client }; this.jobQueue = new JobQueue( @@ -64,19 +66,21 @@ public TestRequestHandlerTests() this.mockExecutionManager = new Mock(); this.mockTestHostManagerFactory.Setup(mf => mf.GetDiscoveryManager()).Returns(this.mockDiscoveryManager.Object); this.mockTestHostManagerFactory.Setup(mf => mf.GetExecutionManager()).Returns(this.mockExecutionManager.Object); + this.mockCommunicationEndpointFactory.Setup(f => f.Create(ConnectionRole.Client)) + .Returns(this.mockCommunicationClient.Object); this.requestHandler = new TestableTestRequestHandler( this.testHostConnectionInfo, - this.mockCommunicationClient.Object, + this.mockCommunicationEndpointFactory.Object, JsonDataSerializer.Instance, jobQueue); + this.requestHandler.InitializeCommunication(); + this.mockCommunicationClient.Raise(e => e.Connected += null, new ConnectedEventArgs(this.mockChannel.Object)); } [TestMethod] public void InitializeCommunicationShouldConnectToServerAsynchronously() { - this.requestHandler.InitializeCommunication(); - this.mockCommunicationClient.Verify(c => c.Start(this.testHostConnectionInfo.Endpoint), Times.Once); } @@ -86,7 +90,7 @@ public void InitializeCommunicationShouldThrowIfServerIsNotAccessible() var connectionInfo = new TestHostConnectionInfo { Endpoint = IPAddress.Loopback + ":123", - Role = ConnectionRole.Host + Role = ConnectionRole.Client }; var socketClient = new SocketClient(); socketClient.Connected += (sender, connectedEventArgs) => @@ -94,7 +98,9 @@ public void InitializeCommunicationShouldThrowIfServerIsNotAccessible() Assert.IsFalse(connectedEventArgs.Connected); Assert.AreEqual(typeof(SocketException), connectedEventArgs.Fault.InnerException.GetType()); }; - var rh = new TestableTestRequestHandler(connectionInfo, socketClient, this.dataSerializer, this.jobQueue); + this.mockCommunicationEndpointFactory.Setup(f => f.Create(ConnectionRole.Client)) + .Returns(socketClient); + var rh = new TestableTestRequestHandler(connectionInfo, this.mockCommunicationEndpointFactory.Object, this.dataSerializer, this.jobQueue); rh.InitializeCommunication(); this.requestHandler.WaitForRequestSenderConnection(1000); @@ -103,14 +109,17 @@ public void InitializeCommunicationShouldThrowIfServerIsNotAccessible() [TestMethod] public void WaitForRequestSenderConnectionShouldWaitUntilConnectionIsSetup() { - this.SetupChannel(); - Assert.IsTrue(this.requestHandler.WaitForRequestSenderConnection(1000)); } [TestMethod] public void WaitForRequestSenderConnectionShouldReturnFalseIfConnectionSetupTimesout() { + this.requestHandler = new TestableTestRequestHandler( + this.testHostConnectionInfo, + this.mockCommunicationEndpointFactory.Object, + JsonDataSerializer.Instance, + jobQueue); this.requestHandler.InitializeCommunication(); Assert.IsFalse(this.requestHandler.WaitForRequestSenderConnection(1)); @@ -119,8 +128,6 @@ public void WaitForRequestSenderConnectionShouldReturnFalseIfConnectionSetupTime [TestMethod] public void ProcessRequestsShouldProcessMessagesUntilSessionCompleted() { - this.SetupChannel(); - var task = this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendSessionEnd(); @@ -133,7 +140,6 @@ public void ProcessRequestsShouldProcessMessagesUntilSessionCompleted() public void ProcessRequestsVersionCheckShouldAckMinimumOfGivenAndHighestSupportedVersion() { var message = new Message { MessageType = MessageType.VersionCheck, Payload = 1 }; - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -152,7 +158,6 @@ public void ProcessRequestsVersionCheckShouldLogErrorIfDiagnosticsEnableFails() } EqtTrace.ErrorOnInitialization = "non-existent-error"; var message = new Message { MessageType = MessageType.VersionCheck, Payload = 1 }; - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -169,7 +174,6 @@ public void ProcessRequestsVersionCheckShouldLogErrorIfDiagnosticsEnableFails() public void ProcessRequestsDiscoveryInitializeShouldSetExtensionPaths() { var message = this.dataSerializer.SerializePayload(MessageType.DiscoveryInitialize, new[] { "testadapter.dll" }); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -183,7 +187,6 @@ public void ProcessRequestsDiscoveryInitializeShouldSetExtensionPaths() public void ProcessRequestsDiscoveryStartShouldStartDiscoveryWithGivenCriteria() { var message = this.dataSerializer.SerializePayload(MessageType.StartDiscovery, new DiscoveryCriteria(new[] { "test.dll" }, 1, string.Empty)); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -198,7 +201,6 @@ public void DiscoveryCompleteShouldSendDiscoveryCompletePayloadOnChannel() { var discoveryComplete = new DiscoveryCompletePayload { TotalTests = 1, LastDiscoveredTests = Enumerable.Empty(), IsAborted = false }; var message = this.dataSerializer.SerializePayload(MessageType.DiscoveryComplete, discoveryComplete); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); @@ -216,7 +218,6 @@ public void DiscoveryCompleteShouldSendDiscoveryCompletePayloadOnChannel() public void ProcessRequestsExecutionInitializeShouldSetExtensionPaths() { var message = this.dataSerializer.SerializePayload(MessageType.ExecutionInitialize, new[] { "testadapter.dll" }); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); @@ -234,7 +235,6 @@ public void ProcessRequestsExecutionStartShouldStartExecutionWithGivenSources() asm["mstestv2"] = new[] {"test1.dll", "test2.dll"}; var testRunCriteriaWithSources = new TestRunCriteriaWithSources(asm, "runsettings", null, null); var message = this.dataSerializer.SerializePayload(MessageType.StartTestExecutionWithSources, testRunCriteriaWithSources); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); @@ -258,7 +258,6 @@ public void ProcessRequestsExecutionStartShouldStartExecutionWithGivenTests() var testCases = new [] { t1, t2 }; var testRunCriteriaWithTests = new TestRunCriteriaWithTests(testCases, "runsettings", null, null); var message = this.dataSerializer.SerializePayload(MessageType.StartTestExecutionWithTests, testRunCriteriaWithTests); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); @@ -280,7 +279,6 @@ public void ProcessRequestsExecutionStartShouldStartExecutionWithGivenTests() public void ProcessRequestsExecutionCancelShouldCancelTestRun() { var message = this.dataSerializer.SerializePayload(MessageType.CancelTestRun, string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -295,7 +293,6 @@ public void ProcessRequestsExecutionCancelShouldCancelTestRun() public void ProcessRequestsExecutionLaunchAdapterProcessWithDebuggerShouldSendAckMessage() { var message = this.dataSerializer.SerializePayload(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -308,7 +305,6 @@ public void ProcessRequestsExecutionLaunchAdapterProcessWithDebuggerShouldSendAc public void ProcessRequestsExecutionAbortShouldStopTestRun() { var message = this.dataSerializer.SerializePayload(MessageType.AbortTestRun, string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -334,7 +330,6 @@ public void SendExecutionCompleteShouldSendTestRunCompletePayloadOnChannel() { this.requestHandler.SendExecutionComplete(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>()); }); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.mockChannel.Setup(mc => mc.Send(It.Is(d => d.Contains(MessageType.ExecutionComplete)))) @@ -363,7 +358,6 @@ public void SendExecutionCompleteShouldSendTestRunCompletePayloadOnChannel() public void LaunchProcessWithDebuggerAttachedShouldSendProcessInformationOnChannel() { var message = this.dataSerializer.SerializePayload(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, "123"); - this.SetupChannel(); this.mockChannel.Setup(mc => mc.Send(It.Is(d => d.Contains(MessageType.LaunchAdapterProcessWithDebuggerAttached)))) .Callback( @@ -383,7 +377,6 @@ public void LaunchProcessWithDebuggerAttachedShouldSendProcessInformationOnChann public void LaunchProcessWithDebuggerAttachedShouldWaitForProcessIdFromRunner() { var message = dataSerializer.SerializePayload(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, "123"); - this.SetupChannel(); this.mockChannel.Setup(mc => mc.Send(It.Is(d => d.Contains(MessageType.LaunchAdapterProcessWithDebuggerAttached)))) .Callback( @@ -407,7 +400,6 @@ public void LaunchProcessWithDebuggerAttachedShouldWaitForProcessIdFromRunner() public void SendLogShouldSendTestMessageWithLevelOnChannel() { var logMsg = "Testing log message on channel"; - this.SetupChannel(); this.mockChannel.Setup(mc => mc.Send(It.Is(d => d.Contains(MessageType.TestMessage)))) .Callback( @@ -428,7 +420,6 @@ public void SendLogShouldSendTestMessageWithLevelOnChannel() [TestMethod] public void ProcessRequestsEndSessionShouldCloseRequestHandler() { - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendSessionEnd(); @@ -440,7 +431,6 @@ public void ProcessRequestsEndSessionShouldCloseRequestHandler() public void ProcessRequestsAbortSessionShouldBeNoOp() { var message = dataSerializer.SerializePayload(MessageType.SessionAbort, string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -453,7 +443,6 @@ public void ProcessRequestsAbortSessionShouldBeNoOp() public void ProcessRequestsInvalidMessageTypeShouldNotThrow() { var message = dataSerializer.SerializePayload("DummyMessage", string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -465,7 +454,6 @@ public void ProcessRequestsInvalidMessageTypeShouldNotThrow() public void ProcessRequestsInvalidMessageTypeShouldProcessFutureMessages() { var message = dataSerializer.SerializePayload("DummyMessage", string.Empty); - this.SetupChannel(); this.ProcessRequestsAsync(this.mockTestHostManagerFactory.Object); this.SendMessageOnChannel(message); @@ -486,12 +474,6 @@ public void DisposeShouldStopCommunicationChannel() this.mockCommunicationClient.Verify(mc => mc.Stop(), Times.Once); } - private void SetupChannel() - { - this.requestHandler.InitializeCommunication(); - this.mockCommunicationClient.Raise(e => e.Connected += null, new ConnectedEventArgs(this.mockChannel.Object)); - } - private void SendMessageOnChannel(Message message) { // Setup message to be returned on deserialization of data @@ -537,8 +519,8 @@ private void VerifyResponseMessageContains(string message) public class TestableTestRequestHandler : TestRequestHandler { - public TestableTestRequestHandler(TestHostConnectionInfo testHostConnectionInfo,ICommunicationEndPoint communicationClient, IDataSerializer dataSerializer, JobQueue jobQueue) - : base(testHostConnectionInfo, communicationClient, dataSerializer, jobQueue, OnAckMessageReceived) + public TestableTestRequestHandler(TestHostConnectionInfo testHostConnectionInfo,ICommunicationEndpointFactory communicationEndpointFactory, IDataSerializer dataSerializer, JobQueue jobQueue) + : base(testHostConnectionInfo, communicationEndpointFactory, dataSerializer, jobQueue, OnAckMessageReceived) { } diff --git a/test/datacollector.UnitTests/DataCollectorMainTests.cs b/test/datacollector.UnitTests/DataCollectorMainTests.cs new file mode 100644 index 0000000000..9a122778c5 --- /dev/null +++ b/test/datacollector.UnitTests/DataCollectorMainTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollector.UnitTests +{ + using System; + using System.Globalization; + using CommunicationUtilities.DataCollection.Interfaces; + using CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + using Moq; + using PlatformAbstractions.Interfaces; + using TestPlatform.DataCollector; + + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + + [TestClass] + public class DataCollectorMainTests + { + private readonly string[] args = {"--port", "1025", "--parentprocessid", "100" }; + + private static readonly string TimoutErrorMessage = + "datacollector process failed to connect to vstest.console process after 90 seconds. This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; + private Mock mockProcessHelper; + private Mock mockEnvironment; + private Mock mockDataCollectionRequestHandler; + private DataCollectorMain dataCollectorMain; + + public DataCollectorMainTests() + { + this.mockProcessHelper = new Mock(); + this.mockEnvironment = new Mock(); + this.mockDataCollectionRequestHandler = new Mock(); + this.dataCollectorMain = new DataCollectorMain(this.mockProcessHelper.Object, this.mockEnvironment.Object, this.mockDataCollectionRequestHandler.Object); + this.mockDataCollectionRequestHandler.Setup(rh => rh.WaitForRequestSenderConnection(It.IsAny())).Returns(true); + } + + [TestCleanup] + public void CleanUp() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, ""); + } + + [TestMethod] + public void RunShouldTimeoutBasedOnEnvVariable() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "10"); + this.dataCollectorMain.Run(args); + this.mockDataCollectionRequestHandler.Verify(rh => rh.WaitForRequestSenderConnection(10 * 1000)); + } + + [TestMethod] + public void RunShouldTimeoutBasedDefaulValueIfEnvVariableNotSet() + { + this.dataCollectorMain.Run(args); + + this.mockDataCollectionRequestHandler.Verify(rh => rh.WaitForRequestSenderConnection(EnvironmentHelper.DefaultConnectionTimeout * 1000)); + } + + [TestMethod] + public void RunShouldThrowIfTimeoutOccured() + { + this.mockDataCollectionRequestHandler.Setup(rh => rh.WaitForRequestSenderConnection(It.IsAny())).Returns(false); + var message = Assert.ThrowsException(() => this.dataCollectorMain.Run(args)).Message; + Assert.AreEqual(message, DataCollectorMainTests.TimoutErrorMessage); + } + + } +} diff --git a/test/testhost.UnitTests/DefaultEngineInvokerTests.cs b/test/testhost.UnitTests/DefaultEngineInvokerTests.cs new file mode 100644 index 0000000000..3f392d06b1 --- /dev/null +++ b/test/testhost.UnitTests/DefaultEngineInvokerTests.cs @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace testhost.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; + using Microsoft.VisualStudio.TestPlatform.TestHost; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + using CommunicationUtilitiesResources = + Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + + [TestClass] + public class DefaultEngineInvokerTests + { + private const int ParentProcessId = 27524; + private static readonly IDictionary argsDictionary = new Dictionary + { + { "--port", "21291" }, + { "--endpoint", "127.0.0.1:021291" }, + { "--role", "client"}, + { "--parentprocessid", ParentProcessId.ToString() }, + { "--diag", @"C:\Users\samadala\src\vstest\log_3.host.18-04-17_20-25-45_48171_1.txt"}, + { "--telemetryoptedin", "false"}, + { "--datacollectionport", "21290"} + }; + private static readonly string TimoutErrorMessage = + "testhost process failed to connect to datacollector process after 90 seconds. This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; + + private Mock mockTestRequestHandler; + private Mock mockDataCollectionTestCaseEventSender; + private Mock mockProcssHelper; + private DefaultEngineInvoker engineInvoker; + + public DefaultEngineInvokerTests() + { + this.mockDataCollectionTestCaseEventSender = new Mock(); + this.mockTestRequestHandler = new Mock(); + this.mockProcssHelper = new Mock(); + this.engineInvoker = new DefaultEngineInvoker( + this.mockTestRequestHandler.Object, + this.mockDataCollectionTestCaseEventSender.Object, + this.mockProcssHelper.Object); + this.mockTestRequestHandler.Setup(h => h.WaitForRequestSenderConnection(It.IsAny())).Returns(true); + this.mockDataCollectionTestCaseEventSender.Setup(s => s.WaitForRequestSenderConnection(It.IsAny())).Returns(true); + } + + [TestCleanup] + public void Cleanup() + { + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); + } + + [TestMethod] + public void InvokeShouldWaitForDefaultTimeoutIfNoEnvVariableSetDuringDataCollectorConnection() + { + this.engineInvoker.Invoke(argsDictionary); + + this.mockDataCollectionTestCaseEventSender.Verify(s => s.WaitForRequestSenderConnection(EnvironmentHelper.DefaultConnectionTimeout * 1000)); + } + + [TestMethod] + public void InvokeShouldWaitBasedOnTimeoutEnvVariableDuringDataCollectorConnection() + { + var timeout = 10; + Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, timeout.ToString()); + this.engineInvoker.Invoke(argsDictionary); + + this.mockDataCollectionTestCaseEventSender.Verify(s => s.WaitForRequestSenderConnection(timeout * 1000)); + } + + [TestMethod] + public void InvokeShouldThrowExceptionIfDataCollectorConnection() + { + this.mockDataCollectionTestCaseEventSender.Setup(s => s.WaitForRequestSenderConnection(It.IsAny())).Returns(false); + var message = Assert.ThrowsException(() => this.engineInvoker.Invoke(argsDictionary)).Message; + + Assert.AreEqual(message, DefaultEngineInvokerTests.TimoutErrorMessage); + } + + [TestMethod] + public void InvokeShouldSetParentProcessExistCallback() + { + this.engineInvoker.Invoke(argsDictionary); + + this.mockProcssHelper.Verify(h => h.SetExitCallback(ParentProcessId, It.IsAny>())); + } + } +}