Skip to content

Commit 2b96e8a

Browse files
authored
Send host tests to helix (#114187)
Update installer pipelines to send host tests to helix instead of running locally - Add a post-build step to the installer jobs to send host tests to Helix - Test runs are named `host-<os>-<arch> @ <helix_queue>` - Remove explicit upload of build artifacts on failure. - This was for test failure repro/investigation. It is now part of the helix correlation payload, so they can be downloaded that way This change only handles platforms that we were already running tests on (linux_x64, osx_x64, windown_x64, windows_x86). We would want further updates to add other platforms (for example, *_arm64, linux_musl_*). This does remove running of `Microsoft.DotNet.CoreSetup.Packaging.Tests` tests in PR/CI. I don't think those are particularly useful at this point - I've haven't seen them fail and find an issue in my time here, Test updates: - Copy debug CRT to output directory when building IJW test library in debug - we need this to run IJW tests on the test machine - Resolve /tmp symlink on macOS for test artifacts and assets path for expected path comparisons - Add retry for restoring test file backup
1 parent 9bcd3e7 commit 2b96e8a

File tree

9 files changed

+192
-62
lines changed

9 files changed

+192
-62
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
parameters:
2+
jobTemplate: ''
3+
variables: []
4+
osGroup: ''
5+
osSubgroup: ''
6+
archType: ''
7+
container: ''
8+
pool: ''
9+
platform: ''
10+
shouldContinueOnError: false
11+
jobParameters: {}
12+
13+
jobs:
14+
- template: ${{ parameters.jobTemplate }}
15+
parameters:
16+
variables: ${{ parameters.variables }}
17+
osGroup: ${{ parameters.osGroup }}
18+
osSubgroup: ${{ parameters.osSubgroup }}
19+
archType: ${{ parameters.archType }}
20+
container: ${{ parameters.container }}
21+
pool: ${{ parameters.pool }}
22+
platform: ${{ parameters.platform }}
23+
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
24+
helixQueues:
25+
26+
# Linux arm
27+
- ${{ if eq(parameters.platform, 'linux_arm') }}:
28+
- (Debian.12.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm32v7
29+
30+
# Linux arm64
31+
- ${{ if eq(parameters.platform, 'linux_arm64') }}:
32+
- (Ubuntu.2404.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-24.04-helix-arm64v8
33+
34+
# Linux musl x64
35+
- ${{ if eq(parameters.platform, 'linux_musl_x64') }}:
36+
- (Alpine.321.Amd64.Open)azurelinux.3.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64
37+
38+
# Linux musl arm64
39+
- ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}:
40+
- (Alpine.321.Arm64.Open)ubuntu.2204.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm64v8
41+
42+
# Linux x64
43+
- ${{ if eq(parameters.platform, 'linux_x64') }}:
44+
- azurelinux.3.amd64.open
45+
46+
# OSX arm64
47+
- ${{ if eq(parameters.platform, 'osx_arm64') }}:
48+
- osx.13.arm64.open
49+
50+
# OSX x64
51+
- ${{ if eq(parameters.platform, 'osx_x64') }}:
52+
- OSX.1200.Amd64.Open
53+
54+
# windows x64
55+
- ${{ if eq(parameters.platform, 'windows_x64') }}:
56+
- Windows.11.Amd64.Client.Open
57+
58+
# windows x86
59+
- ${{ if eq(parameters.platform, 'windows_x86') }}:
60+
- Windows.11.Amd64.Client.Open
61+
62+
# windows arm64
63+
- ${{ if eq(parameters.platform, 'windows_arm64') }}:
64+
- Windows.11.Arm64.Open
65+
66+
${{ insert }}: ${{ parameters.jobParameters }}

eng/pipelines/installer/helix.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
parameters:
2+
archType: ''
3+
osGroup: ''
4+
creator: ''
5+
helixQueues: ''
6+
7+
steps:
8+
- template: /eng/common/templates/steps/send-to-helix.yml
9+
parameters:
10+
DisplayNamePrefix: Send to Helix
11+
HelixProjectPath: src/installer/tests/helixpublish.proj
12+
${{ if ne(parameters.osGroup, 'windows') }}:
13+
HelixProjectArguments: >-
14+
--ci
15+
/p:Configuration=$(_BuildConfig)
16+
/p:TargetArchitecture=${{ parameters.archType }}
17+
/p:TargetOS=${{ parameters.osGroup }}
18+
${{ if eq(parameters.osGroup, 'windows') }}:
19+
HelixProjectArguments: >-
20+
-ci
21+
/p:Configuration=$(_BuildConfig)
22+
/p:TargetArchitecture=${{ parameters.archType }}
23+
/p:TargetOS=${{ parameters.osGroup }}
24+
Creator: ${{ parameters.creator }}
25+
${{ if eq(variables['System.TeamProject'], 'internal') }}:
26+
HelixAccessToken: $(HelixApiAccessToken)
27+
HelixTargetQueues: ${{ replace(lower(join('+', parameters.helixQueues)), '.open', '') }}
28+
${{ if eq(variables['System.TeamProject'], 'public') }}:
29+
HelixTargetQueues: ${{ join('+', parameters.helixQueues) }}

eng/pipelines/installer/steps/upload-job-artifacts.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

eng/pipelines/runtime.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,9 +1260,10 @@ extends:
12601260
buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
12611261
platforms:
12621262
- windows_x86
1263+
helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml
12631264
jobParameters:
12641265
nameSuffix: Installer_Build_And_Test
1265-
buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release -test
1266+
buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release
12661267
dependsOnGlobalBuilds:
12671268
- nameSuffix: CoreCLR_Libraries
12681269
buildConfig: release
@@ -1273,12 +1274,11 @@ extends:
12731274
artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release$(archiveExtension)
12741275
unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
12751276
displayName: 'unified artifacts'
1276-
enablePublishTestResults: true
1277-
testRunTitle: Installer-$(osGroup)$(osSubgroup)_$(archType)
1277+
timeoutInMinutes: 150
12781278
postBuildSteps:
1279-
- template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
1279+
- template: /eng/pipelines/installer/helix.yml
12801280
parameters:
1281-
name: $(osGroup)$(osSubgroup)_$(archType)
1281+
creator: dotnet-bot
12821282
condition:
12831283
or(
12841284
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),
@@ -1292,9 +1292,10 @@ extends:
12921292
- windows_x64
12931293
- osx_x64
12941294
- linux_x64
1295+
helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml
12951296
jobParameters:
12961297
nameSuffix: Installer_Build_And_Test
1297-
buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release -test
1298+
buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release
12981299
dependsOnGlobalBuilds:
12991300
- nameSuffix: CoreCLR_Libraries
13001301
buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
@@ -1305,12 +1306,11 @@ extends:
13051306
artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling)$(archiveExtension)
13061307
unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
13071308
displayName: 'unified artifacts'
1308-
enablePublishTestResults: true
1309-
testRunTitle: Installer-$(osGroup)$(osSubgroup)_$(archType)
1309+
timeoutInMinutes: 150
13101310
postBuildSteps:
1311-
- template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
1311+
- template: /eng/pipelines/installer/helix.yml
13121312
parameters:
1313-
name: $(osGroup)$(osSubgroup)_$(archType)
1313+
creator: dotnet-bot
13141314
condition:
13151315
or(
13161316
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),

src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,17 @@ public SharedTestState()
154154
string ijwhostName = "ijwhost.dll";
155155
File.Copy(Path.Combine(RepoDirectoriesProvider.Default.HostArtifacts, ijwhostName), Path.Combine(folder, ijwhostName));
156156

157-
// Copy over the C++/CLI test library
157+
// Copy over the C++/CLI test library and any dependencies
158158
string ijwLibraryName = "ijw.dll";
159159
File.Copy(Path.Combine(RepoDirectoriesProvider.Default.HostTestArtifacts, ijwLibraryName), Path.Combine(folder, ijwLibraryName));
160+
string ijwDependencies = Path.Combine(RepoDirectoriesProvider.Default.HostTestArtifacts, "ijw-deps");
161+
if (Directory.Exists(ijwDependencies))
162+
{
163+
foreach(string file in Directory.GetFiles(ijwDependencies))
164+
{
165+
File.Copy(file, Path.Combine(folder, Path.GetFileName(file)));
166+
}
167+
}
160168

161169
// Create a runtimeconfig.json for the C++/CLI test library
162170
new RuntimeConfig(Path.Combine(folder, "ijw.runtimeconfig.json"))

src/installer/tests/TestUtils/TestContext.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ static TestContext()
4242
MicrosoftNETCoreAppVersion = GetTestContextVariable("MNA_VERSION");
4343
Tfm = GetTestContextVariable("MNA_TFM");
4444

45-
TestAssetsOutput = GetTestContextVariable("TEST_ASSETS_OUTPUT");
46-
TestArtifactsPath = GetTestContextVariable("TEST_ARTIFACTS");
45+
TestAssetsOutput = ResolveTestContextPath(GetTestContextVariable("TEST_ASSETS_OUTPUT"));
46+
TestArtifactsPath = ResolveTestContextPath(GetTestContextVariable("TEST_ARTIFACTS"));
4747
Directory.CreateDirectory(TestArtifactsPath);
4848

4949
// Create an empty global.json, so running tests from test artifacts is not affected
@@ -68,5 +68,23 @@ public static string GetTestContextVariable(string name)
6868

6969
throw new ArgumentException($"Unable to find variable '{name}' in test context variable file '{_testContextVariableFilePath}'");
7070
}
71+
72+
private static string ResolveTestContextPath(string path)
73+
{
74+
// On macOS, /tmp/ is a symlink. Running apps out of it will resolve the path, so determine the resolved path here.
75+
if (!OperatingSystem.IsMacOS())
76+
return path;
77+
78+
string tmpPath = "/tmp/";
79+
if (!path.StartsWith(tmpPath))
80+
return path;
81+
82+
// No trailing slash in order to properly check the link target
83+
DirectoryInfo tmp = new DirectoryInfo(tmpPath[..^1]);
84+
if (tmp.LinkTarget == null)
85+
return path;
86+
87+
return Path.Combine(tmp.ResolveLinkTarget(true).FullName, path[tmpPath.Length..]);
88+
}
7189
}
7290
}

