Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for building a test exe as single file #42972

Merged
44 commits merged into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7d639a0
Add option for building a test exe as single file
agocke Sep 24, 2020
690efe2
Remove left over test
agocke Oct 2, 2020
2eab45d
Add target to exclude references from single-file
agocke Oct 9, 2020
37cbeb8
First attempt at adding a CI job
agocke Oct 22, 2020
c6bf3dc
Opt-in specific libraries for single-file testing support
agocke Oct 23, 2020
47531d8
Config testing using single-file in build.cmd
agocke Oct 24, 2020
e3d8e2a
Change yml suffix name to SingleFile
agocke Nov 11, 2020
f04fa34
Windows_NT_x64 -> windows_x64
agocke Nov 12, 2020
473d410
Fix for helix queueing
agocke Nov 14, 2020
968fa5a
Respond to host rename
agocke Nov 14, 2020
7daff3f
Change TargetOS to check for windows
agocke Nov 14, 2020
7bca7ff
chmod test exe on linux
agocke Nov 14, 2020
ab19aa3
Direct singlefilehost to the locally built copy
agocke Nov 15, 2020
83e7eee
Adjust singlefilehost copy+call
agocke Nov 16, 2020
bd66b69
Add .exe suffix on Windows
agocke Nov 16, 2020
a9386d2
Move libraries after hosts build to allow for libs.test to depend on …
agocke Nov 17, 2020
53e3958
Split up host and libs packaging and tests
agocke Nov 17, 2020
5b04b1a
Move host packaging
agocke Nov 18, 2020
fb3239b
Move pretest up
agocke Nov 18, 2020
ea82af5
Move packages up as well
agocke Nov 18, 2020
162fe9b
Reorder libs pretest and libs.packages
agocke Nov 18, 2020
508ea02
Add isSingleFile build parameter to limit Linux Helix jobs
agocke Nov 18, 2020
7efb272
Typo
agocke Nov 19, 2020
784b603
Change conditional check
agocke Nov 19, 2020
e8dfc86
Fix yml
agocke Mar 26, 2021
bf57d34
Fix yml
agocke Mar 26, 2021
73c8c4f
Fix neq
agocke Mar 26, 2021
a367ee0
Fix subsets
agocke Mar 27, 2021
a47ea12
Typo
agocke Mar 27, 2021
5490021
Fix
agocke Mar 27, 2021
924892a
Adjust assert
agocke Mar 28, 2021
b42129c
Include code from Michal to skip failing test
agocke Mar 29, 2021
8b733b2
Remove empty ItemGroup
agocke Mar 29, 2021
1ceb9a1
Update src/libraries/Common/tests/SingleFileTestRunner/SingleFileTest…
agocke Mar 30, 2021
6486a3a
Update eng/testing/tests.singlefile.targets
agocke Mar 30, 2021
9b36582
Apply suggestions from code review
agocke Mar 30, 2021
dc9a90f
Use ProjectExclusions
agocke Mar 30, 2021
d47b11e
Merge remote-tracking branch 'upstream/main' into single-file-xunit
agocke Mar 30, 2021
a4d37ec
Merge remote-tracking branch 'origin/single-file-xunit' into single-f…
agocke Mar 30, 2021
a3d6b3b
Update eng/testing/tests.singlefile.targets
agocke Mar 30, 2021
315958b
Revert changes
agocke Mar 30, 2021
202daa6
Remove host build from tests
agocke Mar 30, 2021
2ad8175
Merge remote-tracking branch 'origin/single-file-xunit' into single-f…
agocke Mar 30, 2021
d719b53
Merge remote-tracking branch 'upstream/main' into single-file-xunit
agocke Mar 30, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions eng/pipelines/libraries/helix-queues-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:

# Linux x64
- ${{ if eq(parameters.platform, 'Linux_x64') }}:
- ${{ if eq(parameters.jobParameters.interpreter, '') }}:
- ${{ if and(eq(parameters.jobParameters.interpreter, ''), ne(parameters.jobParameters.isSingleFile, true)) }}:
- ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}:
- (Centos.8.Amd64.Open)Ubuntu.1604.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759
- RedHat.7.Amd64.Open
Expand Down Expand Up @@ -81,7 +81,7 @@ jobs:
- Ubuntu.1804.Amd64.Open
- SLES.15.Amd64.Open
- (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-20200512010621-4f8cef7
- ${{ if eq(parameters.jobParameters.interpreter, 'true') }}:
- ${{ if or(eq(parameters.jobParameters.interpreter, 'true'), eq(parameters.jobParameters.isSingleFile, true)) }}:
# Limiting interp runs as we don't need as much coverage.
- Debian.9.Amd64.Open

Expand Down Expand Up @@ -135,7 +135,7 @@ jobs:
# .NETFramework
- ${{ if eq(parameters.jobParameters.framework, 'net48') }}:
- Windows.10.Amd64.Client19H1.Open

# AllConfigurations
- ${{ if eq(parameters.jobParameters.framework, 'allConfigurations') }}:
- Windows.10.Amd64.Server19H1.Open
Expand Down
22 changes: 22 additions & 0 deletions eng/pipelines/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,28 @@ jobs:
eq(variables['monoContainsChange'], true),
eq(variables['isFullMatrix'], true))

