Use file, not env, for test context variables
authorDavis Goodin <dagood@microsoft.com>
Fri, 12 Jul 2019 20:55:21 +0000 (15:55 -0500)
committerDavis Goodin <dagood@microsoft.com>
Mon, 15 Jul 2019 15:20:14 +0000 (10:20 -0500)
This is the recommended Arcade way to transfer this information. The Arcade SDK doens't support passing env vars while running tests.

Commit migrated from https://github.com/dotnet/core-setup/commit/fb43a6a3abab1b25356b7ee146586d14bb20b195

src/installer/test/Directory.Build.targets
src/installer/test/HostActivation.Tests/DotnetTestXunit.cs
src/installer/test/HostActivation.Tests/LightupAppActivation.cs
src/installer/test/HostActivation.Tests/MultilevelSharedFxLookup.cs
src/installer/test/HostActivation.Tests/SharedFxLookup.cs
src/installer/test/TestUtils/Command.cs
src/installer/test/TestUtils/RepoDirectoriesProvider.cs
src/installer/test/TestUtils/TestArtifact.cs
src/installer/test/TestUtils/TestProjectFixture.cs

index e3ca9ae..a87be0c 100644 (file)
       SourceFiles="@(SharedFrameworkPublishFiles)"
       DestinationFiles="@(SharedFrameworkPublishFiles->'$(TestsOutputDir)sharedFrameworkPublish/%(RecursiveDir)%(Filename)%(Extension)')" />
 
-    <!-- Create file with a name that describes what a test dir is. Useful if path abbreviated. -->
+    <!-- Create files with a name that describes what a test dir is. Useful if path abbreviated. -->
     <WriteLinesToFile
       File="$(TestsOutputRootDir)$(TestsOutputName)-is-$(MSBuildProjectName).txt"
       Overwrite="true"
       Lines="$(MSBuildProjectName) intermediates are located in '$(TestsOutputName)'. Abbreviated to work around path limits on Windows."
       Condition="'$(TestsOutputName)' != '$(MSBuildProjectName)'" />
+    <WriteLinesToFile
+      File="$(TestsOutputDir)$(MSBuildProjectName).txt"
+      Overwrite="true"
+      Lines="$(MSBuildProjectName) intermediates are located in '$(TestsOutputName)'. Abbreviated to work around path limits on Windows."
+      Condition="'$(TestsOutputName)' != '$(MSBuildProjectName)'" />
   </Target>
 
-  <Target Name="DetermineTestOutputDirectory">
-    <GetTargetMachineInfo>
-      <Output TaskParameter="RuntimeIdentifier" PropertyName="_HostRid" />
-    </GetTargetMachineInfo>
-
-    <PropertyGroup>
-      <TestTargetRid Condition="'$(TestTargetRid)' == ''">$(_HostRid)</TestTargetRid>
-      <TestsOutputName Condition="'$(TestsOutputName)' == ''">$(MSBuildProjectName)</TestsOutputName>
-
-      <TestsOutputRootDir Condition="'$(TestsOutputRootDir)' == ''">$(ArtifactsDir)tests/$(ConfigurationGroup)/</TestsOutputRootDir>
-      <TestsOutputDir Condition="'$(TestsOutputDir)' == ''">$(TestsOutputRootDir)$(TestsOutputName)/</TestsOutputDir>
-    </PropertyGroup>
-  </Target>
-
-  <Target Name="SetupTextFixtureEnvironment"
-          Condition="'$(SkipTests)' != 'true'"
+  <Target Name="SetupTestContextVariables"
           DependsOnTargets="
             GetProductVersions;
             DetermineTestOutputDirectory"
-          BeforeTargets="RunTests">
+          BeforeTargets="Build">
     <PropertyGroup>
