Merge in 'release/6.0.1xx' changes

This commit is contained in:
dotnet-bot 2022-03-03 14:14:15 +00:00
commit a2f5d4b03a
27 changed files with 675 additions and 651 deletions

View file

@ -91,12 +91,12 @@ steps:
cp $(Build.SourcesDirectory)/NuGet.config ${{ parameters.tarballDir }}/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/smoke-tests/online.NuGet.Config
dockerVolumeArgs="-v ${{ parameters.tarballDir }}:/tarball"
dockerEnvArgs="-e EXCLUDE_OMNISHARP_TESTS=${{ parameters.excludeOmniSharpTests}}"
dockerEnvArgs="-e SMOKE_TESTS_EXCLUDE_OMNISHARP=${{ parameters.excludeOmniSharpTests}}"
if [[ '${{ parameters.isBootstrapped }}' != 'true' && '${{ parameters.installerBuildResourceId }}' != 'current' ]]; then
dockerVolumeArgs+=" -v $(PIPELINE.WORKSPACE)/${{ parameters.installerBuildResourceId }}/BlobArtifacts/:/BlobArtifacts"
msftSdkTarballName=$(find "$(PIPELINE.WORKSPACE)/${{ parameters.installerBuildResourceId }}/BlobArtifacts/" -name "dotnet-sdk-*-${{ parameters.Platform }}-${{ parameters.buildArch }}.tar.gz" -exec basename {} \;)
dockerEnvArgs+=" -e MSFT_SDK_TARBALL_PATH=/BlobArtifacts/$msftSdkTarballName"
dockerEnvArgs+=" -e SMOKE_TESTS_MSFT_SDK_TARBALL_PATH=/BlobArtifacts/$msftSdkTarballName"
fi
docker run --rm $dockerVolumeArgs -w /tarball $dockerEnvArgs ${{ parameters.container }} ./build.sh --run-smoke-test ${{ parameters.additionalBuildArgs }}
@ -115,7 +115,7 @@ steps:
find artifacts/prebuilt-report/ -exec cp {} --parents -t ${targetFolder} \;
find src/ -type f -name "*.binlog" -exec cp {} --parents -t ${targetFolder} \;
find src/ -type f -name "*.log" -exec cp {} --parents -t ${targetFolder} \;
find test/*/*/*/*/*/*/testing-smoke*/logs -exec cp {} --parents -t ${targetFolder} \;
find test/ -type f -name "*.binlog" -exec cp {} --parents -t ${targetFolder} \;
displayName: Prepare BuildLogs staging directory
continueOnError: true
condition: succeededOrFailed()

View file

@ -159,6 +159,7 @@
<BaselineDataFile>$(ToolsLocalDir)prebuilt-baseline.xml</BaselineDataFile>
<!--Exclude tests that are failing for test enabled projects like - corefx -->
<TestExclusionsDir>$(ProjectDir)test/exclusions/</TestExclusionsDir>
<SmokeTestsDir>$(ProjectDir)test/Microsoft.DotNet.SourceBuild.SmokeTests/</SmokeTestsDir>
</PropertyGroup>
<!-- Import Build tools common props file where repo-independent properties are found -->

View file

@ -95,10 +95,10 @@
<SdkTarballPath>%(SdkTarballItem.Identity)</SdkTarballPath>
</PropertyGroup>
<Exec Command="$(DotnetToolCommand) test ./test/Microsoft.DotNet.SourceBuild.SmokeTests --logger:trx -c $(Configuration)"
<Exec Command="$(DotnetToolCommand) test $(SmokeTestsDir) --logger:trx -c $(Configuration)"
EnvironmentVariables="
DOTNET_TARBALL_PATH=$(SdkTarballPath);
TARGET_RID=$(TargetRid);
SMOKE_TESTS_SDK_TARBALL_PATH=$(SdkTarballPath);
SMOKE_TESTS_TARGET_RID=$(TargetRid);
" />
</Target>
@ -110,21 +110,30 @@
CreateCreateSmokeTestPrereqsTarballIfPrereqsExist"/>
<Target Name="CheckIfCreateSmokeTestPrereqsExistToPack">
<PropertyGroup>
<SmokeTestsArtifactsDir>$(SmokeTestsDir)bin/$(Configuration)/net6.0/</SmokeTestsArtifactsDir>
<SmokeTestsPackagesDir>$(SmokeTestsArtifactsDir)packages/</SmokeTestsPackagesDir>
</PropertyGroup>
<ItemGroup>
<Prereqs Include="test/Microsoft.DotNet.SourceBuild.SmokeTests/bin/$(Configuration)/net6.0/smoke-tests/prereq-packages/**" />
<SmokeTestsPrereqs Include="$(SmokeTestsPackagesDir)**/*.nupkg" />
</ItemGroup>
<Message Text="Found @(Prereqs->Count()) files in prereqs packages dir." Importance="High" />
<Message Text="Found @(SmokeTestsPrereqs->Count()) prereqs in '$(SmokeTestsPackagesDir)'." Importance="High" />
</Target>
<Target Name="CreateCreateSmokeTestPrereqsTarballIfPrereqsExist"
Condition="'@(Prereqs->Count())' != '0'">
Condition="'@(SmokeTestsPrereqs->Count())' != '0'">
<PropertyGroup>
<SmokeTestPrereqsTarballName>$(OutputPath)dotnet-smoke-test-prereqs.$(installerOutputPackageVersion).tar.gz</SmokeTestPrereqsTarballName>
<SmokeTestsPrereqPackagesDir>$(SmokeTestsArtifactsDir)prereq-packages/</SmokeTestsPrereqPackagesDir>
</PropertyGroup>
<Copy SourceFiles="@(SmokeTestsPrereqs)"
DestinationFolder="$(SmokeTestsPrereqPackagesDir)" />
<Exec Command="tar --numeric-owner -czf $(SmokeTestPrereqsTarballName) ."
WorkingDirectory="./test/Microsoft.DotNet.SourceBuild.SmokeTests/bin/$(Configuration)/net6.0/assets/smoke-tests/prereq-packages/"/>
WorkingDirectory="$(SmokeTestsPrereqPackagesDir)"/>
<Message Importance="High" Text="Packaged smoke-test prereqs in '$(SmokeTestPrereqsTarballName)'" />
</Target>

View file

@ -0,0 +1,39 @@
// 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.Linq;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
/// <summary>
/// Basic project create, build, run, publish scenario tests.
/// <see cref="WebScenarioTests"/> for related web scenarios.
/// They are encapsulated in a separate testclass so that they can be run in parallel.
/// </summary>
public class BasicScenarioTests : SmokeTests
{
public BasicScenarioTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
[Theory]
[MemberData(nameof(GetScenarioObjects))]
public void VerifyScenario(TestScenario scenario) => scenario.Execute(DotNetHelper);
private static IEnumerable<object[]> GetScenarioObjects() => GetScenarios().Select(scenario => new object[] { scenario });
private static IEnumerable<TestScenario> GetScenarios()
{
foreach (DotNetLanguage language in Enum.GetValues<DotNetLanguage>())
{
yield return new(nameof(BasicScenarioTests), language, DotNetTemplate.Console, DotNetActions.Build | DotNetActions.Run | DotNetActions.PublishComplex | DotNetActions.PublishR2R);
yield return new(nameof(BasicScenarioTests), language, DotNetTemplate.ClassLib, DotNetActions.Build | DotNetActions.Publish);
yield return new(nameof(BasicScenarioTests), language, DotNetTemplate.XUnit, DotNetActions.Test);
yield return new(nameof(BasicScenarioTests), language, DotNetTemplate.NUnit, DotNetActions.Test);
yield return new(nameof(BasicScenarioTests), language, DotNetTemplate.MSTest, DotNetActions.Test);
}
}
}

