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

[wasm][wbt] Test that dotnet.js could be run from any current directory #69441

Merged
merged 10 commits into from Jul 28, 2022
2 changes: 2 additions & 0 deletions eng/testing/scenarios/BuildWasmAppsJobsList.txt
Expand Up @@ -6,6 +6,7 @@ Wasm.Build.Tests.BlazorWasmBuildPublishTests
Wasm.Build.Tests.BlazorWasmTests
Wasm.Build.Tests.BuildPublishTests
Wasm.Build.Tests.CleanTests
Wasm.Build.Tests.ConfigSrcTests
Wasm.Build.Tests.InvariantGlobalizationTests
Wasm.Build.Tests.LocalEMSDKTests
Wasm.Build.Tests.MainWithArgsTests
Expand All @@ -17,4 +18,5 @@ Wasm.Build.Tests.SatelliteAssembliesTests
Wasm.Build.Tests.WasmBuildAppTest
Wasm.Build.Tests.WasmNativeDefaultsTests
Wasm.Build.Tests.WorkloadTests
Wasm.Build.Tests.WasmRunOutOfAppBundleTests
Wasm.Build.Tests.WasmTemplateTests
6 changes: 5 additions & 1 deletion src/mono/wasm/test-main.js
Expand Up @@ -166,6 +166,7 @@ function initRunArgs() {
runArgs.enableGC = runArgs.enableGC === undefined ? true : runArgs.enableGC;
runArgs.diagnosticTracing = runArgs.diagnosticTracing === undefined ? false : runArgs.diagnosticTracing;
runArgs.debugging = runArgs.debugging === undefined ? false : runArgs.debugging;
runArgs.configSrc = runArgs.configSrc === undefined ? './mono-config.json' : runArgs.configSrc;
// default'ing to true for tests, unless debugging
runArgs.forwardConsole = runArgs.forwardConsole === undefined ? !runArgs.debugging : runArgs.forwardConsole;
}
Expand Down Expand Up @@ -217,6 +218,9 @@ function processQueryArguments(incomingArguments) {
} else {
console.warn("--fetch-random-delay only works on browser")
}
} else if (currentArg.startsWith("--config-src=")) {
const arg = currentArg.substring("--config-src=".length);
runArgs.configSrc = arg;
} else {
break;
}
Expand Down Expand Up @@ -355,7 +359,7 @@ Promise.all([argsPromise, loadDotnetPromise]).then(async ([_, createDotnetRuntim
return createDotnetRuntime(({ MONO, INTERNAL, BINDING, IMPORTS, EXPORTS, Module }) => ({
disableDotnet6Compatibility: true,
config: null,
configSrc: "./mono-config.json",
configSrc: runArgs.configSrc || "./mono-config.json",
onConfigLoaded: (config) => {
if (!Module.config) {
const err = new Error("Could not find ./mono-config.json. Cancelling run");
Expand Down
7 changes: 4 additions & 3 deletions src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs
Expand Up @@ -134,7 +134,8 @@ public BuildTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture bu
string? args = null,
Dictionary<string, string>? envVars = null,
string targetFramework = DefaultTargetFramework,
string? extraXHarnessMonoArgs = null)
string? extraXHarnessMonoArgs = null,
string jsRelativePath = "test-main.js")
{
buildDir ??= _projectDir;
envVars ??= new();
Expand All @@ -156,8 +157,8 @@ public BuildTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture bu
// Use wasm-console.log to get the xharness output for non-browser cases
(string testCommand, string extraXHarnessArgs, bool useWasmConsoleOutput) = host switch
{
RunHost.V8 => ("wasm test", "--js-file=test-main.js --engine=V8 -v trace", true),
RunHost.NodeJS => ("wasm test", "--js-file=test-main.js --engine=NodeJS -v trace", true),
RunHost.V8 => ("wasm test", $"--js-file={jsRelativePath} --engine=V8 -v trace", true),
RunHost.NodeJS => ("wasm test", $"--js-file={jsRelativePath} --engine=NodeJS -v trace", true),
_ => ("wasm test-browser", $"-v trace -b {host} --web-server-use-cop", false)
};

Expand Down
38 changes: 38 additions & 0 deletions src/tests/BuildWasmApps/Wasm.Build.Tests/ConfigSrcTests.cs
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using Xunit;
using Xunit.Abstractions;

#nullable enable

namespace Wasm.Build.Tests
radical marked this conversation as resolved.
Show resolved Hide resolved
{
public class ConfigSrcTests : BuildTestBase
{
public ConfigSrcTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext)
{}

// NOTE: port number determinizes dynamically, so could not generate absolute URI
[Theory]
[BuildAndRun(host: RunHost.V8 | RunHost.NodeJS)]
public void ConfigSrcAbsolutePath(BuildArgs buildArgs, RunHost host, string id)
{
buildArgs = buildArgs with { ProjectName = $"configsrcabsolute_{buildArgs.Config}_{buildArgs.AOT}" };
buildArgs = ExpandBuildArgs(buildArgs);

BuildProject(buildArgs,
id: id,
new BuildProjectOptions(
InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
DotnetWasmFromRuntimePack: !(buildArgs.AOT || buildArgs.Config == "Release")));

string binDir = GetBinDir(baseDir: _projectDir!, config: buildArgs.Config);
string bundleDir = Path.Combine(binDir, "AppBundle");
string configSrc = Path.GetFullPath(Path.Combine(bundleDir, "mono-config.json"));

RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id, extraXHarnessMonoArgs: $"--config-src={configSrc}");
}
}
}
@@ -0,0 +1,83 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using Xunit;
using Xunit.Abstractions;

#nullable enable

namespace Wasm.Build.Tests
radical marked this conversation as resolved.
Show resolved Hide resolved
{
public class WasmRunOutOfAppBundleTests : BuildTestBase
{
public WasmRunOutOfAppBundleTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext)
{}

[Theory]
[BuildAndRun]
public void RunOutOfAppBundle(BuildArgs buildArgs, RunHost host, string id)
{
buildArgs = buildArgs with { ProjectName = $"outofappbundle_{buildArgs.Config}_{buildArgs.AOT}" };
buildArgs = ExpandBuildArgs(buildArgs);

BuildProject(buildArgs,
id: id,
new BuildProjectOptions(
InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
DotnetWasmFromRuntimePack: !(buildArgs.AOT || buildArgs.Config == "Release")));

string binDir = GetBinDir(baseDir: _projectDir!, config: buildArgs.Config);
string appBundleDir = Path.Combine(binDir, "AppBundle");
string tmpBundleDirName = "AppBundleTmp";
string tmpBundleDir = Path.Combine(binDir, tmpBundleDirName);
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of creating this tmpBundleDir in a completely different location, like under Path.GetTempPath()? This would ensure that it isn't dependent on anything in the binDir.
And make sure to add id, and the project name to the dir name, so the different runs don't overlap.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a good method in Node and V8 environments!
I' ll change that style.

However, browsers like Chrome cannot explore the parent directory, so I would like to keep the current style.


if (host == RunHost.Chrome)
{
Directory.Move(appBundleDir, tmpBundleDir);
Directory.CreateDirectory(appBundleDir);
// Create $binDir/AppBundle/AppBundle
Directory.Move(tmpBundleDir, Path.Combine(appBundleDir, "AppBundle"));

string indexHtmlPath = Path.Combine(appBundleDir, "index.html");
if (!File.Exists(indexHtmlPath))
{
var html = @"<html><body><script type=""module"" src=""./AppBundle/test-main.js""></script></body></html>";
File.WriteAllText(indexHtmlPath, html);
}
} else {
CopyAllFiles(appBundleDir, tmpBundleDir);
}

RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id, jsRelativePath: $"../{tmpBundleDirName}/test-main.js");

// Restore AppBundle Dir
if (host == RunHost.Chrome)
{
Directory.Move(Path.Combine(appBundleDir, "AppBundle"), tmpBundleDir);
Directory.Delete(appBundleDir, true);
Directory.Move(tmpBundleDir, appBundleDir);
} else {
Directory.Delete(tmpBundleDir, true);
}
}

private void CopyAllFiles(string srcDir, string destDir)
{
if (!Directory.Exists(destDir))
{
Directory.CreateDirectory(destDir);
}

foreach (var file in Directory.GetFiles(srcDir))
{
File.Copy(file, Path.Combine(destDir, Path.GetFileName(file)), true);
}

foreach (var directory in Directory.GetDirectories(srcDir))
{
CopyAllFiles(directory, Path.Combine(destDir, Path.GetFileName(directory)));
}
}
}
}