Skip to content

Commit

Permalink
[release/8.0-staging] [browser] Fix debugger support (#98494)
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf authored Jul 26, 2024
1 parent 9b70cf8 commit c9c0bf6
Show file tree
Hide file tree
Showing 29 changed files with 337 additions and 99 deletions.
2 changes: 2 additions & 0 deletions eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ Wasm.Build.Tests.WasmTemplateTests
Wasm.Build.Tests.WorkloadTests
Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests
Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests
Wasm.Build.Tests.TestAppScenarios.WasmSdkDebugLevelTests
Wasm.Build.Tests.TestAppScenarios.WasmAppBuilderDebugLevelTests
5 changes: 1 addition & 4 deletions eng/testing/tests.wasm.targets
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
But we do want to set it for Configuration=Debug .
-->
<WasmDebugLevel Condition="'$(Configuration)' == 'Debug' and '$(WasmDebugLevel)' == ''">-1</WasmDebugLevel>
<!-- We want to have WasmDebugLevel=0, but if DebuggerSupport=true then WasmApp.targets
*will* override it. So, set this to "reset-to-zero" here, and reset the value later
in targets. -->
<WasmDebugLevel Condition="'$(DebuggerSupport)' == 'true' and '$(ContinuousIntegrationBuild)' == 'true' and '$(WasmDebugLevel)' == ''">reset-to-zero</WasmDebugLevel>
<WasmDebugLevel Condition="'$(WasmDebugLevel)' == ''">0</WasmDebugLevel>

<TrimMode Condition="'$(TrimMode)' == ''">full</TrimMode>
<JsonSerializerIsReflectionEnabledByDefault Condition="'$(JsonSerializerIsReflectionEnabledByDefault)' == ''">true</JsonSerializerIsReflectionEnabledByDefault>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache)</_BlazorWebAssemblyStartupMemoryCache>
<_BlazorWebAssemblyJiterpreter>$(BlazorWebAssemblyJiterpreter)</_BlazorWebAssemblyJiterpreter>
<_BlazorWebAssemblyRuntimeOptions>$(BlazorWebAssemblyRuntimeOptions)</_BlazorWebAssemblyRuntimeOptions>
<_WasmDebugLevel>$(WasmDebugLevel)</_WasmDebugLevel>
<_WasmDebugLevel Condition="'$(_WasmDebugLevel)' == ''">0</_WasmDebugLevel>
<_WasmDebugLevel Condition="'$(_WasmDebugLevel)' == '0' and ('$(DebuggerSupport)' == 'true' or '$(Configuration)' == 'Debug')">-1</_WasmDebugLevel>

<!-- Workaround for https://github.com/dotnet/sdk/issues/12114-->
<PublishDir Condition="'$(AppendRuntimeIdentifierToOutputPath)' != 'true' AND '$(PublishDir)' == '$(OutputPath)$(RuntimeIdentifier)\$(PublishDirName)\'">$(OutputPath)$(PublishDirName)\</PublishDir>
Expand Down Expand Up @@ -373,7 +370,7 @@ Copyright (c) .NET Foundation. All rights reserved.
AssemblyPath="@(IntermediateAssembly)"
Resources="@(_WasmOutputWithHash)"
DebugBuild="true"
DebugLevel="$(_WasmDebugLevel)"
DebugLevel="$(WasmDebugLevel)"
LinkerEnabled="false"
CacheBootResources="$(BlazorCacheBootResources)"
OutputPath="$(_WasmBuildBootJsonPath)"
Expand All @@ -389,7 +386,8 @@ Copyright (c) .NET Foundation. All rights reserved.
Extensions="@(WasmBootConfigExtension)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)"
ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" />
ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)"
IsPublish="false" />