View file

@ -9,15 +9,18 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests;
internal static class Config
{
public static string DotNetDirectory { get; } =
Environment.GetEnvironmentVariable("DOTNET_DIR") ?? Path.Combine(Directory.GetCurrentDirectory(), ".dotnet");
public static string DotNetTarballPath { get; } = Environment.GetEnvironmentVariable(DotNetTarballPathEnv) ?? string.Empty;
public const string DotNetTarballPathEnv = "DOTNET_TARBALL_PATH";
public static bool ExcludeOmniSharpTests { get; } =
bool.TryParse(Environment.GetEnvironmentVariable("EXCLUDE_OMNISHARP_TESTS"), out bool excludeOmniSharpTests) ? excludeOmniSharpTests : false;
public static bool ExcludeOnlineTests { get; } =
bool.TryParse(Environment.GetEnvironmentVariable("EXCLUDE_ONLINE_TESTS"), out bool excludeOnlineTests) ? excludeOnlineTests : false;
public static string MsftSdkTarballPath { get; } = Environment.GetEnvironmentVariable(MsftSdkTarballPathEnv) ?? string.Empty;
public const string MsftSdkTarballPathEnv = "MSFT_SDK_TARBALL_PATH";
public static string TargetRid { get; } = Environment.GetEnvironmentVariable("TARGET_RID") ?? string.Empty;
public const string DotNetDirectoryEnv = "SMOKE_TESTS_DOTNET_DIR";
public const string ExcludeOmniSharpEnv = "SMOKE_TESTS_EXCLUDE_OMNISHARP";
public const string MsftSdkTarballPathEnv = "SMOKE_TESTS_MSFT_SDK_TARBALL_PATH";
public const string PrereqsPathEnv = "SMOKE_TESTS_PREREQS_PATH";
public const string SdkTarballPathEnv = "SMOKE_TESTS_SDK_TARBALL_PATH";
public const string TargetRidEnv = "SMOKE_TESTS_TARGET_RID";
public static string DotNetDirectory { get; } =
Environment.GetEnvironmentVariable(DotNetDirectoryEnv) ?? Path.Combine(Directory.GetCurrentDirectory(), ".dotnet");
public static string? MsftSdkTarballPath { get; } = Environment.GetEnvironmentVariable(MsftSdkTarballPathEnv);
public static string? PrereqsPath { get; } = Environment.GetEnvironmentVariable(PrereqsPathEnv);
public static string? SdkTarballPath { get; } = Environment.GetEnvironmentVariable(SdkTarballPathEnv);
public static string TargetRid { get; } = Environment.GetEnvironmentVariable(TargetRidEnv) ??
throw new InvalidOperationException($"'{Config.TargetRidEnv}' must be specified");
}

View file

@ -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.
using System;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
[Flags]
public enum DotNetActions
{
None = 0,
Build = 1,
Run = 2,
RunWeb = 4,
Publish = 8,
PublishComplex = 16,
PublishR2R = 32,
Test = 64,
}

View file

@ -8,19 +8,12 @@ using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
public class DotNetFormatTests
public class DotNetFormatTests : SmokeTests
{
private const string UnformattedFileName = "FormatTestUnformatted.cs";
private const string ExpectedFormattedFileName = "FormatTestExpectedFormatted.cs";
private ITestOutputHelper OutputHelper { get; }
private DotNetHelper DotNetHelper { get; }
public DotNetFormatTests(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
DotNetHelper = new DotNetHelper(outputHelper);
}
public DotNetFormatTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
/// <Summary>
/// Format an unformatted project and verify that the output matches the pre-computed solution.
@ -33,14 +26,14 @@ public class DotNetFormatTests
string unformattedCsFilePath = Path.Combine(assetsDirectory, UnformattedFileName);
string expectedFormattedCsFilePath = Path.Combine(assetsDirectory, ExpectedFormattedFileName);
string projectDirectory = DotNetHelper.ExecuteNew("console", "C#", nameof(FormatProject), OutputHelper);
string projectDirectory = DotNetHelper.ExecuteNew("console", nameof(FormatProject), "C#");
string projectFilePath = Path.Combine(projectDirectory, nameof(FormatProject) + ".csproj");
string formattedCsFilePath = Path.Combine(projectDirectory, UnformattedFileName);
File.Copy(unformattedCsFilePath, formattedCsFilePath);
DotNetHelper.ExecuteCmd($"format {projectFilePath}", OutputHelper);
DotNetHelper.ExecuteCmd($"format {projectFilePath}");
BaselineHelper.CompareFiles(expectedFormattedCsFilePath, formattedCsFilePath, OutputHelper);
}

View file