# Build and test libraries under single-file publishing
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
platforms:
- windows_x64
- Linux_x64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be missing osx_x64, is it by design?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were some problems what I tested this earlier. Bringing Mac online would be good, but wasn't necessary for a first pass here.

jobParameters:
testGroup: innerloop
isFullMatrix: ${{ variables.isFullMatrix }}
isSingleFile: true
nameSuffix: SingleFile
buildArgs: -s clr+libs+libs.tests -c $(_BuildConfig) /p:TestSingleFile=true /p:ArchiveTests=true
timeoutInMinutes: 120
# extra steps, run tests
extraStepsTemplate: /eng/pipelines/libraries/helix.yml
extraStepsParameters:
creator: dotnet-bot
testRunNamePrefixSuffix: SingleFile_$(_BuildConfig)

#
# Build the whole product using Mono and run runtime tests
#
Expand Down
62 changes: 62 additions & 0 deletions eng/testing/tests.singlefile.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<BundleDir>$([MSBuild]::NormalizeDirectory('$(OutDir)', 'publish'))</BundleDir>
<RunScriptOutputPath>$([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))</RunScriptOutputPath>
<RuntimeIdentifier>$(PackageRID)</RuntimeIdentifier>

<RunScriptCommand Condition="'$(TargetOS)' == 'windows'">$(AssemblyName).exe</RunScriptCommand>
<RunScriptCommand Condition="'$(TargetOS)' != 'windows'">chmod +rwx $(AssemblyName) &amp;&amp; ./$(AssemblyName)</RunScriptCommand>
</PropertyGroup>

<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<UseAppHost>true</UseAppHost>
<SelfContained>true</SelfContained>
<SingleFileHostSourcePath>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(Configuration)', 'corehost'))/singlefilehost</SingleFileHostSourcePath>
<SingleFileHostSourcePath Condition="'$(TargetOS)' == 'windows'">$(SingleFileHostSourcePath).exe</SingleFileHostSourcePath>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(CommonTestPath)SingleFileTestRunner\SingleFileTestRunner.cs"
Link="Common\SingleFileTestRunner\SingleFileTestRunner.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="xunit.runner.utility" Version="$(XUnitVersion)" />
</ItemGroup>

<Target Name="__ExcludeAssembliesFromSingleFile"
Inputs="%(ResolvedFileToPublish.Identity)"
Outputs="__NewResolvedFiles"
BeforeTargets="_ComputeFilesToBundle">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually try to not depend on private targets which are implementation detail and could change their name or be removed. Is there a public target that runs before this or on the chain of this target that you can hook to?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at the moment, but I think we could probably add something. I'm open to adding a lot more integration points here to help with testing.

<PropertyGroup>
<__Identity>%(ResolvedFileToPublish.Identity)</__Identity>
<__FileName>%(ResolvedFileToPublish.Filename)%(ResolvedFileToPublish.Extension)</__FileName>
</PropertyGroup>

<ItemGroup>
<__NewResolvedFiles Include="@(ResolvedFileToPublish)">
<ExcludeFromSingleFile Condition="'%(__ExcludeFromBundle.Identity)' == '$(__FileName)'">true</ExcludeFromSingleFile>
</__NewResolvedFiles>
</ItemGroup>
</Target>

<Target Name="__UpdateExcludedAssembliesFromSingleFile"
Inputs="ExcludeFromSingleFile"
Outputs="ResolvedFileToPublish"
DependsOnTargets="ComputeResolvedFilesToPublishList"
BeforeTargets="_ComputeFilesToBundle">
<ItemGroup>
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" />
<ResolvedFileToPublish Include="@(__NewResolvedFiles)" />
</ItemGroup>
</Target>

<Target Name="PublishTestAsSingleFile"
Condition="'$(IsCrossTargetingBuild)' != 'true'"
AfterTargets="Build"
DependsOnTargets="Publish;ArchiveTests" />

</Project>
7 changes: 4 additions & 3 deletions eng/testing/tests.targets
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<!-- For browser we need to hook up the target with DependsOnTargets in PublishTestAsSelfContained
because we do a Publish which runs after Build, if we run after PrepareForRun we would generated
an empty zip because we haven't published the selfcontained app. -->
<ArchiveTestsAfterTargets Condition="'$(TargetOS)' == 'Browser'" />
<ArchiveTestsAfterTargets Condition="'$(TargetOS)' == 'Browser' or '$(TestSingleFile)' == 'true'" />
</PropertyGroup>