<ItemGroup>
<FileWrites Include="$(_WasmBuildBootJsonPath)" />
Expand Down Expand Up @@ -566,7 +564,7 @@ Copyright (c) .NET Foundation. All rights reserved.
AssemblyPath="@(IntermediateAssembly)"
Resources="@(_WasmPublishBootResourceWithHash)"
DebugBuild="false"
DebugLevel="$(_WasmDebugLevel)"
DebugLevel="$(WasmDebugLevel)"
LinkerEnabled="$(PublishTrimmed)"
CacheBootResources="$(BlazorCacheBootResources)"
OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json"
Expand All @@ -582,7 +580,8 @@ Copyright (c) .NET Foundation. All rights reserved.
Extensions="@(WasmBootConfigExtension)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)"
ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" />
ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)"
IsPublish="true" />

<ItemGroup>
<FileWrites Include="$(IntermediateOutputPath)blazor.publish.boot.json" />
Expand Down
7 changes: 6 additions & 1 deletion src/mono/wasi/build/WasiApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@

<Target Name="_WasiDefaultGenerateAppBundle">

<PropertyGroup>
<_WasmOutputSymbolsToAppBundle Condition="'$(CopyOutputSymbolsToPublishDirectory)' == 'true' and '$(_IsPublishing)' == 'true'">true</_WasmOutputSymbolsToAppBundle>
<_WasmOutputSymbolsToAppBundle Condition="'$(_WasmOutputSymbolsToAppBundle)' == ''">false</_WasmOutputSymbolsToAppBundle>
</PropertyGroup>

<WasiAppBuilder
AppDir="$(WasmAppDir)"
Assemblies="@(_WasmAssembliesInternal)"
Expand All @@ -382,7 +387,7 @@
FilesToIncludeInFileSystem="@(WasmFilesToIncludeInFileSystem)"
ExtraFilesToDeploy="@(WasmExtraFilesToDeploy)"
NativeAssets="@(WasmNativeAsset)"
DebugLevel="$(WasmDebugLevel)"
OutputSymbolsToAppBundle="$(_WasmOutputSymbolsToAppBundle)"
/>
</Target>

Expand Down
4 changes: 4 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ public string CreateBlazorWasmTemplateProject(string id)

