From ecfbe8e73fc7e5c83d3f89f9fc528470f5099c0b Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 4 Mar 2024 11:20:53 +0000 Subject: [PATCH 1/3] Allow running WebAssembly E2E tests on multithreaded runtime via a single MSBuild flag --- .../BlazorWasmTestAppFixture.cs | 6 ++++ .../Components.TestServer/ClientStartup.cs | 1 + .../Components.TestServer/CorsStartup.cs | 1 + .../MultipleComponents.cs | 1 + .../Components.TestServer/Program.cs | 19 ++++++++---- .../WebAssemblyTestHelper.cs | 31 +++++++++++++++++++ .../test/testassets/Directory.Build.props | 15 +++++++++ 7 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs index 9b70be5e2a6c..48273b47af8c 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using TestServer; using DevHostServerProgram = Microsoft.AspNetCore.Components.WebAssembly.DevServer.Server.Program; namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; @@ -60,6 +61,11 @@ protected override IHost CreateWebHost() args.Add(Environment); } + if (WebAssemblyTestHelper.MultithreadingIsEnabled()) + { + args.Add("--apply-cop-headers"); + } + return DevHostServerProgram.BuildWebHost(args.ToArray()); } diff --git a/src/Components/test/testassets/Components.TestServer/ClientStartup.cs b/src/Components/test/testassets/Components.TestServer/ClientStartup.cs index 219dbcce18a1..c99a0f5f4837 100644 --- a/src/Components/test/testassets/Components.TestServer/ClientStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/ClientStartup.cs @@ -34,6 +34,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/subdir", app => { // Add it before to ensure it takes priority over files in wwwroot + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/CorsStartup.cs b/src/Components/test/testassets/Components.TestServer/CorsStartup.cs index 5f66e9f7e30d..d70eef3d93a1 100644 --- a/src/Components/test/testassets/Components.TestServer/CorsStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/CorsStartup.cs @@ -49,6 +49,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs b/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs index 1069b6e8df65..94dc5d35eff0 100644 --- a/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs +++ b/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs @@ -39,6 +39,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/Client/multiple-components", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/Program.cs b/src/Components/test/testassets/Components.TestServer/Program.cs index a21c65cb8358..16d5a35b81d2 100644 --- a/src/Components/test/testassets/Components.TestServer/Program.cs +++ b/src/Components/test/testassets/Components.TestServer/Program.cs @@ -54,14 +54,21 @@ private static (IHost host, string basePath) CreateDevServerHost(string[] args) var contentRoot = typeof(Program).Assembly.GetCustomAttributes() .Single(a => a.Key == "Microsoft.AspNetCore.InternalTesting.BasicTestApp.ContentRoot") .Value; + var finalArgs = new List(); + finalArgs.AddRange(args); + finalArgs.AddRange( + [ + "--contentroot", contentRoot, + "--pathbase", "/subdir", + "--applicationpath", typeof(BasicTestApp.Program).Assembly.Location, + ]); - var finalArgs = args.Concat(new[] + if (WebAssemblyTestHelper.MultithreadingIsEnabled()) { - "--contentroot", contentRoot, - "--pathbase", "/subdir", - "--applicationpath", typeof(BasicTestApp.Program).Assembly.Location, - }).ToArray(); - var host = DevServerProgram.BuildWebHost(finalArgs); + finalArgs.Add("--apply-cop-headers"); + } + + var host = DevServerProgram.BuildWebHost(finalArgs.ToArray()); return (host, "/subdir"); } diff --git a/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs b/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs new file mode 100644 index 000000000000..7bbb51418cd7 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; + +namespace TestServer; + +public static class WebAssemblyTestHelper +{ + public static bool MultithreadingIsEnabled() + { + var entrypointAssembly = Assembly.GetExecutingAssembly(); + var attribute = entrypointAssembly.GetCustomAttributes() + .FirstOrDefault(x => x.Key.Equals("Microsoft.AspNetCore.InternalTesting.RunWebAssemblyE2ETestsWithMultithreading", StringComparison.Ordinal)); + return attribute is not null && bool.Parse(attribute.Value); + } + + public static void ServeCoopHeadersIfWebAssemblyThreadingEnabled(IApplicationBuilder app) + { + if (MultithreadingIsEnabled()) + { + app.Use(async (ctx, next) => + { + // Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer. + ctx.Response.Headers.Append("Cross-Origin-Embedder-Policy", "require-corp"); + ctx.Response.Headers.Append("Cross-Origin-Opener-Policy", "same-origin"); + await next(ctx); + }); + } + } +} diff --git a/src/Components/test/testassets/Directory.Build.props b/src/Components/test/testassets/Directory.Build.props index e431fcb4f79d..95ad3bfd69f6 100644 --- a/src/Components/test/testassets/Directory.Build.props +++ b/src/Components/test/testassets/Directory.Build.props @@ -3,5 +3,20 @@ true + + + true + + + + <_Parameter1>Microsoft.AspNetCore.InternalTesting.RunWebAssemblyE2ETestsWithMultithreading + <_Parameter2>true + + From 3e30562a050e54f4794ca994bfe2e8bc63aa038c Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 4 Mar 2024 14:33:55 +0000 Subject: [PATCH 2/3] Add it to the remaining E2E test apps --- .../testassets/Components.TestServer/AuthenticationStartup.cs | 1 + .../test/testassets/Components.TestServer/HotReloadStartup.cs | 1 + .../Components.TestServer/InternationalizationStartup.cs | 1 + .../Components.TestServer/RazorComponentEndpointsStartup.cs | 2 ++ .../test/testassets/Components.TestServer/SaveState.cs | 1 + .../StartupWithMapFallbackToClientSideBlazor.cs | 1 + 6 files changed, 7 insertions(+) diff --git a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs index f92842b82d1b..190584e60f56 100644 --- a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs @@ -52,6 +52,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs index d9b275f5851a..51269338ae33 100644 --- a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs @@ -33,6 +33,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); } + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs b/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs index 2ed1cfdb3ff2..9c6a68af89ee 100644 --- a/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs @@ -34,6 +34,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs index 860bbd2b4a53..6dd3c4cb16b6 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs @@ -57,6 +57,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); + if (!env.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); diff --git a/src/Components/test/testassets/Components.TestServer/SaveState.cs b/src/Components/test/testassets/Components.TestServer/SaveState.cs index b5bb7819fbd2..db8c55174a9d 100644 --- a/src/Components/test/testassets/Components.TestServer/SaveState.cs +++ b/src/Components/test/testassets/Components.TestServer/SaveState.cs @@ -37,6 +37,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); } + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs b/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs index d40f802fe8f9..3da94cd6639b 100644 --- a/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs +++ b/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs @@ -33,6 +33,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // The client-side files middleware needs to be here because the base href in hardcoded to /subdir/ app.Map("/subdir", subApp => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); subApp.UseBlazorFrameworkFiles(); subApp.UseStaticFiles(); From 9d8b924fda96c2fba473fd9db3aaa097a4ef9e82 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 4 Mar 2024 18:11:04 +0000 Subject: [PATCH 3/3] Don't use the MT runtime by in E2E tests by default The point of this PR is just to make it easy for us to enable this locally when we want --- src/Components/test/testassets/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/test/testassets/Directory.Build.props b/src/Components/test/testassets/Directory.Build.props index 95ad3bfd69f6..ad5e636d6eb6 100644 --- a/src/Components/test/testassets/Directory.Build.props +++ b/src/Components/test/testassets/Directory.Build.props @@ -10,7 +10,7 @@ headers if and only if this flag is set. Note that until https://github.com/dotnet/runtime/issues/98502 is fixed, you will have to delete artifacts\obj directories after changing this flag. --> - true +