<!-- Archive test binaries. -->
Expand All @@ -37,7 +37,7 @@

<PropertyGroup>
<_ZipSourceDirectory>$(OutDir)</_ZipSourceDirectory>
<_ZipSourceDirectory Condition="'$(TargetOS)' == 'Browser'">$(BundleDir)</_ZipSourceDirectory>
<_ZipSourceDirectory Condition="'$(TargetOS)' == 'Browser' or '$(TestSingleFile)' == 'true'">$(BundleDir)</_ZipSourceDirectory>
</PropertyGroup>

<MakeDir Directories="$(TestArchiveTestsDir)" />
Expand Down Expand Up @@ -118,10 +118,11 @@
</Target>

<Import Project="$(MSBuildThisFileDirectory)tests.mobile.targets" Condition="'$(TargetsMobile)' == 'true'" />
<Import Project="$(MSBuildThisFileDirectory)tests.singlefile.targets" Condition="'$(TestSingleFile)' == 'true'" />
<Import Project="$(MSBuildThisFileDirectory)xunit\xunit.targets" Condition="'$(TestFramework)' == 'xunit'" />

<!-- Main test targets -->
<Target Name="Test" DependsOnTargets="$(TestDependsOn)" />

<Import Project="$(MSBuildThisFileDirectory)outerBuild.targets" Condition="'$(IsCrossTargetingBuild)' == 'true'" />
</Project>
4 changes: 2 additions & 2 deletions eng/testing/xunit/xunit.console.targets
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<UseXunitExcludesTxtFile Condition="'$(TargetOS)' == 'Android' or '$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'iOSSimulator' or '$(TargetOS)' == 'tvOS' or '$(TargetOS)' == 'tvOSSimulator'">true</UseXunitExcludesTxtFile>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetsMobile)' != 'true'">
<PropertyGroup Condition="'$(TargetsMobile)' != 'true' and '$(TestSingleFile)' != 'true'">
<_depsFileArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json</_depsFileArgument>
<RunScriptCommand Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">"$(RunScriptHost)" exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileArgument) xunit.console.dll</RunScriptCommand>
<RunScriptCommand Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">xunit.console.exe</RunScriptCommand>
Expand Down Expand Up @@ -36,7 +36,7 @@
<XunitExcludesTxtFileContent>$(_withoutCategories.Replace(';', '%0dcategory='))</XunitExcludesTxtFileContent>
</PropertyGroup>

<ItemGroup>
<ItemGroup Condition="'$(TestSingleFile)' != 'true'">
<PackageReference Include="Microsoft.DotNet.XUnitConsoleRunner"
Version="$(MicrosoftDotNetXUnitConsoleRunnerVersion)"
Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
Expand Down
2 changes: 1 addition & 1 deletion eng/testing/xunit/xunit.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageReference Include="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsVersion)" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' != 'true' AND '$(PublishingTestsRun)' != 'true'">
<ItemGroup Condition="'$(ArchiveTests)' != 'true' and '$(PublishingTestsRun)' != 'true' and '$(TestSingleFile)' != 'true'">
<!-- Microsoft.Net.Test.Sdk brings a lot of assemblies with it. To reduce helix payload submission size we disable it on CI. -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitRunnerVisualStudioVersion)" GeneratePathProperty="true" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
using System.Xml.Linq;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

