diff --git a/eng/pipelines/common/templates/wasm-library-tests.yml b/eng/pipelines/common/templates/wasm-library-tests.yml
index eb64ac55ee7a01..6037b4529ecaa8 100644
--- a/eng/pipelines/common/templates/wasm-library-tests.yml
+++ b/eng/pipelines/common/templates/wasm-library-tests.yml
@@ -49,11 +49,17 @@ jobs:
ne(dependencies.evaluate_paths.outputs.SetPathVars_any_other_than_wasm_wbt_dbg.containsChange, true))
- name: _wasmRunSmokeTestsOnlyArg
value: /p:RunSmokeTestsOnly=${{ eq(parameters.shouldRunSmokeOnly, true) }}
+ - name: chromeInstallArg
+ ${{ if containsValue(parameters.scenarios, 'wasmtestonbrowser') }}:
+ value: /p:InstallChromeForTests=true
+ ${{ else }}:
+ value: ''
+
jobParameters:
isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
testGroup: innerloop
nameSuffix: LibraryTests${{ parameters.nameSuffix }}
- buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=$(_hostedOs) $(_wasmRunSmokeTestsOnlyArg) ${{ parameters.extraBuildArgs }}
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=$(_hostedOs) $(_wasmRunSmokeTestsOnlyArg) $(chromeInstallArg) ${{ parameters.extraBuildArgs }}
timeoutInMinutes: 240
# if !alwaysRun, then:
# if this is runtime-wasm (isWasmOnlyBuild):
diff --git a/eng/testing/ProvisioningVersions.props b/eng/testing/ProvisioningVersions.props
index 63fc5a13c7e77c..ef88b2d9e4921a 100644
--- a/eng/testing/ProvisioningVersions.props
+++ b/eng/testing/ProvisioningVersions.props
@@ -1,31 +1,30 @@
-
+
+ stable
+
+ win
+ linux
+ mac
+
+ false
+
+ $(ArtifactsBinDir)chrome\
+ $(ArtifactsBinDir)chromedriver\
+
+
+ 3
+
+ $(ArtifactsBinDir)firefox\
+ $([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(FirefoxRevision).stamp'))
+
+
- 972765
- https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/$(ChromiumRevision)/chrome-linux.zip
- https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/$(ChromiumRevision)/chromedriver_linux64.zip
- chrome-linux
- chromedriver_linux64
- chrome
97.0.1
https://ftp.mozilla.org/pub/firefox/releases/$(FirefoxRevision)/linux-x86_64/en-US/firefox-$(FirefoxRevision).tar.bz2
firefox
-
-
- 972766
- https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/$(ChromiumRevision)/chrome-win.zip
- https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/$(ChromiumRevision)/chromedriver_win32.zip
- chrome-win
- chromedriver_win32
- chrome.exe
-
diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh
index 2d5152215635a8..077f891d051051 100644
--- a/eng/testing/WasmRunnerTemplate.sh
+++ b/eng/testing/WasmRunnerTemplate.sh
@@ -53,6 +53,10 @@ if [[ -z "$XHARNESS_ARGS" ]]; then
XHARNESS_ARGS="$JS_ENGINE $JS_ENGINE_ARGS $MAIN_JS"
fi
+if [[ -n "$PREPEND_PATH" ]]; then
+ export PATH=$PREPEND_PATH:$PATH
+fi
+
if [[ -n "$XUNIT_RANDOM_ORDER_SEED" ]]; then
WasmXHarnessMonoArgs="${WasmXHarnessMonoArgs} --setenv=XUNIT_RANDOM_ORDER_SEED=${XUNIT_RANDOM_ORDER_SEED}"
fi
diff --git a/eng/testing/provisioning.targets b/eng/testing/provisioning.targets
deleted file mode 100644
index 040f423fa19f92..00000000000000
--- a/eng/testing/provisioning.targets
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
- $(ArtifactsBinDir)chrome\
- $(ArtifactsBinDir)chromedriver\
- $(ArtifactsBinDir)\
- $(BrowserStampDir).install-chrome-$(ChromiumRevision).stamp
- $(BrowserStampDir).install-chromedriver-$(ChromiumRevision).stamp
- $(ArtifactsBinDir)firefox\
- $(BrowserStampDir).install-firefox-$(FirefoxRevision).stamp
-
-
-
-
-
-
-
- <_StampFile Include="$(BrowserStampDir).install-chrome*.stamp" />
-
-
-
-
-
-
-
-
-
-
-
- <_ChromeBinaryPath>$([MSBuild]::NormalizePath($(ChromeDir), $(ChromiumDirName), $(ChromiumBinaryName)))
-
-
-
-
-
-
-
-
-
-
-
-
- <_StampFile Include="$(BrowserStampDir).install-chromedriver*.stamp" />
-
-
-
-
-
-
-
-
-
-
-
- <_ChromeDriverBinaryPath>$([MSBuild]::NormalizePath($(ChromeDriverDir), $(ChromeDriverDirName), 'chromedriver'))
-
-
-
-
-
-
-
-
-
-
-
- <_StampFile Include="$(BrowserStampDir).install-firefox*.stamp" />
-
-
-
-
-
-
-
-
-
-
-
-
- <_FirefoxBinaryPath>$([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxBinaryName)))
-
-
-
-
-
-
-
-
-
diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets
index b0e7e5507f52ce..aa1ab7b2cdce58 100644
--- a/eng/testing/tests.wasm.targets
+++ b/eng/testing/tests.wasm.targets
@@ -31,8 +31,16 @@
true
false
_GetWorkloadsToInstall;$(InstallWorkloadUsingArtifactsDependsOn)
+ true
+
+
+
true
@@ -46,6 +54,9 @@
helix
helix
local
+
+ <_WasmBrowserPathForTests Condition="'$(BROWSER_PATH_FOR_TESTS)' != ''">$(BROWSER_PATH_FOR_TESTS)
+ <_WasmBrowserPathForTests Condition="'$(_WasmBrowserPathForTests)' == '' and '$(InstallChromeForTests)' == 'true'">$(ChromeBinaryPath)
@@ -94,6 +105,7 @@
<_XHarnessArgs >$(_XHarnessArgs) -s dotnet.js.symbols
<_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbol-patterns wasm-symbol-patterns.txt
<_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbolicator WasmSymbolicator.dll,Microsoft.WebAssembly.Internal.SymbolicatorWrapperForXHarness
+ <_XHarnessArgs Condition="'$(_WasmBrowserPathForTests)' != ''" >$(_XHarnessArgs) "--browser-path=$(_WasmBrowserPathForTests)"
<_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli)
@@ -290,7 +302,8 @@
-
+
+
<_NodeNpmModuleString Include="%(NodeNpmModule.Identity):%(NodeNpmModule.Alias)" />
@@ -304,10 +317,17 @@
+
+
+
+
+
+
+
diff --git a/eng/testing/wasm-provisioning.targets b/eng/testing/wasm-provisioning.targets
new file mode 100644
index 00000000000000..63238cdbc248a6
--- /dev/null
+++ b/eng/testing/wasm-provisioning.targets
@@ -0,0 +1,127 @@
+
+
+
+
+ chrome-linux
+ chromedriver_linux64
+ chrome
+ chromedriver
+ <_ChromeOSPrefix>Linux_x64
+
+
+
+ chrome-win
+ chromedriver_win32
+ chrome.exe
+ chromedriver.exe
+ <_ChromeOSPrefix>Win_x64
+
+
+
+ <_BrowserStampDir>$(ArtifactsBinDir)\
+ $([MSBuild]::NormalizePath($(ChromeDir), $(ChromeDirName), $(ChromeBinaryName)))
+ $([MSBuild]::NormalizePath($(ChromeDriverDir), $(ChromeDriverDirName), $(ChromeDriverBinaryName)))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_StampFile Include="$(_BrowserStampDir).install-firefox*.stamp" />
+
+
+
+
+
+
+
+
+
+
+
+
+ <_FirefoxBinaryPath>$([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxBinaryName)))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(_ChromeBaseSnapshotUrl)/chrome-linux.zip
+ $(_ChromeBaseSnapshotUrl)/chromedriver_linux64.zip
+
+
+ $(_ChromeBaseSnapshotUrl)/chrome-win.zip
+ $(_ChromeBaseSnapshotUrl)/chromedriver_win32.zip
+
+
+
+ $([MSBuild]::NormalizePath('$(ChromeDir)', '.install-$(ChromeVersion)-$(ChromeRevision).stamp'))
+ $([MSBuild]::NormalizePath('$(ChromeDriverDir)', '.install-$(ChromeVersion)-$(ChromeRevision).stamp'))
+
+
+
diff --git a/src/libraries/pretest.proj b/src/libraries/pretest.proj
index ac4f3c9021c0cf..dc68ed802a4480 100644
--- a/src/libraries/pretest.proj
+++ b/src/libraries/pretest.proj
@@ -29,6 +29,9 @@
+
+
-
+
@@ -97,7 +97,7 @@
-
+
@@ -161,14 +161,19 @@
-
+
+
+
+
-
-
+
+
diff --git a/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj b/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj
index dc6b252078fc3e..a213bd210a98aa 100644
--- a/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj
+++ b/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj
@@ -13,15 +13,13 @@
true
true
- true
+ true
false
true
-
-
RunScriptTemplate.cmd
RunScriptTemplate.sh
@@ -52,8 +50,8 @@
-
-
+
+
@@ -74,6 +72,9 @@
+
+
+
diff --git a/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.cmd b/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.cmd
index e2568eff83f798..08a8b04d5f43e7 100644
--- a/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.cmd
+++ b/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.cmd
@@ -58,6 +58,10 @@ if [%XHARNESS_ARGS%] == [] (
set "XHARNESS_ARGS=%JS_ENGINE% %JS_ENGINE_ARGS% %BROWSER_PATH% %MAIN_JS%"
)
+if [%PREPEND_PATH%] NEQ [] (
+ set "PATH=%PREPEND_PATH%;%PATH%"
+)
+
echo EXECUTION_DIR=%EXECUTION_DIR%
echo SCENARIO=%SCENARIO%
echo XHARNESS_OUT=%XHARNESS_OUT%
diff --git a/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.sh b/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.sh
index be117f00639094..d1f987199555eb 100644
--- a/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.sh
+++ b/src/mono/wasm/Wasm.Build.Tests/data/RunScriptTemplate.sh
@@ -53,6 +53,10 @@ if [[ -z "$XHARNESS_ARGS" ]]; then
XHARNESS_ARGS="$JS_ENGINE $JS_ENGINE_ARGS $MAIN_JS"
fi
+if [[ -n "$PREPEND_PATH" ]]; then
+ export PATH=$PREPEND_PATH:$PATH
+fi
+
echo EXECUTION_DIR=$EXECUTION_DIR
echo SCENARIO=$SCENARIO
echo XHARNESS_OUT=$XHARNESS_OUT
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj
index 45e5d54b85f467..0962b33581bcf0 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj
@@ -8,11 +8,11 @@
chrome
$(DefineConstants);RUN_IN_CHROME
windows
- true
+ true
true
-
+
diff --git a/src/tasks/WasmBuildTasks/GetChromeVersions.cs b/src/tasks/WasmBuildTasks/GetChromeVersions.cs
new file mode 100644
index 00000000000000..81a65abb6bd8ae
--- /dev/null
+++ b/src/tasks/WasmBuildTasks/GetChromeVersions.cs
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Net;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.Build.Framework;
+
+using MBU = Microsoft.Build.Utilities;
+
+#nullable enable
+
+namespace Microsoft.WebAssembly.Build.Tasks;
+
+public class GetChromeVersions : MBU.Task
+{
+ private const string s_allJsonUrl = "http://omahaproxy.appspot.com/all.json";
+ private const string s_snapshotBaseUrl = $"https://storage.googleapis.com/chromium-browser-snapshots";
+ private const int s_versionCheckThresholdDays = 3;
+ private const int s_numBranchPositionsToTry = 30;
+ private static readonly HttpClient s_httpClient = new();
+
+ public string Channel { get; set; } = "stable";
+
+ [Required, NotNull]
+ public string OSIdentifier { get; set; } = string.Empty;
+
+ // Used in https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Linux_x64/
+ [Required, NotNull]
+ public string? OSPrefix { get; set; }
+
+ [Required, NotNull]
+ public string IntermediateOutputPath { get; set; } = string.Empty;
+
+ // start at the branch position found in all.json, and try to
+ // download chrome, and chromedriver. If not found, then try up to
+ // MaxLowerBranchPositionsToCheck lower versions
+ public int MaxLowerBranchPositionsToCheck { get; set; } = 10;
+
+ [Output]
+ public string ChromeVersion { get; set; } = string.Empty;
+ [Output]
+ public string BranchPosition { get; set; } = string.Empty;
+ [Output]
+ public string BaseSnapshotUrl { get; set; } = string.Empty;
+ [Output]
+ public string V8Version { get; set; } = string.Empty;
+
+ public override bool Execute() => ExecuteInternalAsync().Result;
+
+ private async Task ExecuteInternalAsync()
+ {
+ if (!Directory.Exists(IntermediateOutputPath))
+ {
+ Log.LogError($"Cannot find {nameof(IntermediateOutputPath)}={IntermediateOutputPath}");
+ return false;
+ }
+
+ try
+ {
+ ChromeVersionSpec version = await GetChromeVersionAsync().ConfigureAwait(false);
+ BaseSnapshotUrl = await GetChromeUrlsAsync(version).ConfigureAwait(false);
+ ChromeVersion = version.version;
+ V8Version = version.v8_version;
+ BranchPosition = version.branch_base_position;
+
+ return !Log.HasLoggedErrors;
+ }
+ catch (LogAsErrorException laee)
+ {
+ Log.LogError(laee.Message);
+ return false;
+ }
+ }
+
+ private async Task GetChromeUrlsAsync(ChromeVersionSpec version)
+ {
+ string baseUrl = $"{s_snapshotBaseUrl}/{OSPrefix}";
+
+ int branchPosition = int.Parse(version.branch_base_position);
+ for (int i = 0; i < s_numBranchPositionsToTry; i++)
+ {
+ string branchUrl = $"{baseUrl}/{branchPosition}";
+ string url = $"{branchUrl}/REVISIONS";
+
+ Log.LogMessage(MessageImportance.Low, $"Checking if {url} exists ..");
+ HttpResponseMessage response = await s_httpClient
+ .GetAsync(url, HttpCompletionOption.ResponseHeadersRead)
+ .ConfigureAwait(false);
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ Log.LogMessage(MessageImportance.Low, $"Found {url}");
+ return branchUrl;
+ }
+
+ branchPosition += 1;
+ }
+
+ throw new LogAsErrorException($"Could not find a chrome snapshot folder under {baseUrl}, " +
+ $"for branch positions {version.branch_base_position} to " +
+ $"{branchPosition}, for version {version.version}.");
+ }
+
+ private async Task GetChromeVersionAsync()
+ {
+ using Stream stream = await GetAllJsonContentsAsync().ConfigureAwait(false);
+
+ PerOSVersions[]? perOSVersions = await JsonSerializer
+ .DeserializeAsync(stream)
+ .ConfigureAwait(false);
+ if (perOSVersions is null)
+ throw new LogAsErrorException($"Failed to read chrome versions from {s_allJsonUrl}");
+
+ PerOSVersions[] foundOSVersions = perOSVersions.Where(osv => osv.os == OSIdentifier).ToArray();
+ if (foundOSVersions.Length == 0)
+ {
+ string availableOSIds = string.Join(", ", perOSVersions.Select(osv => osv.os).Distinct().Order());
+ throw new LogAsErrorException($"Unknown OS identifier '{OSIdentifier}'. OS identifiers found " +
+ $"in all.json: {availableOSIds}");
+ }
+
+ ChromeVersionSpec[] foundChromeVersions = foundOSVersions
+ .SelectMany(osv => osv.versions)
+ .Where(cv => cv.channel == Channel)
+ .ToArray();
+
+ if (foundChromeVersions.Length == 0)
+ {
+ string availableChannels = string.Join(", ", perOSVersions
+ .SelectMany(osv => osv.versions)
+ .Select(cv => cv.channel)
+ .Distinct()
+ .Order());
+ throw new LogAsErrorException($"Unknown chrome channel '{Channel}'. Channels found in all.json: " +
+ availableChannels);
+ }
+
+ return foundChromeVersions[0];
+ }
+
+ private async Task GetAllJsonContentsAsync()
+ {
+ string allJsonPath = Path.Combine(IntermediateOutputPath, "all.json");
+
+ // Don't download all.json on every build, instead do that
+ // only every few days
+ if (File.Exists(allJsonPath) &&
+ (DateTime.UtcNow - File.GetLastWriteTimeUtc(allJsonPath)).TotalDays < s_versionCheckThresholdDays)
+ {
+ Log.LogMessage(MessageImportance.Low,
+ $"{s_allJsonUrl} will not be downloaded again, as ${allJsonPath} " +
+ $"is less than {s_versionCheckThresholdDays} old.");
+ }
+ else
+ {
+ try
+ {
+ Log.LogMessage(MessageImportance.Low, $"Downloading {s_allJsonUrl} ...");
+ Stream stream = await s_httpClient.GetStreamAsync(s_allJsonUrl).ConfigureAwait(false);
+ using FileStream fs = File.OpenWrite(allJsonPath);
+ await stream.CopyToAsync(fs).ConfigureAwait(false);
+ }
+ catch (HttpRequestException hre)
+ {
+ throw new LogAsErrorException($"Failed to download {s_allJsonUrl}: {hre.Message}");
+ }
+ }
+
+ return File.OpenRead(allJsonPath);
+ }
+
+
+ private sealed record PerOSVersions(string os, ChromeVersionSpec[] versions);
+ private sealed record ChromeVersionSpec(string os, string channel, string version, string branch_base_position, string v8_version);
+}
diff --git a/src/tasks/WasmBuildTasks/WasmBuildTasks.csproj b/src/tasks/WasmBuildTasks/WasmBuildTasks.csproj
index fd88116ca0a855..32f7be8a7fa50f 100644
--- a/src/tasks/WasmBuildTasks/WasmBuildTasks.csproj
+++ b/src/tasks/WasmBuildTasks/WasmBuildTasks.csproj
@@ -7,6 +7,8 @@
+
+