From 960849bc1190f98a910cbf45ddca07588ebb9322 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 4 Apr 2024 15:08:13 -0700 Subject: [PATCH] Make host tests use single copy of shared framework (#100588) - Only create one .NET install layout to be shared by all host tests - Add `pretest.proj` for `host.pretest` subset that builds all test project assets and creates the single .NET install layout - Fix `NativeHostApis` tests that were editing the .NET install layout directly (instead of creating a copy to edit) - Remove some unnecessary copying/creating of SDKs and frameworks by sharing the fixture across tests - Update host testing doc with simpler setup instructions and more details around investigating test failures --- docs/workflow/testing/host/testing.md | 21 +- eng/Subsets.props | 2 +- src/installer/tests/Directory.Build.targets | 20 -- .../HostActivation.Tests/NativeHostApis.cs | 224 +++++++++--------- .../Assertions/CommandResultAssertions.cs | 21 +- src/installer/tests/TestUtils/TestContext.cs | 3 +- src/installer/tests/pretest.proj | 22 ++ 7 files changed, 167 insertions(+), 146 deletions(-) create mode 100644 src/installer/tests/pretest.proj diff --git a/docs/workflow/testing/host/testing.md b/docs/workflow/testing/host/testing.md index 46f7761be1fa1..a217d1dd0ab98 100644 --- a/docs/workflow/testing/host/testing.md +++ b/docs/workflow/testing/host/testing.md @@ -37,16 +37,16 @@ dotnet build src\installer\tests\HostActivation.Tests The host tests depend on: 1. Pre-built [test project](/src/installer/tests/Assets/Projects) output which will be copied and run by the tests. The `host.pretest` subset builds these projects. - 2. Product binaries in a directory layout matching that of a .NET install - 3. TestContextVariables.txt file with property and value pairs which will be read by the tests + 2. Product binaries in a directory layout matching that of a .NET install. The `host.pretest` subset creates this layout. + 3. TestContextVariables.txt files with property and value pairs which will be read by the tests. The `host.tests` subset creates these files as part of building the tests. When [running all tests](#running-all-tests), the build is configured such that these are created/performed before the start of the test run. In order to create (or update) these dependencies without running all tests: - 1. Build the `host.pretest` subset. By default, this is included in the `host` subset. This corresponds to (1) above. - 2. Run the `SetUpSharedFrameworkPublish` and `SetupTestContextVariables` targets for the desired test project. This corresponds to (2) and (3) above. For example: + 1. Build the `host.pretest` subset. By default, this is included in the `host` subset. This corresponds to (1) and (2) above. + 2. Build the desired test project. This corresponds to (3) above. Building the test itself will run the `SetupTestContextVariables` target, but it can also be run independently - for example: ``` - dotnet build src\installer\tests\HostActivation.Tests -t:SetUpSharedFrameworkPublish;SetupTestContextVariables -p:RuntimeConfiguration=Release -p:LibrariesConfiguration=Release + dotnet build src\installer\tests\HostActivation.Tests -t:SetupTestContextVariables -p:RuntimeConfiguration=Release -p:LibrariesConfiguration=Release ``` ## Running tests @@ -86,6 +86,15 @@ If you built the runtime or libraries with a different configuration from the ho build.cmd -vs Microsoft.DotNet.CoreSetup -rc Release -lc Release ``` +## Investigating failures + +When [running all tests](#running-all-tests), reports with results will be generated under `\artifacts\TestResults`. When [running individual tests](#running-specific-tests), results will be output to the console by default and can be configured via [`dotnet test` options](https://learn.microsoft.com/dotnet/core/tools/dotnet-test#options). + +In order to test the hosting components, the tests launch a separate process (e.g. `dotnet`, apphost, native host) and validate the expected output (standard output and error) of the launched process. This usually involves copying or creating test artifacts in the form of an application to run or a .NET install to run against. + +On failure, tests will report the file, arguments, and environment for the launched process that failed validation. With [preserved test artifacts](#preserving-test-artifacts), this information can be used to directly debug the specific scenario that the test was running. + ### Preserving test artifacts -In order to test the hosting components, the tests launch a separate process (e.g. `dotnet`, apphost, native host) and validate the expected output (standard output and error) of the launched process. This usually involves copying or creating test artifacts in the form of an application to run or a .NET install to run against. The tests will delete these artifacts after the test finishes. To allow inspection or usage after the test finishes, set the environment variable `PRESERVE_TEST_RUNS=1` to avoid deleting the test artifacts. +The tests will delete any generated test artifacts after the test finishes. To allow inspection or usage after the test finishes, set the environment variable `PRESERVE_TEST_RUNS=1` to avoid deleting the test artifacts. + diff --git a/eng/Subsets.props b/eng/Subsets.props index 63aca146463a5..499e9c3cb645f 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -500,7 +500,7 @@ - + diff --git a/src/installer/tests/Directory.Build.targets b/src/installer/tests/Directory.Build.targets index 5e952873f92e4..9bfb4ffbea286 100644 --- a/src/installer/tests/Directory.Build.targets +++ b/src/installer/tests/Directory.Build.targets @@ -1,25 +1,5 @@ - - - - - - - - Path.Combine(ExeDir, "pf"); - public string SelfRegistered => Path.Combine(ExeDir, "sr"); - public string WorkingDir => Path.Combine(_app.Location, "wd"); - public string ProgramFilesGlobalSdkDir => Path.Combine(ProgramFiles, "dotnet", "sdk"); - public string ProgramFilesGlobalFrameworksDir => Path.Combine(ProgramFiles, "dotnet", "shared"); - public string SelfRegisteredGlobalSdkDir => Path.Combine(SelfRegistered, "sdk"); + private readonly TestArtifact _artifact; + + public string EmptyGlobalJsonDir => Path.Combine(_artifact.Location, "wd"); + + public string ExeDir => Path.Combine(_artifact.Location, "ed"); public string LocalSdkDir => Path.Combine(ExeDir, "sdk"); public string LocalFrameworksDir => Path.Combine(ExeDir, "shared"); + public string[] LocalSdks = new[] { "0.1.2", "5.6.7-preview", "1.2.3" }; + public List<(string fwName, string[] fwVersions)> LocalFrameworks = + new List<(string fwName, string[] fwVersions)>() + { + ("HostFxr.Test.B", new[] { "4.0.0", "5.6.7-A" }), + ("HostFxr.Test.C", new[] { "3.0.0" }) + }; + + public string ProgramFiles => Path.Combine(_artifact.Location, "pf"); + public string ProgramFilesGlobalSdkDir => Path.Combine(ProgramFiles, "dotnet", "sdk"); + public string ProgramFilesGlobalFrameworksDir => Path.Combine(ProgramFiles, "dotnet", "shared"); public string[] ProgramFilesGlobalSdks = new[] { "4.5.6", "1.2.3", "2.3.4-preview" }; public List<(string fwName, string[] fwVersions)> ProgramFilesGlobalFrameworks = new List<(string fwName, string[] fwVersions)>() @@ -49,26 +54,20 @@ private class SdkResolutionFixture ("HostFxr.Test.A", new[] { "1.2.3", "3.0.0" }), ("HostFxr.Test.B", new[] { "5.6.7-A" }) }; + + public string SelfRegistered => Path.Combine(_artifact.Location, "sr"); + public string SelfRegisteredGlobalSdkDir => Path.Combine(SelfRegistered, "sdk"); public string[] SelfRegisteredGlobalSdks = new[] { "3.0.0", "15.1.4-preview", "5.6.7" }; - public string[] LocalSdks = new[] { "0.1.2", "5.6.7-preview", "1.2.3" }; - public List<(string fwName, string[] fwVersions)> LocalFrameworks = - new List<(string fwName, string[] fwVersions)>() - { - ("HostFxr.Test.B", new[] { "4.0.0", "5.6.7-A" }), - ("HostFxr.Test.C", new[] { "3.0.0" }) - }; - public SdkResolutionFixture(SharedTestState state) + public SdkAndFrameworkFixture() { - Dotnet = TestContext.BuiltDotNet; - - _app = state.HostApiInvokerApp.Copy(); + _artifact = TestArtifact.Create(nameof(SdkAndFrameworkFixture)); - Directory.CreateDirectory(WorkingDir); + Directory.CreateDirectory(EmptyGlobalJsonDir); // start with an empty global.json, it will be ignored, but prevent one lying on disk // on a given machine from impacting the test. - GlobalJson.CreateEmpty(WorkingDir); + GlobalJson.CreateEmpty(EmptyGlobalJsonDir); foreach (string sdk in ProgramFilesGlobalSdks) { @@ -114,16 +113,20 @@ static void AddFrameworkDirectory(string frameworkDir, string name, string versi File.WriteAllText(Path.Combine(versionDir, $"{name}.deps.json"), string.Empty); } } + + public void Dispose() + { + _artifact.Dispose(); + } } [Fact] [PlatformSpecific(TestPlatforms.Windows)] // The test setup only works on Windows (and MLL was Windows-only anyway) public void Hostfxr_get_available_sdks_with_multilevel_lookup() { - var f = new SdkResolutionFixture(sharedTestState); - // Starting with .NET 7, multi-level lookup is completely disabled for hostfxr API calls. // This test is still valuable to validate that it is in fact disabled + var f = sharedTestState.SdkAndFrameworkFixture; string expectedList = string.Join(';', new[] { Path.Combine(f.LocalSdkDir, "0.1.2"), @@ -132,26 +135,22 @@ public void Hostfxr_get_available_sdks_with_multilevel_lookup() }); string api = ApiNames.hostfxr_get_available_sdks; - using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath)) - { - f.Dotnet.Exec(f.AppDll, api, f.ExeDir) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) - .EnableTracingAndCaptureOutputs() - .Execute() - .Should().Pass() - .And.ReturnStatusCode(api, Constants.ErrorCode.Success) - .And.HaveStdOutContaining($"{api} sdks:[{expectedList}]"); - } + sharedTestState.TestBehaviorEnabledDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.ReturnStatusCode(api, Constants.ErrorCode.Success) + .And.HaveStdOutContaining($"{api} sdks:[{expectedList}]"); } [Fact] - public void Hostfxr_get_available_sdks_without_multilevel_lookup() + public void Hostfxr_get_available_sdks() { - // Without multi-level lookup: get only sdks sorted by ascending version - - var f = new SdkResolutionFixture(sharedTestState); + // Get SDKs sorted by ascending version + var f = sharedTestState.SdkAndFrameworkFixture; string expectedList = string.Join(';', new[] { Path.Combine(f.LocalSdkDir, "0.1.2"), @@ -160,7 +159,7 @@ public void Hostfxr_get_available_sdks_without_multilevel_lookup() }); string api = ApiNames.hostfxr_get_available_sdks; - f.Dotnet.Exec(f.AppDll, api, f.ExeDir) + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir) .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -173,15 +172,14 @@ public void Hostfxr_resolve_sdk2_without_global_json_or_flags() { // with no global.json and no flags, pick latest SDK - var f = new SdkResolutionFixture(sharedTestState); - + var f = sharedTestState.SdkAndFrameworkFixture; string expectedData = string.Join(';', new[] { ("resolved_sdk_dir", Path.Combine(f.LocalSdkDir, "5.6.7-preview")), }); string api = ApiNames.hostfxr_resolve_sdk2; - f.Dotnet.Exec(f.AppDll, api, f.ExeDir, f.WorkingDir, "0") + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir, f.EmptyGlobalJsonDir, "0") .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -194,15 +192,14 @@ public void Hostfxr_resolve_sdk2_without_global_json_and_disallowing_previews() { // Without global.json and disallowing previews, pick latest non-preview - var f = new SdkResolutionFixture(sharedTestState); - + var f = sharedTestState.SdkAndFrameworkFixture; string expectedData = string.Join(';', new[] { ("resolved_sdk_dir", Path.Combine(f.LocalSdkDir, "1.2.3")) }); string api = ApiNames.hostfxr_resolve_sdk2; - f.Dotnet.Exec(f.AppDll, api, f.ExeDir, f.WorkingDir, "disallow_prerelease") + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir, f.EmptyGlobalJsonDir, "disallow_prerelease") .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -217,24 +214,26 @@ public void Hostfxr_resolve_sdk2_with_global_json_and_disallowing_previews() // since flag has no impact if global.json specifies a preview. // Also check that global.json that impacted resolution is reported. - var f = new SdkResolutionFixture(sharedTestState); - - string requestedVersion = "5.6.6-preview"; - string globalJson = GlobalJson.CreateWithVersion(f.WorkingDir, requestedVersion); - string expectedData = string.Join(';', new[] + var f = sharedTestState.SdkAndFrameworkFixture; + using (TestArtifact workingDir = TestArtifact.Create(nameof(workingDir))) { - ("resolved_sdk_dir", Path.Combine(f.LocalSdkDir, "5.6.7-preview")), - ("global_json_path", globalJson), - ("requested_version", requestedVersion), - }); + string requestedVersion = "5.6.6-preview"; + string globalJson = GlobalJson.CreateWithVersion(workingDir.Location, requestedVersion); + string expectedData = string.Join(';', new[] + { + ("resolved_sdk_dir", Path.Combine(f.LocalSdkDir, "5.6.7-preview")), + ("global_json_path", globalJson), + ("requested_version", requestedVersion), + }); - string api = ApiNames.hostfxr_resolve_sdk2; - f.Dotnet.Exec(f.AppDll, api, f.ExeDir, f.WorkingDir, "disallow_prerelease") - .EnableTracingAndCaptureOutputs() - .Execute() - .Should().Pass() - .And.ReturnStatusCode(api, Constants.ErrorCode.Success) - .And.HaveStdOutContaining($"{api} data:[{expectedData}]"); + string api = ApiNames.hostfxr_resolve_sdk2; + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir, workingDir.Location, "disallow_prerelease") + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.ReturnStatusCode(api, Constants.ErrorCode.Success) + .And.HaveStdOutContaining($"{api} data:[{expectedData}]"); + } } [Fact] @@ -249,7 +248,7 @@ public void Hostfxr_corehost_set_error_writer_test() [Fact] public void Hostfxr_get_dotnet_environment_info_dotnet_root_only() { - var f = new SdkResolutionFixture(sharedTestState); + var f = sharedTestState.SdkAndFrameworkFixture; string expectedSdkVersions = string.Join(";", new[] { "0.1.2", @@ -286,7 +285,7 @@ public void Hostfxr_get_dotnet_environment_info_dotnet_root_only() }); string api = ApiNames.hostfxr_get_dotnet_environment_info; - f.Dotnet.Exec(f.AppDll, api, f.ExeDir) + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, f.ExeDir) .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -302,7 +301,7 @@ public void Hostfxr_get_dotnet_environment_info_dotnet_root_only() [PlatformSpecific(TestPlatforms.Windows)] // The test setup only works on Windows (and MLL was Windows-only anyway) public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_with_dotnet_root() { - var f = new SdkResolutionFixture(sharedTestState); + var f = sharedTestState.SdkAndFrameworkFixture; string expectedSdkVersions = string.Join(';', new[] { "0.1.2", @@ -338,58 +337,49 @@ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_with_dotn Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.C") }); - using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath)) - { - string api = ApiNames.hostfxr_get_dotnet_environment_info; - f.Dotnet.Exec(f.AppDll, new[] { api, f.ExeDir }) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) - .EnableTracingAndCaptureOutputs() - .Execute() - .Should().Pass() - .And.ReturnStatusCode(api, Constants.ErrorCode.Success) - .And.HaveStdOutContaining($"{api} sdk versions:[{expectedSdkVersions}]") - .And.HaveStdOutContaining($"{api} sdk paths:[{expectedSdkPaths}]") - .And.HaveStdOutContaining($"{api} framework names:[{expectedFrameworkNames}]") - .And.HaveStdOutContaining($"{api} framework versions:[{expectedFrameworkVersions}]") - .And.HaveStdOutContaining($"{api} framework paths:[{expectedFrameworkPaths}]"); - } + string api = ApiNames.hostfxr_get_dotnet_environment_info; + sharedTestState.TestBehaviorEnabledDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, new[] { api, f.ExeDir }) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.ReturnStatusCode(api, Constants.ErrorCode.Success) + .And.HaveStdOutContaining($"{api} sdk versions:[{expectedSdkVersions}]") + .And.HaveStdOutContaining($"{api} sdk paths:[{expectedSdkPaths}]") + .And.HaveStdOutContaining($"{api} framework names:[{expectedFrameworkNames}]") + .And.HaveStdOutContaining($"{api} framework versions:[{expectedFrameworkVersions}]") + .And.HaveStdOutContaining($"{api} framework paths:[{expectedFrameworkPaths}]"); } [Fact] [PlatformSpecific(TestPlatforms.Windows)] // The test setup only works on Windows (and MLL was Windows-only anyway) public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only() { - var f = new SdkResolutionFixture(sharedTestState); + var f = sharedTestState.SdkAndFrameworkFixture; // Multi-level lookup is completely disabled on 7+ // The test runs the API with the dotnet root directory set to a location which doesn't have any SDKs or frameworks - using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath)) - { - // We pass f.WorkingDir so that we don't resolve dotnet_dir to the global installation - // in the native side. - string api = ApiNames.hostfxr_get_dotnet_environment_info; - f.Dotnet.Exec(f.AppDll, api, f.WorkingDir) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) - .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) - .EnableTracingAndCaptureOutputs() - .Execute() - .Should().Pass() - .And.ReturnStatusCode(api, Constants.ErrorCode.Success) - .And.HaveStdOutContaining($"{api} sdk versions:[]") - .And.HaveStdOutContaining($"{api} sdk paths:[]") - .And.HaveStdOutContaining($"{api} framework names:[]") - .And.HaveStdOutContaining($"{api} framework versions:[]") - .And.HaveStdOutContaining($"{api} framework paths:[]"); - } + string api = ApiNames.hostfxr_get_dotnet_environment_info; + sharedTestState.TestBehaviorEnabledDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, sharedTestState.HostApiInvokerApp.Location) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.ReturnStatusCode(api, Constants.ErrorCode.Success) + .And.HaveStdOutContaining($"{api} sdk versions:[]") + .And.HaveStdOutContaining($"{api} sdk paths:[]") + .And.HaveStdOutContaining($"{api} framework names:[]") + .And.HaveStdOutContaining($"{api} framework versions:[]") + .And.HaveStdOutContaining($"{api} framework paths:[]"); } [Fact] public void Hostfxr_get_dotnet_environment_info_global_install_path() { string api = ApiNames.hostfxr_get_dotnet_environment_info; - var f = new SdkResolutionFixture(sharedTestState); - f.Dotnet.Exec(f.AppDll, api) + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api) .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -399,9 +389,8 @@ public void Hostfxr_get_dotnet_environment_info_global_install_path() [Fact] public void Hostfxr_get_dotnet_environment_info_result_is_nullptr_fails() { - var f = new SdkResolutionFixture(sharedTestState); string api = ApiNames.hostfxr_get_dotnet_environment_info; - f.Dotnet.Exec(f.AppDll, api, "test_invalid_result_ptr") + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, "test_invalid_result_ptr") .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() @@ -412,13 +401,11 @@ public void Hostfxr_get_dotnet_environment_info_result_is_nullptr_fails() [Fact] public void Hostfxr_get_dotnet_environment_info_reserved_is_not_nullptr_fails() { - var f = new SdkResolutionFixture(sharedTestState); string api = ApiNames.hostfxr_get_dotnet_environment_info; - f.Dotnet.Exec(f.AppDll, api, "test_invalid_reserved_ptr") + TestContext.BuiltDotNet.Exec(sharedTestState.HostApiInvokerApp.AppDll, api, "test_invalid_reserved_ptr") .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() - // 0x80008081 (InvalidArgFailure) .And.ReturnStatusCode(api, Constants.ErrorCode.InvalidArgFailure) .And.HaveStdErrContaining($"{api} received an invalid argument: reserved should be null."); } @@ -460,6 +447,11 @@ public class SharedTestState : IDisposable { public TestApp HostApiInvokerApp { get; } + public DotNetCli TestBehaviorEnabledDotNet { get; } + private readonly TestArtifact copiedDotnet; + + internal SdkAndFrameworkFixture SdkAndFrameworkFixture { get; } + public SharedTestState() { HostApiInvokerApp = TestApp.CreateFromBuiltAssets("HostApiInvokerApp"); @@ -469,11 +461,23 @@ public SharedTestState() // On non-Windows, we can't just P/Invoke to already loaded hostfxr, so copy it next to the app dll. File.Copy(Binaries.HostFxr.FilePath, Path.Combine(HostApiInvokerApp.Location, Binaries.HostFxr.FileName)); } + + // Make a copy of the built .NET, as we will enable test-only behaviour + copiedDotnet = TestArtifact.CreateFromCopy(nameof(NativeHostApis), TestContext.BuiltDotNet.BinPath); + TestBehaviorEnabledDotNet = new DotNetCli(copiedDotnet.Location); + + // Enable test-only behavior for the copied .NET. We don't bother disabling the behaviour later, + // as we just delete the entire copy after the tests run. + _ = TestOnlyProductBehavior.Enable(TestBehaviorEnabledDotNet.GreatestVersionHostFxrFilePath); + + SdkAndFrameworkFixture = new SdkAndFrameworkFixture(); } public void Dispose() { HostApiInvokerApp?.Dispose(); + copiedDotnet.Dispose(); + SdkAndFrameworkFixture.Dispose(); } } } diff --git a/src/installer/tests/TestUtils/Assertions/CommandResultAssertions.cs b/src/installer/tests/TestUtils/Assertions/CommandResultAssertions.cs index a43b140618950..63f369b2a214d 100644 --- a/src/installer/tests/TestUtils/Assertions/CommandResultAssertions.cs +++ b/src/installer/tests/TestUtils/Assertions/CommandResultAssertions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Linq; using System.Text.RegularExpressions; using FluentAssertions; using FluentAssertions.Execution; @@ -147,13 +148,17 @@ public AndConstraint NotFileContains(string path, strin } public string GetDiagnosticsInfo() - { - return $"{Environment.NewLine}" + - $"File Name: {Result.StartInfo.FileName}{Environment.NewLine}" + - $"Arguments: {Result.StartInfo.Arguments}{Environment.NewLine}" + - $"Exit Code: {Result.ExitCode}{Environment.NewLine}" + - $"StdOut:{Environment.NewLine}{Result.StdOut}{Environment.NewLine}" + - $"StdErr:{Environment.NewLine}{Result.StdErr}{Environment.NewLine}"; - } + => $""" + + File Name: {Result.StartInfo.FileName} + Arguments: {Result.StartInfo.Arguments} + Environment: + {string.Join(Environment.NewLine, Result.StartInfo.Environment.Where(i => i.Key.StartsWith(Constants.DotnetRoot.EnvironmentVariable)).Select(i => $" {i.Key} = {i.Value}"))} + Exit Code: 0x{Result.ExitCode:x} + StdOut: + {Result.StdOut} + StdErr: + {Result.StdErr} + """; } } diff --git a/src/installer/tests/TestUtils/TestContext.cs b/src/installer/tests/TestUtils/TestContext.cs index 74bcf5c4f2392..4c2f7994c9890 100644 --- a/src/installer/tests/TestUtils/TestContext.cs +++ b/src/installer/tests/TestUtils/TestContext.cs @@ -43,8 +43,9 @@ static TestContext() TestAssetsOutput = GetTestContextVariable("TEST_ASSETS_OUTPUT"); TestArtifactsPath = GetTestContextVariable("TEST_ARTIFACTS"); + Directory.CreateDirectory(TestArtifactsPath); - BuiltDotNet = new DotNetCli(Path.Combine(TestArtifactsPath, "sharedFrameworkPublish")); + BuiltDotNet = new DotNetCli(Path.Combine(TestAssetsOutput, "sharedFrameworkPublish")); } public static string GetTestContextVariable(string name) diff --git a/src/installer/tests/pretest.proj b/src/installer/tests/pretest.proj new file mode 100644 index 0000000000000..b97a2e77c2e13 --- /dev/null +++ b/src/installer/tests/pretest.proj @@ -0,0 +1,22 @@ + + + + + + + + + + + + + +