-      <!-- The tests use the TEST_ARTIFACTS env variable to determine the artifacts folder and then later compare that path to its expected path.
-           So, the TEST_ARTIFACTS variable has to have system specific path separators or the string compoarison will fail. -->
+      <!--
+        The tests use the TEST_ARTIFACTS variable to determine the artifacts folder and then later
+        compare that path to its expected path. So, the TEST_ARTIFACTS variable has to have system
+        specific path separators or the string compoarison will fail.
+      -->
       <DirectorySeparatorChar>$([System.IO.Path]::DirectorySeparatorChar)</DirectorySeparatorChar>
       <SystemPathTestsOutputDir>$([System.String]::Copy('$(TestsOutputDir)').Replace('/', '$(DirectorySeparatorChar)'))</SystemPathTestsOutputDir>
       <SystemPathTestsOutputDir>$([System.String]::Copy('$(SystemPathTestsOutputDir)').Replace('\', '$(DirectorySeparatorChar)'))</SystemPathTestsOutputDir>
-    </PropertyGroup>
-
-    <!-- Set properties used inside tests as environment variables. -->
-    <ItemGroup>
-      <TestRunnerEnvironmentVariable Include="NUGET_PACKAGES=$(TestRestorePackagesPath)" />
-      <TestRunnerEnvironmentVariable Include="TEST_ARTIFACTS=$(SystemPathTestsOutputDir)" />
-      <TestRunnerEnvironmentVariable Include="TEST_TARGETRID=$(TestTargetRid)" />
-      <TestRunnerEnvironmentVariable Include="BUILDRID=$(OutputRid)" />
-      <TestRunnerEnvironmentVariable Include="BUILD_ARCHITECTURE=$(TargetArchitecture)" />
-      <TestRunnerEnvironmentVariable Include="BUILD_CONFIGURATION=$(ConfigurationGroup)" />
-      <TestRunnerEnvironmentVariable Include="MNA_VERSION=$(ProductVersion)" />
-      <TestRunnerEnvironmentVariable Include="MNA_TFM=$(NETCoreAppFramework)" />
-      <TestRunnerEnvironmentVariable Include="DOTNET_SDK_PATH=$(DotNetRoot)" />
-    </ItemGroup>
-  </Target>
-
-  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory).., Directory.Build.targets))\Directory.Build.targets" />
-
-  <!--
-    Rewrite Arcade RunTests target to add TestRunnerEnvironmentVariable support. In the future we
-    should switch to a file to transfer this information, or derive the info from information on
-    disk. Env vars are not likely to be supported in upstream Arcade.
-
-    See https://github.com/dotnet/arcade/issues/3077.
-  -->
-  <!-- <OVERRIDE> https://github.com/dotnet/arcade/blob/dc538a29793fd56618d0fa3186e2388d47d00c19/src/Microsoft.DotNet.Arcade.Sdk/tools/XUnit/XUnit.targets#L25-L120 -->
-  <!-- 
-    Include '*' target to force running tests even if the input assemblies haven't changed and the outputs are present.
-    This matches the common expectations that test command always runs all tests in scope.
-  -->
-  <Target Name="RunTests"
-          Inputs="@(TestToRun);*"
-          Outputs="%(TestToRun.ResultsStdOutPath);%(TestToRun.ResultsXmlPath);%(TestToRun.ResultsHtmlPath)">
-
-    <PropertyGroup>
-      <_TestEnvironment>%(TestToRun.EnvironmentDisplay)</_TestEnvironment>
-      <_TestAssembly>%(TestToRun.Identity)</_TestAssembly>
-      <_TestRuntime>%(TestToRun.TestRuntime)</_TestRuntime>
-      <_TestRunnerAdditionalArguments>%(TestToRun.TestRunnerAdditionalArguments)</_TestRunnerAdditionalArguments>
-
-      <!-- Always use net472 for desktop to enable displaying source location from Portable PDBs in stack traces -->
-      <_TestRunnerTargetFramework>net472</_TestRunnerTargetFramework>
-      <_TestRunnerTargetFramework Condition="'$(_TestRuntime)' == 'Core'">netcoreapp2.0</_TestRunnerTargetFramework>
-      <_TestRunnerTargetFramework Condition="%(TestToRun.TargetFramework) == 'netcoreapp1.1' or %(TestToRun.TargetFramework) == 'netcoreapp1.0'">netcoreapp1.0</_TestRunnerTargetFramework>
-    </PropertyGroup>
-
-    <PropertyGroup Condition="'$(_TestRuntime)' == 'Core'">
-      <_TargetFileNameNoExt>$([System.IO.Path]::GetFileNameWithoutExtension('$(_TestAssembly)'))</_TargetFileNameNoExt>
-      <_TargetDir>$([System.IO.Path]::GetDirectoryName('$(_TestAssembly)'))\</_TargetDir>
-      <_CoreRuntimeConfigPath>$(_TargetDir)$(_TargetFileNameNoExt).runtimeconfig.json</_CoreRuntimeConfigPath>
-      <_CoreDepsPath>$(_TargetDir)$(_TargetFileNameNoExt).deps.json</_CoreDepsPath>
-      
-      <_TestRunner Condition="'%(TestToRun.Architecture)'=='x86' And Exists('$(DotNetRoot)x86\dotnet.exe')">$(DotNetRoot)x86\dotnet.exe</_TestRunner>
-      <_TestRunner Condition="'$(_TestRunner)'==''">$(DotNetTool)</_TestRunner>
-      
-      <_TestRunnerArgs>exec --depsfile "$(_CoreDepsPath)" --runtimeconfig "$(_CoreRuntimeConfigPath)" $(TestRuntimeAdditionalArguments) "$(NuGetPackageRoot)xunit.runner.console/$(XUnitVersion)/tools/$(_TestRunnerTargetFramework)/xunit.console.dll" "$(_TestAssembly)" -noautoreporters -xml "%(TestToRun.ResultsXmlPath)" -html "%(TestToRun.ResultsHtmlPath)" $(_TestRunnerAdditionalArguments)</_TestRunnerArgs>
-    </PropertyGroup>
-
-    <PropertyGroup Condition="'$(_TestRuntime)' != 'Core'">
-      <_XUnitConsoleExe>xunit.console.exe</_XUnitConsoleExe>
-      <_XUnitConsoleExe Condition="'%(TestToRun.Architecture)' == 'x86'">xunit.console.x86.exe</_XUnitConsoleExe>
-      <_XUnitConsoleExePath>$(NuGetPackageRoot)xunit.runner.console\$(XUnitVersion)\tools\$(_TestRunnerTargetFramework)\$(_XUnitConsoleExe)</_XUnitConsoleExePath>
-
-      <_TestRunnerArgs>"$(_TestAssembly)" -noshadow -xml "%(TestToRun.ResultsXmlPath)" -html "%(TestToRun.ResultsHtmlPath)" $(_TestRunnerAdditionalArguments)</_TestRunnerArgs>
-      <_TestRunnerArgs Condition="'$(_TestRuntime)' == 'Mono'">$(TestRuntimeAdditionalArguments) "$(_XUnitConsoleExePath)" $(_TestRunnerArgs)</_TestRunnerArgs>
 