@ -12,46 +12,199 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests;
internal class DotNetHelper
{
private static readonly object s_lockObj = new object();
private static readonly string s_timestamp = DateTime.Now.ToString("yyyyMMddHHmmssffff");
private static readonly object s_lockObj = new();
public string DotNetPath { get; }
public static string DotNetPath { get; } = Path.Combine(Config.DotNetDirectory, "dotnet");
public static string LogsDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "logs");
public static string PackagesDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "packages");
public static string ProjectsDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), $"projects-{DateTime.Now:yyyyMMddHHmmssffff}");
private ITestOutputHelper OutputHelper { get; }
public DotNetHelper(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
lock (s_lockObj)
{
if (!Directory.Exists(Config.DotNetDirectory))
{
if (!File.Exists(Config.DotNetTarballPath))
if (!File.Exists(Config.SdkTarballPath))
{
throw new InvalidOperationException($"Tarball path '{Config.DotNetTarballPath}' specified in {Config.DotNetTarballPathEnv} does not exist.");
throw new InvalidOperationException($"Tarball path '{Config.SdkTarballPath}' specified in {Config.SdkTarballPath} does not exist.");
}
Directory.CreateDirectory(Config.DotNetDirectory);
ExecuteHelper.ExecuteProcessValidateExitCode("tar", $"xzf {Config.DotNetTarballPath} -C {Config.DotNetDirectory}", outputHelper);
ExecuteHelper.ExecuteProcessValidateExitCode("tar", $"xzf {Config.SdkTarballPath} -C {Config.DotNetDirectory}", outputHelper);
}
if (!Directory.Exists(ProjectsDirectory))
{
Directory.CreateDirectory(ProjectsDirectory);
InitNugetConfig();
}
if (!Directory.Exists(PackagesDirectory))
{
Directory.CreateDirectory(PackagesDirectory);
}
if (!Directory.Exists(LogsDirectory))
{
Directory.CreateDirectory(LogsDirectory);
}
}
DotNetPath = Path.Combine(Config.DotNetDirectory, "dotnet");
}
public void ExecuteCmd(string args, ITestOutputHelper outputHelper)
private static void InitNugetConfig()
{
(Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess(DotNetPath, args, outputHelper);
bool useLocalPackages = !string.IsNullOrEmpty(Config.PrereqsPath);
string nugetConfigPrefix = useLocalPackages ? "local" : "online";
string nugetConfigPath = Path.Combine(ProjectsDirectory, "NuGet.Config");
File.Copy(
Path.Combine(BaselineHelper.GetAssetsDirectory(), $"{nugetConfigPrefix}.NuGet.Config"),
nugetConfigPath);
Assert.Equal(0, executeResult.Process.ExitCode);
if (useLocalPackages)
{
if (!Directory.Exists(Config.PrereqsPath))
{
throw new InvalidOperationException(
$"Prereqs path '{Config.PrereqsPath}' specified in {Config.PrereqsPathEnv} does not exist.");
}
string nugetConfig = File.ReadAllText(nugetConfigPath);
nugetConfig = nugetConfig.Replace("SMOKE_TEST_PACKAGE_FEED", Config.PrereqsPath);
File.WriteAllText(nugetConfigPath, nugetConfig);
}
}
public void ExecuteCmd(string args, string? workingDirectory = null)
{
(Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess(
DotNetPath,
args,
OutputHelper,
configure: (process) => ConfigureProcess(process, workingDirectory));
ExecuteHelper.ValidateExitCode(executeResult);
}
public static void ConfigureProcess(Process process, string? workingDirectory, bool setPath = false)
{
if (workingDirectory != null)
{
process.StartInfo.WorkingDirectory = workingDirectory;
}
process.StartInfo.EnvironmentVariables["DOTNET_CLI_TELEMETRY_OPTOUT"] = "1";
process.StartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "1";
process.StartInfo.EnvironmentVariables["DOTNET_ROOT"] = Config.DotNetDirectory;
process.StartInfo.EnvironmentVariables["NUGET_PACKAGES"] = PackagesDirectory;
if (setPath)
{
process.StartInfo.EnvironmentVariables["PATH"] = $"{Config.DotNetDirectory}:{Environment.GetEnvironmentVariable("PATH")}";
}
}
public void ExecuteBuild(string projectName) =>
ExecuteCmd($"build {GetBinLogOption(projectName, "build")}", GetProjectDirectory(projectName));
/// <summary>
/// Create a new .NET project and return the path to the created project folder.
/// </summary>
public string ExecuteNew(string projectType, string language, string name, ITestOutputHelper outputHelper)
public string ExecuteNew(string projectType, string name, string? language = null, string? customArgs = null)
{
string outputDirectory = Path.Combine(Directory.GetCurrentDirectory(), $"projects-{s_timestamp}", name);
string projectDirectory = GetProjectDirectory(name);
string options = $"--name {name} --output {projectDirectory}";
if (language != null)
{
options += $" --language \"{language}\"";
}
if (string.IsNullOrEmpty(customArgs))
{
options += $" {customArgs}";
}
ExecuteCmd($"new {projectType} --language \"{language}\" --name {name} --output {outputDirectory}", outputHelper);
ExecuteCmd($"new {projectType} {options}");
return outputDirectory;
return projectDirectory;
}
public void ExecutePublish(string projectName, bool? selfContained = null, string? rid = null, bool trimmed = false, bool readyToRun = false)
{
string options = string.Empty;
string binlogDifferentiator = string.Empty;
if (selfContained.HasValue)
{
options += $"--self-contained {selfContained.Value.ToString().ToLowerInvariant()}";
if (selfContained.Value)
{
binlogDifferentiator += "self-contained";
if (!string.IsNullOrEmpty(rid))
{
options += $" -r {rid}";
binlogDifferentiator += $"-{rid}";
}
if (trimmed)
{
options += " /p:PublishTrimmed=true";
binlogDifferentiator += "-trimmed";
}
if (readyToRun)
{
options += " /p:PublishReadyToRun=true";
binlogDifferentiator += "-R2R";
}
}
}
ExecuteCmd(
$"publish {options} {GetBinLogOption(projectName, "publish", binlogDifferentiator)}",
GetProjectDirectory(projectName));
}
public void ExecuteRun(string projectName) =>
ExecuteCmd($"run {GetBinLogOption(projectName, "run")}", GetProjectDirectory(projectName));
public void ExecuteRunWeb(string projectName)
{
(Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess(
DotNetPath,
$"run {GetBinLogOption(projectName, "run")}",
OutputHelper,
configure: configureProcess,
millisecondTimeout: 30000);
ExecuteHelper.ValidateExitCode(executeResult);
void configureProcess(Process process)
{
ConfigureProcess(process, GetProjectDirectory(projectName));
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
if (e.Data?.Contains("Application started. Press Ctrl+C to shut down.") ?? false)
{
ExecuteHelper.ExecuteProcessValidateExitCode("kill", $"-s TERM {process.Id}", OutputHelper);
}
});
}
}
public void ExecuteTest(string projectName) =>
ExecuteCmd($"test {GetBinLogOption(projectName, "test")}", GetProjectDirectory(projectName));
private static string GetBinLogOption(string projectName, string command, string? differentiator = null)
{
string fileName = $"{projectName}-{command}";
if (!string.IsNullOrEmpty(differentiator))
{
fileName += $"-{differentiator}";
}
return $"/bl:{Path.Combine(LogsDirectory, $"{fileName}.binlog")}";
}
private static string GetProjectDirectory(string projectName) => Path.Combine(ProjectsDirectory, projectName);
}

View file

@ -0,0 +1,12 @@
// 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 Microsoft.DotNet.SourceBuild.SmokeTests;
public enum DotNetLanguage
{
CSharp,
FSharp,
VB
}

View file

@ -0,0 +1,18 @@
// 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;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
public static class DotNetLanguageExtensions
{
public static string ToCliName(this DotNetLanguage language) => language switch
{
DotNetLanguage.CSharp => "C#",
DotNetLanguage.FSharp => "F#",
DotNetLanguage.VB => "VB",
_ => throw new NotImplementedException()
};
}

View file

@ -0,0 +1,23 @@
// 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 Microsoft.DotNet.SourceBuild.SmokeTests;
public enum DotNetTemplate
{
Console,
ClassLib,
XUnit,
NUnit,
MSTest,
Web,
Mvc,
Razor,
BlazorWasm,
BlazorServer,
WebApi,
WebApp,
Worker,
Angular,
}

View file

@ -0,0 +1,22 @@
// 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;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
public static class DotNetTemplateExtensions
{
public static string GetName(this DotNetTemplate template) => Enum.GetName(template)?.ToLowerInvariant() ?? throw new NotSupportedException();
public static bool IsAspNetCore(this DotNetTemplate template) =>
template == DotNetTemplate.Web
|| template == DotNetTemplate.Mvc
|| template == DotNetTemplate.WebApi
|| template == DotNetTemplate.Razor
|| template == DotNetTemplate.BlazorWasm
|| template == DotNetTemplate.BlazorServer
|| template == DotNetTemplate.Worker
|| template == DotNetTemplate.Angular;
}

View file