public class SingleFileTestRunner : XunitTestFramework
{
private SingleFileTestRunner(IMessageSink messageSink)
: base(messageSink) { }

public static int Main(string[] args)
{
var asm = typeof(SingleFileTestRunner).Assembly;
Console.WriteLine("Running assembly:" + asm.FullName);

var diagnosticSink = new ConsoleDiagnosticMessageSink();
var testsFinished = new TaskCompletionSource();
var testSink = new TestMessageSink();
var summarySink = new DelegatingExecutionSummarySink(testSink,
() => false,
(completed, summary) => Console.WriteLine($"Tests run: {summary.Total}, Errors: {summary.Errors}, Failures: {summary.Failed}, Skipped: {summary.Skipped}. Time: {TimeSpan.FromSeconds((double)summary.Time).TotalSeconds}s"));
var resultsXmlAssembly = new XElement("assembly");
var resultsSink = new DelegatingXmlCreationSink(summarySink, resultsXmlAssembly);

testSink.Execution.TestSkippedEvent += args => { Console.WriteLine($"[SKIP] {args.Message.Test.DisplayName}"); };
testSink.Execution.TestFailedEvent += args => { Console.WriteLine($"[FAIL] {args.Message.Test.DisplayName}{Environment.NewLine}{Xunit.ExceptionUtility.CombineMessages(args.Message)}{Environment.NewLine}{Xunit.ExceptionUtility.CombineStackTraces(args.Message)}"); };

testSink.Execution.TestAssemblyFinishedEvent += args =>
{
Console.WriteLine($"Finished {args.Message.TestAssembly.Assembly}{Environment.NewLine}");
testsFinished.SetResult();
};

var xunitTestFx = new SingleFileTestRunner(diagnosticSink);
var asmInfo = Reflector.Wrap(asm);
var asmName = asm.GetName();

var discoverySink = new TestDiscoverySink();
var discoverer = xunitTestFx.CreateDiscoverer(asmInfo);
discoverer.Find(false, discoverySink, TestFrameworkOptions.ForDiscovery());
discoverySink.Finished.WaitOne();
XunitFilters filters = new XunitFilters();
filters.ExcludedTraits.Add("category", new List<string> { "failing" });
var filteredTestCases = discoverySink.TestCases.Where(filters.Filter).ToList();
var executor = xunitTestFx.CreateExecutor(asmName);
executor.RunTests(filteredTestCases, resultsSink, TestFrameworkOptions.ForExecution());

resultsSink.Finished.WaitOne();

var failed = resultsSink.ExecutionSummary.Failed > 0 || resultsSink.ExecutionSummary.Errors > 0;
return failed ? 1 : 0;
}
}

internal class ConsoleDiagnosticMessageSink : IMessageSink
{
public bool OnMessage(IMessageSinkMessage message)
{
if (message is IDiagnosticMessage diagnosticMessage)
{
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@
<WasmFilesToIncludeFromPublishDir Include="$(AssemblyName).dll" />
<WasmFilesToIncludeFromPublishDir Include="$(AssemblyName).pdb" />
</ItemGroup>
<ItemGroup>
<!-- Assemblies that should be excluded from the bundle -->
<__ExcludeFromBundle Include="TestAssembly.dll" />
</ItemGroup>
</Project>
20 changes: 13 additions & 7 deletions src/libraries/tests.proj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<TestPackages Condition="'$(TestPackages)' == ''">false</TestPackages>
<TestTrimming Condition="'$(TestTrimming)' == ''">false</TestTrimming>
</PropertyGroup>

<!-- Projects that don't support code coverage measurement. -->
<ItemGroup Condition="'$(Coverage)' == 'true'">
<ProjectExclusions Include="$(CommonTestPath)Common.Tests.csproj" />
Expand Down Expand Up @@ -107,17 +107,17 @@
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.NameResolution\tests\UnitTests\System.Net.NameResolution.Unit.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.NetworkInformation\tests\FunctionalTests\System.Net.NetworkInformation.Functional.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Ping\tests\FunctionalTests\System.Net.Ping.Functional.Tests.csproj" />

<!-- https://github.com/dotnet/runtime/issues/49191 -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Quic\tests\FunctionalTests\System.Net.Quic.Functional.Tests.csproj" />

<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Requests\tests\System.Net.Requests.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Security\tests\FunctionalTests\System.Net.Security.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Sockets\tests\FunctionalTests\System.Net.Sockets.Tests.csproj" />

<!-- https://github.com/dotnet/runtime/issues/49192-->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.WebClient\tests\System.Net.WebClient.Tests.csproj" />

<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.WebSockets\tests\System.Net.WebSockets.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.WebSockets.Client\tests\System.Net.WebSockets.Client.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Numerics.Tensors\tests\System.Numerics.Tensors.Tests.csproj" />
Expand Down Expand Up @@ -320,6 +320,12 @@
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TestSingleFile)' == 'true'">
<!-- Run only a small randomly chosen set of passing test suites -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)*\tests\**\*.Tests.csproj" />
<ProjectExclusions Remove="$(MSBuildThisFileDirectory)System.Collections\tests\System.Collections.Tests.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)*\tests\**\*.Tests.csproj"
Exclude="@(ProjectExclusions)"
Expand Down Expand Up @@ -348,7 +354,7 @@
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\tvOS\**\*.Test.csproj"
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(TargetOS)' == 'Android'">
<ProjectReference Include="$(MonoProjectRoot)sample\Android\AndroidSampleApp.csproj"
BuildInParallel="false" />
Expand All @@ -357,7 +363,7 @@
Exclude="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\AOT\Android.Device_Emulator.Aot.Test.csproj"
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(TargetOS)' == 'Browser'">
<ProjectReference Include="$(MonoProjectRoot)sample\wasm\**\*.Sample.csproj"
BuildInParallel="false" />
Expand Down