-      <_TestRunner Condition="'$(_TestRuntime)' == 'Mono'">$(MonoTool)</_TestRunner>
-      <_TestRunner Condition="'$(_TestRuntime)' != 'Mono'">$(_XUnitConsoleExePath)</_TestRunner>
-    </PropertyGroup>
-
-    <PropertyGroup>
-      <_TestRunnerCommand>"$(_TestRunner)" $(_TestRunnerArgs)</_TestRunnerCommand>
-
-      <!-- 
-        Redirect std output of the runner.
-        Note that xUnit outputs failure info to both STDOUT (stack trace, message) and STDERR (failed test name) 
-      -->
-      <_TestRunnerCommand Condition="'$(TestCaptureOutput)' != 'false'">$(_TestRunnerCommand) > "%(TestToRun.ResultsStdOutPath)" 2>&amp;1</_TestRunnerCommand>
+      <!-- This is defined when building in Visual Studio, not DotNetRoot. -->
+      <DotNetRoot Condition="'$(DotNetRoot)' == ''">$(NetCoreRoot)</DotNetRoot>
     </PropertyGroup>
 
+    <!--
+      Set up properties used inside tests. Write them to a text file so that they can be found
+      inside the VS Test Explorer context the same way as the XUnit runner will find them.
+      See https://github.com/dotnet/arcade/issues/3077.
+    -->
     <ItemGroup>