src/installer/tests/TestUtils/TestFileBackup.cs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,28 +76,13 @@ public void Dispose()
7676
// This is a known problem where the actual Delete call is not 100% synchronous
7777
// the OS reports a success but the file/folder is not fully removed yet.
7878
// So implement a simple retry with a short timeout.
79-
IOException exception = null;
80-
for (int retryCount = 5; retryCount > 0; retryCount--)
81-
{
82-
try
79+
RetryOnIOError(() =>
8380
{
8481
Directory.Delete(_backupPath, recursive: true);
85-
if (!Directory.Exists(_backupPath))
86-
{
87-
return;
88-
}
89-
}
90-
catch (IOException ex)
91-
{
92-
exception = ex;
93-
}
94-
95-
System.Threading.Thread.Sleep(200);
96-
}
97-
98-
throw new Exception(
99-
$"Failed to delete the backup folder {_backupPath} even after retries.\r\n"
100-
+ (exception == null ? "" : exception.ToString()));
82+
return !Directory.Exists(_backupPath);
83+
},
84+
$"Failed to delete the backup folder {_backupPath} even after retries."
85+
);
10186
}
10287
}
10388

@@ -110,8 +95,44 @@ private static void CopyOverDirectory(string source, string destination)
11095

11196
foreach (string file in Directory.GetFiles(source))
11297
{
113-
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), overwrite: true);
98+
// Some files may still be reported as in use my the OS - for example immediately after
99+
// process exit. Simple retry to separate this case from a file being intentionally locked.
100+
RetryOnIOError(() =>
101+
{
102+
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), overwrite: true);
103+
return true;
104+
},
105+
$"Failed to restore file {Path.GetFileName(file)}"
106+
);
114107
}
115108
}
109+
110+
private static void RetryOnIOError(Func<bool> action, string errorMessage, int maxRetries = 5)
111+
{
112+
IOException exception = null;
113+
for (int i = 0; i < maxRetries; i++)
114+
{
115+
try
116+
{
117+
if (action())
118+
{
119+
return;
120+
}
121+
}
122+
catch (IOException e)
123+
{
124+
exception = e;
125+
}
126+
127+
System.Threading.Thread.Sleep(200);
128+
}
129+
130+
throw new Exception(
131+
$"""
132+
{errorMessage}
133+
{(exception == null ? "" : exception.ToString())}
134+
""");
135+
136+
}
116137
}
117138
}