if (options.ExpectSuccess && options.AssertAppBundle)
{
// Because we do relink in Release publish by default
if (options.Config == "Release")
options = options with { ExpectedFileType = NativeFilesType.Relinked };

AssertBundle(res.Output, options with { IsPublish = true });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public async Task LoadAppSettingsBasedOnApplicationEnvironment(string applicatio
CopyTestAsset("WasmBasicTestApp", "AppSettingsTests");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(
var result = await RunSdkStyleAppForPublish(new(
Configuration: "Debug",
TestScenario: "AppSettingsTest",
BrowserQueryString: new Dictionary<string, string> { ["applicationEnvironment"] = applicationEnvironment }
Expand Down
21 changes: 14 additions & 7 deletions src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,29 @@ protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix
_projectDir = Path.Combine(_projectDir!, "App");
}

protected void BuildProject(string configuration)
protected void BuildProject(string configuration, bool assertAppBundle = true, params string[] extraArgs)
{
(CommandResult result, _) = BlazorBuild(new BlazorBuildOptions(Id, configuration));
(CommandResult result, _) = BlazorBuild(new BlazorBuildOptions(Id, configuration, AssertAppBundle: assertAppBundle), extraArgs);
result.EnsureSuccessful();
}

protected void PublishProject(string configuration)
protected void PublishProject(string configuration, bool assertAppBundle = true, params string[] extraArgs)
{
(CommandResult result, _) = BlazorPublish(new BlazorBuildOptions(Id, configuration));
(CommandResult result, _) = BlazorPublish(new BlazorBuildOptions(Id, configuration, AssertAppBundle: assertAppBundle), extraArgs);
result.EnsureSuccessful();
}

protected ToolCommand CreateDotNetCommand() => new DotNetCommand(s_buildEnv, _testOutput)
.WithWorkingDirectory(_projectDir!)
.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir);

protected async Task<RunResult> RunSdkStyleApp(RunOptions options)
protected Task<RunResult> RunSdkStyleAppForBuild(RunOptions options)
=> RunSdkStyleApp(options, BlazorRunHost.DotnetRun);

protected Task<RunResult> RunSdkStyleAppForPublish(RunOptions options)
=> RunSdkStyleApp(options, BlazorRunHost.WebServer);

private async Task<RunResult> RunSdkStyleApp(RunOptions options, BlazorRunHost host = BlazorRunHost.DotnetRun)
{
string queryString = "?test=" + options.TestScenario;
if (options.BrowserQueryString != null)
Expand All @@ -67,9 +73,10 @@ protected async Task<RunResult> RunSdkStyleApp(RunOptions options)
CheckCounter: false,
Config: options.Configuration,
OnConsoleMessage: OnConsoleMessage,
QueryString: queryString);
QueryString: queryString,
Host: host);

await BlazorRunForBuildWithDotnetRun(blazorRunOptions);
await BlazorRunTest(blazorRunOptions);

void OnConsoleMessage(IConsoleMessage msg)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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 abstract class DebugLevelTestsBase : AppTestBase
{
public DebugLevelTestsBase(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

protected void AssertDebugLevel(RunResult result, int value)
{
Assert.Collection(
result.TestOutput,
m => Assert.Equal($"WasmDebugLevel: {value}", m)
);
}

protected abstract void SetupProject(string projectId);
protected abstract Task<RunResult> RunForBuild(string configuration);
protected abstract Task<RunResult> RunForPublish(string configuration);

[Theory]
[InlineData("Debug")]
[InlineData("Release")]
public async Task BuildWithDefaultLevel(string configuration)
{
SetupProject($"DebugLevelTests_BuildWithDefaultLevel_{configuration}");
BuildProject(configuration, assertAppBundle: false);

var result = await RunForBuild(configuration);
AssertDebugLevel(result, -1);
}

[Theory]
[InlineData("Debug", 1)]
[InlineData("Release", 1)]
[InlineData("Debug", 0)]
[InlineData("Release", 0)]
public async Task BuildWithExplicitValue(string configuration, int debugLevel)
{
SetupProject($"DebugLevelTests_BuildWithExplicitValue_{configuration}");
BuildProject(configuration, assertAppBundle: false, extraArgs: $"-p:WasmDebugLevel={debugLevel}");

var result = await RunForBuild(configuration);
AssertDebugLevel(result, debugLevel);
}

[Theory]
[InlineData("Debug")]
[InlineData("Release")]
public async Task PublishWithDefaultLevel(string configuration)
{
SetupProject($"DebugLevelTests_PublishWithDefaultLevel_{configuration}");
PublishProject(configuration, assertAppBundle: false);

var result = await RunForPublish(configuration);
AssertDebugLevel(result, 0);
}

[Theory]
[InlineData("Debug", 1)]
[InlineData("Release", 1)]
[InlineData("Debug", -1)]
[InlineData("Release", -1)]
public async Task PublishWithExplicitValue(string configuration, int debugLevel)
{
SetupProject($"DebugLevelTests_PublishWithExplicitValue_{configuration}");
PublishProject(configuration, assertAppBundle: false, extraArgs: $"-p:WasmDebugLevel={debugLevel}");

var result = await RunForPublish(configuration);
AssertDebugLevel(result, debugLevel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task LoadLazyAssemblyBeforeItIsNeeded()
CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "LazyLoadingTest"));
var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LazyLoadingTest"));
Assert.True(result.TestOutput.Any(m => m.Contains("FirstName")), "The lazy loading test didn't emit expected message with JSON");
}

Expand All @@ -36,7 +36,7 @@ public async Task FailOnMissingLazyAssembly()
CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(
var result = await RunSdkStyleAppForPublish(new(
Configuration: "Debug",
TestScenario: "LazyLoadingTest",
BrowserQueryString: new Dictionary<string, string> { ["loadRequiredAssembly"] = "false" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public async Task LoadLibraryInitializer()
CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_LoadLibraryInitializer");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "LibraryInitializerTest"));
var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LibraryInitializerTest"));
Assert.Collection(
result.TestOutput,
m => Assert.Equal("LIBRARY_INITIALIZER_TEST = 1", m)
Expand All @@ -42,7 +42,7 @@ public async Task AbortStartupOnError()
CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_AbortStartupOnError");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(
var result = await RunSdkStyleAppForPublish(new(
Configuration: "Debug",
TestScenario: "LibraryInitializerTest",
BrowserQueryString: new Dictionary<string, string> { ["throwError"] = "true" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload)
CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(
var result = await RunSdkStyleAppForPublish(new(
Configuration: "Debug",
TestScenario: "DownloadResourceProgressTest",
BrowserQueryString: new Dictionary<string, string> { ["failAssemblyDownload"] = failAssemblyDownload.ToString().ToLowerInvariant() }
Expand All @@ -54,24 +54,4 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload)
: "The download progress test did emit unexpected message about failing download"
);
}

[Fact]
public async Task OutErrOverrideWorks()
{
CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks");
PublishProject("Debug");

var result = await RunSdkStyleApp(new(
Configuration: "Debug",
TestScenario: "OutErrOverrideWorks"
));
Assert.True(
result.ConsoleOutput.Any(m => m.Contains("Emscripten out override works!")),
"Emscripten out override doesn't work"
);
Assert.True(
result.ConsoleOutput.Any(m => m.Contains("Emscripten err override works!")),
"Emscripten err override doesn't work"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public async Task LoadSatelliteAssembly()
CopyTestAsset("WasmBasicTestApp", "SatelliteLoadingTests");
BuildProject("Debug");

var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "SatelliteAssembliesTest"));
var result = await RunSdkStyleAppForBuild(new(Configuration: "Debug", TestScenario: "SatelliteAssembliesTest"));
Assert.Collection(
result.TestOutput,
m => Assert.Equal("default: hello", m),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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 WasmAppBuilderDebugLevelTests : DebugLevelTestsBase
{
public WasmAppBuilderDebugLevelTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

protected override void SetupProject(string projectId)
{
Id = $"{projectId}_{GetRandomId()}";
string projectfile = CreateWasmTemplateProject(Id, "wasmconsole", extraArgs: "-f net8.0");
string projectDir = Path.GetDirectoryName(projectfile)!;
string mainJs = Path.Combine(projectDir, "main.mjs");
string mainJsContent = File.ReadAllText(mainJs);
mainJsContent = mainJsContent
.Replace("await dotnet.run()", "console.log('TestOutput -> WasmDebugLevel: ' + config.debugLevel); exit(0)");
File.WriteAllText(mainJs, mainJsContent);
}

protected override Task<RunResult> RunForBuild(string configuration)
{
CommandResult res = new RunCommand(s_buildEnv, _testOutput)
.WithWorkingDirectory(_projectDir!)
.ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}");

return Task.FromResult(ProcessRunOutput(res));
}

private RunResult ProcessRunOutput(CommandResult res)
{
var output = res.Output.Split(Environment.NewLine);
_testOutput.WriteLine($"DEBUG: parsed lines '{String.Join(", ", output)}'");

var prefix = "[] TestOutput -> ";
var testOutput = output
.Where(l => l.StartsWith(prefix))
.Select(l => l.Substring(prefix.Length))
.ToArray();

_testOutput.WriteLine($"DEBUG: testOutput '{String.Join(", ", testOutput)}'");
return new RunResult(res.ExitCode, testOutput, output);
}

protected override Task<RunResult> RunForPublish(string configuration)
{
// WasmAppBuilder does publish to the same folder as build (it overrides the output),
// and thus using dotnet run work correctly for publish as well.
CommandResult res = new RunCommand(s_buildEnv, _testOutput)
.WithWorkingDirectory(_projectDir!)
.ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}");

return Task.FromResult(ProcessRunOutput(res));
}
}
Loading

0 comments on commit c9c0bf6

Please sign in to comment.