-      <_OutputFiles Include="%(TestToRun.ResultsXmlPath)" />
-      <_OutputFiles Include="%(TestToRun.ResultsHtmlPath)" />
-      <_OutputFiles Include="%(TestToRun.ResultsStdOutPath)" />
+      <TestContextVariable Include="NUGET_PACKAGES=$(TestRestorePackagesPath)" />
+      <TestContextVariable Include="TEST_ARTIFACTS=$(SystemPathTestsOutputDir)" />
+      <TestContextVariable Include="TEST_TARGETRID=$(TestTargetRid)" />
+      <TestContextVariable Include="BUILDRID=$(OutputRid)" />
+      <TestContextVariable Include="BUILD_ARCHITECTURE=$(TargetArchitecture)" />
+      <TestContextVariable Include="BUILD_CONFIGURATION=$(ConfigurationGroup)" />
+      <TestContextVariable Include="MNA_VERSION=$(ProductVersion)" />
+      <TestContextVariable Include="MNA_TFM=$(NETCoreAppFramework)" />
+      <TestContextVariable Include="DOTNET_SDK_PATH=$(DotNetRoot)" />
     </ItemGroup>
 
-    <MakeDir Directories="@(_OutputFiles->'%(RootDir)%(Directory)')"/>
-    <Delete Files="@(_OutputFiles)" />
-
-    <Message Text="Running tests: $(_TestAssembly) [$(_TestEnvironment)]" Importance="high"/>
-    <!-- <CHANGE> Add env var parameter, taking TestRunnerEnvironmentVariable items. -->
-    <Exec
-      Command='$(_TestRunnerCommand)'
-      EnvironmentVariables="@(TestRunnerEnvironmentVariable)"
-      LogStandardErrorAsError="false"
-      WorkingDirectory="$(_TargetDir)"
-      IgnoreExitCode="true">
-    <!-- </CHANGE> -->
-      <Output TaskParameter="ExitCode" PropertyName="_TestErrorCode" />
-    </Exec>
-
-    <!--
-      Add command line to the log.
-    -->
-    <WriteLinesToFile File="%(TestToRun.ResultsStdOutPath)" 
-                      Overwrite="false" 
-                      Lines=";=== COMMAND LINE ===;$(_TestRunnerCommand)"
-                      Condition="'$(TestCaptureOutput)' != 'false'" />
+    <WriteLinesToFile
+      File="$(OutDir)TestContextVariables.txt"
+      Overwrite="true"
+      Lines="@(TestContextVariable)" />
+  </Target>
 
-    <!--
-      Report test status.
-    -->
-    <Message Text="Tests succeeded: $(_TestAssembly) [$(_TestEnvironment)]" Condition="'$(_TestErrorCode)' == '0'" Importance="high" />
+  <Target Name="DetermineTestOutputDirectory">
+    <GetTargetMachineInfo>
+      <Output TaskParameter="RuntimeIdentifier" PropertyName="_HostRid" />
+    </GetTargetMachineInfo>
 
     <PropertyGroup>
-      <_ResultsFileToDisplay>%(TestToRun.ResultsHtmlPath)</_ResultsFileToDisplay>
-      <_ResultsFileToDisplay Condition="!Exists('$(_ResultsFileToDisplay)')">%(TestToRun.ResultsStdOutPath)</_ResultsFileToDisplay>
-    </PropertyGroup>
-
-    <!-- 
-      Ideally we would set ContinueOnError="ErrorAndContinue" so that when a test fails in multi-targeted test project
-      we'll still run tests for all target frameworks. ErrorAndContinue doesn't work well on Linux though: https://github.com/Microsoft/msbuild/issues/3961.
-    -->
-    <Error Text="Tests failed: $(_ResultsFileToDisplay) [$(_TestEnvironment)]" Condition="'$(_TestErrorCode)' != '0'" File="XUnit" />
+      <TestTargetRid Condition="'$(TestTargetRid)' == ''">$(_HostRid)</TestTargetRid>
+      <TestsOutputName Condition="'$(TestsOutputName)' == ''">$(MSBuildProjectName)</TestsOutputName>
 
