Ejemplo n.º 1
0
        public async Task <bool> InstallAspNetAppIfNeededAsync()
        {
            try
            {
                if (File.Exists(Options.AspNetRuntime))
                {
                    var appRuntimePath = $"{Options.DotnetRoot}/shared/Microsoft.AspNetCore.App/{Options.RuntimeVersion}";
                    Console.WriteLine($"Creating directory: {appRuntimePath}");
                    Directory.CreateDirectory(appRuntimePath);
                    Console.WriteLine($"Set ASPNET_RUNTIME_PATH: {appRuntimePath}");
                    EnvironmentVariables.Add("ASPNET_RUNTIME_PATH", appRuntimePath);
                    Console.WriteLine($"Found AspNetRuntime: {Options.AspNetRuntime}, extracting *.txt,json,dll to {appRuntimePath}");
                    using (var archive = ZipFile.OpenRead(Options.AspNetRuntime))
                    {
                        foreach (var entry in archive.Entries)
                        {
                            // These are the only extensions that end up in the shared fx directory
                            if (entry.Name.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) ||
                                entry.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ||
                                entry.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                            {
                                entry.ExtractToFile(Path.Combine(appRuntimePath, entry.Name), overwrite: true);
                            }
                        }
                    }

                    DisplayContents(appRuntimePath);

                    Console.WriteLine($"Adding current directory to nuget sources: {Options.HELIX_WORKITEM_ROOT}");

                    await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
                                               $"nuget add source {Options.HELIX_WORKITEM_ROOT} --configfile NuGet.config",
                                               environmentVariables : EnvironmentVariables,
                                               outputDataReceived : Console.WriteLine,
                                               errorDataReceived : Console.Error.WriteLine);

                    await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
                                               "nuget add source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json --configfile NuGet.config",
                                               environmentVariables : EnvironmentVariables,
                                               outputDataReceived : Console.WriteLine,
                                               errorDataReceived : Console.Error.WriteLine);

                    // Write nuget sources to console, useful for debugging purposes
                    await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
                                               "nuget list source",
                                               environmentVariables : EnvironmentVariables,
                                               outputDataReceived : Console.WriteLine,
                                               errorDataReceived : Console.Error.WriteLine);

                    await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
                                               $"tool install dotnet-ef --global --version {Options.EfVersion}",
                                               environmentVariables : EnvironmentVariables,
                                               outputDataReceived : Console.WriteLine,
                                               errorDataReceived : Console.Error.WriteLine,
                                               throwOnError : false); // EF tool is sometimes already installed so we can ignore this failure

                    // ';' is the path separator on Windows, and ':' on Unix
                    Options.Path += RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ";" : ":";
                    Options.Path += $"{Environment.GetEnvironmentVariable("DOTNET_CLI_HOME")}/.dotnet/tools";
                    EnvironmentVariables["PATH"] = Options.Path;
                }
                else
                {
                    Console.WriteLine($"No AspNetRuntime found: {Options.AspNetRuntime}, skipping...");
                }
                return(true);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception in InstallAspNetAppIfNeeded: {e.ToString()}");
                return(false);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Invoked when a timeout occurs and we need to dump all of the test processes and shut down
        /// the runnner.
        /// </summary>
        private static async Task HandleTimeout(Options options, CancellationToken cancellationToken)
        {
            async Task DumpProcess(Process targetProcess, string procDumpExeFilePath, string dumpFilePath)
            {
                var name = targetProcess.ProcessName;

                // Our space for saving dump files is limited. Skip dumping for processes that won't contribute
                // to bug investigations.
                if (name == "procdump" || name == "conhost")
                {
                    return;
                }

                ConsoleUtil.Write($"Dumping {name} {targetProcess.Id} to {dumpFilePath} ... ");
                try
                {
                    var args          = $"-accepteula -ma {targetProcess.Id} {dumpFilePath}";
                    var processInfo   = ProcessRunner.CreateProcess(procDumpExeFilePath, args, cancellationToken: cancellationToken);
                    var processOutput = await processInfo.Result;

                    // The exit code for procdump doesn't obey standard windows rules.  It will return non-zero
                    // for successful cases (possibly returning the count of dumps that were written).  Best
                    // backup is to test for the dump file being present.
                    if (File.Exists(dumpFilePath))
                    {
                        ConsoleUtil.WriteLine($"succeeded ({new FileInfo(dumpFilePath).Length} bytes)");
                    }
                    else
                    {
                        ConsoleUtil.WriteLine($"FAILED with {processOutput.ExitCode}");
                        ConsoleUtil.WriteLine($"{procDumpExeFilePath} {args}");
                        ConsoleUtil.WriteLine(string.Join(Environment.NewLine, processOutput.OutputLines));
                    }
                }
                catch (Exception ex) when(!cancellationToken.IsCancellationRequested)
                {
                    ConsoleUtil.WriteLine("FAILED");
                    ConsoleUtil.WriteLine(ex.Message);
                    Logger.Log("Failed to dump process", ex);
                }
            }

            ConsoleUtil.WriteLine("Roslyn Error: test timeout exceeded, dumping remaining processes");
            var procDumpInfo = GetProcDumpInfo(options);

            if (procDumpInfo != null)
            {
                var counter = 0;
                foreach (var proc in ProcessUtil.GetProcessTree(Process.GetCurrentProcess()).OrderBy(x => x.ProcessName))
                {
                    var dumpDir = PrimaryProcessNames.Contains(proc.ProcessName)
                        ? procDumpInfo.Value.DumpDirectory
                        : procDumpInfo.Value.SecondaryDumpDirectory;
                    var dumpFilePath = Path.Combine(dumpDir, $"{proc.ProcessName}-{counter}.dmp");
                    await DumpProcess(proc, procDumpInfo.Value.ProcDumpFilePath, dumpFilePath);

                    counter++;
                }
            }
            else
            {
                ConsoleUtil.WriteLine("Could not locate procdump");
            }

            WriteLogFile(options);
        }
Ejemplo n.º 3
0
        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 <string>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--sdk" },
                    description: "The version of the sdk being used")
                {
                    Argument = new Argument <string>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--runtime" },
                    description: "The version of the runtime being used")
                {
                    Argument = new Argument <string>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--queue" },
                    description: "The name of the Helix queue being run on")
                {
                    Argument = new Argument <string>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--arch" },
                    description: "The architecture being run on")
                {
                    Argument = new Argument <string>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--quarantined" },
                    description: "Whether quarantined tests should run or not")
                {
                    Argument = new Argument <bool>(), Required = true
                },

                new Option(
                    aliases: new string[] { "--ef" },
                    description: "The version of the EF tool to use")
                {
                    Argument = new Argument <string>(), Required = true
                },
            };

            var parseResult    = command.Parse(args);
            var target         = parseResult.ValueForOption <string>("--target");
            var sdkVersion     = parseResult.ValueForOption <string>("--sdk");
            var runtimeVersion = parseResult.ValueForOption <string>("--runtime");
            var helixQueue     = parseResult.ValueForOption <string>("--queue");
            var architecture   = parseResult.ValueForOption <string>("--arch");
            var quarantined    = parseResult.ValueForOption <bool>("--quarantined");
            var efVersion      = parseResult.ValueForOption <string>("--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 <string, string>();

            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);
        }