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

AnyCPU tests to choose default architecture based on process #2206

Merged
merged 7 commits into from Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -203,14 +203,44 @@ public async Task<bool> LaunchTestHostAsync(TestProcessStartInfo testHostStartIn
EqtTrace.Verbose("DotnetTestHostmanager: File {0}, doesnot exist", depsFilePath);
}

// If Testhost.exe is available use it
var exeName = this.architecture == Architecture.X86 ? "testhost.x86.exe" : "testhost.exe";
var fullExePath = Path.Combine(sourceDirectory, exeName);
if (this.platformEnvironment.OperatingSystem.Equals(PlatformOperatingSystem.Windows) && this.fileHelper.Exists(fullExePath))
var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json"));
var testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory);

// If testhost.exe is available use it
bool testHostExeFound = false;
if (this.platformEnvironment.OperatingSystem.Equals(PlatformOperatingSystem.Windows))
{
startInfo.FileName = fullExePath;
var exeName = this.architecture == Architecture.X86 ? "testhost.x86.exe" : "testhost.exe";
var fullExePath = Path.Combine(sourceDirectory, exeName);
EqtTrace.Verbose("DotnetTestHostManager: test host exe path : " + fullExePath);

// check for testhost.exe in sourceDirectory. If not found, check in nuget folder.
if (this.fileHelper.Exists(fullExePath))
{
startInfo.FileName = fullExePath;
testHostExeFound = true;
}
else
{
// Check if testhost.dll is found in nuget folder.
if (testHostPath.Contains("microsoft.testplatform.testhost"))
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
{
var folderName = this.architecture == Architecture.X86 ? "x86" : "x64";
var testHostNugetPath = Directory.GetParent(Directory.GetParent(Directory.GetParent(testHostPath).FullName).FullName);
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved

var testHostExeNugetPath = Path.Combine(testHostNugetPath.FullName, "build", "netcoreapp2.1", folderName, exeName);
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved

if (this.fileHelper.Exists(testHostExeNugetPath))
{
EqtTrace.Verbose("DotnetTestHostManager: Testhost.exe/testhost.x86.exe found at path: " + testHostExeNugetPath);
startInfo.FileName = testHostExeNugetPath;
testHostExeFound = true;
}
}
}
}
else

if (!testHostExeFound)
{
var currentProcessPath = this.processHelper.GetCurrentProcessFileName();

Expand All @@ -227,9 +257,6 @@ public async Task<bool> LaunchTestHostAsync(TestProcessStartInfo testHostStartIn
startInfo.FileName = this.dotnetHostHelper.GetDotnetPath();
}

var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json"));
var testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory);

EqtTrace.Verbose("DotnetTestHostmanager: Full path of testhost.dll is {0}", testHostPath);
args = "exec" + args;
args += " " + testHostPath.AddDoubleQuote();
Expand Down
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(Platform)' == 'x86' AND '$(OS)' == 'Windows_NT'">
<ItemGroup Condition=" ('$(Platform)' == 'x86' OR '$(PlatformTarget)' == 'x86') AND '$(OS)' == 'Windows_NT'">
<Content Include="$(MSBuildThisFileDirectory)x86\testhost.x86.exe">
<Link>testhost.x86.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand All @@ -12,7 +12,7 @@
<Visible>False</Visible>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' != 'x86' AND '$(OS)' == 'Windows_NT'" >
<ItemGroup Condition=" ('$(Platform)' == 'x64' OR '$(PlatformTarget)' == 'x64') AND '$(OS)' == 'Windows_NT'" >
Copy link
Contributor

Choose a reason for hiding this comment

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

OS [](start = 89, length = 2)

what happens when we give mulitple PlatformTargets

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With multiple PlatformTargets, dotnet build generates AnyCPU dll (then picks testhost from nuget path depending upon default architecture)

<Content Include="$(MSBuildThisFileDirectory)x64\testhost.exe">
<Link>testhost.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
24 changes: 19 additions & 5 deletions src/vstest.console/TestPlatformHelpers/TestRequestManager.cs
Expand Up @@ -29,6 +29,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Utilities;

/// <summary>
Expand All @@ -47,6 +48,7 @@ internal class TestRequestManager : ITestRequestManager
private readonly object syncObject = new object();
private readonly Task<IMetricsPublisher> metricsPublisher;
private bool isDisposed;
private IProcessHelper processHelper;

