From ca5cd91d6854a4ce941887cca6a1d04fa67d36be Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 1 Apr 2020 09:01:34 -0700 Subject: [PATCH] Replace RunTests scripts with .NET app (#20337) --- .../content/RunTests/Directory.Build.props | 2 + .../content/RunTests/Directory.Build.targets | 2 + eng/helix/content/RunTests/ProcessResult.cs | 20 ++ eng/helix/content/RunTests/ProcessUtil.cs | 158 ++++++++++++ eng/helix/content/RunTests/Program.cs | 235 ++++++++++++++++++ eng/helix/content/RunTests/RunTests.csproj | 11 + eng/helix/content/default.NuGet.config | 1 + eng/helix/content/runtests.cmd | 90 +------ eng/helix/content/runtests.sh | 84 +------ src/ProjectTemplates/test/Helpers/Project.cs | 14 +- 10 files changed, 444 insertions(+), 173 deletions(-) create mode 100644 eng/helix/content/RunTests/Directory.Build.props create mode 100644 eng/helix/content/RunTests/Directory.Build.targets create mode 100644 eng/helix/content/RunTests/ProcessResult.cs create mode 100644 eng/helix/content/RunTests/ProcessUtil.cs create mode 100644 eng/helix/content/RunTests/Program.cs create mode 100644 eng/helix/content/RunTests/RunTests.csproj diff --git a/eng/helix/content/RunTests/Directory.Build.props b/eng/helix/content/RunTests/Directory.Build.props new file mode 100644 index 0000000000..c1df2220dd --- /dev/null +++ b/eng/helix/content/RunTests/Directory.Build.props @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/eng/helix/content/RunTests/Directory.Build.targets b/eng/helix/content/RunTests/Directory.Build.targets new file mode 100644 index 0000000000..c1df2220dd --- /dev/null +++ b/eng/helix/content/RunTests/Directory.Build.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/eng/helix/content/RunTests/ProcessResult.cs b/eng/helix/content/RunTests/ProcessResult.cs new file mode 100644 index 0000000000..9e293c02c8 --- /dev/null +++ b/eng/helix/content/RunTests/ProcessResult.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace RunTests +{ + public class ProcessResult + { + public ProcessResult(string standardOutput, string standardError, int exitCode) + { + StandardOutput = standardOutput; + StandardError = standardError; + ExitCode = exitCode; + } + + public string StandardOutput { get; } + public string StandardError { get; } + public int ExitCode { get; } + } +} diff --git a/eng/helix/content/RunTests/ProcessUtil.cs b/eng/helix/content/RunTests/ProcessUtil.cs new file mode 100644 index 0000000000..8c25f9fb5d --- /dev/null +++ b/eng/helix/content/RunTests/ProcessUtil.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace RunTests +{ + public static class ProcessUtil + { + [DllImport("libc", SetLastError = true, EntryPoint = "kill")] + private static extern int sys_kill(int pid, int sig); + + public static async Task RunAsync( + string filename, + string arguments, + string? workingDirectory = null, + bool throwOnError = true, + IDictionary? environmentVariables = null, + Action? outputDataReceived = null, + Action? errorDataReceived = null, + Action? onStart = null, + CancellationToken cancellationToken = default) + { + Console.WriteLine($"Running '{filename} {arguments}'"); + using var process = new Process() + { + StartInfo = + { + FileName = filename, + Arguments = arguments, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + EnableRaisingEvents = true + }; + + + if (workingDirectory != null) + { + process.StartInfo.WorkingDirectory = workingDirectory; + } + + if (environmentVariables != null) + { + foreach (var kvp in environmentVariables) + { + process.StartInfo.Environment.Add(kvp); + } + } + + var outputBuilder = new StringBuilder(); + process.OutputDataReceived += (_, e) => + { + if (e.Data != null) + { + if (outputDataReceived != null) + { + outputDataReceived.Invoke(e.Data); + } + else + { + outputBuilder.AppendLine(e.Data); + } + } + }; + + var errorBuilder = new StringBuilder(); + process.ErrorDataReceived += (_, e) => + { + if (e.Data != null) + { + if (errorDataReceived != null) + { + errorDataReceived.Invoke(e.Data); + } + else + { + errorBuilder.AppendLine(e.Data); + } + } + }; + + var processLifetimeTask = new TaskCompletionSource(); + + process.Exited += (_, e) => + { + Console.WriteLine($"'{process.StartInfo.FileName} {process.StartInfo.Arguments}' completed with exit code '{process.ExitCode}'"); + if (throwOnError && process.ExitCode != 0) + { + processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode}")); + } + else + { + processLifetimeTask.TrySetResult(new ProcessResult(outputBuilder.ToString(), errorBuilder.ToString(), process.ExitCode)); + } + }; + + process.Start(); + onStart?.Invoke(process.Id); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + var cancelledTcs = new TaskCompletionSource(); + await using var _ = cancellationToken.Register(() => cancelledTcs.TrySetResult(null)); + + var result = await Task.WhenAny(processLifetimeTask.Task, cancelledTcs.Task); + + if (result == cancelledTcs.Task) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + sys_kill(process.Id, sig: 2); // SIGINT + + var cancel = new CancellationTokenSource(); + + await Task.WhenAny(processLifetimeTask.Task, Task.Delay(TimeSpan.FromSeconds(5), cancel.Token)); + + cancel.Cancel(); + } + + if (!process.HasExited) + { + process.CloseMainWindow(); + + if (!process.HasExited) + { + process.Kill(); + } + } + } + + return await processLifetimeTask.Task; + } + + public static void KillProcess(int pid) + { + try + { + using var process = Process.GetProcessById(pid); + process?.Kill(); + } + catch (ArgumentException) { } + catch (InvalidOperationException) { } + } + } +} diff --git a/eng/helix/content/RunTests/Program.cs b/eng/helix/content/RunTests/Program.cs new file mode 100644 index 0000000000..1535d6663e --- /dev/null +++ b/eng/helix/content/RunTests/Program.cs @@ -0,0 +1,235 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace RunTests +{ + class Program + { + static async Task Main(string[] args) + { + var command = new RootCommand() + { + new Option( + aliases: new string[] { "--target", "-t" }, + description: "The test dll to run") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--sdk" }, + description: "The version of the sdk being used") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--runtime" }, + description: "The version of the runtime being used") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--queue" }, + description: "The name of the Helix queue being run on") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--arch" }, + description: "The architecture being run on") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--quarantined" }, + description: "Whether quarantined tests should run or not") + { Argument = new Argument(), Required = true }, + + new Option( + aliases: new string[] { "--ef" }, + description: "The version of the EF tool to use") + { Argument = new Argument(), Required = true }, + }; + + var parseResult = command.Parse(args); + var target = parseResult.ValueForOption("--target"); + var sdkVersion = parseResult.ValueForOption("--sdk"); + var runtimeVersion = parseResult.ValueForOption("--runtime"); + var helixQueue = parseResult.ValueForOption("--queue"); + var architecture = parseResult.ValueForOption("--arch"); + var quarantined = parseResult.ValueForOption("--quarantined"); + var efVersion = parseResult.ValueForOption("--ef"); + + var HELIX_WORKITEM_ROOT = Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"); + + var path = Environment.GetEnvironmentVariable("PATH"); + var dotnetRoot = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + + // Rename default.NuGet.config to NuGet.config if there is not a custom one from the project + // We use a local NuGet.config file to avoid polluting global machine state and avoid relying on global machine state + if (!File.Exists("NuGet.config")) + { + File.Copy("default.NuGet.config", "NuGet.config"); + } + + var environmentVariables = new Dictionary(); + environmentVariables.Add("PATH", path); + environmentVariables.Add("DOTNET_ROOT", dotnetRoot); + environmentVariables.Add("helix", helixQueue); + + Console.WriteLine($"Current Directory: {HELIX_WORKITEM_ROOT}"); + var helixDir = HELIX_WORKITEM_ROOT; + Console.WriteLine($"Setting HELIX_DIR: {helixDir}"); + environmentVariables.Add("HELIX_DIR", helixDir); + environmentVariables.Add("NUGET_FALLBACK_PACKAGES", helixDir); + var nugetRestore = Path.Combine(helixDir, "nugetRestore"); + Console.WriteLine($"Creating nuget restore directory: {nugetRestore}"); + environmentVariables.Add("NUGET_RESTORE", nugetRestore); + var dotnetEFFullPath = Path.Combine(nugetRestore, $"dotnet-ef/{efVersion}/tools/netcoreapp3.1/any/dotnet-ef.exe"); + Console.WriteLine($"Set DotNetEfFullPath: {dotnetEFFullPath}"); + environmentVariables.Add("DotNetEfFullPath", dotnetEFFullPath); + + Console.WriteLine("Checking for Microsoft.AspNetCore.App/"); + if (Directory.Exists("Microsoft.AspNetCore.App")) + { + Console.WriteLine($"Found Microsoft.AspNetCore.App/, copying to {dotnetRoot}/shared/Microsoft.AspNetCore.App/{runtimeVersion}"); + foreach (var file in Directory.EnumerateFiles("Microsoft.AspNetCore.App", "*.*", SearchOption.AllDirectories)) + { + File.Copy(file, $"{dotnetRoot}/shared/Microsoft.AspNetCore.App/{runtimeVersion}", overwrite: true); + } + + Console.WriteLine($"Adding current directory to nuget sources: {HELIX_WORKITEM_ROOT}"); + + await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + $"nuget add source {HELIX_WORKITEM_ROOT} --configfile NuGet.config", + environmentVariables: environmentVariables); + + await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + "nuget add source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json --configfile NuGet.config", + environmentVariables: environmentVariables); + + // Write nuget sources to console, useful for debugging purposes + await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + "nuget list source", + environmentVariables: environmentVariables, + outputDataReceived: Console.WriteLine, + errorDataReceived: Console.WriteLine); + + await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + $"tool install dotnet-ef --global --version {efVersion}", + environmentVariables: environmentVariables); + + // ';' is the path separator on Windows, and ':' on Unix + path += RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ";" : ":"; + path += $"{Environment.GetEnvironmentVariable("DOTNET_CLI_HOME")}/.dotnet/tools"; + environmentVariables["PATH"] = path; + } + + Directory.CreateDirectory(nugetRestore); + + // Rename default.runner.json to xunit.runner.json if there is not a custom one from the project + if (!File.Exists("xunit.runner.json")) + { + File.Copy("default.runner.json", "xunit.runner.json"); + } + + Console.WriteLine(); + Console.WriteLine("Displaying directory contents:"); + foreach (var file in Directory.EnumerateFiles("./")) + { + Console.WriteLine(Path.GetFileName(file)); + } + foreach (var file in Directory.EnumerateDirectories("./")) + { + Console.WriteLine(Path.GetFileName(file)); + } + Console.WriteLine(); + + // Run test discovery so we know if there are tests to run + var discoveryResult = await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + $"vstest {target} -lt", + environmentVariables: environmentVariables); + + if (discoveryResult.StandardOutput.Contains("Exception thrown")) + { + Console.WriteLine("Exception thrown during test discovery."); + Console.WriteLine(discoveryResult.StandardOutput); + Environment.Exit(1); + return; + } + + var exitCode = 0; + var commonTestArgs = $"vstest {target} --logger:xunit --logger:\"console;verbosity=normal\" --blame"; + if (quarantined) + { + Console.WriteLine("Running quarantined tests."); + + // Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md + var result = await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + commonTestArgs + " --TestCaseFilter:\"Quarantined=true\"", + environmentVariables: environmentVariables, + outputDataReceived: Console.WriteLine, + errorDataReceived: Console.WriteLine, + throwOnError: false); + + if (result.ExitCode != 0) + { + Console.WriteLine($"Failure in quarantined tests. Exit code: {result.ExitCode}."); + } + } + else + { + Console.WriteLine("Running non-quarantined tests."); + + // Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md + var result = await ProcessUtil.RunAsync($"{dotnetRoot}/dotnet", + commonTestArgs + " --TestCaseFilter:\"Quarantined!=true\"", + environmentVariables: environmentVariables, + outputDataReceived: Console.WriteLine, + errorDataReceived: Console.Error.WriteLine, + throwOnError: false); + + if (result.ExitCode != 0) + { + Console.WriteLine($"Failure in non-quarantined tests. Exit code: {result.ExitCode}."); + exitCode = result.ExitCode; + } + } + + // 'testResults.xml' is the file Helix looks for when processing test results + Console.WriteLine(); + if (File.Exists("TestResults/TestResults.xml")) + { + Console.WriteLine("Copying TestResults/TestResults.xml to ./testResults.xml"); + File.Copy("TestResults/TestResults.xml", "testResults.xml"); + } + else + { + Console.WriteLine("No test results found."); + } + + var HELIX_WORKITEM_UPLOAD_ROOT = Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT"); + Console.WriteLine($"Copying artifacts/log/ to {HELIX_WORKITEM_UPLOAD_ROOT}/"); + if (Directory.Exists("artifacts/log")) + { + foreach (var file in Directory.EnumerateFiles("artifacts/log", "*.log", SearchOption.AllDirectories)) + { + // Combine the directory name + log name for the copied log file name to avoid overwriting duplicate test names in different test projects + var logName = $"{Path.GetFileName(Path.GetDirectoryName(file))}_{Path.GetFileName(file)}"; + Console.WriteLine($"Copying: {file} to {Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, logName)}"); + // Need to copy to HELIX_WORKITEM_UPLOAD_ROOT and HELIX_WORKITEM_UPLOAD_ROOT/../ in order for Azure Devops attachments to link properly and for Helix to store the logs + File.Copy(file, Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, logName)); + File.Copy(file, Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, "..", logName)); + } + } + else + { + Console.WriteLine("No logs found in artifacts/log"); + } + + Console.WriteLine("Completed Helix job."); + Environment.Exit(exitCode); + } + } +} diff --git a/eng/helix/content/RunTests/RunTests.csproj b/eng/helix/content/RunTests/RunTests.csproj new file mode 100644 index 0000000000..39f671c641 --- /dev/null +++ b/eng/helix/content/RunTests/RunTests.csproj @@ -0,0 +1,11 @@ + + + + Exe + netcoreapp5.0 + + + + + + diff --git a/eng/helix/content/default.NuGet.config b/eng/helix/content/default.NuGet.config index ade6630535..3a9f6b3272 100644 --- a/eng/helix/content/default.NuGet.config +++ b/eng/helix/content/default.NuGet.config @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/eng/helix/content/runtests.cmd b/eng/helix/content/runtests.cmd index 18e47240ed..d71ff1b6ce 100644 --- a/eng/helix/content/runtests.cmd +++ b/eng/helix/content/runtests.cmd @@ -3,13 +3,9 @@ REM Need delayed expansion !PATH! so parens in the path don't mess up the parens setlocal enabledelayedexpansion REM Use '$' as a variable name prefix to avoid MSBuild variable collisions with these variables -set $target=%1 set $sdkVersion=%2 set $runtimeVersion=%3 -set $helixQueue=%4 set $arch=%5 -set $quarantined=%6 -set $efVersion=%7 set DOTNET_HOME=%HELIX_CORRELATION_PAYLOAD%\sdk set DOTNET_ROOT=%DOTNET_HOME%\%$arch% @@ -24,89 +20,11 @@ powershell.exe -NoProfile -ExecutionPolicy unrestricted -Command "[Net.ServicePo echo "Installing Runtime" powershell.exe -NoProfile -ExecutionPolicy unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -useb 'https://dot.net/v1/dotnet-install.ps1'))) -Architecture %$arch% -Runtime dotnet -Version %$runtimeVersion% -InstallDir %DOTNET_ROOT%" -REM "Rename default.NuGet.config to NuGet.config if there is not a custom one from the project" -if not EXIST ".\NuGet.config" ( - copy default.NuGet.config NuGet.config -) - -echo "Checking for Microsoft.AspNetCore.App" -if EXIST ".\Microsoft.AspNetCore.App" ( - echo "Found Microsoft.AspNetCore.App, copying to %DOTNET_ROOT%\shared\Microsoft.AspNetCore.App\%runtimeVersion%" - xcopy /i /y ".\Microsoft.AspNetCore.App" %DOTNET_ROOT%\shared\Microsoft.AspNetCore.App\%runtimeVersion%\ - - echo "Adding current directory to nuget sources: %HELIX_WORKITEM_ROOT%" - dotnet nuget add source %HELIX_WORKITEM_ROOT% --configfile NuGet.config - dotnet nuget add source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json --configfile NuGet.config - dotnet nuget list source - dotnet tool install dotnet-ef --global --version %$efVersion% - - set PATH=!PATH!;%DOTNET_CLI_HOME%\.dotnet\tools -) - -echo "Current Directory: %HELIX_WORKITEM_ROOT%" -set HELIX=%$helixQueue% -set HELIX_DIR=%HELIX_WORKITEM_ROOT% -set NUGET_FALLBACK_PACKAGES=%HELIX_DIR% -set NUGET_RESTORE=%HELIX_DIR%\nugetRestore -set DotNetEfFullPath=%HELIX_DIR%\nugetRestore\dotnet-ef\%$efVersion%\tools\netcoreapp3.1\any\dotnet-ef.exe -echo "Set DotNetEfFullPath: %DotNetEfFullPath%" -echo "Setting HELIX_DIR: %HELIX_DIR%" -echo Creating nuget restore directory: %NUGET_RESTORE% -mkdir %NUGET_RESTORE% -mkdir logs - -REM "Rename default.runner.json to xunit.runner.json if there is not a custom one from the project" -if not EXIST ".\xunit.runner.json" ( - copy default.runner.json xunit.runner.json -) - -dir - -%DOTNET_ROOT%\dotnet vstest %$target% -lt >discovered.txt -find /c "Exception thrown" discovered.txt -REM "ERRORLEVEL is not %ERRORLEVEL%" https://blogs.msdn.microsoft.com/oldnewthing/20080926-00/?p=20743/ -if not errorlevel 1 ( - echo Exception thrown during test discovery. 1>&2 - type discovered.txt 1>&2 - exit /b 1 -) - set exit_code=0 - -if %$quarantined%==True ( - set %$quarantined=true -) - -REM Disable "!Foo!" expansions because they break the filter syntax -setlocal disabledelayedexpansion -set NONQUARANTINE_FILTER="Quarantined!=true" -set QUARANTINE_FILTER="Quarantined=true" -if %$quarantined%==true ( - echo Running quarantined tests. - %DOTNET_ROOT%\dotnet vstest %$target% --logger:xunit --logger:"console;verbosity=normal" --blame --TestCaseFilter:%QUARANTINE_FILTER% - if errorlevel 1 ( - echo Failure in quarantined test 1>&2 - REM DO NOT EXIT and DO NOT SET EXIT_CODE to 1 - ) -) else ( - REM Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md - echo Running non-quarantined tests. - %DOTNET_ROOT%\dotnet vstest %$target% --logger:xunit --logger:"console;verbosity=normal" --blame --TestCaseFilter:%NONQUARANTINE_FILTER% - if errorlevel 1 ( - echo Failure in non-quarantined test 1>&2 - set exit_code=1 - REM DO NOT EXIT - ) -) - -echo "Copying TestResults\TestResults.xml to ." -copy TestResults\TestResults.xml testResults.xml -echo "Copying artifacts/logs to %HELIX_WORKITEM_UPLOAD_ROOT%\..\" -for /R artifacts/log %%f in (*.log) do ( - echo "Copying: %%f" - copy "%%f" %HELIX_WORKITEM_UPLOAD_ROOT%\..\ - copy "%%f" %HELIX_WORKITEM_UPLOAD_ROOT%\ +dotnet restore RunTests\RunTests.csproj --source https://api.nuget.org/v3/index.json --ignore-failed-sources +dotnet run --project RunTests\RunTests.csproj -- --target %1 --sdk %2 --runtime %3 --queue %4 --arch %5 --quarantined %6 --ef %7 +if errorlevel 1 ( + set exit_code=1 ) exit /b %exit_code% - diff --git a/eng/helix/content/runtests.sh b/eng/helix/content/runtests.sh index 26a9f45339..a8665ab51c 100755 --- a/eng/helix/content/runtests.sh +++ b/eng/helix/content/runtests.sh @@ -1,12 +1,7 @@ #!/usr/bin/env bash -test_binary_path="$1" dotnet_sdk_version="$2" dotnet_runtime_version="$3" -helix_queue_name="$4" -target_arch="$5" -quarantined="$6" -efVersion="$7" RESET="\033[0m" RED="\033[0;31m" @@ -30,19 +25,6 @@ export DOTNET_CLI_HOME="$DIR/.home$RANDOM" export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 -# Used by SkipOnHelix attribute -export helix="$helix_queue_name" -export HELIX_DIR="$DIR" -export NUGET_FALLBACK_PACKAGES="$DIR" -export DotNetEfFullPath=$DIR\nugetRestore\dotnet-ef\$efVersion\tools\netcoreapp3.1\any\dotnet-ef.dll -echo "Set DotNetEfFullPath: $DotNetEfFullPath" -export NUGET_RESTORE="$DIR/nugetRestore" -echo "Creating nugetRestore directory: $NUGET_RESTORE" -mkdir $NUGET_RESTORE -mkdir logs - -ls -laR - RESET="\033[0m" RED="\033[0;31m" YELLOW="\033[0;33m" @@ -93,35 +75,6 @@ if [ $? -ne 0 ]; then done fi -# Rename default.NuGet.config to NuGet.config if there is not a custom one from the project -if [ ! -f "NuGet.config" ] -then - cp default.NuGet.config NuGet.config -fi - -# Copy over any local shared fx if found -if [ -d "Microsoft.AspNetCore.App" ] -then - echo "Found Microsoft.AspNetCore.App directory, copying to $DOTNET_ROOT/shared/Microsoft.AspNetCore.App/$dotnet_runtime_version." - cp -r Microsoft.AspNetCore.App $DOTNET_ROOT/shared/Microsoft.AspNetCore.App/$dotnet_runtime_version - - echo "Adding current directory to nuget sources: $DIR" - dotnet nuget add source $DIR --configfile NuGet.config - dotnet nuget add source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json --configfile NuGet.config - dotnet nuget list source - - dotnet tool install dotnet-ef --global --version $efVersion - - # Ensure tools are on on PATH - export PATH="$PATH:$DOTNET_CLI_HOME/.dotnet/tools" -fi - -# Rename default.runner.json to xunit.runner.json if there is not a custom one from the project -if [ ! -f "xunit.runner.json" ] -then - cp default.runner.json xunit.runner.json -fi - if [ -e /proc/self/coredump_filter ]; then # Include memory in private and shared file-backed mappings in the dump. # This ensures that we can see disassembly from our shared libraries when @@ -129,40 +82,11 @@ if [ -e /proc/self/coredump_filter ]; then echo -n 0x3F > /proc/self/coredump_filter fi +# dontet-install.sh seems to affect the Linux filesystem and causes test flakiness unless we sync the filesystem before running tests sync -$DOTNET_ROOT/dotnet vstest $test_binary_path -lt >discovered.txt -if grep -q "Exception thrown" discovered.txt; then - echo -e "${RED}Exception thrown during test discovery${RESET}". - cat discovered.txt - exit 1 -fi - exit_code=0 +$DOTNET_ROOT/dotnet restore RunTests/RunTests.csproj --source https://api.nuget.org/v3/index.json --ignore-failed-sources +$DOTNET_ROOT/dotnet run --project RunTests/RunTests.csproj -- --target $1 --sdk $2 --runtime $3 --queue $4 --arch $5 --quarantined $6 --ef $7 -# Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md -NONQUARANTINE_FILTER="Quarantined!=true" -QUARANTINE_FILTER="Quarantined=true" -if [ "$quarantined" == true ]; then - echo "Running all tests including quarantined." - $DOTNET_ROOT/dotnet vstest $test_binary_path --logger:xunit --logger:"console;verbosity=normal" --blame --TestCaseFilter:"$QUARANTINE_FILTER" - if [ $? != 0 ]; then - echo "Quarantined tests failed!" 1>&2 - # DO NOT EXIT - fi -else - echo "Running non-quarantined tests." - $DOTNET_ROOT/dotnet vstest $test_binary_path --logger:xunit --logger:"console;verbosity=normal" --blame --TestCaseFilter:"$NONQUARANTINE_FILTER" - exit_code=$? - if [ $exit_code != 0 ]; then - echo "Non-quarantined tests failed!" 1>&2 - # DO NOT EXIT - fi -fi - -echo "Copying TestResults/TestResults to ." -cp TestResults/TestResults.xml testResults.xml -echo "Copying artifacts/logs to $HELIX_WORKITEM_UPLOAD_ROOT/" -cp `find . -name \*.log` $HELIX_WORKITEM_UPLOAD_ROOT/../ -cp `find . -name \*.log` $HELIX_WORKITEM_UPLOAD_ROOT/ -exit $exit_code +exit $? diff --git a/src/ProjectTemplates/test/Helpers/Project.cs b/src/ProjectTemplates/test/Helpers/Project.cs index 68642c48f4..64f21104c4 100644 --- a/src/ProjectTemplates/test/Helpers/Project.cs +++ b/src/ProjectTemplates/test/Helpers/Project.cs @@ -27,11 +27,11 @@ namespace Templates.Test.Helpers public static bool IsCIEnvironment => typeof(Project).Assembly.GetCustomAttributes() .Any(a => a.Key == "ContinuousIntegrationBuild"); - public static string ArtifactsLogDir => (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HELIX_DIR"))) + public static string ArtifactsLogDir => (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT"))) ? GetAssemblyMetadata("ArtifactsLogDir") - : Path.Combine(Environment.GetEnvironmentVariable("HELIX_DIR"), "logs"); - - public static string DotNetEfFullPath => (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath"))) + : Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT"); + + public static string DotNetEfFullPath => (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath"))) ? typeof(ProjectFactoryFixture).Assembly.GetCustomAttributes() .First(attribute => attribute.Key == "DotNetEfFullPath") .Value @@ -309,7 +309,7 @@ namespace Templates.Test.Helpers internal async Task RunDotNetEfCreateMigrationAsync(string migrationName) { var args = $"--verbose --no-build migrations add {migrationName}"; - + // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); @@ -324,7 +324,7 @@ namespace Templates.Test.Helpers { command = "dotnet-ef"; } - + var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); await result.Exited; return result; @@ -353,7 +353,7 @@ namespace Templates.Test.Helpers { command = "dotnet-ef"; } - + var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); await result.Exited; return result;