src/installer/tests/helixpublish.proj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
<Project Sdk="Microsoft.DotNet.Helix.Sdk">
1+
<Project Sdk="Microsoft.DotNet.Helix.Sdk" DefaultTargets="Test">
22

33
<PropertyGroup>
44
<HelixArchitecture>$(TargetArchitecture)</HelixArchitecture>
55
<HelixBuild Condition="'$(HelixBuild)' == ''">$(BUILD_BUILDNUMBER)</HelixBuild>
66
<HelixBuild Condition="'$(HelixBuild)' == ''">default</HelixBuild>
77
<HelixConfiguration>$(Configuration)</HelixConfiguration>
88
<HelixType>test/host</HelixType>
9+
<TestRunNamePrefix>host-$(TargetOS)-$(TargetArchitecture)-$(Configuration) @ </TestRunNamePrefix>
910

1011
<IncludeDotNetCli>true</IncludeDotNetCli>
1112
<DotNetCliPackageType>sdk</DotNetCliPackageType>
@@ -46,7 +47,7 @@
4647
</MSBuild>
4748
<ItemGroup>
4849
<HostTestProject>
49-
<Command>dotnet test $([System.IO.Path]::GetFileName($(_TargetPath))) $(TestRunnerAdditionalArguments)</Command>
50+
<Command>dotnet test $([System.IO.Path]::GetFileName($(_TargetPath))) $(TestRunnerAdditionalArguments) --logger trx --results-directory .</Command>
5051
<PayloadDirectory>$(_PayloadDirectory)</PayloadDirectory>
5152
</HostTestProject>
5253
</ItemGroup>
@@ -58,6 +59,7 @@
5859
<PayloadDirectory>%(HostTestProject.PayloadDirectory)</PayloadDirectory>
5960
<Command>%(HostTestProject.Command)</Command>
6061
<PreCommands>@(_HelixPreCommands)</PreCommands>
62+
<Timeout>00:30:00</Timeout>
6163
</HelixWorkItem>
6264
</ItemGroup>
6365
</Target>

src/native/corehost/test/ijw/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,15 @@ remove_ijw_incompatible_target_options(ijw)
1010
add_ijw_msbuild_project_properties(ijw ijwhost)
1111

1212
install_with_stripped_symbols(ijw TARGETS corehost_test)
13+
14+
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
15+
# Copy over the debug CRT so that it is available for test runs
16+
file(
17+
GLOB_RECURSE
18+
DEBUG_CRT_FILES
19+
$ENV{VCToolsRedistDir}/onecore/debug_nonredist/${ARCH_TARGET_NAME}/Microsoft.VC*.DebugCRT/vcruntime*d.dll
20+
$ENV{VCToolsRedistDir}/onecore/debug_nonredist/${ARCH_TARGET_NAME}/Microsoft.VC*.DebugCRT/msvcp*d.dll
21+
$ENV{ExtensionSdkDir}/Microsoft.UniversalCRT.Debug/$ENV{UCRTVersion}/Redist/Debug/${ARCH_TARGET_NAME}/ucrtbased.dll
22+
)
23+
install(FILES ${DEBUG_CRT_FILES} DESTINATION corehost_test/ijw-deps)
24+
endif ()

0 commit comments

Comments
 (0)