/// <summary>
/// Maintains the current active execution request
Expand All @@ -69,18 +71,20 @@ public TestRequestManager()
TestRunResultAggregator.Instance,
TestPlatformEventSource.Instance,
new InferHelper(AssemblyMetadataProvider.Instance),
MetricsPublisherFactory.GetMetricsPublisher(IsTelemetryOptedIn(), CommandLineOptions.Instance.IsDesignMode))
MetricsPublisherFactory.GetMetricsPublisher(IsTelemetryOptedIn(), CommandLineOptions.Instance.IsDesignMode),
new ProcessHelper())
{
}

internal TestRequestManager(CommandLineOptions commandLineOptions, ITestPlatform testPlatform, TestRunResultAggregator testRunResultAggregator, ITestPlatformEventSource testPlatformEventSource, InferHelper inferHelper, Task<IMetricsPublisher> metricsPublisher)
internal TestRequestManager(CommandLineOptions commandLineOptions, ITestPlatform testPlatform, TestRunResultAggregator testRunResultAggregator, ITestPlatformEventSource testPlatformEventSource, InferHelper inferHelper, Task<IMetricsPublisher> metricsPublisher, IProcessHelper processHelper)
{
this.testPlatform = testPlatform;
this.commandLineOptions = commandLineOptions;
this.testRunResultAggregator = testRunResultAggregator;
this.testPlatformEventSource = testPlatformEventSource;
this.inferHelper = inferHelper;
this.metricsPublisher = metricsPublisher;
this.processHelper = processHelper;
}

#endregion
Expand Down Expand Up @@ -381,9 +385,19 @@ private bool UpdateRunSettingsIfRequired(string runsettingsXml, List<string> sou
settingsUpdated |= this.UpdateFramework(document, navigator, sources, sourceFrameworks, registrar, out Framework chosenFramework);

// Choose default architecture based on the framework
// For .NET core, the default platform architecture should be x64.
var defaultArchitecture = chosenFramework.Name.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) >= 0
|| chosenFramework.Name.IndexOf("netcoreapp", StringComparison.OrdinalIgnoreCase) >= 0 ? Architecture.X64 : Architecture.X86;
// For .NET core, the default platform architecture should be based on the process.
// For a 64 bit process,
Architecture defaultArchitecture = Architecture.X64;
if (chosenFramework.Name.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) >= 0
|| chosenFramework.Name.IndexOf("netcoreapp", StringComparison.OrdinalIgnoreCase) >= 0)
{
var currentProcessName = this.processHelper.GetProcessName(this.processHelper.GetCurrentProcessId());
defaultArchitecture = (currentProcessName.StartsWith("vstest.console") || Environment.Is64BitProcess) ? Architecture.X64 : Architecture.X86;
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
defaultArchitecture = Architecture.X86;
}

settingsUpdated |= this.UpdatePlatform(document, navigator, sources, sourcePlatforms, defaultArchitecture, out Architecture chosenPlatform);
this.CheckSourcesForCompatibility(chosenFramework, chosenPlatform, sourcePlatforms, sourceFrameworks, registrar);
Expand Down
Expand Up @@ -244,6 +244,7 @@ public void GetTestHostProcessStartInfoShouldUseTestHostX86ExePresentOnWindows()
{
var testhostExePath = "testhost.x86.exe";
this.mockFileHelper.Setup(ph => ph.Exists(testhostExePath)).Returns(true);
this.mockFileHelper.Setup(ph => ph.Exists("testhost.dll")).Returns(true);
this.mockEnvironment.Setup(ev => ev.OperatingSystem).Returns(PlatformOperatingSystem.Windows);

var startInfo = this.GetDefaultStartInfo();
Expand All @@ -264,10 +265,11 @@ public void GetTestHostProcessStartInfoShouldUseDotnetExeOnUnix()
}

[TestMethod]
public void GetTestHostProcessStartInfoShouldUseTestHostExeIsPresentOnWindows()
public void GetTestHostProcessStartInfoShouldUseTestHostExeIfPresentOnWindows()
{
var testhostExePath = "testhost.exe";
this.mockFileHelper.Setup(ph => ph.Exists(testhostExePath)).Returns(true);
this.mockFileHelper.Setup(ph => ph.Exists("testhost.dll")).Returns(true);
this.mockEnvironment.Setup(ev => ev.OperatingSystem).Returns(PlatformOperatingSystem.Windows);

this.dotnetHostManager.Initialize(this.mockMessageLogger.Object, "<RunSettings><RunConfiguration><TargetPlatform>x64</TargetPlatform></RunConfiguration></RunSettings>");
Expand All @@ -276,6 +278,144 @@ public void GetTestHostProcessStartInfoShouldUseTestHostExeIsPresentOnWindows()
StringAssert.Contains(startInfo.FileName, testhostExePath);
}