-    <ItemGroup>
-      <FileWrites Include="@(_OutputFiles)"/>
-    </ItemGroup>
+      <TestsOutputRootDir Condition="'$(TestsOutputRootDir)' == ''">$(ArtifactsDir)tests/$(ConfigurationGroup)/</TestsOutputRootDir>
+      <TestsOutputDir Condition="'$(TestsOutputDir)' == ''">$(TestsOutputRootDir)$(TestsOutputName)/</TestsOutputDir>
+    </PropertyGroup>
   </Target>
-  <!-- </OVERRIDE> -->
 
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory).., Directory.Build.targets))\Directory.Build.targets" />
 </Project>
index a580023..8adaf88 100644 (file)
@@ -85,7 +85,7 @@ namespace Microsoft.DotNet.Tools.Publish.Tests
             if ( ! File.Exists(dotnetTestXunitDll))
             {
                 throw new Exception(
-                    $"Unable to find dotnet-test-xunit.dll, ensure {nameof(DotnetTestXunitVersion)} is updated to the version in Portable/StandaloneTestApp");
+                    $"Unable to find '{dotnetTestXunitDll}', ensure {nameof(DotnetTestXunitVersion)} is updated to the version in Portable/StandaloneTestApp");
             }
 
             return dotnetTestXunitDll;
index 2cd68bd..e3dd30e 100644 (file)
@@ -30,7 +30,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
 
             // From the artifacts dir, it's possible to find where the sharedFrameworkPublish folder is. We need
             // to locate it because we'll copy its contents into other folders
-            string artifactsDir = Environment.GetEnvironmentVariable("TEST_ARTIFACTS");
+            string artifactsDir = new RepoDirectoriesProvider().GetTestContextVariable("TEST_ARTIFACTS");
             string builtDotnet = Path.Combine(artifactsDir, "sharedFrameworkPublish");
 
             // The dotnetLightupSharedFxLookup dir will contain some folders and files that will be necessary to perform the tests
