Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specifying environment variables in RunSettings file #2128

Merged
merged 5 commits into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -101,17 +102,18 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH
{
EqtTrace.Verbose("ProxyExecutionManager: Test host is always Lazy initialize.");
}
var testPackages = new List<string>(testRunCriteria.HasSpecificSources ? testRunCriteria.Sources :

var testSources = new List<string>(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(
Expand All @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Base class for any operations that the client needs to drive through the engine.
/// </summary>
Expand Down Expand Up @@ -96,7 +96,7 @@ protected ProxyOperationManager(IRequestData requestData, ITestRequestSender req
/// <returns>
/// Returns true if Communation is established b/w runner and host
/// </returns>
public virtual bool SetupChannel(IEnumerable<string> sources)
public virtual bool SetupChannel(IEnumerable<string> sources, string runSettings)
{
this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();
var connTimeout = EnvironmentHelper.GetConnectionTimeout();
Expand All @@ -120,8 +120,11 @@ public virtual bool SetupChannel(IEnumerable<string> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public void Initialize()
this.dataCollectionPort = this.dataCollectionRequestSender.InitializeCommunication();

// Warn the user that execution will wait for debugger attach.
this.dataCollectionProcessId = this.dataCollectionLauncher.LaunchDataCollector(null, this.GetCommandLineArguments(this.dataCollectionPort));
this.dataCollectionProcessId = this.dataCollectionLauncher.LaunchDataCollector(InferRunSettingsHelper.GetEnvironmentVariables(SettingsXml), this.GetCommandLineArguments(this.dataCollectionPort));
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
EqtTrace.Info("ProxyDataCollectionManager.Initialize: Launched datacollector processId: {0} port: {1}", this.dataCollectionProcessId, this.dataCollectionPort);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acollector processId: {0} port: {1}", this.dataCollectionProcessId, this.dataColl [](start = 78, length = 81)

Log env vars used to launch process


var connectionTimeout = this.GetConnectionTimeout(dataCollectionProcessId);
Expand Down
46 changes: 46 additions & 0 deletions src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -377,6 +379,50 @@ private static List<string> GetNodeAttributes(XPathNavigator node)
return null;
}

/// <summary>
/// Returns a dictionary of environment variables given in run settings
/// </summary>
/// <param name="runsettingsXml">The run settings xml string</param>
/// <returns>Environment Variables Dictionary</returns>
public static Dictionary<string, string> GetEnvironmentVariables(string runSettings)
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
{
Dictionary<string, string> 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<string, string>();
var childNodes = node.SelectChildren(XPathNodeType.Element);

while (childNodes.MoveNext())
{
if (!environmentVariables.ContainsKey(childNodes.Current.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContainsKey [](start = 50, length = 11)

You can use TryAdd, instead of checking and then adding.

{
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;
}

/// <summary>
/// Updates the <c>RunConfiguration.TargetPlatform</c> value for a run settings. if the value is already set, behavior depends on overwrite.
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/vstest.console/Processors/RunSettingsArgumentProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -137,6 +138,12 @@ public void Initialize(string argument)
this.runSettingsManager.AddDefaultRunSettings();

this.commandLineOptions.SettingsFile = argument;

if (this.runSettingsManager.QueryRunSettingsNode("RunConfiguration.EnvironmentVariables") != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"RunConfiguration.EnvironmentVariables" [](start = 65, length = 39)

Constants ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not available

{
this.commandLineOptions.InIsolation = true;
this.runSettingsManager.UpdateRunSettingsNode(InIsolationArgumentExecutor.RunSettingsPath, "true");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, why is this required if the CLI option is already set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}
catch (XmlException exception)
{
Expand Down
31 changes: 31 additions & 0 deletions test/Microsoft.TestPlatform.AcceptanceTests/RunsettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = @"<RunSettings>
<RunConfiguration>
<EnvironmentVariables>
<RANDOM_PATH>C:\temp</RANDOM_PATH>
</EnvironmentVariables>
</RunConfiguration>
</RunSettings>";

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<string, string> runConfigurationDictionary)
{
var runsettingsPath = Path.Combine(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,19 +334,23 @@ public void StartTestRunShouldInitializeExtensionsWithExistingDataCOllectorExten
[TestMethod]
public void SetupChannelShouldThrowExceptionIfClientConnectionTimeout()
{
string runsettings = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <DataCollectionRunSettings>\r\n <DataCollectors >{0}</DataCollectors>\r\n </DataCollectionRunSettings>\r\n</RunSettings>";

this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(false);
this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny<TestProcessStartInfo>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(false));

Assert.ThrowsException<TestPlatformException>(() => this.testExecutionManager.SetupChannel(new List<string> { "source.dll" }));
Assert.ThrowsException<TestPlatformException>(() => this.testExecutionManager.SetupChannel(new List<string> { "source.dll" }, runsettings));
}

[TestMethod]
public void SetupChannelShouldThrowExceptionIfTestHostExitedBeforeConnectionIsEstablished()
{
string runsettings = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <DataCollectionRunSettings>\r\n <DataCollectors >{0}</DataCollectors>\r\n </DataCollectionRunSettings>\r\n</RunSettings>";

this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(false);
this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny<TestProcessStartInfo>(), It.IsAny<CancellationToken>())).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<TestPlatformException>(() => this.testExecutionManager.SetupChannel(new List<string> { "source.dll" })).Message);
Assert.AreEqual(string.Format(CrossPlatEngineResources.Resources.TestHostExitedWithError, "I crashed!"), Assert.ThrowsException<TestPlatformException>(() => this.testExecutionManager.SetupChannel(new List<string> { "source.dll" }, runsettings)).Message);
}

[TestMethod]
Expand Down Expand Up @@ -522,9 +526,11 @@ public void StartTestRunShouldInitiateTestRunForTestsThroughTheServer()
[TestMethod]
public void CloseShouldSignalToServerSessionEndIfTestHostWasLaunched()
{
string runsettings = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <DataCollectionRunSettings>\r\n <DataCollectors >{0}</DataCollectors>\r\n </DataCollectionRunSettings>\r\n</RunSettings>";

this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(true);

this.testExecutionManager.SetupChannel(new List<string> { "source.dll" });
this.testExecutionManager.SetupChannel(new List<string> { "source.dll" }, runsettings);

this.testExecutionManager.Close();

Expand All @@ -542,9 +548,11 @@ public void CloseShouldNotSendSignalToServerSessionEndIfTestHostWasNotLaunched()
[TestMethod]
public void CloseShouldSignalServerSessionEndEachTime()
{
string runsettings = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <DataCollectionRunSettings>\r\n <DataCollectors >{0}</DataCollectors>\r\n </DataCollectionRunSettings>\r\n</RunSettings>";

this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(true);

this.testExecutionManager.SetupChannel(new List<string> { "source.dll" });
this.testExecutionManager.SetupChannel(new List<string> { "source.dll" }, runsettings);

this.testExecutionManager.Close();
this.testExecutionManager.Close();
Expand Down
Loading