@ -13,7 +13,12 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests;
internal static class ExecuteHelper
{
public static (Process Process, string StdOut, string StdErr) ExecuteProcess(
string fileName, string args, ITestOutputHelper outputHelper, bool logOutput = false)
string fileName,
string args,
ITestOutputHelper outputHelper,
bool logOutput = false,
Action<Process>? configure = null,
int millisecondTimeout = -1)
{
outputHelper.WriteLine($"Executing: {fileName} {args}");
@ -36,6 +41,8 @@ internal static class ExecuteHelper
process.StartInfo.Environment.Remove(key);
}
configure?.Invoke(process);
StringBuilder stdOutput = new();
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) => stdOutput.AppendLine(e.Data));
@ -45,7 +52,14 @@ internal static class ExecuteHelper
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
process.WaitForExit(millisecondTimeout);
if (!process.HasExited)
{
outputHelper.WriteLine($"Killing: {fileName} {args}");
process.Kill(true);
process.WaitForExit();
}
string output = stdOutput.ToString().Trim();
if (logOutput && !string.IsNullOrWhiteSpace(output))
@ -65,16 +79,21 @@ internal static class ExecuteHelper
public static string ExecuteProcessValidateExitCode(string fileName, string args, ITestOutputHelper outputHelper)
{
(Process Process, string StdOut, string StdErr) result = ExecuteHelper.ExecuteProcess(fileName, args, outputHelper);
ValidateExitCode(result);
return result.StdOut;
}
public static void ValidateExitCode((Process Process, string StdOut, string StdErr) result)
{
if (result.Process.ExitCode != 0)
{
ProcessStartInfo startInfo = result.Process.StartInfo;
string msg = $"Failed to execute {startInfo.FileName} {startInfo.Arguments}" +
$"{Environment.NewLine}Exit code: {result.Process.ExitCode}" +
$"{Environment.NewLine}Standard Error: {result.StdErr}";
$"{Environment.NewLine}{result.StdOut}" +
$"{Environment.NewLine}{result.StdErr}";
throw new InvalidOperationException(msg);
}
return result.StdOut;
}
}

View file

@ -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.
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
internal static class HttpClientExtensions
{
public static async Task DownloadFileAsync(this HttpClient client, Uri uri, string path)
{
using Stream stream = await client.GetStreamAsync(uri);
using FileStream fileStream = new(path, FileMode.OpenOrCreate);
await stream.CopyToAsync(fileStream);
}
}

