diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index d334bf664f..8ba381f1ac 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -98,7 +98,7 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve this.baseTestDiscoveryEventsHandler = eventHandler; try { - this.isCommunicationEstablished = this.SetupChannel(discoveryCriteria.Sources); + this.isCommunicationEstablished = this.SetupChannel(discoveryCriteria.Sources, discoveryCriteria.RunSettings); if (this.isCommunicationEstablished) { diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index 8ef7f8c375..07c15ac150 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -20,6 +20,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.ClientProtocol; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + using Microsoft.VisualStudio.TestPlatform.Utilities; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; @@ -101,17 +102,18 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH { EqtTrace.Verbose("ProxyExecutionManager: Test host is always Lazy initialize."); } - var testPackages = new List(testRunCriteria.HasSpecificSources ? testRunCriteria.Sources : + + var testSources = new List(testRunCriteria.HasSpecificSources ? testRunCriteria.Sources : // If the test execution is with a test filter, group them by sources testRunCriteria.Tests.GroupBy(tc => tc.Source).Select(g => g.Key)); - this.isCommunicationEstablished = this.SetupChannel(testPackages); + this.isCommunicationEstablished = this.SetupChannel(testSources, testRunCriteria.TestRunSettings); if (this.isCommunicationEstablished) { this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); - this.InitializeExtensions(testPackages); + this.InitializeExtensions(testSources); // This code should be in sync with InProcessProxyExecutionManager.StartTestRun executionContext var executionContext = new TestExecutionContext( @@ -131,12 +133,12 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH if (testRunCriteria.HasSpecificSources) { - var runRequest = testRunCriteria.CreateTestRunCriteriaForSources(testHostManager, runsettings, executionContext, testPackages); + var runRequest = testRunCriteria.CreateTestRunCriteriaForSources(testHostManager, runsettings, executionContext, testSources); this.RequestSender.StartTestRun(runRequest, this); } else { - var runRequest = testRunCriteria.CreateTestRunCriteriaForTests(testHostManager, runsettings, executionContext, testPackages); + var runRequest = testRunCriteria.CreateTestRunCriteriaForTests(testHostManager, runsettings, executionContext, testSources); this.RequestSender.StartTestRun(runRequest, this); } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs index c82e18877c..1eea63e8c1 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs @@ -25,7 +25,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client 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. /// @@ -96,7 +96,7 @@ protected ProxyOperationManager(IRequestData requestData, ITestRequestSender req /// /// Returns true if Communation is established b/w runner and host /// - public virtual bool SetupChannel(IEnumerable sources) + public virtual bool SetupChannel(IEnumerable sources, string runSettings) { this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); var connTimeout = EnvironmentHelper.GetConnectionTimeout(); @@ -120,8 +120,11 @@ public virtual bool SetupChannel(IEnumerable sources) this.testHostManager.HostLaunched += this.TestHostManagerHostLaunched; this.testHostManager.HostExited += this.TestHostManagerHostExited; + // Get envVars from run settings + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettings); + // Get the test process start info - var testHostStartInfo = this.UpdateTestProcessStartInfo(this.testHostManager.GetTestHostProcessStartInfo(sources, null, connectionInfo)); + var testHostStartInfo = this.UpdateTestProcessStartInfo(this.testHostManager.GetTestHostProcessStartInfo(sources, envVars, connectionInfo)); try { // Launch the test host. diff --git a/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs b/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs index d93407d8ad..564618e37f 100644 --- a/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs +++ b/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs @@ -7,6 +7,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Utilities using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using System; using System.Collections.Generic; + using System.Dynamic; using System.Globalization; using System.IO; using System.Text; @@ -36,6 +37,7 @@ public class InferRunSettingsHelper private const string TargetFrameworkNodePath = @"/RunSettings/RunConfiguration/TargetFrameworkVersion"; private const string ResultsDirectoryNodePath = @"/RunSettings/RunConfiguration/ResultsDirectory"; private const string TargetDeviceNodePath = @"/RunSettings/RunConfiguration/TargetDevice"; + private const string EnvironmentVariablesNodePath = @"/RunSettings/RunConfiguration/EnvironmentVariables"; private const string multiTargettingForwardLink = @"http://go.microsoft.com/fwlink/?LinkID=236877&clcid=0x409"; // To make things compatible for older runsettings @@ -377,6 +379,50 @@ private static List GetNodeAttributes(XPathNavigator node) return null; } + /// + /// Returns a dictionary of environment variables given in run settings + /// + /// The run settings xml string + /// Environment Variables Dictionary + public static Dictionary GetEnvironmentVariables(string runSettings) + { + Dictionary environmentVariables = null; + try + { + using (var stream = new StringReader(runSettings)) + using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings)) + { + var document = new XmlDocument(); + document.Load(reader); + var runSettingsNavigator = document.CreateNavigator(); + + var node = runSettingsNavigator.SelectSingleNode(EnvironmentVariablesNodePath); + if (node == null) + { + return null; + } + + environmentVariables = new Dictionary(); + var childNodes = node.SelectChildren(XPathNodeType.Element); + + while (childNodes.MoveNext()) + { + if (!environmentVariables.ContainsKey(childNodes.Current.Name)) + { + environmentVariables.Add(childNodes.Current.Name, childNodes.Current?.Value); + } + } + } + } + catch (Exception ex) + { + EqtTrace.Error("Error while trying to read environment variables settings. Message: {0}", ex.ToString()); + return null; + } + + return environmentVariables; + } + /// /// Updates the RunConfiguration.TargetPlatform value for a run settings. if the value is already set, behavior depends on overwrite. /// diff --git a/src/vstest.console/Processors/RunSettingsArgumentProcessor.cs b/src/vstest.console/Processors/RunSettingsArgumentProcessor.cs index 59e3b99c91..734386c18c 100644 --- a/src/vstest.console/Processors/RunSettingsArgumentProcessor.cs +++ b/src/vstest.console/Processors/RunSettingsArgumentProcessor.cs @@ -4,6 +4,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors { using System; + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; @@ -137,6 +138,12 @@ public void Initialize(string argument) this.runSettingsManager.AddDefaultRunSettings(); this.commandLineOptions.SettingsFile = argument; + + if (this.runSettingsManager.QueryRunSettingsNode("RunConfiguration.EnvironmentVariables") != null) + { + this.commandLineOptions.InIsolation = true; + this.runSettingsManager.UpdateRunSettingsNode(InIsolationArgumentExecutor.RunSettingsPath, "true"); + } } catch (XmlException exception) { diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/RunsettingsTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/RunsettingsTests.cs index b7acdda347..ac66c63dda 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/RunsettingsTests.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/RunsettingsTests.cs @@ -447,6 +447,37 @@ public void LegacySettingsAssemblyResolution(RunnerInfo runnerInfo) #endregion + #region RunSettings With EnvironmentVariables Settings Tests + + [TestMethod] + [NetFullTargetFrameworkDataSource] + [NetCoreTargetFrameworkDataSource] + public void EnvironmentVariablesSettingsShouldSetEnvironmentVariables(RunnerInfo runnerInfo) + { + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + + var testAssemblyPath = this.GetAssetFullPath("EnvironmentVariablesTestProject.dll"); + + var runsettingsXml = @" + + + C:\temp + + + "; + + File.WriteAllText(this.runsettingsPath, runsettingsXml); + + var arguments = PrepareArguments( + testAssemblyPath, + string.Empty, + this.runsettingsPath, this.FrameworkArgValue, runnerInfo.InIsolationValue); + this.InvokeVsTest(arguments); + this.ValidateSummaryStatus(1, 0, 0); + } + + #endregion + private string GetRunsettingsFilePath(Dictionary runConfigurationDictionary) { var runsettingsPath = Path.Combine( diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 63df3b2536..1f00950e37 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -334,19 +334,23 @@ public void StartTestRunShouldInitializeExtensionsWithExistingDataCOllectorExten [TestMethod] public void SetupChannelShouldThrowExceptionIfClientConnectionTimeout() { + string runsettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny(), It.IsAny())).Returns(false); this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); - Assert.ThrowsException(() => this.testExecutionManager.SetupChannel(new List { "source.dll" })); + Assert.ThrowsException(() => this.testExecutionManager.SetupChannel(new List { "source.dll" }, runsettings)); } [TestMethod] public void SetupChannelShouldThrowExceptionIfTestHostExitedBeforeConnectionIsEstablished() { + string runsettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny(), It.IsAny())).Returns(false); this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true)).Callback(() => { this.mockTestHostManager.Raise(t => t.HostExited += null, new HostProviderEventArgs("I crashed!")); }); - Assert.AreEqual(string.Format(CrossPlatEngineResources.Resources.TestHostExitedWithError, "I crashed!"), Assert.ThrowsException(() => this.testExecutionManager.SetupChannel(new List { "source.dll" })).Message); + Assert.AreEqual(string.Format(CrossPlatEngineResources.Resources.TestHostExitedWithError, "I crashed!"), Assert.ThrowsException(() => this.testExecutionManager.SetupChannel(new List { "source.dll" }, runsettings)).Message); } [TestMethod] @@ -522,9 +526,11 @@ public void StartTestRunShouldInitiateTestRunForTestsThroughTheServer() [TestMethod] public void CloseShouldSignalToServerSessionEndIfTestHostWasLaunched() { + string runsettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny(), It.IsAny())).Returns(true); - this.testExecutionManager.SetupChannel(new List { "source.dll" }); + this.testExecutionManager.SetupChannel(new List { "source.dll" }, runsettings); this.testExecutionManager.Close(); @@ -542,9 +548,11 @@ public void CloseShouldNotSendSignalToServerSessionEndIfTestHostWasNotLaunched() [TestMethod] public void CloseShouldSignalServerSessionEndEachTime() { + string runsettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny(), It.IsAny())).Returns(true); - this.testExecutionManager.SetupChannel(new List { "source.dll" }); + this.testExecutionManager.SetupChannel(new List { "source.dll" }, runsettings); this.testExecutionManager.Close(); this.testExecutionManager.Close(); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs index 96bafc2b74..8a5a634f0f 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs @@ -49,6 +49,8 @@ public class ProxyOperationManagerTests : ProxyBaseManagerTests private int connectionTimeout = EnvironmentHelper.DefaultConnectionTimeout * 1000; + private string defaultRunSettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + 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."; @@ -73,10 +75,10 @@ public void SetupChannelShouldLaunchTestHost() var expectedStartInfo = new TestProcessStartInfo(); this.mockRequestSender.Setup(rs => rs.InitializeCommunication()).Returns(123); this.mockTestHostManager.Setup( - th => th.GetTestHostProcessStartInfo(Enumerable.Empty(), null, It.IsAny())) + th => th.GetTestHostProcessStartInfo(Enumerable.Empty(), It.IsAny>(), It.IsAny())) .Returns(expectedStartInfo); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockTestHostManager.Verify(thl => thl.LaunchTestHostAsync(It.Is(si => si == expectedStartInfo), It.IsAny()), Times.Once); } @@ -87,13 +89,13 @@ public void SetupChannelShouldCreateTimestampedLogFileForHost() this.mockRequestSender.Setup(rs => rs.InitializeCommunication()).Returns(123); EqtTrace.InitializeTrace("log.txt", PlatformTraceLevel.Verbose); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockTestHostManager.Verify( th => th.GetTestHostProcessStartInfo( It.IsAny>(), - null, + It.IsAny>(), It.Is( t => t.LogFile.Contains("log.host." + DateTime.Now.ToString("yy-MM-dd")) && t.LogFile.Contains("_" + Thread.CurrentThread.ManagedThreadId + ".txt")))); @@ -108,14 +110,14 @@ public void SetupChannelShouldCreateTimestampedLogFileForHost() public void SetupChannelShouldAddRunnerProcessIdForTestHost() { this.mockRequestSender.Setup(rs => rs.InitializeCommunication()).Returns(123); - - this.testOperationManager.SetupChannel(Enumerable.Empty()); + + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockTestHostManager.Verify( th => th.GetTestHostProcessStartInfo( It.IsAny>(), - null, + It.IsAny>(), It.Is(t => t.RunnerProcessId.Equals(Process.GetCurrentProcess().Id)))); } @@ -129,20 +131,20 @@ public void SetupChannelShouldAddCorrectTraceLevelForTestHost() #endif this.mockRequestSender.Setup(rs => rs.InitializeCommunication()).Returns(123); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockTestHostManager.Verify( th => th.GetTestHostProcessStartInfo( It.IsAny>(), - null, + It.IsAny>(), It.Is(t => t.TraceLevel == (int)PlatformTraceLevel.Info))); } [TestMethod] public void SetupChannelShouldSetupServerForCommunication() { - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(s => s.InitializeCommunication(), Times.Once); } @@ -151,16 +153,16 @@ public void SetupChannelShouldSetupServerForCommunication() public void SetupChannelShouldCallHostServerIfRunnerIsServer() { var connectionInfo = new TestHostConnectionInfo - { - Endpoint = IPAddress.Loopback + ":0", - Role = ConnectionRole.Host, - Transport = Transport.Sockets - }; + { + Endpoint = IPAddress.Loopback + ":0", + Role = ConnectionRole.Host, + Transport = Transport.Sockets + }; ProtocolConfig protocolConfig = new ProtocolConfig { Version = 2 }; var mockCommunicationServer = new Mock(); mockCommunicationServer.Setup(mc => mc.Start(connectionInfo.Endpoint)).Returns(IPAddress.Loopback + ":123").Callback( - () => { mockCommunicationServer.Raise(s=>s.Connected += null, mockCommunicationServer.Object, new ConnectedEventArgs(this.mockChannel.Object)); }); + () => { mockCommunicationServer.Raise(s => s.Connected += null, mockCommunicationServer.Object, new ConnectedEventArgs(this.mockChannel.Object)); }); var testRequestSender = new TestRequestSender(mockCommunicationServer.Object, connectionInfo, mockDataSerializer.Object, protocolConfig, CLIENTPROCESSEXITWAIT); this.SetupChannelMessage(MessageType.VersionCheck, MessageType.VersionCheck, protocolConfig.Version); @@ -169,20 +171,20 @@ public void SetupChannelShouldCallHostServerIfRunnerIsServer() var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object); - localTestOperationManager.SetupChannel(Enumerable.Empty()); + localTestOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); - mockCommunicationServer.Verify(s => s.Start(IPAddress.Loopback.ToString()+":0"), Times.Once); + mockCommunicationServer.Verify(s => s.Start(IPAddress.Loopback.ToString() + ":0"), Times.Once); } [TestMethod] public void SetupChannelShouldCallSetupClientIfRunnerIsClient() { var connectionInfo = new TestHostConnectionInfo - { - Endpoint = IPAddress.Loopback + ":124", - Role = ConnectionRole.Host, - Transport = Transport.Sockets - }; + { + Endpoint = IPAddress.Loopback + ":124", + Role = ConnectionRole.Host, + Transport = Transport.Sockets + }; ProtocolConfig protocolConfig = new ProtocolConfig { Version = 2 }; var mockCommunicationEndpoint = new Mock(); mockCommunicationEndpoint.Setup(mc => mc.Start(connectionInfo.Endpoint)).Returns(connectionInfo.Endpoint).Callback(() => @@ -200,7 +202,7 @@ public void SetupChannelShouldCallSetupClientIfRunnerIsClient() var localTestOperationManager = new TestableProxyOperationManager(this.mockRequestData.Object, testRequestSender, this.mockTestHostManager.Object); - localTestOperationManager.SetupChannel(Enumerable.Empty()); + localTestOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); mockCommunicationEndpoint.Verify(s => s.Start(It.IsAny()), Times.Once); } @@ -208,8 +210,8 @@ public void SetupChannelShouldCallSetupClientIfRunnerIsClient() [TestMethod] public void SetupChannelShouldNotInitializeIfConnectionIsAlreadyInitialized() { - this.testOperationManager.SetupChannel(Enumerable.Empty()); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(s => s.InitializeCommunication(), Times.Once); } @@ -217,7 +219,7 @@ public void SetupChannelShouldNotInitializeIfConnectionIsAlreadyInitialized() [TestMethod] public void SetupChannelShouldWaitForTestHostConnection() { - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny()), Times.Once); } @@ -225,8 +227,8 @@ public void SetupChannelShouldWaitForTestHostConnection() [TestMethod] public void SetupChannelShouldNotWaitForTestHostConnectionIfConnectionIsInitialized() { - this.testOperationManager.SetupChannel(Enumerable.Empty()); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny()), Times.Exactly(1)); } @@ -237,7 +239,7 @@ public void SetupChannelShouldHonorTimeOutSetByUser() Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "100"); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(100000, It.IsAny())).Returns(true); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(100000, It.IsAny()), Times.Exactly(1)); } @@ -250,7 +252,7 @@ public void SetupChannelShouldThrowIfWaitForTestHostConnectionTimesOut() var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); - var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty())).Message; + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)).Message; Assert.AreEqual(message, ProxyOperationManagerTests.TimoutErrorMessage); } @@ -264,7 +266,7 @@ public void SetupChannelShouldThrowTestPlatformExceptionIfRequestCancelled() var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, cancellationTokenSource); cancellationTokenSource.Cancel(); - var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty())).Message; + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)).Message; StringAssert.Equals("Cancelling the operation as requested.", message); } @@ -279,7 +281,7 @@ public void SetupChannelShouldThrowTestPlatformExceptionIfRequestCancelledDuring var cancellationTokenSource = new CancellationTokenSource(); var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, cancellationTokenSource); - var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty())).Message; + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)).Message; StringAssert.Equals("Cancelling the operation as requested.", message); } @@ -293,7 +295,7 @@ public void SetupChannelShouldThrowTestPlatformExceptionIfRequestCancelledPostHo this.mockTestHostManager.Setup(rs => rs.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Callback(() => cancellationTokenSource.Cancel()); var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object, cancellationTokenSource); - var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty())).Message; + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)).Message; StringAssert.Equals("Cancelling the operation as requested.", message); } @@ -304,15 +306,15 @@ public void SetupChannelShouldThrowIfLaunchTestHostFails() this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny())).Returns(true); var operationManager = new TestableProxyOperationManager(this.mockRequestData.Object, this.mockRequestSender.Object, this.mockTestHostManager.Object); - - var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty())).Message; + + var message = Assert.ThrowsException(() => operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)).Message; Assert.AreEqual(message, string.Format(CultureInfo.CurrentUICulture, Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources.InitializationFailed)); } [TestMethod] public void SetupChannelShouldCheckVersionWithTestHost() { - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Once); } @@ -321,7 +323,7 @@ public void SetupChannelShouldThrowExceptionIfVersionCheckFails() { // Make the version check fail this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Throws(new TestPlatformException("Version check failed")); - Assert.ThrowsException(() => this.testOperationManager.SetupChannel(Enumerable.Empty())); + Assert.ThrowsException(() => this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings)); } [TestMethod] @@ -331,7 +333,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShoul 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); - operationManager.SetupChannel(Enumerable.Empty()); + operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Never); } @@ -343,7 +345,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShould 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); - operationManager.SetupChannel(Enumerable.Empty()); + operationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Once); } @@ -352,7 +354,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShould public void CloseShouldEndSessionIfHostWasLaunched() { this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny())).Returns(true); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.testOperationManager.Close(); @@ -380,11 +382,11 @@ public void CloseShouldResetChannelInitialization() { this.SetupWaitForTestHostExit(); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny())).Returns(true); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.testOperationManager.Close(); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.mockTestHostManager.Verify(th => th.LaunchTestHostAsync(It.IsAny(), It.IsAny()), Times.Exactly(2)); } @@ -393,7 +395,7 @@ public void CloseShouldTerminateTesthostProcessIfWaitTimesout() { // Ensure testhost start returns a dummy process id this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout, It.IsAny())).Returns(true); - this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); this.testOperationManager.Close(); @@ -443,7 +445,7 @@ public void UpdateTestProcessStartInfoShouldUpdateTelemetryOptedInArgTrueIfTelem .Returns(Task.FromResult(true)); // Act. - testOperationManager.SetupChannel(Enumerable.Empty()); + testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); // Verify. Assert.IsTrue(receivedTestProcessInfo.Arguments.Contains("--telemetryoptedin true")); @@ -469,7 +471,7 @@ public void UpdateTestProcessStartInfoShouldUpdateTelemetryOptedInArgFalseIfTele .Returns(Task.FromResult(true)); // Act. - testOperationManager.SetupChannel(Enumerable.Empty()); + testOperationManager.SetupChannel(Enumerable.Empty(), this.defaultRunSettings); // Verify. Assert.IsTrue(receivedTestProcessInfo.Arguments.Contains("--telemetryoptedin false")); diff --git a/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs b/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs index 111f1e97a8..d2f11736ae 100644 --- a/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs +++ b/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs @@ -558,6 +558,84 @@ public void TryGetLegacySettingsForRunSettingsWithValidLegacySettingsShouldRetur Assert.AreEqual(expectedExecutionAttributes, legacySettings["ExecutionAttributes"]); } + [TestMethod] + public void GetEnvironmentVariablesWithValidValuesInRunSettingsShouldReturnValidDictionary() + { + string runSettingsXml = @" + + + C:\temp + C:\temp2 + + + "; + + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml); + + Assert.AreEqual(2, envVars.Count); + Assert.AreEqual(envVars["RANDOM_PATH"], @"C:\temp"); + Assert.AreEqual(envVars["RANDOM_PATH2"], @"C:\temp2"); + } + + [TestMethod] + public void GetEnvironmentVariablesWithDuplicateEnvValuesInRunSettingsShouldReturnValidDictionary() + { + string runSettingsXml = @" + + + C:\temp + C:\temp2 + + + "; + + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml); + + Assert.AreEqual(1, envVars.Count); + Assert.AreEqual(envVars["RANDOM_PATH"], @"C:\temp"); + } + + [TestMethod] + public void GetEnvironmentVariablesWithEmptyVariablesInRunSettingsShouldReturnEmptyDictionary() + { + string runSettingsXml = @" + + + + + "; + + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml); + Assert.AreEqual(0, envVars.Count); + } + + [TestMethod] + public void GetEnvironmentVariablesWithInvalidValuesInRunSettingsShouldReturnNull() + { + string runSettingsXml = @" + + + + + + "; + + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml); + Assert.IsNull(envVars); + } + + [TestMethod] + public void GetEnvironmentVariablesWithoutEnvVarNodeInRunSettingsShouldReturnNull() + { + string runSettingsXml = @" + + + "; + + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml); + Assert.IsNull(envVars); + } + #region RunSettingsIncompatibeWithTestSettings Tests [TestMethod] diff --git a/test/TestAssets/EnvironmentVariablesTestProject/EnvironmentVariablesTestProject.csproj b/test/TestAssets/EnvironmentVariablesTestProject/EnvironmentVariablesTestProject.csproj new file mode 100644 index 0000000000..a5170114de --- /dev/null +++ b/test/TestAssets/EnvironmentVariablesTestProject/EnvironmentVariablesTestProject.csproj @@ -0,0 +1,15 @@ + + + + net451;netcoreapp2.1 + + false + + + + + + + + + diff --git a/test/TestAssets/EnvironmentVariablesTestProject/UnitTest1.cs b/test/TestAssets/EnvironmentVariablesTestProject/UnitTest1.cs new file mode 100644 index 0000000000..bb6b2fcadc --- /dev/null +++ b/test/TestAssets/EnvironmentVariablesTestProject/UnitTest1.cs @@ -0,0 +1,16 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace EnvironmentVariablesTestProject +{ + [TestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + var envVar = Environment.GetEnvironmentVariable("RANDOM_PATH"); + Assert.AreEqual(envVar, @"C:\temp"); + } + } +} diff --git a/test/TestAssets/TestAssets.sln/TestAssets.sln b/test/TestAssets/TestAssets.sln/TestAssets.sln index 317e3dfc53..2b827bef68 100644 --- a/test/TestAssets/TestAssets.sln/TestAssets.sln +++ b/test/TestAssets/TestAssets.sln/TestAssets.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27106.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NUnitAdapterPerfTestProject", "..\PerfAssets\NUnitAdapterPerfTestProject\NUnitAdapterPerfTestProject.csproj", "{F22A8D65-0581-4CC7-9C1C-9BC9F9E80DA4}" EndProject @@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NewtonSoftDependency", "..\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppDomainGetAssembliesTestProject", "..\AppDomainGetAssembliesTestProject\AppDomainGetAssembliesTestProject.csproj", "{BF090BCE-CC7D-4359-93E2-30F2B454F751}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvironmentVariablesTestProject", "..\EnvironmentVariablesTestProject\EnvironmentVariablesTestProject.csproj", "{BA53C202-55D6-4BBC-A24A-444B2D5F6309}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -141,6 +143,10 @@ Global {BF090BCE-CC7D-4359-93E2-30F2B454F751}.Debug|Any CPU.Build.0 = Debug|Any CPU {BF090BCE-CC7D-4359-93E2-30F2B454F751}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF090BCE-CC7D-4359-93E2-30F2B454F751}.Release|Any CPU.Build.0 = Release|Any CPU + {BA53C202-55D6-4BBC-A24A-444B2D5F6309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA53C202-55D6-4BBC-A24A-444B2D5F6309}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA53C202-55D6-4BBC-A24A-444B2D5F6309}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA53C202-55D6-4BBC-A24A-444B2D5F6309}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/vstest.console.UnitTests/Processors/RunSettingsArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/RunSettingsArgumentProcessorTests.cs index c3a41188e6..b0181f8ee2 100644 --- a/test/vstest.console.UnitTests/Processors/RunSettingsArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/RunSettingsArgumentProcessorTests.cs @@ -7,7 +7,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.Processors using System.IO; using System.Xml; - using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -15,15 +14,18 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.Processors using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using vstest.console.UnitTests.Processors; using Moq; using System.Text; + using ExceptionUtilities = Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.ExceptionUtilities; + [TestClass] public class RunSettingsArgumentProcessorTests { - private IRunSettingsProvider settingsProvider; + private TestableRunSettingsProvider settingsProvider; [TestInitialize] public void Init() @@ -309,6 +311,58 @@ public void InitializeShouldPreserveActualJapaneseString() File.Delete(runsettingsFile); } + [TestMethod] + public void InitializeShouldSetInIsolataionToTrueIfEnvironmentVariablesSpecified() + { + var settingsXml = @"C:\temp"; + + // Arrange. + var fileName = "C:\\temp\\r.runsettings"; + + var executor = new TestableRunSettingsArgumentExecutor( + CommandLineOptions.Instance, + this.settingsProvider, + settingsXml); + + // Setup mocks. + var mockFileHelper = new Mock(); + mockFileHelper.Setup(fh => fh.Exists(It.IsAny())).Returns(true); + executor.FileHelper = mockFileHelper.Object; + + // Act. + executor.Initialize(fileName); + + // Assert. + Assert.IsTrue(CommandLineOptions.Instance.InIsolation); + Assert.AreEqual("true", this.settingsProvider.QueryRunSettingsNode(InIsolationArgumentExecutor.RunSettingsPath)); + } + + [TestMethod] + public void InitializeShouldNotSetInIsolataionToTrueIfEnvironmentVariablesNotSpecified() + { + var settingsXml = @""; + + /// Arrange. + var fileName = "C:\\temp\\r.runsettings"; + + var executor = new TestableRunSettingsArgumentExecutor( + CommandLineOptions.Instance, + this.settingsProvider, + settingsXml); + + // Setup mocks. + var mockFileHelper = new Mock(); + mockFileHelper.Setup(fh => fh.Exists(It.IsAny())).Returns(true); + executor.FileHelper = mockFileHelper.Object; + + // Act. + executor.Initialize(fileName); + + // Assert. + Assert.IsFalse(CommandLineOptions.Instance.InIsolation); + Assert.IsNull(this.settingsProvider.QueryRunSettingsNode(InIsolationArgumentExecutor.RunSettingsPath)); + } + #endregion #region Testable Implementations