Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.MSTestV2.CLIAutomation;
using Microsoft.Testing.Platform.Acceptance.IntegrationTests;
using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers;
using Microsoft.Testing.TestInfrastructure;

namespace MSTest.Acceptance.IntegrationTests;

Expand All @@ -12,6 +14,9 @@ public sealed class AppDomainTests : AcceptanceTestBase<NopAssetFixture>
{
private const string AssetName = "AppDomainTests";

private const string RunSettingsWithDisableAppDomainTrue = "<RunSettings><RunConfiguration><DisableAppDomain>true</DisableAppDomain></RunConfiguration></RunSettings>";
private const string RunSettingsWithDisableAppDomainFalse = "<RunSettings><RunConfiguration><DisableAppDomain>false</DisableAppDomain></RunConfiguration></RunSettings>";

private const string SingleTestSourceCode = """
#file AppDomainTests.csproj
<Project Sdk="MSTest.Sdk/$MSTestVersion$" >
Expand Down Expand Up @@ -123,5 +128,113 @@ public async Task DiscoverTests_With_VSTest(bool? disableAppDomain)
Assert.AreEqual(0, compilationResult.ExitCode);
}

[TestMethod]
[DataRow(true)]
[DataRow(false)]
[DataRow(null)]
public async Task RunTests_With_VSTestConsole_Directly(bool? disableAppDomain)
{
using TestAsset testAsset = await TestAsset.GenerateAssetAsync(
AssetName,
SingleTestSourceCode
.PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)
.PatchCodeWithReplace("$TargetFramework$", TargetFrameworks.NetFramework[0]));

// Build the test project
DotnetMuxerResult buildResult = await DotnetCli.RunAsync(
$"build {testAsset.TargetAssetPath} -c Debug",
AcceptanceFixture.NuGetGlobalPackagesFolder.Path,
workingDirectory: testAsset.TargetAssetPath,
cancellationToken: TestContext.CancellationToken);
Assert.AreEqual(0, buildResult.ExitCode, $"Build failed: {buildResult.StandardOutput}");

// Get the DLL path
string dllPath = GetTestDllPath(testAsset.TargetAssetPath, TargetFrameworks.NetFramework[0]);
Assert.IsTrue(File.Exists(dllPath), $"Test DLL not found at {dllPath}");

// Prepare run settings
string runSettings = GetRunSettingsXml(disableAppDomain);

// Run tests using vstest.console.exe directly
string vstestConsolePath = VSTestConsoleLocator.GetConsoleRunnerPath();
string arguments = $"\"{dllPath}\"";
if (!string.IsNullOrEmpty(runSettings))
{
string runSettingsPath = Path.Combine(testAsset.TargetAssetPath, "test.runsettings");
await File.WriteAllTextAsync(runSettingsPath, runSettings);
arguments += $" /Settings:\"{runSettingsPath}\"";
}

using var commandLine = new CommandLine();
int exitCode = await commandLine.RunAsyncAndReturnExitCodeAsync(
$"\"{vstestConsolePath}\" {arguments}",
workingDirectory: testAsset.TargetAssetPath,
cancellationToken: TestContext.CancellationToken);

Assert.AreEqual(0, exitCode, $"Tests failed.\nStdOut: {commandLine.StandardOutput}\nStdErr: {commandLine.ErrorOutput}");
Assert.IsTrue(commandLine.StandardOutput.Contains("Passed 2") || commandLine.StandardOutput.Contains("Passed: 2"),
$"Expected 2 passed tests but got: {commandLine.StandardOutput}");
}

[TestMethod]
[DataRow(true)]
[DataRow(false)]
[DataRow(null)]
public async Task DiscoverTests_With_VSTestConsole_Directly(bool? disableAppDomain)
{
using TestAsset testAsset = await TestAsset.GenerateAssetAsync(
AssetName,
SingleTestSourceCode
.PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)
.PatchCodeWithReplace("$TargetFramework$", TargetFrameworks.NetFramework[0]));

// Build the test project
DotnetMuxerResult buildResult = await DotnetCli.RunAsync(
$"build {testAsset.TargetAssetPath} -c Debug",
AcceptanceFixture.NuGetGlobalPackagesFolder.Path,
workingDirectory: testAsset.TargetAssetPath,
cancellationToken: TestContext.CancellationToken);
Assert.AreEqual(0, buildResult.ExitCode, $"Build failed: {buildResult.StandardOutput}");

// Get the DLL path
string dllPath = GetTestDllPath(testAsset.TargetAssetPath, TargetFrameworks.NetFramework[0]);
Assert.IsTrue(File.Exists(dllPath), $"Test DLL not found at {dllPath}");

// Prepare run settings
string runSettings = GetRunSettingsXml(disableAppDomain);

// Run discovery using vstest.console.exe directly
string vstestConsolePath = VSTestConsoleLocator.GetConsoleRunnerPath();
string arguments = $"\"{dllPath}\" /ListTests";
if (!string.IsNullOrEmpty(runSettings))
{
string runSettingsPath = Path.Combine(testAsset.TargetAssetPath, "test.runsettings");
await File.WriteAllTextAsync(runSettingsPath, runSettings);
arguments += $" /Settings:\"{runSettingsPath}\"";
}

using var commandLine = new CommandLine();
int exitCode = await commandLine.RunAsyncAndReturnExitCodeAsync(
$"\"{vstestConsolePath}\" {arguments}",
workingDirectory: testAsset.TargetAssetPath,
cancellationToken: TestContext.CancellationToken);

Assert.AreEqual(0, exitCode, $"Discovery failed.\nStdOut: {commandLine.StandardOutput}\nStdErr: {commandLine.ErrorOutput}");
Assert.IsTrue(commandLine.StandardOutput.Contains("AppDomainTests.UnitTest1.TestMethod1"),
$"Expected to find TestMethod1 but got: {commandLine.StandardOutput}");
Assert.IsTrue(commandLine.StandardOutput.Contains("AppDomainTests.UnitTest1.TestMethod2"),
$"Expected to find TestMethod2 but got: {commandLine.StandardOutput}");
}

private static string GetTestDllPath(string assetPath, string targetFramework) =>
Path.Combine(assetPath, "bin", "Debug", targetFramework, $"{AssetName}.dll");

private static string GetRunSettingsXml(bool? disableAppDomain) => disableAppDomain switch
{
true => RunSettingsWithDisableAppDomainTrue,
false => RunSettingsWithDisableAppDomainFalse,
null => string.Empty,
};

public TestContext TestContext { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
<Compile Include="$(RepoRoot)test\IntegrationTests\Microsoft.Testing.Platform.Acceptance.IntegrationTests\Helpers\AcceptanceFixture.cs" Link="Helpers\AcceptanceFixture.cs" />
<Compile Include="$(RepoRoot)test\IntegrationTests\Microsoft.Testing.Platform.Acceptance.IntegrationTests\Helpers\AcceptanceTestBase.cs" Link="Helpers\AcceptanceTestBase.cs" />
<Compile Include="$(RepoRoot)test\IntegrationTests\Microsoft.Testing.Platform.Acceptance.IntegrationTests\ServerMode\**\*.cs" Link="ServerMode\%(RecursiveDir)%(FileName)%(Extension)" />
<Compile Include="$(RepoRoot)test\Utilities\Automation.CLI\VSTestConsoleLocator.cs" Link="Helpers\VSTestConsoleLocator.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MSBuild.StructuredLogger" />
<PackageReference Include="StreamJsonRpc" />
<PackageReference Include="Microsoft.TestPlatform" />
</ItemGroup>

<!-- Packages needed for the test assets but that we don't want to reference -->
Expand Down
46 changes: 1 addition & 45 deletions test/Utilities/Automation.CLI/CLITestBase.e2e.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract partial class CLITestBase
protected CLITestBase()
{
s_vsTestConsoleWrapper = new(
GetConsoleRunnerPath(),
VSTestConsoleLocator.GetConsoleRunnerPath(),
new()
{
EnvironmentVariables = new()
Expand Down Expand Up @@ -65,51 +65,7 @@ public void InvokeVsTestForExecution(string[] sources, string runSettings = "",
}
}

public static string GetNugetPackageFolder()
{
string nugetPackagesFolderPath = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
if (!string.IsNullOrEmpty(nugetPackagesFolderPath))
{
Assert.IsTrue(Directory.Exists(nugetPackagesFolderPath), $"Found environment variable 'NUGET_PACKAGES' and NuGet package folder '{nugetPackagesFolderPath}' should exist");

return nugetPackagesFolderPath;
}

string userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
nugetPackagesFolderPath = Path.Combine(userProfile, ".nuget", "packages");
Assert.IsTrue(Directory.Exists(nugetPackagesFolderPath), $"NuGet package folder '{nugetPackagesFolderPath}' should exist");

return nugetPackagesFolderPath;
}

/// <summary>
/// Gets the path to <c>vstest.console.exe</c>.
/// </summary>
/// <returns>Full path to <c>vstest.console.exe</c>.</returns>
public static string GetConsoleRunnerPath()
{
string testPlatformNuGetPackageFolder = Path.Combine(
GetNugetPackageFolder(),
TestPlatformCLIPackageName,
GetTestPlatformVersion());
if (!Directory.Exists(testPlatformNuGetPackageFolder))
{
throw new DirectoryNotFoundException($"Test platform NuGet package folder '{testPlatformNuGetPackageFolder}' does not exist");
}

string vstestConsolePath = Path.Combine(
testPlatformNuGetPackageFolder,
"tools",
"net462",
"Common7",
"IDE",
"Extensions",
"TestPlatform",
"vstest.console.exe");
return !File.Exists(vstestConsolePath)
? throw new InvalidOperationException($"Could not find vstest.console.exe in {vstestConsolePath}")
: vstestConsolePath;
}

/// <summary>
/// Validate if the discovered tests list contains provided tests.
Expand Down
94 changes: 94 additions & 0 deletions test/Utilities/Automation.CLI/VSTestConsoleLocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;

namespace Microsoft.MSTestV2.CLIAutomation;

/// <summary>
/// Helper class to locate vstest.console.exe.
/// </summary>
public static class VSTestConsoleLocator
{
private const string TestPlatformCLIPackageName = "Microsoft.TestPlatform";

/// <summary>
/// Gets the path to <c>vstest.console.exe</c>.
/// </summary>
/// <returns>Full path to <c>vstest.console.exe</c>.</returns>
public static string GetConsoleRunnerPath()
{
string testPlatformNuGetPackageFolder = Path.Combine(
GetNugetPackageFolder(),
TestPlatformCLIPackageName,
GetTestPlatformVersion());
if (!Directory.Exists(testPlatformNuGetPackageFolder))
{
throw new DirectoryNotFoundException($"Test platform NuGet package folder '{testPlatformNuGetPackageFolder}' does not exist");
}

string vstestConsolePath = Path.Combine(
testPlatformNuGetPackageFolder,
"tools",
"net462",
"Common7",
"IDE",
"Extensions",
"TestPlatform",
"vstest.console.exe");
return !File.Exists(vstestConsolePath)
? throw new InvalidOperationException($"Could not find vstest.console.exe in {vstestConsolePath}")
: vstestConsolePath;
}

private static string GetNugetPackageFolder()
{
string? nugetPackagesFolderPath = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
if (!string.IsNullOrEmpty(nugetPackagesFolderPath))
{
Assert.IsTrue(Directory.Exists(nugetPackagesFolderPath), $"Found environment variable 'NUGET_PACKAGES' and NuGet package folder '{nugetPackagesFolderPath}' should exist");

return nugetPackagesFolderPath;
}

string? userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
if (string.IsNullOrEmpty(userProfile))
{
throw new InvalidOperationException("USERPROFILE environment variable is not set");
}

nugetPackagesFolderPath = Path.Combine(userProfile, ".nuget", "packages");
Assert.IsTrue(Directory.Exists(nugetPackagesFolderPath), $"NuGet package folder '{nugetPackagesFolderPath}' should exist");

return nugetPackagesFolderPath;
}

private static string GetTestPlatformVersion()
{
string cpmFilePath = Path.Combine(GetArtifactsBinFolderPath(), "..", "..", "Directory.Packages.props");
using FileStream fileStream = File.OpenRead(cpmFilePath);
#pragma warning disable CA3075 // Insecure DTD processing in XML
using var xmlTextReader = new XmlTextReader(fileStream) { Namespaces = false };
#pragma warning restore CA3075 // Insecure DTD processing in XML
var cpmXml = new XmlDocument();
cpmXml.Load(xmlTextReader);

XmlNode? testSdkVersion = cpmXml.DocumentElement?.SelectSingleNode("PropertyGroup/MicrosoftNETTestSdkVersion");
if (testSdkVersion is null)
{
throw new InvalidOperationException($"Could not find MicrosoftNETTestSdkVersion in {cpmFilePath}");
}

return testSdkVersion.InnerText;
}

private static string GetArtifactsBinFolderPath()
{
string assemblyLocation = Assembly.GetExecutingAssembly().Location;

string artifactsBinFolder = Path.GetFullPath(Path.Combine(assemblyLocation, @"..\..\..\.."));
Assert.IsTrue(Directory.Exists(artifactsBinFolder));

return artifactsBinFolder;
}
}
Loading