Create a script to generate the Microsoft.WSL.TestData nuget package (#41405)

Blue committed Aug 21, 2026 at 20:47 UTC 4bc9ed298c08845f1365c6af9b87b889809d9588
4 files changed +240 -109
tools/test/download-test-data-rpms.ps1 deleted
-73
@@ -1,73 +0,0 @@
1 -
2 -[CmdletBinding(PositionalBinding = $False)]
3 -param (
4 - [Parameter(Mandatory = $true)][string]$Target,
5 - [string]$BaseUrl = "https://packages.microsoft.com/azurelinux/3.0/prod/base"
6 -)
7 -
8 -$ErrorActionPreference = "Stop"
9 -Set-StrictMode -Version Latest
10 -$ProgressPreference = "SilentlyContinue"
11 -
12 -$archMap = @{
13 - "x64" = "x86_64"
14 - "arm64" = "aarch64"
15 -}
16 -
17 -$packages = @("socat", "readline", "ncurses-libs")
18 -
19 -function Get-LatestRpmUrl {
20 - param (
21 - [string]$RepoUrl,
22 - [string]$Arch,
23 - [string]$Package
24 - )
25 -
26 - $letter = $Package.Substring(0, 1).ToLowerInvariant()
27 - $listingUrl = "$RepoUrl/$Arch/Packages/$letter/"
28 -
29 - $listing = curl.exe --fail -sSL $listingUrl
30 - if ($LASTEXITCODE -ne 0) {
31 - throw "Failed to list packages at $listingUrl"
32 - }
33 -
34 - $pattern = 'href="(?<file>' + [regex]::Escape($Package) + '-(?<ver>[0-9][0-9.]*)-(?<rel>[0-9]+)\.azl[0-9]+\.' + $Arch + '\.rpm)"'
35 - $matches = [regex]::Matches($listing, $pattern)
36 - if ($matches.Count -eq 0) {
37 - throw "No '$Package' rpm found for '$Arch' at $listingUrl"
38 - }
39 -
40 - $latest = $matches |
41 - Sort-Object -Property `
42 - @{ Expression = { [version]$_.Groups["ver"].Value } }, `
43 - @{ Expression = { [int]$_.Groups["rel"].Value } } |
44 - Select-Object -Last 1
45 -
46 - return "$listingUrl$($latest.Groups['file'].Value)"
47 -}
48 -
49 -foreach ($archEntry in $archMap.GetEnumerator()) {
50 - $nugetArch = $archEntry.Key
51 - $repoArch = $archEntry.Value
52 -
53 - $archInput = Join-Path $Target $nugetArch
54 - if (-not (Test-Path -Path $archInput -PathType Container)) {
55 - Write-Warning "Skipping '$nugetArch': '$archInput' does not exist."
56 - continue
57 - }
58 -
59 - $packagesDir = Join-Path $archInput "packages"
60 - New-Item -ItemType Directory -Path $packagesDir -Force | Out-Null
61 -
62 - foreach ($package in $packages) {
63 - $url = Get-LatestRpmUrl -RepoUrl $BaseUrl -Arch $repoArch -Package $package
64 - $fileName = Split-Path -Path $url -Leaf
65 - $destination = Join-Path $packagesDir $fileName
66 -
67 - Write-Output "[$nugetArch] Downloading $url"
68 - curl.exe --fail -sSL -o $destination $url
69 - if ($LASTEXITCODE -ne 0) {
70 - throw "Failed to download $url"
71 - }
72 - }
73 -}
\ No newline at end of file
tools/test/generate-test-data.ps1 new
+239
@@ -0,0 +1,239 @@
1 +[CmdletBinding(PositionalBinding = $false)]
2 +param (
3 + [Parameter(Mandatory)]
4 + [string]$Version,
5 + [string]$Distribution
6 +)
7 +
8 +$ErrorActionPreference = "Stop"
9 +Set-StrictMode -Version Latest
10 +
11 +$WorkingDirectory = Join-Path $PSScriptRoot "test-data"
12 +$OutputDirectory = $PWD.Path
13 +
14 +$wslArguments = @()
15 +if (-not [string]::IsNullOrEmpty($Distribution)) {
16 + $wslArguments += @("--distribution", $Distribution)
17 +}
18 +$wslArguments += "--exec"
19 +
20 +function Invoke-WslCommand {
21 + param (
22 + [Parameter(Mandatory = $true)][string[]]$Command,
23 + [switch]$CaptureOutput
24 + )
25 +
26 + if ($CaptureOutput) {
27 + $output = & wsl.exe @wslArguments @Command
28 + if ($LASTEXITCODE -ne 0) {
29 + throw "WSL command failed with exit code $LASTEXITCODE`: $($Command -join ' ')"
30 + }
31 +
32 + return $output
33 + }
34 +
35 + & wsl.exe @wslArguments @Command
36 + if ($LASTEXITCODE -ne 0) {
37 + throw "WSL command failed with exit code $LASTEXITCODE`: $($Command -join ' ')"
38 + }
39 +}
40 +
41 +function ConvertTo-WslPath {
42 + param (
43 + [Parameter(Mandatory = $true)][string]$Path
44 + )
45 +
46 + $result = Invoke-WslCommand -Command @("wslpath", "-a", $Path) -CaptureOutput
47 + return ($result | Select-Object -Last 1).Trim()
48 +}
49 +
50 +function Enable-ForeignArchitectureBuilds {
51 + $nativeArchitecture = (
52 + Invoke-WslCommand -Command @("docker", "version", "--format", "{{.Server.Arch}}") -CaptureOutput |
53 + Select-Object -Last 1
54 + ).Trim()
55 +
56 + foreach ($architecture in @("amd64", "arm64")) {
57 + if ($architecture -eq $nativeArchitecture) {
58 + continue
59 + }
60 +
61 + Write-Host "Installing Docker binfmt support for $architecture"
62 + Invoke-WslCommand -Command @(
63 + "docker", "container", "run",
64 + "--privileged",
65 + "--rm",
66 + "tonistiigi/binfmt",
67 + "--install", $architecture
68 + )
69 + }
70 +}
71 +
72 +function Download-TestDataRpms {
73 + param (
74 + [Parameter(Mandatory = $true)][string]$NugetArchitecture,
75 + [Parameter(Mandatory = $true)][string]$DockerArchitecture
76 + )
77 +
78 + $packagesDirectory = Join-Path $WorkingDirectory "$NugetArchitecture\packages"
79 + New-Item -ItemType Directory -Path $packagesDirectory -Force | Out-Null
80 + $packagesPath = ConvertTo-WslPath $packagesDirectory
81 +
82 + Write-Host "[$NugetArchitecture] Downloading Azure Linux RPMs"
83 + $downloadCommand = @(
84 + "tdnf reinstall -y --downloadonly --downloaddir=/packages readline ncurses-libs",
85 + "tdnf install -y --downloadonly --downloaddir=/packages socat"
86 + ) -join " && "
87 +
88 + Invoke-WslCommand -Command @(
89 + "docker", "container", "run",
90 + "--rm",
91 + "--platform", "linux/$DockerArchitecture",
92 + "--volume", "${packagesPath}:/packages",
93 + "mcr.microsoft.com/azurelinux/base/core:3.0",
94 + "sh", "-c", $downloadCommand
95 + )
96 +
97 + $downloadedPackages = @(Get-ChildItem -LiteralPath $packagesDirectory -Filter "*.rpm" -File)
98 + if ($downloadedPackages.Count -ne 3) {
99 + throw "Expected 3 RPMs for $NugetArchitecture, found $($downloadedPackages.Count)."
100 + }
101 +}
102 +
103 +function Export-DockerImage {
104 + param (
105 + [Parameter(Mandatory = $true)][string]$Image,
106 + [Parameter(Mandatory = $true)][string]$DockerArchitecture,
107 + [Parameter(Mandatory = $true)][string]$OutputPath,
108 + [string]$Source
109 + )
110 +
111 + if ([string]::IsNullOrEmpty($Source)) {
112 + $Source = "docker-daemon:$Image"
113 + }
114 +
115 + $outputDirectory = Split-Path -Parent $OutputPath
116 + $outputFileName = Split-Path -Leaf $OutputPath
117 + $wslOutputDirectory = ConvertTo-WslPath $outputDirectory
118 +
119 + Invoke-WslCommand -Command @(
120 + "docker", "container", "run",
121 + "--rm",
122 + "--volume", "/var/run/docker.sock:/var/run/docker.sock",
123 + "--volume", "${wslOutputDirectory}:/output",
124 + "quay.io/skopeo/stable",
125 + "copy",
126 + "--override-arch", $DockerArchitecture,
127 + $Source,
128 + "docker-archive:/output/${outputFileName}:$Image"
129 + )
130 +
131 + # Adjust the tar padding to match docker's behavior so the "wslc image save" tests match the size of the tars in the testdata package.
132 + $archive = Get-Item -LiteralPath $OutputPath
133 + [long]$tarRecordSize = 10KB
134 + $paddedLength = [Math]::Ceiling($archive.Length / $tarRecordSize) * $tarRecordSize
135 + if ($paddedLength -ne $archive.Length) {
136 + $stream = [System.IO.File]::OpenWrite($archive.FullName)
137 + try {
138 + $stream.SetLength($paddedLength)
139 + }
140 + finally {
141 + $stream.Dispose()
142 + }
143 + }
144 +}
145 +
146 +function Export-TestImages {
147 + param (
148 + [Parameter(Mandatory = $true)][string]$NugetArchitecture,
149 + [Parameter(Mandatory = $true)][string]$DockerArchitecture
150 + )
151 +
152 + $architectureDirectory = Join-Path $WorkingDirectory $NugetArchitecture
153 + New-Item -ItemType Directory -Path $architectureDirectory -Force | Out-Null
154 +
155 + $images = [ordered]@{
156 + "alpine:latest" = "alpine-latest.tar"
157 + "debian:latest" = "debian-latest.tar"
158 + "hello-world:latest" = "HelloWorldSaved.tar"
159 + "python:3.12-alpine" = "python-3_12-alpine.tar"
160 + }
161 +
162 + foreach ($entry in $images.GetEnumerator()) {
163 + Write-Host "[$NugetArchitecture] Downloading $($entry.Key)"
164 + Export-DockerImage `
165 + -Image $entry.Key `
166 + -DockerArchitecture $DockerArchitecture `
167 + -OutputPath (Join-Path $architectureDirectory $entry.Value) `
168 + -Source "docker://docker.io/library/$($entry.Key)"
169 + }
170 +
171 + Invoke-WslCommand -Command @("docker", "image", "pull", "--platform", "linux/$DockerArchitecture", "hello-world:latest")
172 +
173 + $containerId = $null
174 + try {
175 + $containerId = (
176 + Invoke-WslCommand -Command @(
177 + "docker", "container", "create", "--platform", "linux/$DockerArchitecture", "hello-world:latest"
178 + ) -CaptureOutput |
179 + Select-Object -Last 1
180 + ).Trim()
181 +
182 + $exportPath = ConvertTo-WslPath (Join-Path $architectureDirectory "HelloWorldExported.tar")
183 + Invoke-WslCommand -Command @("docker", "container", "export", "--output", $exportPath, $containerId)
184 + }
185 + finally {
186 + if (-not [string]::IsNullOrEmpty($containerId)) {
187 + Invoke-WslCommand -Command @("docker", "container", "rm", "--force", $containerId)
188 + }
189 + }
190 +
191 + Write-Host "[$NugetArchitecture] Building wslc-registry:latest"
192 + $buildContext = ConvertTo-WslPath (Join-Path $PSScriptRoot "images\wslc-registry")
193 + Invoke-WslCommand -Command @(
194 + "docker", "image", "build",
195 + "--platform", "linux/$DockerArchitecture",
196 + "--pull",
197 + "--tag", "wslc-registry:latest",
198 + $buildContext
199 + )
200 +
201 + Export-DockerImage `
202 + -Image "wslc-registry:latest" `
203 + -DockerArchitecture $DockerArchitecture `
204 + -OutputPath (Join-Path $architectureDirectory "wslc-registry.tar")
205 +}
206 +
207 +try {
208 + if (Test-Path -LiteralPath $WorkingDirectory) {
209 + Remove-Item -LiteralPath $WorkingDirectory -Recurse -Force
210 + }
211 +
212 + New-Item -ItemType Directory -Path $WorkingDirectory -Force | Out-Null
213 +
214 + Write-Host "Checking Docker in WSL"
215 + Invoke-WslCommand -Command @("docker", "version")
216 + Enable-ForeignArchitectureBuilds
217 +
218 + Export-TestImages -NugetArchitecture "x64" -DockerArchitecture "amd64"
219 + Export-TestImages -NugetArchitecture "arm64" -DockerArchitecture "arm64"
220 +
221 + Download-TestDataRpms -NugetArchitecture "x64" -DockerArchitecture "amd64"
222 + Download-TestDataRpms -NugetArchitecture "arm64" -DockerArchitecture "arm64"
223 +
224 + $nuspecPath = Join-Path $WorkingDirectory "Microsoft.WSL.TestData.nuspec"
225 + Copy-Item -LiteralPath (Join-Path $PSScriptRoot "Microsoft.WSL.TestData.nuspec") -Destination $nuspecPath -Force
226 +
227 + Write-Host "Building test data NuGet. Input: $WorkingDirectory. Version: $Version"
228 + & (Join-Path $PSScriptRoot "..\..\_deps\nuget.exe") pack $nuspecPath `
229 + -Properties "version=$Version" `
230 + -OutputDirectory $OutputDirectory
231 + if ($LASTEXITCODE -ne 0) {
232 + throw "NuGet pack failed with exit code $LASTEXITCODE."
233 + }
234 +}
235 +finally {
236 + if (Test-Path -LiteralPath $WorkingDirectory) {
237 + Remove-Item -LiteralPath $WorkingDirectory -Recurse -Force
238 + }
239 +}
tools/test/images/wslc-registry/Dockerfile
+1 -1
@@ -3,6 +3,6 @@ FROM registry:3
3 RUN apk add --no-cache apache2-utils
4
5 COPY entrypoint.sh /entrypoint.sh
6 -RUN chmod +x /entrypoint.sh
6 +RUN sed -i 's/\r$//' /entrypoint.sh && chmod +x /entrypoint.sh
7
8 ENTRYPOINT ["/entrypoint.sh"]
tools/test/pack-test-data.ps1 deleted
-35
@@ -1,35 +0,0 @@
1 -<#
2 -.SYNOPSIS
3 - Helper to pack WSL test data nuget.
4 -.PARAMETER InputDirectory
5 - Directory containing arch-specific subdirectories (x64, arm64) with test data.
6 -.PARAMETER Version
7 - Nuget package version.
8 -.PARAMETER OutputDirectory
9 - Directory to place the packaged nuget file. Default to current working directory.
10 -#>
11 -
12 -[CmdletBinding(PositionalBinding=$False, DefaultParameterSetName='vm')]
13 -param (
14 - [Parameter(Mandatory = $true)][string]$InputDirectory,
15 - [Parameter(Mandatory = $true)][string]$Version,
16 - [string]$OutputDirectory = $PWD.Path
17 -)
18 -
19 -$ErrorActionPreference = "Stop"
20 -Set-StrictMode -Version Latest
21 -
22 -if (-not (Test-Path -Path $InputDirectory -PathType Container)) {
23 - throw("The path '$InputDirectory' is not an existing directory.")
24 -}
25 -
26 -$hasArch = (Test-Path "$InputDirectory\x64") -or (Test-Path "$InputDirectory\arm64")
27 -if (-not $hasArch) {
28 - throw("The input directory must contain at least one architecture subdirectory (x64, arm64).")
29 -}
30 -
31 -echo "Building test data nuget. Input: $InputDirectory. Version: $Version"
32 -
33 -Copy-Item -Path "$PSScriptRoot\Microsoft.WSL.TestData.nuspec" -Destination "$InputDirectory" -Force
34 -
35 -& "$PSScriptRoot\..\..\_deps\nuget.exe" pack "$InputDirectory\Microsoft.WSL.TestData.nuspec" -Properties "version=$Version" -OutputDirectory "$OutputDirectory"
\ No newline at end of file