[TestMethod]
public void GetTestHostProcessStartInfoShouldUseTestHostExeFromNugetIfNotFoundInSourceLocation()
{
var testhostExePath = "testhost.exe";
this.dotnetHostManager.Initialize(this.mockMessageLogger.Object, "<RunSettings><RunConfiguration><TargetPlatform>x64</TargetPlatform></RunConfiguration></RunSettings>");
this.mockFileHelper.Setup(ph => ph.Exists(testhostExePath)).Returns(false);
this.mockFileHelper.Setup(ph => ph.Exists("C:\\packages\\microsoft.testplatform.testhost\\15.0.0-Dev\\build\\netcoreapp2.1\\x64\\testhost.exe")).Returns(true);
this.mockEnvironment.Setup(ev => ev.OperatingSystem).Returns(PlatformOperatingSystem.Windows);
var sourcePath = Path.Combine($"{Path.DirectorySeparatorChar}tmp", "test.dll");

string runtimeConfigFileContent =
@"{
""runtimeOptions"": {
""additionalProbingPaths"": [
""C:\\packages""
]
}
}";

string depsFileContent =
@"{
""runtimeTarget"": {
""name"": "".NETCoreApp,Version=v1.0"",
""signature"": ""8f25843f8e35a3e80ef4ae98b95117ea5c468b3f""
},
""compilationOptions"": {},
""targets"": {
"".NETCoreApp,Version=v1.0"": {
""microsoft.testplatform.testhost/15.0.0-Dev"": {
""dependencies"": {
""Microsoft.TestPlatform.ObjectModel"": ""15.0.0-Dev"",
""Newtonsoft.Json"": ""9.0.1""
},
""runtime"": {
""lib/netstandard1.5/Microsoft.TestPlatform.CommunicationUtilities.dll"": { },
""lib/netstandard1.5/Microsoft.TestPlatform.CrossPlatEngine.dll"": { },
""lib/netstandard1.5/Microsoft.VisualStudio.TestPlatform.Common.dll"": { },
""lib/netstandard1.5/testhost.dll"": { }
}
}
}
},
""libraries"": {
""microsoft.testplatform.testhost/15.0.0-Dev"": {
""type"": ""package"",
""serviceable"": true,
""sha512"": ""sha512-enO8sZmjbhXOfiZ6hV2ncaknaHnQbrGVsHUJzzu2Dmoh4fHFro4BF1Y4+sb4LOQhu4b3DFYPRj1ncd1RQK6HmQ=="",
""path"": ""microsoft.testplatform.testhost/15.0.0-Dev"",
""hashPath"": ""microsoft.testplatform.testhost.15.0.0-Dev""
}
}
}";

MemoryStream runtimeConfigStream = new MemoryStream(Encoding.UTF8.GetBytes(runtimeConfigFileContent));
this.mockFileHelper.Setup(ph => ph.GetStream("\\tmp\\test.runtimeconfig.dev.json", FileMode.Open, FileAccess.Read)).Returns(runtimeConfigStream);
this.mockFileHelper.Setup(ph => ph.Exists("\\tmp\\test.runtimeconfig.dev.json")).Returns(true);

MemoryStream depsFileStream = new MemoryStream(Encoding.UTF8.GetBytes(depsFileContent));
this.mockFileHelper.Setup(ph => ph.GetStream("\\tmp\\test.deps.json", FileMode.Open, FileAccess.Read)).Returns(depsFileStream);
this.mockFileHelper.Setup(ph => ph.Exists("\\tmp\\test.deps.json")).Returns(true);

string testHostFullPath = @"C:\packages\microsoft.testplatform.testhost/15.0.0-Dev\lib/netstandard1.5/testhost.dll";
this.mockFileHelper.Setup(ph => ph.Exists(testHostFullPath)).Returns(true);

var startInfo = this.dotnetHostManager.GetTestHostProcessStartInfo(new[] { sourcePath }, null, this.defaultConnectionInfo);

StringAssert.Contains(startInfo.FileName, "C:\\packages\\microsoft.testplatform.testhost\\15.0.0-Dev\\build\\netcoreapp2.1\\x64\\testhost.exe");
}

