Wasm.Build.Tests.WasmSIMDTests
Wasm.Build.Tests.WasmTemplateTests
Wasm.Build.Tests.WorkloadTests
+Wasm.Build.Tests.TestAppScenarios.DownloadResourceProgressTests
if (options.BrowserQueryString != null)
queryString += "&" + string.Join("&", options.BrowserQueryString.Select(kvp => $"{kvp.Key}={kvp.Value}"));
- page = await runner.RunAsync(runCommand, runArgs, onConsoleMessage: OnConsoleMessage, modifyBrowserUrl: url => url + queryString);
+ page = await runner.RunAsync(runCommand, runArgs, onConsoleMessage: OnConsoleMessage, modifyBrowserUrl: url =>
+ {
+ url += queryString;
+ _testOutput.WriteLine($"Opening browser at {url}");
+ return url;
+ });
void OnConsoleMessage(IConsoleMessage msg)
{
--- /dev/null
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+#nullable enable
+
+namespace Wasm.Build.Tests.TestAppScenarios;
+
+public class DownloadResourceProgressTests : AppTestBase
+{
+ public DownloadResourceProgressTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
+ : base(output, buildContext)
+ {
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task DownloadProgressFinishes(bool failAssemblyDownload)
+ {
+ CopyTestAsset("WasmBasicTestApp", $"DownloadResourceProgressTests_{failAssemblyDownload}");
+ PublishProject("Debug");
+
+ var result = await RunSdkStyleApp(new(
+ Configuration: "Debug",
+ ForPublish: true,
+ TestScenario: "DownloadResourceProgressTest",
+ BrowserQueryString: new Dictionary<string, string> { ["failAssemblyDownload"] = failAssemblyDownload.ToString().ToLowerInvariant() }
+ ));
+ Assert.True(
+ result.TestOutput.Any(m => m.Contains("DownloadResourceProgress: Finished")),
+ "The download progress test didn't emit expected error message"
+ );
+ Assert.True(
+ result.ConsoleOutput.Any(m => m.Contains("Retrying download")) == failAssemblyDownload,
+ failAssemblyDownload
+ ? "The download progress test didn't emit expected message about retrying download"
+ : "The download progress test did emit unexpected message about retrying download"
+ );
+ Assert.False(
+ result.ConsoleOutput.Any(m => m.Contains("Retrying download (2)")),
+ "The download progress test did emit unexpected message about second download retry"
+ );
+ Assert.True(
+ result.TestOutput.Any(m => m.Contains("Throw error instead of downloading resource") == failAssemblyDownload),
+ failAssemblyDownload
+ ? "The download progress test didn't emit expected message about failing download"
+ : "The download progress test did emit unexpected message about failing download"
+ );
+ }
+}
}
declare const createDotnetRuntime: CreateDotnetRuntimeType;
-export { AssetEntry, CreateDotnetRuntimeType, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
+export { AssetEntry, CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
// second attempt only after all first attempts are queued
await loaderHelpers.allDownloadsQueued.promise;
try {
+ mono_log_debug(`Retrying download '${asset.name}'`);
return await start_asset_download_with_throttle(asset);
} catch (err) {
asset.pendingDownloadInternal = undefined;
// third attempt after small delay
await delay(100);
+
+ mono_log_debug(`Retrying download (2) '${asset.name}' after delay`);
return await start_asset_download_with_throttle(asset);
}
}
}
let resourcesLoaded = 0;
-let totalResources = 0;
+const totalResources = new Set<string>();
const behaviorByName = (name: string): AssetBehaviours | "other" => {
return name === "dotnet.native.wasm" ? "dotnetwasm"
const type = monoToBlazorAssetTypeMap[asset.behavior];
if (type !== undefined) {
const res = resourceLoader.loadResource(asset.name, asset.resolvedUrl!, asset.hash!, type);
- asset.pendingDownload = res;
- totalResources++;
+ totalResources.add(asset.name!);
res.response.then(() => {
resourcesLoaded++;
if (module.onDownloadResourceProgress)
- module.onDownloadResourceProgress(resourcesLoaded, totalResources);
+ module.onDownloadResourceProgress(resourcesLoaded, totalResources.size);
});
return res;
// The .NET Foundation licenses this file to you under the MIT license.
import type { IMemoryView } from "../marshal";
-import type { CreateDotnetRuntimeType, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI, AssetEntry, ResourceRequest, GlobalizationMode } from ".";
+import type { CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI, AssetEntry, ResourceRequest, GlobalizationMode } from ".";
import type { EmscriptenModule } from "./emscripten";
import type { dotnet, exit } from "../loader/index";
export {
EmscriptenModule,
- RuntimeAPI, ModuleAPI, DotnetModuleConfig, CreateDotnetRuntimeType, MonoConfig, IMemoryView, AssetEntry, ResourceRequest, GlobalizationMode,
+ RuntimeAPI, ModuleAPI, DotnetHostBuilder, DotnetModuleConfig, CreateDotnetRuntimeType, MonoConfig, IMemoryView, AssetEntry, ResourceRequest, GlobalizationMode,
dotnet, exit
};
exit(2, new Error("Missing test scenario. Supply query argument 'test'."));
}
+function testOutput(msg) {
+ console.log(`TestOutput -> ${msg}`);
+}
+
// Prepare base runtime parameters
dotnet
.withElementOnExit()
case "AppSettingsTest":
dotnet.withApplicationEnvironment(params.get("applicationEnvironment"));
break;
+ case "DownloadResourceProgressTest":
+ if (params.get("failAssemblyDownload") === "true") {
+ let assemblyCounter = 0;
+ let failAtAssemblyNumbers = [
+ Math.floor(Math.random() * 5),
+ Math.floor(Math.random() * 5) + 5,
+ Math.floor(Math.random() * 5) + 10
+ ];
+ dotnet.withDiagnosticTracing(true).withResourceLoader((type, name, defaultUri, integrity) => {
+ if (type !== "assembly")
+ return defaultUri;
+
+ assemblyCounter++;
+ if (!failAtAssemblyNumbers.includes(assemblyCounter))
+ return defaultUri;
+
+ testOutput("Throw error instead of downloading resource");
+ const error = new Error("Simulating a failed fetch");
+ error.silent = true;
+ throw error;
+ });
+ }
+ dotnet.withModuleConfig({
+ onDownloadResourceProgress: (loaded, total) => {
+ console.log(`DownloadResourceProgress: ${loaded} / ${total}`);
+ if (loaded === total && loaded !== 0) {
+ testOutput("DownloadResourceProgress: Finished");
+ }
+ }
+ });
+ break;
}
const { getAssemblyExports, getConfig, INTERNAL } = await dotnet.create();
exports.AppSettingsTest.Run();
exit(0);
break;
+ case "DownloadResourceProgressTest":
+ exit(0);
+ break;
default:
console.error(`Unknown test case: ${testCase}`);
exit(3);
+ break;
}
} catch (e) {
exit(1, e);