View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.SourceBuild.SmokeTests", "Microsoft.DotNet.SourceBuild.SmokeTests.csproj", "{FEB5A0B5-460B-432A-BED8-243557188AFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FEB5A0B5-460B-432A-BED8-243557188AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEB5A0B5-460B-432A-BED8-243557188AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEB5A0B5-460B-432A-BED8-243557188AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEB5A0B5-460B-432A-BED8-243557188AFF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {75929D76-EEB5-4793-8335-DF623CC72B56}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,71 @@
// 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.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
/// <summary>
/// OmniSharp tests to ensure it works with a source-built sdk.
/// </summary>
public class OmniSharpTests : SmokeTests
{
private string OmniSharpDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "omnisharp");
public OmniSharpTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
[SkippableTheory(Config.ExcludeOmniSharpEnv, skipOnTrue: true)]
[InlineData(DotNetTemplate.BlazorWasm)]
[InlineData(DotNetTemplate.BlazorServer)]
[InlineData(DotNetTemplate.ClassLib)]
[InlineData(DotNetTemplate.Console)]
[InlineData(DotNetTemplate.MSTest)]
[InlineData(DotNetTemplate.Mvc)]
[InlineData(DotNetTemplate.NUnit)]
[InlineData(DotNetTemplate.Web)]
[InlineData(DotNetTemplate.WebApp)]
[InlineData(DotNetTemplate.WebApi)]
[InlineData(DotNetTemplate.Worker)]
[InlineData(DotNetTemplate.XUnit)]
public async void VerifyScenario(DotNetTemplate template)
{
await InitializeOmniSharp();
string templateName = template.GetName();
string projectName = $"{nameof(OmniSharpTests)}_{templateName}";
string projectDirectory = DotNetHelper.ExecuteNew(templateName, projectName);
(Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess(
Path.Combine(OmniSharpDirectory, "run"),
$"-s {projectDirectory}",
OutputHelper,
logOutput: true,
millisecondTimeout: 5000,
configure: (process) => DotNetHelper.ConfigureProcess(process, projectDirectory, setPath: true));
Assert.NotEqual(0, executeResult.Process.ExitCode);
Assert.DoesNotContain("ERROR", executeResult.StdOut);
Assert.DoesNotContain("ERROR", executeResult.StdErr);
}
private async Task InitializeOmniSharp()
{
if (!Directory.Exists(OmniSharpDirectory))
{
using HttpClient client = new();
string omniSharpTarballFile = "omnisharp-linux-x64.tar.gz";
Uri omniSharpTarballUrl = new($"https://github.com/OmniSharp/omnisharp-roslyn/releases/latest/download/{omniSharpTarballFile}");
await client.DownloadFileAsync(omniSharpTarballUrl, omniSharpTarballFile);
Directory.CreateDirectory(OmniSharpDirectory);
ExecuteHelper.ExecuteProcessValidateExitCode("tar", $"xzf {omniSharpTarballFile} -C {OmniSharpDirectory}", OutputHelper);
}
}
}

View file

@ -4,6 +4,7 @@
* Various configuration settings are stored in `Config.cs`
## Prereq Packages
Some prerelease scenarios, usually security updates, require non-source-built packages which are not publicly available.
Place these packages in the tarball's `packages/smoke-test-prereqs`. When prereq packages are required, the
`EXCLUDE_ONLINE_TESTS=true` environment variable should be set when running tests via `build.sh --run-smoke-test`.
Specify the directory where these packages can be found via the `SMOKE_TESTS_PREREQS_PATH` environment variable when running tests via `build.sh --run-smoke-test` e.g.
`SMOKE_TESTS_PREREQS_PATH=packages/smoke-test-prereqs`.

View file

@ -7,21 +7,13 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
public class SdkContentTests
public class SdkContentTests : SmokeTests
{
private ITestOutputHelper OutputHelper { get; }
private DotNetHelper DotNetHelper { get; }
public SdkContentTests(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
DotNetHelper = new DotNetHelper(outputHelper);
}
public SdkContentTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
/// <Summary>
/// Verifies the file layout of the source built sdk tarball to the Microsoft build.
@ -30,24 +22,13 @@ public class SdkContentTests
/// This makes the baseline durable between releases. This does mean however, entries
/// in the baseline may appear identical if the diff is version specific.
/// </Summary>
[Fact]
[SkippableFact(new[] { Config.MsftSdkTarballPathEnv, Config.MsftSdkTarballPathEnv }, skipOnNullOrWhiteSpace: true)]
public void CompareMsftToSb()
{
if (string.IsNullOrWhiteSpace(Config.MsftSdkTarballPath))
{
OutputHelper.WriteLine($"skipping {nameof(CompareMsftToSb)} because {Config.MsftSdkTarballPathEnv} was not specified.");
return;
}
if (!File.Exists(Config.MsftSdkTarballPath))
{
throw new InvalidOperationException($"Tarball path '{Config.MsftSdkTarballPath}' specified in {Config.MsftSdkTarballPathEnv} does not exist.");
}
const string msftFileListingFileName = "msftSdkFiles.txt";
const string sbFileListingFileName = "sbSdkFiles.txt";
WriteTarballFileList(Config.MsftSdkTarballPath, msftFileListingFileName);
WriteTarballFileList(Config.DotNetTarballPath, sbFileListingFileName);
WriteTarballFileList(Config.SdkTarballPath, sbFileListingFileName);
string diff = BaselineHelper.DiffFiles(msftFileListingFileName, sbFileListingFileName, OutputHelper);
diff = RemoveVersionedPaths(diff);
@ -56,8 +37,13 @@ public class SdkContentTests
BaselineHelper.CompareContents("MsftToSbSdk.diff", diff, OutputHelper);
}
private void WriteTarballFileList(string tarballPath, string outputFileName)
private void WriteTarballFileList(string? tarballPath, string outputFileName)
{
if (!File.Exists(tarballPath))
{
throw new InvalidOperationException($"Tarball path '{tarballPath}' does not exist.");
}
string fileListing = ExecuteHelper.ExecuteProcessValidateExitCode("tar", $"tf {tarballPath}", OutputHelper);
IEnumerable<string> files = fileListing.Split(Environment.NewLine).OrderBy(path => path);
File.WriteAllLines(outputFileName, files);
@ -72,7 +58,7 @@ public class SdkContentTests
return diffSegmentRegex.Replace(result, "@@ ------------ @@");
}
private string RemoveRids(string diff) => diff.Replace(Config.TargetRid, "bannana.rid");
private static string RemoveRids(string diff) => diff.Replace(Config.TargetRid, "banana.rid");
private static string RemoveVersionedPaths(string source)
{

View file

@ -0,0 +1,40 @@
// 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 Xunit;
namespace Microsoft.DotNet.SourceBuild.SmokeTests
{
/// <summary>
/// A Fact that will be skipped based on the specified environment variable's value.
/// </summary>
internal class SkippableFactAttribute : FactAttribute
{
public SkippableFactAttribute(string envName, bool skipOnNullOrWhiteSpace = false, bool skipOnTrue = false) =>
CheckEnvs(skipOnNullOrWhiteSpace, skipOnTrue, (skip) => Skip = skip, envName);
public SkippableFactAttribute(string[] envNames, bool skipOnNullOrWhiteSpace = false, bool skipOnTrue = false) =>
CheckEnvs(skipOnNullOrWhiteSpace, skipOnTrue, (skip) => Skip = skip, envNames);
public static void CheckEnvs(bool skipOnNullOrWhiteSpace, bool skipOnTrue, Action<string> setSkip, params string[] envNames)
{
foreach (string envName in envNames)
{
string? envValue = Environment.GetEnvironmentVariable(envName);
if (skipOnNullOrWhiteSpace && string.IsNullOrWhiteSpace(envValue))
{
setSkip($"Skipping because `{envName}` is null or whitespace");
break;
}
else if (skipOnTrue && bool.TryParse(envValue, out bool boolValue) && boolValue)
{
setSkip($"Skipping because `{envName}` is set to True");
break;
}
}
}
}
}

View file

@ -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.
using Xunit;
namespace Microsoft.DotNet.SourceBuild.SmokeTests
{
/// <summary>
/// A Theory that will be skipped based on the specified environment variable's value.
/// </summary>
internal class SkippableTheoryAttribute : TheoryAttribute
{
public SkippableTheoryAttribute(string envName, bool skipOnNullOrWhiteSpace = false, bool skipOnTrue = false) =>
SkippableFactAttribute.CheckEnvs(skipOnNullOrWhiteSpace, skipOnTrue, (skip) => Skip = skip, envName);
public SkippableTheoryAttribute(string[] envNames, bool skipOnNullOrWhiteSpace = false, bool skipOnTrue = false) =>
SkippableFactAttribute.CheckEnvs(skipOnNullOrWhiteSpace, skipOnTrue, (skip) => Skip = skip, envNames);
}
}

View file

@ -1,45 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Diagnostics;
using System.IO;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
// This test suite invokes the smoke-test.sh which should be considered legacy. Those tests should be migrated to this test suite overtime.
public class SmokeTests
/// <summary>
/// Shared base class for all smoke tests.
/// </summary>
public abstract class SmokeTests
{
private ITestOutputHelper OutputHelper { get; }
private DotNetHelper DotNetHelper { get; }
internal DotNetHelper DotNetHelper { get; }
internal ITestOutputHelper OutputHelper { get; }
public SmokeTests(ITestOutputHelper outputHelper)
protected SmokeTests(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
DotNetHelper = new DotNetHelper(outputHelper);
}
[Fact]
public void SmokeTestsScript()
{
string smokeTestArgs = $"--dotnetDir {Directory.GetParent(DotNetHelper.DotNetPath)} --projectOutput --archiveRestoredPackages --targetRid {Config.TargetRid}";
if (Config.TargetRid.Contains("osx"))
{
smokeTestArgs += " --excludeWebHttpsTests";
}
if (Config.ExcludeOmniSharpTests)
{
smokeTestArgs += " --excludeOmniSharpTests";
}
if (Config.ExcludeOnlineTests)
{
smokeTestArgs += " --excludeOnlineTests";
}
(Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess("./assets/smoke-tests/smoke-test.sh", smokeTestArgs, OutputHelper);
Assert.Equal(0, executeResult.Process.ExitCode);
OutputHelper = outputHelper;
}
}

View file

@ -0,0 +1,67 @@
// 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;
namespace Microsoft.DotNet.SourceBuild.SmokeTests
{
public class TestScenario
{
public DotNetActions Commands { get; }
public DotNetLanguage Language { get; }
public bool NoHttps { get; set; } = Config.TargetRid.Contains("osx");
public string ScenarioName { get; }
public DotNetTemplate Template { get; }
public TestScenario(string scenarioName, DotNetLanguage language, DotNetTemplate template, DotNetActions commands = DotNetActions.None)
{
ScenarioName = scenarioName;
Template = template;
Language = language;
Commands = commands;
}
internal void Execute(DotNetHelper dotNetHelper)
{
// Don't use the cli language name in the project name because it may contain '#': https://github.com/dotnet/roslyn/issues/51692
string projectName = $"{ScenarioName}_{Template}_{Language}";
string customNewArgs = Template.IsAspNetCore() && NoHttps ? "--no-https" : string.Empty;
dotNetHelper.ExecuteNew(Template.GetName(), projectName, Language.ToCliName(), customArgs: customNewArgs);
if (Commands.HasFlag(DotNetActions.Build))
{
dotNetHelper.ExecuteBuild(projectName);
}
if (Commands.HasFlag(DotNetActions.Run))
{
if (Template.IsAspNetCore())
{
dotNetHelper.ExecuteRunWeb(projectName);
}
else
{
dotNetHelper.ExecuteRun(projectName);
}
}
if (Commands.HasFlag(DotNetActions.Publish))
{
dotNetHelper.ExecutePublish(projectName);
}
if (Commands.HasFlag(DotNetActions.PublishComplex))
{
dotNetHelper.ExecutePublish(projectName, selfContained: false);
dotNetHelper.ExecutePublish(projectName, selfContained: true, Config.TargetRid);
dotNetHelper.ExecutePublish(projectName, selfContained: true, "linux-x64");
}
if (Commands.HasFlag(DotNetActions.PublishR2R))
{
dotNetHelper.ExecutePublish(projectName, selfContained: true, "linux-x64", trimmed: true, readyToRun: true);
}
if (Commands.HasFlag(DotNetActions.Test))
{
dotNetHelper.ExecuteTest(projectName);
}
}
}
}

View file

@ -0,0 +1,42 @@
// 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.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
/// <summary>
/// Web project create, build, run, publish scenario tests.
/// <see cref="BaseScenarioTests"/> for related basic scenarios.
/// They are encapsulated in a separate testclass so that they can be run in parallel.
/// </summary>
public class WebScenarioTests : SmokeTests
{
public WebScenarioTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
[Theory]
[MemberData(nameof(GetScenarioObjects))]
public void VerifyScenario(TestScenario scenario) => scenario.Execute(DotNetHelper);
private static IEnumerable<object[]> GetScenarioObjects() => GetScenarios().Select(scenario => new object[] { scenario });
private static IEnumerable<TestScenario> GetScenarios()
{
foreach (DotNetLanguage language in new[] { DotNetLanguage.CSharp, DotNetLanguage.FSharp })
{
yield return new(nameof(WebScenarioTests), language, DotNetTemplate.Web, DotNetActions.Build | DotNetActions.Run | DotNetActions.PublishComplex);
yield return new(nameof(WebScenarioTests), language, DotNetTemplate.Mvc, DotNetActions.Build | DotNetActions.Run | DotNetActions.Publish) { NoHttps = true };
yield return new(nameof(WebScenarioTests), language, DotNetTemplate.WebApi, DotNetActions.Build | DotNetActions.Run | DotNetActions.Publish);
}
yield return new(nameof(WebScenarioTests), DotNetLanguage.CSharp, DotNetTemplate.Razor, DotNetActions.Build | DotNetActions.Run | DotNetActions.Publish);
yield return new(nameof(WebScenarioTests), DotNetLanguage.CSharp, DotNetTemplate.BlazorWasm, DotNetActions.Build | DotNetActions.Run | DotNetActions.Publish);
yield return new(nameof(WebScenarioTests), DotNetLanguage.CSharp, DotNetTemplate.BlazorServer, DotNetActions.Build | DotNetActions.Run | DotNetActions.Publish);
yield return new(nameof(WebScenarioTests), DotNetLanguage.CSharp, DotNetTemplate.Worker);
yield return new(nameof(WebScenarioTests), DotNetLanguage.CSharp, DotNetTemplate.Angular);
}
}

View file

@ -4,22 +4,15 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
using System.Linq;
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
public class XmlDocTests
public class XmlDocTests : SmokeTests
{
private ITestOutputHelper OutputHelper { get; }
private DotNetHelper DotNetHelper { get; }
public XmlDocTests(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
DotNetHelper = new DotNetHelper(outputHelper);
}
public XmlDocTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
/// <Summary>
/// Verifies every targeting pack assembly has a xml doc file.

View file

@ -2,7 +2,6 @@
<configuration>
<packageSources>
<clear />
<add key="source-built-packages" value="SOURCE_BUILT_PACKAGES" />
<add key="smoke-test-prereqs" value="SMOKE_TEST_PACKAGE_FEED" />
</packageSources>
</configuration>

View file

@ -1,529 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_ROOT="$(cd -P "$( dirname "$0" )" && pwd)"
TARBALL_PREFIX=dotnet-sdk-
VERSION_PREFIX=6.0
# See https://github.com/dotnet/source-build/issues/579, this version
# needs to be compatible with the runtime produced from source-build
DEV_CERTS_VERSION_DEFAULT=6.0.0-preview.6.21355.2
ARTIFACTS_DIR="$SCRIPT_ROOT/../../../../../../../artifacts/"
executingUserHome=${HOME:-}
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
# Use uname to determine what the CPU is.
cpuName=$(uname -p)
# Some Linux platforms report unknown for platform, but the arch for machine.
if [[ "$cpuName" == "unknown" ]]; then
cpuName=$(uname -m)
fi
case $cpuName in
aarch64)
buildArch=arm64
;;
amd64|x86_64)
buildArch=x64
;;
armv*l)
buildArch=arm
;;
i686)
buildArch=x86
;;
s390x)
buildArch=s390x
;;
*)
echo "Unknown CPU $cpuName detected, treating it as x64"
buildArch=x64
;;
esac
projectOutput=false
keepProjects=false
dotnetDir=""
configuration="Release"
excludeNonWebTests=false
excludeWebTests=false
excludeWebNoHttpsTests=false
excludeWebHttpsTests=false
excludeLocalTests=false
excludeOnlineTests=false
excludeOmniSharpTests=${excludeOmniSharpTests:-false}
devCertsVersion="$DEV_CERTS_VERSION_DEFAULT"
testingDir="$SCRIPT_ROOT/testing-smoke-$(date +"%m%d%H%M%S")"
cliDir="$testingDir/builtCli"
logsDir="$testingDir/logs"
logFile="$logsDir/smoke-test.log"
omnisharpLogFile="$logsDir/omnisharp.log"
restoredPackagesDir="$testingDir/packages"
testingHome="$testingDir/home"
archiveRestoredPackages=false
smokeTestPrebuilts="$SCRIPT_ROOT/prereq-packages"
nonSbSmokeTestPrebuilts="$SCRIPT_ROOT/non-source-built-prereq-packages"
runningOnline=false
runningHttps=false
function usage() {
echo ""
echo "usage:"
echo " --dotnetDir the directory from which to run dotnet"
echo " --configuration the configuration being tested (default=Release)"
echo " --targetRid override the target rid to use when needed (e.g. for self-contained publish tests)"
echo " --projectOutput echo dotnet's output to console"
echo " --keepProjects keep projects after tests are complete"
echo " --minimal run minimal set of tests - local sources only, no web"
echo " --excludeNonWebTests don't run tests for non-web projects"
echo " --excludeWebTests don't run tests for web projects"
echo " --excludeWebNoHttpsTests don't run web project tests with --no-https"
echo " --excludeWebHttpsTests don't run web project tests with https using dotnet-dev-certs"
echo " --excludeLocalTests exclude tests that use local sources for nuget packages"
echo " --excludeOnlineTests exclude test that use online sources for nuget packages"
echo " --excludeOmniSharpTests don't run the OmniSharp tests"
echo " --devCertsVersion <version> use dotnet-dev-certs <version> instead of default $DEV_CERTS_VERSION_DEFAULT"
echo " --archiveRestoredPackages capture all restored packages to $smokeTestPrebuilts"
echo ""
}
while :; do
if [ $# -le 0 ]; then
break
fi
lowerI="$(echo "$1" | awk '{print tolower($0)}')"
case $lowerI in
'-?'|-h|--help)
usage
exit 0
;;
--dotnetdir)
shift
dotnetDir="$1"
;;
--configuration)
shift
configuration="$1"
;;
--targetrid)
shift
targetRid="$1"
;;
--projectoutput)
projectOutput=true
;;
--keepprojects)
keepProjects=true
;;
--minimal)
excludeOnlineTests=true
;;
--excludenonwebtests)
excludeNonWebTests=true
;;
--excludewebtests)
excludeWebTests=true
;;
--excludewebnohttpstests)
excludeWebNoHttpsTests=true
;;
--excludewebhttpstests)
excludeWebHttpsTests=true
;;
--excludelocaltests)
excludeLocalTests=true
;;
--excludeonlinetests)
excludeOnlineTests=true
;;
--excludeomnisharptests)
excludeOmniSharpTests=true
;;
--devcertsversion)
shift
devCertsVersion="$1"
;;
--archiverestoredpackages)
archiveRestoredPackages=true
;;
*)
echo "Unrecognized argument '$1'"
usage
exit 1
;;
esac
shift
done
function doCommand() {
lang=$1
proj=$2
shift; shift;
echo "starting language $lang, type $proj" | tee -a smoke-test.log
dotnetCmd=${dotnetDir}/dotnet
# rename '#'' to 'Sharp' to workaround https://github.com/dotnet/roslyn/issues/51692
projectDir="${lang//#/Sharp}_${proj}"
mkdir "${projectDir}"
cd "${projectDir}"
newArgs="new $proj -lang $lang"
while :; do
if [ $# -le 0 ]; then
break
fi
case "$1" in
--new-arg)
shift
newArgs="$newArgs $1"
;;
*)
break
;;
esac
shift
done
while :; do
if [ $# -le 0 ]; then
break
fi
binlogOnlinePart="local"
binlogHttpsPart="nohttps"
if [ "$runningOnline" == "true" ]; then
binlogOnlinePart="online"
fi
if [ "$runningHttps" == "true" ]; then
binlogHttpsPart="https"
fi
binlogPrefix="$logsDir/${projectDir}_${binlogOnlinePart}_${binlogHttpsPart}_"
binlog="${binlogPrefix}$1.binlog"
echo " running $1" | tee -a "$logFile"
if [ "$1" == "new" ]; then
if [ "$projectOutput" == "true" ]; then
"${dotnetCmd}" $newArgs --no-restore | tee -a "$logFile"
else
"${dotnetCmd}" $newArgs --no-restore >> "$logFile" 2>&1
fi
elif [[ "$1" == "run" && "$proj" =~ ^(web|mvc|webapi|razor|blazorwasm|blazorserver)$ ]]; then
# A separate log file that we will over-write all the time.
exitLogFile="$testingDir/exitLogFile"
echo > "$exitLogFile"
# Run an application in the background and redirect its
# stdout+stderr to a separate process (tee). The tee process
# writes its input to 2 files:
# - Either the normal log or stdout
# - A log that's only used to find out when it's safe to kill
# the application.
if [ "$projectOutput" == "true" ]; then
"${dotnetCmd}" $1 2>&1 > >(tee -a "$exitLogFile") &
else
"${dotnetCmd}" $1 2>&1 > >(tee -a "$logFile" "$exitLogFile" >/dev/null) &
fi
webPid=$!
killCommand="pkill -SIGTERM -P $webPid"
echo " waiting up to 30 seconds for web project with pid $webPid..."
echo " to clean up manually after an interactive cancellation, run: $killCommand"
for seconds in $(seq 30); do
if grep 'Application started. Press Ctrl+C to shut down.' "$exitLogFile"; then
echo " app ready for shutdown after $seconds seconds"
break
fi
sleep 1
done
echo " stopping $webPid" | tee -a "$logFile"
$killCommand
wait $!
echo " terminated with exit code $?" | tee -a "$logFile"
elif [ "$1" == "multi-rid-publish" ]; then
if [ "$lang" == "F#" ]; then
runPublishScenarios() {
"${dotnetCmd}" publish --self-contained false /bl:"${binlogPrefix}publish-fx-dep.binlog"
"${dotnetCmd}" publish --self-contained true -r "$targetRid" /bl:"${binlogPrefix}publish-self-contained-${targetRid}.binlog"
"${dotnetCmd}" publish --self-contained true -r linux-x64 /bl:"${binlogPrefix}publish-self-contained-portable.binlog"
"${dotnetCmd}" publish --self-contained true -r linux-x64 /bl:"${binlogPrefix}publish-self-contained-R2R-portable.binlog" /p:PublishTrimmed=true /p:PublishReadyToRun=true
}
else
runPublishScenarios() {
"${dotnetCmd}" publish --self-contained false /bl:"${binlogPrefix}publish-fx-dep.binlog"
"${dotnetCmd}" publish --self-contained true -r "$targetRid" /bl:"${binlogPrefix}publish-self-contained-${targetRid}.binlog"
"${dotnetCmd}" publish --self-contained true -r linux-x64 /bl:"${binlogPrefix}publish-self-contained-portable.binlog"
"${dotnetCmd}" publish --self-contained true -r linux-x64 /bl:"${binlogPrefix}publish-self-contained-R2R-portable.binlog" /p:PublishTrimmed=true /p:PublishReadyToRun=true
}
fi
if [ "$projectOutput" == "true" ]; then
runPublishScenarios | tee -a "$logFile"
else
runPublishScenarios >> "$logFile" 2>&1
fi
else
if [ "$lang" == "F#" ]; then
# F# tries to use a truncated version number unless we pass it this flag. see https://github.com/dotnet/source-build/issues/2554
if [ "$projectOutput" == "true" ]; then
"${dotnetCmd}" $1 /bl:"$binlog" | tee -a "$logFile"
else
"${dotnetCmd}" $1 /bl:"$binlog" >> "$logFile" 2>&1
fi
else
if [ "$projectOutput" == "true" ]; then
"${dotnetCmd}" $1 /bl:"$binlog" | tee -a "$logFile"
else
"${dotnetCmd}" $1 /bl:"$binlog" >> "$logFile" 2>&1
fi
fi
fi
if [ $? -eq 0 ]; then
echo " $1 succeeded" >> "$logFile"
else
echo " $1 failed with exit code $?" | tee -a "$logFile"
fi
shift
done
cd ..
if [ "$keepProjects" == "false" ]; then
rm -rf "${projectDir}"
fi
echo "finished language $lang, type $proj" | tee -a smoke-test.log
}
function setupDevCerts() {
echo "Setting up dotnet-dev-certs $devCertsVersion to generate dev certificate" | tee -a "$logFile"
(
set -x
"$dotnetDir/dotnet" tool install -g dotnet-dev-certs --version "$devCertsVersion" --add-source https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
export DOTNET_ROOT="$dotnetDir"
"$testingHome/.dotnet/tools/dotnet-dev-certs" https
) >> "$logFile" 2>&1
}
function runAllTests() {
# Run tests for each language and template
if [ "$excludeNonWebTests" == "false" ]; then
doCommand C# console new restore build run multi-rid-publish
doCommand C# classlib new restore build multi-rid-publish
doCommand C# xunit new restore test
doCommand C# nunit new restore test
doCommand C# mstest new restore test
doCommand VB console new restore build run multi-rid-publish
doCommand VB classlib new restore build multi-rid-publish
doCommand VB xunit new restore test
doCommand VB nunit new restore test
doCommand VB mstest new restore test
doCommand F# console new restore build run multi-rid-publish
doCommand F# classlib new restore build multi-rid-publish
doCommand F# xunit new restore test
doCommand F# nunit new restore test
doCommand F# mstest new restore test
fi
if [ "$excludeWebTests" == "false" ]; then
if [ "$excludeWebNoHttpsTests" == "false" ]; then
runningHttps=false
runWebTests --new-arg --no-https
fi
if [ "$excludeWebHttpsTests" == "false" ]; then
runningHttps=true
setupDevCerts
runWebTests
fi
fi
}
function runWebTests() {
doCommand C# web "$@" new restore build run multi-rid-publish
doCommand C# mvc "$@" new restore build run multi-rid-publish
doCommand C# webapi "$@" new restore build multi-rid-publish
doCommand C# razor "$@" new restore build run multi-rid-publish
doCommand C# blazorwasm "$@" new restore build run publish
doCommand C# blazorserver "$@" new restore build run publish
doCommand C# worker new restore
doCommand C# angular new restore
doCommand F# web "$@" new restore build run multi-rid-publish
doCommand F# mvc "$@" new restore build run multi-rid-publish
doCommand F# webapi "$@" new restore build run multi-rid-publish
}
function runOmniSharpTests() {
dotnetCmd=${dotnetDir}/dotnet
rm -rf workdir
mkdir workdir
pushd workdir
curl -sSLO "https://github.com/OmniSharp/omnisharp-roslyn/releases/latest/download/omnisharp-linux-x64.tar.gz"
mkdir omnisharp
pushd omnisharp
tar xf "../omnisharp-linux-x64.tar.gz"
popd
for project in blazorwasm blazorserver classlib console mstest mvc nunit web webapp webapi worker xunit ; do
mkdir hello-$project
pushd hello-$project
"${dotnetCmd}" new $project
popd
./omnisharp/run -s "$(readlink -f hello-$project)" > "$omnisharpLogFile" &
sleep 5
pkill -P $$
# Omnisharp spawns off a number of processes. They all include the
# current directory as a process argument, so use that to identify and
# kill them.
pgrep -f "$(pwd)"
kill "$(pgrep -f "$(pwd)")"
cat "$omnisharpLogFile"
if grep ERROR "$omnisharpLogFile"; then
echo "test failed"
exit 1
else
echo "OK"
fi
done
popd
}
function resetCaches() {
rm -rf "$testingHome"
mkdir "$testingHome"
HOME="$testingHome"
# clean restore path
rm -rf "$restoredPackagesDir"
# Copy NuGet plugins if running user has HOME and we have auth. In particular, the auth plugin.
if [ "${internalPackageFeedPat:-}" ] && [ "${executingUserHome:-}" ]; then
cp -r "$executingUserHome/.nuget/" "$HOME/.nuget/" || :
fi
}
function setupSmokeTestFeed() {
# Setup smoke-test-packages if they exist
if [ -e "$nonSbSmokeTestPrebuilts" ]; then
sed -i.bakSmokeTestFeed "s|SMOKE_TEST_PACKAGE_FEED|$nonSbSmokeTestPrebuilts|g" "$testingDir/NuGet.Config"
else
sed -i.bakSmokeTestFeed "/SMOKE_TEST_PACKAGE_FEED/d" "$testingDir/NuGet.Config"
fi
}
function copyRestoredPackages() {
if [ "$archiveRestoredPackages" == "true" ]; then
rm -rf "$smokeTestPrebuilts"
rm -rf "$nonSbSmokeTestPrebuilts"
mkdir -p "$smokeTestPrebuilts"
mkdir -p "$nonSbSmokeTestPrebuilts"
find "$restoredPackagesDir" -iname "*.nupkg" -exec mv {} "$smokeTestPrebuilts" \;
smokeTestPackages=$(find "$smokeTestPrebuilts" -iname "*.nupkg" -type f -printf "%f\n" | tr '[A-Z]' '[a-z]' | sort)
sourceBuiltPackages=$(find "$SOURCE_BUILT_PKGS_PATH" -iname "*.nupkg" -type f -printf "%f\n" | tr '[A-Z]' '[a-z]' | sort)
echo "Removing smoke-test prereq packages that are source built:"
comm -23 <(printf "$smokeTestPackages") <(printf "$sourceBuiltPackages") | while read line
do
echo "$line"
cp "$smokeTestPrebuilts/$line" "$nonSbSmokeTestPrebuilts"
done
fi
}
echo "RID to test: ${targetRid?not specified. Use ./build.sh --run-smoke-test to detect RID, or specify manually.}"
# Clean up and create directory
if [ -e "$testingDir" ]; then
rm -rf "$testingDir"
fi
mkdir -p "$testingDir"
mkdir -p "$logsDir"
cd "$testingDir"
# Create blank Directory.Build files to avoid traversing to source-build infra.
echo "<Project />" | tee Directory.Build.props > Directory.Build.targets
# Unzip dotnet if the dotnetDir is not specified
if [ "$dotnetDir" == "" ]; then
OUTPUT_DIR="$ARTIFACTS_DIR$buildArch/$configuration/"
DOTNET_TARBALL="$(ls "${OUTPUT_DIR}${TARBALL_PREFIX}${VERSION_PREFIX}"*)"
mkdir -p "$cliDir"
tar xzf "$DOTNET_TARBALL" -C "$cliDir"
dotnetDir="$cliDir"
else
if ! [[ "$dotnetDir" = /* ]]; then
dotnetDir="$SCRIPT_ROOT/$dotnetDir"
fi
fi
echo SDK under test is:
"$dotnetDir/dotnet" --info
# setup restore path
export NUGET_PACKAGES="$restoredPackagesDir"
SOURCE_BUILT_PKGS_PATH="${ARTIFACTS_DIR}obj/$buildArch/$configuration/blob-feed/packages/"
export DOTNET_ROOT="$dotnetDir"
export PATH="$dotnetDir:$PATH"
# Run all tests, online restore sources first, local restore sources second
if [ "$excludeOnlineTests" == "false" ]; then
resetCaches
runningOnline=true
# Setup NuGet.Config to use online restore sources
if [ -e "$SCRIPT_ROOT/online.NuGet.Config" ]; then
cp "$SCRIPT_ROOT/online.NuGet.Config" "$testingDir/NuGet.Config"
echo "$testingDir/NuGet.Config Contents:"
cat "$testingDir/NuGet.Config"
fi
echo "RUN ALL TESTS - ONLINE RESTORE SOURCE"
runAllTests
copyRestoredPackages
echo "ONLINE RESTORE SOURCE - ALL TESTS PASSED!"
fi
if [ "$excludeLocalTests" == "false" ]; then
resetCaches
runningOnline=false
# Setup NuGet.Config with local restore source
if [ -e "$SCRIPT_ROOT/local.NuGet.Config" ]; then
cp "$SCRIPT_ROOT/local.NuGet.Config" "$testingDir/NuGet.Config"
sed -i.bak "s|SOURCE_BUILT_PACKAGES|$SOURCE_BUILT_PKGS_PATH|g" "$testingDir/NuGet.Config"
setupSmokeTestFeed
echo "$testingDir/NuGet.Config Contents:"
cat "$testingDir/NuGet.Config"
fi
echo "RUN ALL TESTS - LOCAL RESTORE SOURCE"
runAllTests
echo "LOCAL RESTORE SOURCE - ALL TESTS PASSED!"
fi
if [ "$excludeOmniSharpTests" == "false" ]; then
runOmniSharpTests
fi
echo "ALL TESTS PASSED!"