[TestMethod]
public void GetTestHostProcessStartInfoShouldUseTestHostX86ExeFromNugetIfNotFoundInSourceLocation()
{
var testhostExePath = "testhost.x86.exe";
Copy link
Contributor

Choose a reason for hiding this comment

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

See if you can reduce this test by mocking only the relevant call, I am not sure if your change is related to this.

this.dotnetHostManager.Initialize(this.mockMessageLogger.Object, "<RunSettings><RunConfiguration><TargetPlatform>x86</TargetPlatform></RunConfiguration></RunSettings>");
this.mockFileHelper.Setup(ph => ph.Exists(testhostExePath)).Returns(false);
this.mockFileHelper.Setup(ph => ph.Exists("C:\\packages\\microsoft.testplatform.testhost\\15.0.0-Dev\\build\\netcoreapp2.1\\x86\\testhost.x86.exe")).Returns(true);
this.mockEnvironment.Setup(ev => ev.OperatingSystem).Returns(PlatformOperatingSystem.Windows);
var sourcePath = Path.Combine($"{Path.DirectorySeparatorChar}tmp", "test.dll");

string runtimeConfigFileContent =
@"{
""runtimeOptions"": {
""additionalProbingPaths"": [
""C:\\packages""
]
}
}";

string depsFileContent =
@"{
""runtimeTarget"": {
""name"": "".NETCoreApp,Version=v1.0"",
""signature"": ""8f25843f8e35a3e80ef4ae98b95117ea5c468b3f""
},
""compilationOptions"": {},
""targets"": {
"".NETCoreApp,Version=v1.0"": {
""microsoft.testplatform.testhost/15.0.0-Dev"": {
""dependencies"": {
""Microsoft.TestPlatform.ObjectModel"": ""15.0.0-Dev"",
""Newtonsoft.Json"": ""9.0.1""
},
""runtime"": {
""lib/netstandard1.5/Microsoft.TestPlatform.CommunicationUtilities.dll"": { },
""lib/netstandard1.5/Microsoft.TestPlatform.CrossPlatEngine.dll"": { },
""lib/netstandard1.5/Microsoft.VisualStudio.TestPlatform.Common.dll"": { },
""lib/netstandard1.5/testhost.dll"": { }
}
}
}
},
""libraries"": {
""microsoft.testplatform.testhost/15.0.0-Dev"": {
""type"": ""package"",
""serviceable"": true,
""sha512"": ""sha512-enO8sZmjbhXOfiZ6hV2ncaknaHnQbrGVsHUJzzu2Dmoh4fHFro4BF1Y4+sb4LOQhu4b3DFYPRj1ncd1RQK6HmQ=="",
""path"": ""microsoft.testplatform.testhost/15.0.0-Dev"",
""hashPath"": ""microsoft.testplatform.testhost.15.0.0-Dev""
}
}
}";

MemoryStream runtimeConfigStream = new MemoryStream(Encoding.UTF8.GetBytes(runtimeConfigFileContent));
this.mockFileHelper.Setup(ph => ph.GetStream("\\tmp\\test.runtimeconfig.dev.json", FileMode.Open, FileAccess.Read)).Returns(runtimeConfigStream);
this.mockFileHelper.Setup(ph => ph.Exists("\\tmp\\test.runtimeconfig.dev.json")).Returns(true);

MemoryStream depsFileStream = new MemoryStream(Encoding.UTF8.GetBytes(depsFileContent));
this.mockFileHelper.Setup(ph => ph.GetStream("\\tmp\\test.deps.json", FileMode.Open, FileAccess.Read)).Returns(depsFileStream);
this.mockFileHelper.Setup(ph => ph.Exists("\\tmp\\test.deps.json")).Returns(true);

string testHostFullPath = @"C:\packages\microsoft.testplatform.testhost/15.0.0-Dev\lib/netstandard1.5/testhost.dll";
this.mockFileHelper.Setup(ph => ph.Exists(testHostFullPath)).Returns(true);

var startInfo = this.dotnetHostManager.GetTestHostProcessStartInfo(new[] { sourcePath }, null, this.defaultConnectionInfo);

StringAssert.Contains(startInfo.FileName, "C:\\packages\\microsoft.testplatform.testhost\\15.0.0-Dev\\build\\netcoreapp2.1\\x86\\testhost.x86.exe");
}

[TestMethod]
public void LaunchTestHostShouldLaunchProcessWithNullEnvironmentVariablesOrArgs()
{
Expand Down