index 2956d90..2b05a3e 100644 (file)
@@ -48,7 +48,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
         {
             // From the artifacts dir, it's possible to find where the sharedFrameworkPublish folder is. We need
             // to locate it because we'll copy its contents into other folders
-            string artifactsDir = Environment.GetEnvironmentVariable("TEST_ARTIFACTS");
+            string artifactsDir = new RepoDirectoriesProvider().GetTestContextVariable("TEST_ARTIFACTS");
             _builtDotnet = Path.Combine(artifactsDir, "sharedFrameworkPublish");
 
             // The dotnetMultilevelSharedFxLookup dir will contain some folders and files that will be
index 63390d4..e7cd16d 100644 (file)
@@ -34,7 +34,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
         {
             // From the artifacts dir, it's possible to find where the sharedFrameworkPublish folder is. We need
             // to locate it because we'll copy its contents into other folders
-            string artifactsDir = Environment.GetEnvironmentVariable("TEST_ARTIFACTS");
+            string artifactsDir = new RepoDirectoriesProvider().GetTestContextVariable("TEST_ARTIFACTS");
             _builtDotnet = Path.Combine(artifactsDir, "sharedFrameworkPublish");
 
             // The dotnetSharedFxLookup dir will contain some folders and files that will be
index f75c683..cb178a6 100644 (file)
@@ -251,7 +251,7 @@ namespace Microsoft.DotNet.Cli.Build.Framework
         public Command WithUserProfile(string userprofile)
         {
             string userDir;
-            if (RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows)
+            if (InternalAbstractions.RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows)
             {
                 userDir = "USERPROFILE";
             }
index ed6252b..f30695f 100644 (file)
@@ -1,6 +1,9 @@
 using System;
 using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.IO;
+using System.Linq;
 
 namespace Microsoft.DotNet.CoreSetup.Test
 {
@@ -10,7 +13,11 @@ namespace Microsoft.DotNet.CoreSetup.Test
         public string BuildArchitecture { get; }
         public string TargetRID { get; }
         public string MicrosoftNETCoreAppVersion { get; }
+        public string Configuration { get; }
         public string RepoRoot { get; }
+        public string BaseArtifactsFolder { get; }
+        public string BaseBinFolder { get; }
+        public string BaseObjFolder { get; }
         public string Artifacts { get; }
         public string HostArtifacts { get; }
         public string BuiltDotnet { get; }
@@ -18,6 +25,9 @@ namespace Microsoft.DotNet.CoreSetup.Test
         public string CorehostPackages { get; }
         public string DotnetSDK { get; }
 
+        private string _testContextVariableFilePath { get; }
+        private ImmutableDictionary<string, string> _testContextVariables { get; }
+
         public RepoDirectoriesProvider(
             string repoRoot = null,
             string artifacts = null,
@@ -29,34 +39,72 @@ namespace Microsoft.DotNet.CoreSetup.Test
         {
             RepoRoot = repoRoot ?? GetRepoRootDirectory();
 
-            string baseArtifactsFolder = artifacts ?? Path.Combine(RepoRoot, "artifacts");
-            string baseBinFolder = artifacts ?? Path.Combine(baseArtifactsFolder, "bin");
-            string baseObjFolder = artifacts ?? Path.Combine(baseArtifactsFolder, "obj");
+            _testContextVariableFilePath = Path.Combine(
+                Directory.GetCurrentDirectory(),
+                "TestContextVariables.txt");
+
+            _testContextVariables = File.ReadAllLines(_testContextVariableFilePath)
+                .ToImmutableDictionary(
+                    line => line.Substring(0, line.IndexOf('=')),
+                    line => line.Substring(line.IndexOf('=') + 1),
+                    StringComparer.OrdinalIgnoreCase);
+
+            BaseArtifactsFolder = artifacts ?? Path.Combine(RepoRoot, "artifacts");
+            BaseBinFolder = artifacts ?? Path.Combine(BaseArtifactsFolder, "bin");
+            BaseObjFolder = artifacts ?? Path.Combine(BaseArtifactsFolder, "obj");
 
-            TargetRID = Environment.GetEnvironmentVariable("TEST_TARGETRID");
-            BuildRID = Environment.GetEnvironmentVariable("BUILDRID");
-            BuildArchitecture = Environment.GetEnvironmentVariable("BUILD_ARCHITECTURE");
-            MicrosoftNETCoreAppVersion = microsoftNETCoreAppVersion ?? Environment.GetEnvironmentVariable("MNA_VERSION");
+            TargetRID = GetTestContextVariable("TEST_TARGETRID");
+            BuildRID = GetTestContextVariable("BUILDRID");
+            BuildArchitecture = GetTestContextVariable("BUILD_ARCHITECTURE");
+            MicrosoftNETCoreAppVersion = microsoftNETCoreAppVersion ?? GetTestContextVariable("MNA_VERSION");
 
-            string configuration = Environment.GetEnvironmentVariable("BUILD_CONFIGURATION");
-            string osPlatformConfig = $"{BuildRID}.{configuration}";
+            Configuration = GetTestContextVariable("BUILD_CONFIGURATION");
+            string osPlatformConfig = $"{BuildRID}.{Configuration}";
 
-            DotnetSDK = dotnetSdk ?? Environment.GetEnvironmentVariable("DOTNET_SDK_PATH");
+            DotnetSDK = dotnetSdk ?? GetTestContextVariable("DOTNET_SDK_PATH");
 
             if (!Directory.Exists(DotnetSDK))
             {
                 throw new InvalidOperationException("ERROR: Test SDK folder not found.");
             }
 
-            Artifacts = Path.Combine(baseBinFolder, osPlatformConfig);
+            Artifacts = Path.Combine(BaseBinFolder, osPlatformConfig);
             HostArtifacts = artifacts ?? Path.Combine(Artifacts, "corehost");
 
             NugetPackages = nugetPackages ??
-                Environment.GetEnvironmentVariable("NUGET_PACKAGES") ??
+                GetTestContextVariable("NUGET_PACKAGES") ??
                 Path.Combine(RepoRoot, ".packages");
 
             CorehostPackages = corehostPackages ?? Path.Combine(Artifacts, "corehost");
-            BuiltDotnet = builtDotnet ?? Path.Combine(baseObjFolder, osPlatformConfig, "sharedFrameworkPublish");
+            BuiltDotnet = builtDotnet ?? Path.Combine(BaseObjFolder, osPlatformConfig, "sharedFrameworkPublish");
+        }
+
+        public string GetTestContextVariable(string name)
+        {
+            return GetTestContextVariableOrNull(name) ?? throw new ArgumentException(
+                $"Unable to find variable '{name}' in " +
+                $"test context variable file '{_testContextVariableFilePath}'");
+        }
+
+        public string GetTestContextVariableOrNull(string name)
+        {
+            // Allow env var override, although normally the test context variables file is used.
+            // Don't accept NUGET_PACKAGES env override specifically: Arcade sets this and it leaks
+            // in during build.cmd/sh runs, replacing the test-specific dir.
+            if (!name.Equals("NUGET_PACKAGES", StringComparison.OrdinalIgnoreCase))
+            {
+                if (Environment.GetEnvironmentVariable(name) is string envValue)
+                {
+                    return envValue;
+                }
+            }
+
+            if (_testContextVariables.TryGetValue(name, out string value))
+            {
+                return value;
+            }
+
+            return null;
         }
 
         private static string GetRepoRootDirectory()
index e49b520..d989a37 100644 (file)
@@ -10,20 +10,21 @@ namespace Microsoft.DotNet.CoreSetup.Test
 {
     public class TestArtifact : IDisposable
     {
+        private static readonly Lazy<RepoDirectoriesProvider> _repoDirectoriesProvider =
+            new Lazy<RepoDirectoriesProvider>(() => new RepoDirectoriesProvider());
+
+        private static readonly Lazy<bool> _preserveTestRuns = new Lazy<bool>(() =>
+            _repoDirectoriesProvider.Value.GetTestContextVariableOrNull("PRESERVE_TEST_RUNS") == "1");
+
         private static readonly string TestArtifactDirectoryEnvironmentVariable = "TEST_ARTIFACTS";
         private static readonly Lazy<string> _testArtifactsPath = new Lazy<string>(() =>
         {
-            return Environment.GetEnvironmentVariable(TestArtifactDirectoryEnvironmentVariable)
+            return _repoDirectoriesProvider.Value.GetTestContextVariable(TestArtifactDirectoryEnvironmentVariable)
                    ?? Path.Combine(AppContext.BaseDirectory, TestArtifactDirectoryEnvironmentVariable);
         });
 
-        public static string TestArtifactsPath
-        {
-            get
-            {
-                return _testArtifactsPath.Value;
-            }
-        }
+        public static bool PreserveTestRuns() => _preserveTestRuns.Value;
+        public static string TestArtifactsPath => _testArtifactsPath.Value;
 
         public string Location { get; }
         public string Name { get; }
@@ -66,11 +67,6 @@ namespace Microsoft.DotNet.CoreSetup.Test
             _copies.Clear();
         }
 
-        public static bool PreserveTestRuns()
-        {
-            return Environment.GetEnvironmentVariable("PRESERVE_TEST_RUNS") == "1";
-        }
-
         protected static string GetNewTestArtifactPath(string artifactName)
         {
             int projectCount = 0;
index 6d4bfa3..e69ef93 100644 (file)
@@ -36,10 +36,10 @@ namespace Microsoft.DotNet.CoreSetup.Test
         {
             ValidateRequiredDirectories(repoDirectoriesProvider);
 
-            Framework = framework ?? Environment.GetEnvironmentVariable("MNA_TFM");
-
             RepoDirProvider = repoDirectoriesProvider;
 
+            Framework = framework ?? RepoDirProvider.GetTestContextVariable("MNA_TFM");
+
             SdkDotnet = new DotNetCli(repoDirectoriesProvider.DotnetSDK);
             CurrentRid = repoDirectoriesProvider.TargetRID;