Skip to content

AnyCPU tests to choose default architecture based on process #2206

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

Merged
merged 7 commits into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -203,14 +203,45 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo(
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);

// check for testhost.exe in sourceDirectory. If not found, check in nuget folder.
if (this.fileHelper.Exists(fullExePath))
{
EqtTrace.Verbose("DotnetTestHostManager: Testhost.exe/testhost.x86.exe found at path: " + fullExePath);
startInfo.FileName = fullExePath;
testHostExeFound = true;
}
else
{
// Check if testhost.dll is found in nuget folder.
if (testHostPath.IndexOf("microsoft.testplatform.testhost", StringComparison.OrdinalIgnoreCase) >= 0)
{
// testhost.dll is present in path {testHostNugetRoot}\lib\netcoreapp2.1\testhost.dll
// testhost.(x86).exe is present in location {testHostNugetRoot}\build\netcoreapp2.1\{x86/x64}\{testhost.x86.exe/testhost.exe}
var folderName = this.architecture == Architecture.X86 ? "x86" : "x64";
var testHostNugetRoot = new DirectoryInfo(testHostPath).Parent.Parent.Parent;
var testHostExeNugetPath = Path.Combine(testHostNugetRoot.FullName, "build", "netcoreapp2.1", folderName, exeName);

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 +258,6 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo(
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
Original file line number Diff line number Diff line change
@@ -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
20 changes: 15 additions & 5 deletions src/vstest.console/TestPlatformHelpers/TestRequestManager.cs
Original file line number Diff line number Diff line change
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,15 @@ 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.X86;
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("dotnet", StringComparison.OrdinalIgnoreCase) && !Environment.Is64BitProcess) ? Architecture.X86: Architecture.X64;
}

settingsUpdated |= this.UpdatePlatform(document, navigator, sources, sourcePlatforms, defaultArchitecture, out Architecture chosenPlatform);
this.CheckSourcesForCompatibility(chosenFramework, chosenPlatform, sourcePlatforms, sourceFrameworks, registrar);
Expand Down
Original file line number Diff line number Diff line change
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
Loading