Skip to content

Commit

Permalink
[browser] Fix debugger support in WasmAppBuilder (dotnet#100675)
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf authored May 31, 2024
1 parent 59f2833 commit f190f34
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 146 deletions.
3 changes: 2 additions & 1 deletion eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ Wasm.Build.Tests.WasmSIMDTests
Wasm.Build.Tests.WasmTemplateTests
Wasm.Build.Tests.WorkloadTests
Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests
Wasm.Build.Tests.TestAppScenarios.DebugLevelTests
Wasm.Build.Tests.TestAppScenarios.WasmSdkDebugLevelTests
Wasm.Build.Tests.TestAppScenarios.WasmAppBuilderDebugLevelTests
2 changes: 2 additions & 0 deletions src/mono/browser/build/BrowserWasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
<!-- TODO: set this from some user-facing property? -1 means use the default baked into dotnet.native.js -->
<_WasmPThreadPoolInitialSize Condition="'$(_WasmPThreadPoolInitialSize)' == ''">-1</_WasmPThreadPoolInitialSize>
<_WasmPThreadPoolUnusedSize Condition="'$(_WasmPThreadPoolUnusedSize)' == ''">-1</_WasmPThreadPoolUnusedSize>
<_WasmIsPublishing Condition="'$(_WasmIsPublishing)' == '' and '$(_IsPublishing)' != ''">$(_IsPublishing)</_WasmIsPublishing>
</PropertyGroup>

<ItemGroup>
Expand All @@ -152,6 +153,7 @@
ExtraConfig="@(WasmExtraConfig)"
NativeAssets="@(WasmNativeAsset)"
DebugLevel="$(WasmDebugLevel)"
IsPublish="$(_WasmIsPublishing)"
IncludeThreadsWorker="$(WasmEnableThreads)"
PThreadPoolInitialSize="$(_WasmPThreadPoolInitialSize)"
PThreadPoolUnusedSize="$(_WasmPThreadPoolUnusedSize)"
Expand Down
109 changes: 0 additions & 109 deletions src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTests.cs

This file was deleted.

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
@@ -0,0 +1,70 @@
// 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");
string projectDir = Path.GetDirectoryName(projectfile)!;
string mainJs = Path.Combine(projectDir, "main.mjs");
string mainJsContent = File.ReadAllText(mainJs);
mainJsContent = mainJsContent
.Replace("import { dotnet }", "import { dotnet, exit }")
.Replace("await runMainAndExit()", "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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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 WasmSdkDebugLevelTests : DebugLevelTestsBase
{
public WasmSdkDebugLevelTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

protected override void SetupProject(string projectId) => CopyTestAsset("WasmBasicTestApp", projectId, "App");

protected override Task<RunResult> RunForBuild(string configuration) => RunSdkStyleAppForBuild(new(
Configuration: configuration,
TestScenario: "DebugLevelTest"
));

protected override Task<RunResult> RunForPublish(string configuration) => RunSdkStyleAppForPublish(new(
Configuration: configuration,
TestScenario: "DebugLevelTest"
));

[Theory]
[InlineData("Debug")]
[InlineData("Release")]
public async Task PublishWithDefaultLevelAndPdbs(string configuration)
{
SetupProject($"DebugLevelTests_PublishWithDefaultLevelAndPdbs_{configuration}");
PublishProject(configuration, assertAppBundle: false, extraArgs: $"-p:CopyOutputSymbolsToPublishDirectory=true");

var result = await RunForPublish(configuration);
AssertDebugLevel(result, -1);
}
}
2 changes: 1 addition & 1 deletion src/mono/wasm/build/WasmApp.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@
<!-- Use a unique property, so the already run wasm targets can also run -->
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="WasmNestedPublishApp"
Properties="_WasmInNestedPublish_UniqueProperty_XYZ=true;;WasmBuildingForNestedPublish=true;DeployOnBuild=;_IsPublishing=">
Properties="_WasmInNestedPublish_UniqueProperty_XYZ=true;;WasmBuildingForNestedPublish=true;DeployOnBuild=;_IsPublishing=;_WasmIsPublishing=$(_IsPublishing)">
<Output TaskParameter="TargetOutputs" ItemName="WasmNestedPublishAppResultItems" />
</MSBuild>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Microsoft.NET.Sdk.WebAssembly
{
public class BootJsonBuilderHelper(TaskLoggingHelper Log, bool IsMultiThreaded)
public class BootJsonBuilderHelper(TaskLoggingHelper Log, string DebugLevel, bool IsMultiThreaded, bool IsPublish)
{
private static readonly string[] coreAssemblyNames = [
"System.Private.CoreLib",
Expand Down Expand Up @@ -106,5 +106,35 @@ static void AddDictionary(StringBuilder sb, Dictionary<string, string>? res)

return null;
}

public int GetDebugLevel(bool hasPdb)
{
int? debugLevel = ParseOptionalInt(DebugLevel);

// If user didn't give us a value, check if we have any PDB.
if (debugLevel == null && hasPdb)
debugLevel = -1;

// Fallback to -1 for build, or 0 for publish
debugLevel ??= IsPublish ? 0 : -1;

return debugLevel.Value;
}

public bool? ParseOptionalBool(string value)
{
if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out var boolValue))
return null;

return boolValue;
}

public int? ParseOptionalInt(string value)
{
if (string.IsNullOrEmpty(value) || !int.TryParse(value, out var intValue))
return null;

return intValue;
}
}
}
Loading

0 comments on commit f190f34

Please sign in to comment.