From e6688b20d3a165546464804bd97712f6512e4153 Mon Sep 17 00:00:00 2001 From: Damian Hickey Date: Wed, 18 Feb 2026 11:40:22 +0100 Subject: [PATCH] Migrate Bff.Tests to xUnit v3 with MTP support --- @progress.txt | 31 +++++ bff/test/Bff.Tests/AssemblyInfo.cs | 4 + .../Bff.Tests/Benchmarks/BenchmarksTests.cs | 12 +- bff/test/Bff.Tests/Bff.Tests.csproj | 4 +- bff/test/Bff.Tests/BffFrontendIndexTests.cs | 4 +- .../Bff.Tests/BffFrontendMatchingTests.cs | 4 +- bff/test/Bff.Tests/BffFrontendSigninTests.cs | 4 +- .../Bff.Tests/BffOptionsConfigurationTests.cs | 4 +- bff/test/Bff.Tests/BffRemoteApiTests.cs | 3 +- bff/test/Bff.Tests/BffScenarioTests.cs | 4 +- .../BffWithoutExplicitFrontendTests.cs | 6 +- bff/test/Bff.Tests/Blazor/BffBlazorTests.cs | 6 +- .../Configuration/ConfigBindingTests.cs | 5 +- bff/test/Bff.Tests/ConventionTests.cs | 130 +----------------- .../FrontendCountDiagnosticEntryTests.cs | 4 +- .../Endpoints/DPoPRemoteEndpointTests.cs | 6 +- .../DPoPTestsWithManualAuthentication.cs | 5 +- .../Bff.Tests/Endpoints/LocalEndpointTests.cs | 4 +- .../BackchannelLogoutEndpointTests.cs | 5 +- .../Management/LoginEndpointTests.cs | 6 +- .../Management/LogoutEndpointTests.cs | 4 +- .../Management/ManagementBasePathTests.cs | 4 +- .../Endpoints/Management/UserEndpointTests.cs | 4 +- .../Endpoints/RemoteEndpointTests.cs | 3 +- bff/test/Bff.Tests/Endpoints/WireupTests.cs | 4 +- bff/test/Bff.Tests/Endpoints/YarpTests.cs | 3 +- .../SessionIntegrationTests.cs | 6 +- .../EntityFramework/UserSessionStoreTests.cs | 8 +- .../Headers/ApiAndBffUseForwardedHeaders.cs | 4 +- .../Headers/ApiUseForwardedHeaders.cs | 4 +- bff/test/Bff.Tests/Headers/GeneralTests.cs | 3 +- ...ccessTokenRetriever_Extensibility_tests.cs | 4 +- bff/test/Bff.Tests/LicensingTests.cs | 4 +- .../MultiFrontend/FrontendSelectorTests.cs | 6 +- .../SessionManagement/CookieSlidingTests.cs | 5 +- .../RevokeRefreshTokenTests.cs | 4 +- .../ServerSideTicketStoreTests.cs | 4 +- bff/test/Bff.Tests/TestInfra/BffTestBase.cs | 10 +- .../Bff.Tests/TestInfra/TestHostContext.cs | 2 - .../Bff.Tests/TestInfra/TestInfraTests.cs | 4 +- 40 files changed, 101 insertions(+), 240 deletions(-) create mode 100644 @progress.txt create mode 100644 bff/test/Bff.Tests/AssemblyInfo.cs diff --git a/@progress.txt b/@progress.txt new file mode 100644 index 000000000..65a485594 --- /dev/null +++ b/@progress.txt @@ -0,0 +1,31 @@ +## Progress - xUnit v3 with MTP Migration + +### Story 1: Upgrade shared test infrastructure (COMPLETED) +- Commit: c85a70f32 +- Branch: dh/xunit-v3-mtp + +#### Changes Made: +1. **Directory.Packages.props**: Removed xUnit v2 packages (xunit.core, xunit.runner.visualstudio, Xunit.SkippableFact, Verify.Xunit, Serilog.Sinks.XUnit, Meziantou.Extensions.Logging.Xunit, Microsoft.Playwright.Xunit, coverlet.collector). Added xUnit v3 packages (xunit.v3.core, xunit.v3.core.mtp-v2, xunit.v3.extensibility.core, Microsoft.Testing.Extensions.CodeCoverage, Verify.XunitV3, MartinCostello.Logging.XUnit.v3, Microsoft.Playwright.Xunit.v3). + +2. **test.props**: Updated to use xunit.v3.core.mtp-v2 and Microsoft.Testing.Extensions.CodeCoverage. Added OutputType=exe and UseMicrosoftTestingPlatformRunner=true for MTP support. + +3. **shared/Xunit.Playwright/Xunit.Playwright.csproj**: Changed xunit.core to xunit.v3.extensibility.core (since it's a library, not a test project). Changed Microsoft.Playwright.Xunit to Microsoft.Playwright.Xunit.v3. Removed Serilog.Sinks.XUnit and Xunit.SkippableFact. + +4. **shared/Xunit.Playwright/PlaywrightTestBase.cs**: Updated to xUnit v3 APIs. Changed namespace from Microsoft.Playwright.Xunit to Microsoft.Playwright.Xunit.v3. Added using Xunit.v3 for BeforeAfterTestAttribute. Constructor no longer takes ITestOutputHelper (uses TestContext.Current.TestOutputHelper). Changed InitializeAsync/DisposeAsync from Task to ValueTask. Updated BeforeAfterTestAttribute.Before/After signatures to include IXunitTest parameter. Renamed Output to TestOutputHelper. + +5. **shared/Xunit.Playwright/IntegrationTestBase.cs**: Same pattern as PlaywrightTestBase - removed ITestOutputHelper from constructor, use TestContext.Current.TestOutputHelper. Renamed Output to TestOutputHelper. Changed Skip.If to Assert.Skip. + +6. **shared/Xunit.Playwright/AppHostFixture.cs**: Changed InitializeAsync/DisposeAsync from Task to ValueTask. Changed Skip.If to Assert.Skip. + +7. **Deleted files**: Retries directory (RetryableFact.cs, RetryableTestCase.cs, RetryableTestDiscoverer.cs) - incompatible with v3. xunit.runner.json files from IdentityServer test projects. + +#### Important Notes for Next Stories: +- `xunit.v3.extensibility.core` is needed for library projects (like Xunit.Playwright) that aren't test projects themselves. `xunit.v3.core` requires OutputType=exe. +- xUnit v3 `BeforeAfterTestAttribute` is in `Xunit.v3` namespace and methods take `(MethodInfo, IXunitTest)` instead of just `(MethodInfo)`. +- `IAsyncLifetime.InitializeAsync()` returns `ValueTask` (not `Task`) in xUnit v3. Same for `DisposeAsync()`. +- `PageTest` from Microsoft.Playwright.Xunit.v3 also uses `ValueTask` for InitializeAsync/DisposeAsync. +- `ITestOutputHelper` is in `Xunit` namespace (not `Xunit.Abstractions`). +- `TestContext.Current.TestOutputHelper!` replaces constructor-injected `ITestOutputHelper`. +- Property renamed from `Output` to `TestOutputHelper` - downstream test classes that reference `Output` will need updating. +- `Skip.If(true, ...)` replaced with `Assert.Skip(...)` (built-in to xUnit v3). +- Test projects (Stories 2-5) still reference old packages and won't build until they are migrated. diff --git a/bff/test/Bff.Tests/AssemblyInfo.cs b/bff/test/Bff.Tests/AssemblyInfo.cs new file mode 100644 index 000000000..ea3e2a365 --- /dev/null +++ b/bff/test/Bff.Tests/AssemblyInfo.cs @@ -0,0 +1,4 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +[assembly: CaptureConsole] diff --git a/bff/test/Bff.Tests/Benchmarks/BenchmarksTests.cs b/bff/test/Bff.Tests/Benchmarks/BenchmarksTests.cs index 99917cd95..9cbdfdd62 100644 --- a/bff/test/Bff.Tests/Benchmarks/BenchmarksTests.cs +++ b/bff/test/Bff.Tests/Benchmarks/BenchmarksTests.cs @@ -10,13 +10,21 @@ public static class BenchmarkTests public class Login(Login.Fixture fixture) : TestBase(fixture) { - public class Fixture : MultiFrontendBenchmarks, IAsyncLifetime; + public class Fixture : MultiFrontendBenchmarks, IAsyncLifetime + { + ValueTask IAsyncLifetime.InitializeAsync() => new ValueTask(InitializeAsync()); + ValueTask IAsyncDisposable.DisposeAsync() => new ValueTask(DisposeAsync()); + } } public class Proxy(Proxy.Fixture fixture) : TestBase(fixture) { - public class Fixture : SingleFrontendBenchmarks, IAsyncLifetime; + public class Fixture : SingleFrontendBenchmarks, IAsyncLifetime + { + ValueTask IAsyncLifetime.InitializeAsync() => new ValueTask(InitializeAsync()); + ValueTask IAsyncDisposable.DisposeAsync() => new ValueTask(DisposeAsync()); + } } //public class Yarp(Yarp.Fixture fixture) diff --git a/bff/test/Bff.Tests/Bff.Tests.csproj b/bff/test/Bff.Tests/Bff.Tests.csproj index 7eedb22da..c883aa828 100644 --- a/bff/test/Bff.Tests/Bff.Tests.csproj +++ b/bff/test/Bff.Tests/Bff.Tests.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -17,7 +17,7 @@ - + diff --git a/bff/test/Bff.Tests/BffFrontendIndexTests.cs b/bff/test/Bff.Tests/BffFrontendIndexTests.cs index 563a8d974..63b122525 100644 --- a/bff/test/Bff.Tests/BffFrontendIndexTests.cs +++ b/bff/test/Bff.Tests/BffFrontendIndexTests.cs @@ -8,13 +8,11 @@ using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Hybrid; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; public class BffFrontendIndexTests : BffTestBase { - public BffFrontendIndexTests(ITestOutputHelper output) : base(output) => + public BffFrontendIndexTests() : base() => // Disable the map to '/' for the test Bff.MapGetForRoot = false; diff --git a/bff/test/Bff.Tests/BffFrontendMatchingTests.cs b/bff/test/Bff.Tests/BffFrontendMatchingTests.cs index 26e2eaf9f..52e0b4e8b 100644 --- a/bff/test/Bff.Tests/BffFrontendMatchingTests.cs +++ b/bff/test/Bff.Tests/BffFrontendMatchingTests.cs @@ -5,15 +5,13 @@ using System.Net; using Duende.Bff.DynamicFrontends; using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.HttpOverrides; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; public class BffFrontendMatchingTests : BffTestBase { private static readonly BffFrontendName NoFrontendSelected = BffFrontendName.Parse("no_frontend_selected"); - public BffFrontendMatchingTests(ITestOutputHelper output) : base(output) + public BffFrontendMatchingTests() : base() { // Add a frontend that should never be matched AddOrUpdateFrontend(Some.NeverMatchingFrontEnd()); diff --git a/bff/test/Bff.Tests/BffFrontendSigninTests.cs b/bff/test/Bff.Tests/BffFrontendSigninTests.cs index a2368d4f6..cf6c8d5ef 100644 --- a/bff/test/Bff.Tests/BffFrontendSigninTests.cs +++ b/bff/test/Bff.Tests/BffFrontendSigninTests.cs @@ -12,13 +12,11 @@ using Duende.Bff.Yarp; using Duende.IdentityServer.Extensions; using Microsoft.Extensions.Caching.Hybrid; using Microsoft.IdentityModel.Protocols.OpenIdConnect; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; public class BffFrontendSigninTests : BffTestBase { - public BffFrontendSigninTests(ITestOutputHelper output) : base(output) => + public BffFrontendSigninTests() : base() => Bff.OnConfigureApp += app => { app.MapGet("/secret", (HttpContext c) => diff --git a/bff/test/Bff.Tests/BffOptionsConfigurationTests.cs b/bff/test/Bff.Tests/BffOptionsConfigurationTests.cs index 3671566f2..c9ad480c8 100644 --- a/bff/test/Bff.Tests/BffOptionsConfigurationTests.cs +++ b/bff/test/Bff.Tests/BffOptionsConfigurationTests.cs @@ -7,11 +7,9 @@ using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.Extensions.Options; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; -public class BffOptionsConfigurationTests(ITestOutputHelper output) : BffTestBase(output) +public class BffOptionsConfigurationTests : BffTestBase { [Theory] [MemberData(nameof(AllSetups))] diff --git a/bff/test/Bff.Tests/BffRemoteApiTests.cs b/bff/test/Bff.Tests/BffRemoteApiTests.cs index b05930a42..403bf9dad 100644 --- a/bff/test/Bff.Tests/BffRemoteApiTests.cs +++ b/bff/test/Bff.Tests/BffRemoteApiTests.cs @@ -10,14 +10,13 @@ using Duende.Bff.Configuration; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; -using Xunit.Abstractions; using Resource = Duende.Bff.AccessTokenManagement.Resource; namespace Duende.Bff.Tests; public class BffRemoteApiTests : BffTestBase { - public BffRemoteApiTests(ITestOutputHelper output) : base(output) => + public BffRemoteApiTests() : base() => Bff.OnConfigureBff += bff => { bff.AddRemoteApis(); diff --git a/bff/test/Bff.Tests/BffScenarioTests.cs b/bff/test/Bff.Tests/BffScenarioTests.cs index 0f48e3e4c..278776361 100644 --- a/bff/test/Bff.Tests/BffScenarioTests.cs +++ b/bff/test/Bff.Tests/BffScenarioTests.cs @@ -3,11 +3,9 @@ using Duende.AccessTokenManagement; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; -public class BffScenarioTests(ITestOutputHelper output) : BffTestBase(output) +public class BffScenarioTests : BffTestBase { [Fact] public async Task When_using_bff_as_host_and_client_credentials_token_manager_with_no_http_context_still_works() diff --git a/bff/test/Bff.Tests/BffWithoutExplicitFrontendTests.cs b/bff/test/Bff.Tests/BffWithoutExplicitFrontendTests.cs index 9737edf24..40f11c29b 100644 --- a/bff/test/Bff.Tests/BffWithoutExplicitFrontendTests.cs +++ b/bff/test/Bff.Tests/BffWithoutExplicitFrontendTests.cs @@ -3,13 +3,11 @@ using Duende.Bff.Tests.TestInfra; using Duende.IdentityServer.Extensions; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; -public class BffWithoutExplicitFrontendTests(ITestOutputHelper output) : BffTestBase(output) +public class BffWithoutExplicitFrontendTests : BffTestBase { - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { Bff.OnConfigureApp += app => { diff --git a/bff/test/Bff.Tests/Blazor/BffBlazorTests.cs b/bff/test/Bff.Tests/Blazor/BffBlazorTests.cs index 0b2456bc0..dc1687141 100644 --- a/bff/test/Bff.Tests/Blazor/BffBlazorTests.cs +++ b/bff/test/Bff.Tests/Blazor/BffBlazorTests.cs @@ -8,14 +8,12 @@ using Duende.Bff.Tests.Blazor.Components; using Duende.Bff.Tests.TestInfra; using Microsoft.EntityFrameworkCore; using UserSessionDb; -using Xunit.Abstractions; - namespace Bff.Tests.Blazor; -public class BffBlazorTests(ITestOutputHelper testOutputHelper) : BffTestBase(testOutputHelper) +public class BffBlazorTests : BffTestBase { private bool _addServerSideSessions = true; - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { Bff.MapGetForRoot = false; Bff.OnConfigureServices += services => diff --git a/bff/test/Bff.Tests/Configuration/ConfigBindingTests.cs b/bff/test/Bff.Tests/Configuration/ConfigBindingTests.cs index a3a25f6a2..950c86131 100644 --- a/bff/test/Bff.Tests/Configuration/ConfigBindingTests.cs +++ b/bff/test/Bff.Tests/Configuration/ConfigBindingTests.cs @@ -6,7 +6,6 @@ using Duende.Bff.DynamicFrontends; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.Extensions.Options; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Configuration; @@ -133,9 +132,9 @@ public class OptionsMonitorExplorationTests } -public class ConfigBindingTests(ITestOutputHelper output) : BffTestBase(output) +public class ConfigBindingTests : BffTestBase { - private readonly ITestOutputHelper _output = output; + private readonly ITestOutputHelper _output = TestContext.Current.TestOutputHelper!; /// diff --git a/bff/test/Bff.Tests/ConventionTests.cs b/bff/test/Bff.Tests/ConventionTests.cs index 14003ef69..c77a4a312 100644 --- a/bff/test/Bff.Tests/ConventionTests.cs +++ b/bff/test/Bff.Tests/ConventionTests.cs @@ -15,12 +15,12 @@ using Duende.Bff.Internal; using Duende.Bff.SessionManagement.SessionStore; using Duende.Bff.SessionManagement.TicketStore; using Duende.Bff.Yarp; -using Xunit.Abstractions; namespace Duende.Bff.Tests; -public class ConventionTests(ITestOutputHelper output) +public class ConventionTests { + private readonly ITestOutputHelper _output = TestContext.Current.TestOutputHelper!; public static readonly Assembly BffAssembly = typeof(BffBuilder).Assembly; public static readonly Assembly BffBlazorAssembly = typeof(BffBlazorServerOptions).Assembly; public static readonly Assembly BffBlazorClientAssembly = typeof(BffBlazorClientOptions).Assembly; @@ -224,7 +224,7 @@ public class ConventionTests(ITestOutputHelper output) foreach (var failure in failures) { - output.WriteLine(failure); + _output.WriteLine(failure); } failures.ShouldBeEmpty(); @@ -240,128 +240,6 @@ public class ConventionTests(ITestOutputHelper output) return type.IsNestedPrivate || type.IsNotPublic; } - -#nullable disable - [Fact] - public void AccessTokenManagement_is_not_exposed() - { - var accessTokenManagementNamespace = typeof(IClientCredentialsTokenManager).Namespace!; - List errors = new(); - - foreach (var type in AllTypes) - { - // Only consider public types - if (!type.IsPublic) - { - continue; - } - - // Check if the type itself is in the forbidden namespace - if (type.Namespace != null && type.Namespace.StartsWith(accessTokenManagementNamespace)) - { - errors.Add($"Type {type.FullName} is public and in forbidden namespace."); - } - - // Check public members for forbidden types - var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | - BindingFlags.DeclaredOnly); - foreach (var member in members) - { - switch (member) - { - case MethodInfo method: - // Skip implicit and explicit conversion operators - if (method.Name == "op_Implicit") - { - break; - } - - if (IsForbiddenType(method.ReturnType)) - { - errors.Add( - $"{type.FullName}.{method.Name} returns forbidden type {method.ReturnType.FullName}"); - } - - foreach (var param in method.GetParameters()) - { - if (IsForbiddenType(param.ParameterType)) - { - errors.Add( - $"{type.FullName}.{method.Name} parameter '{param.Name}' is forbidden type {param.ParameterType.FullName}"); - } - } - - break; - case PropertyInfo prop: - if (IsForbiddenType(prop.PropertyType)) - { - errors.Add( - $"{type.FullName}.{prop.Name} property is forbidden type {prop.PropertyType.FullName}"); - } - - break; - case FieldInfo field: - if (IsForbiddenType(field.FieldType)) - { - errors.Add( - $"{type.FullName}.{field.Name} field is forbidden type {field.FieldType.FullName}"); - } - - break; - case EventInfo evt: - - if (IsForbiddenType(evt.EventHandlerType!)) - { - errors.Add( - $"{type.FullName}.{evt.Name} event is forbidden type {evt.EventHandlerType.FullName}"); - } - - break; - } - } - } - - if (errors.Any()) - { - output.WriteLine("AccessTokenManagement is exposed. Errors found:"); - foreach (var error in errors) - { - output.WriteLine(error); - } - - errors.ShouldBeEmpty( - "AccessTokenManagement types should not be exposed in BFF public API. Please review the types and ensure they are internal or private."); - } - - bool IsForbiddenType(Type t) - { - if (t.Namespace != null && t.Namespace.StartsWith(accessTokenManagementNamespace)) - { - return true; - } - - if (t.IsGenericType) - { - foreach (var arg in t.GetGenericArguments()) - { - if (IsForbiddenType(arg)) - { - return true; - } - } - } - - if (t.IsArray) - { - return IsForbiddenType(t.GetElementType()!); - } - - return false; - } - } - -#nullable enable - private static List GetStrongTypedStringTypes() { // Find all types implementing IStringValue @@ -413,7 +291,7 @@ public class ConventionTests(ITestOutputHelper output) foreach (var failure in failures) { - output.WriteLine(failure); + _output.WriteLine(failure); } failures.ShouldBeEmpty(); diff --git a/bff/test/Bff.Tests/Diagnostics/FrontendCountDiagnosticEntryTests.cs b/bff/test/Bff.Tests/Diagnostics/FrontendCountDiagnosticEntryTests.cs index ce867f077..883ada238 100644 --- a/bff/test/Bff.Tests/Diagnostics/FrontendCountDiagnosticEntryTests.cs +++ b/bff/test/Bff.Tests/Diagnostics/FrontendCountDiagnosticEntryTests.cs @@ -3,11 +3,9 @@ using Duende.Bff.DynamicFrontends; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Diagnostics; -public class FrontendCountDiagnosticEntryTests(ITestOutputHelper testOutputHelper) : BffTestBase(testOutputHelper) +public class FrontendCountDiagnosticEntryTests : BffTestBase { [Fact] public async Task Should_print_the_number_of_frontends_during_defined_interval() diff --git a/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs index bc54f29a5..a42c9e58f 100644 --- a/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs @@ -6,13 +6,11 @@ using Duende.Bff.AccessTokenManagement; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints; -public class DPoPRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(output) +public class DPoPRemoteEndpointTests : BffTestBase { - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { var idSrvClient = IdentityServer.AddClient(The.ClientId, Bff.Url()); diff --git a/bff/test/Bff.Tests/Endpoints/DPoPTestsWithManualAuthentication.cs b/bff/test/Bff.Tests/Endpoints/DPoPTestsWithManualAuthentication.cs index 9b2515840..6b4d0dcad 100644 --- a/bff/test/Bff.Tests/Endpoints/DPoPTestsWithManualAuthentication.cs +++ b/bff/test/Bff.Tests/Endpoints/DPoPTestsWithManualAuthentication.cs @@ -7,13 +7,12 @@ using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; -public class DPoPTestsWithManualAuthentication(ITestOutputHelper output) : BffTestBase(output), IAsyncLifetime +public class DPoPTestsWithManualAuthentication : BffTestBase, IAsyncLifetime { - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { Bff.EnableBackChannelHandler = false; var idSrvClient = IdentityServer.AddClient(The.ClientId, Bff.Url()); diff --git a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs index 1e40ddc0d..88ebbbd99 100644 --- a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs @@ -6,11 +6,9 @@ using Duende.Bff.DynamicFrontends; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.Authentication; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints; -public class LocalEndpointTests(ITestOutputHelper output) : BffTestBase(output) +public class LocalEndpointTests : BffTestBase { public HttpStatusCode LocalApiResponseStatus { get; set; } = HttpStatusCode.OK; diff --git a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs index 2dc67bf22..7ba656db2 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs @@ -5,18 +5,17 @@ using System.Net; using Duende.Bff.DynamicFrontends; using Duende.Bff.SessionManagement.SessionStore; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class BackchannelLogoutEndpointTests : BffTestBase { - public BackchannelLogoutEndpointTests(ITestOutputHelper output) : base(output) => Bff.OnConfigureBff += bff => + public BackchannelLogoutEndpointTests() : base() => Bff.OnConfigureBff += bff => { bff.AddServerSideSessions(); }; - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await base.InitializeAsync(); diff --git a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs index 868c71348..92f2e8e20 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs @@ -4,13 +4,11 @@ using System.Net; using Duende.Bff.Configuration; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints.Management; -public class LoginEndpointTests(ITestOutputHelper output) : BffTestBase(output) +public class LoginEndpointTests : BffTestBase { - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await base.InitializeAsync(); Bff.BffOptions.ConfigureOpenIdConnectDefaults = opt => { The.DefaultOpenIdConnectConfiguration(opt); }; diff --git a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs index e2030433e..03fafbbf3 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs @@ -6,11 +6,9 @@ using System.Security.Claims; using Duende.Bff.Tests.TestInfra; using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints.Management; -public class LogoutEndpointTests(ITestOutputHelper output) : BffTestBase(output) +public class LogoutEndpointTests : BffTestBase { [Theory] [MemberData(nameof(AllSetups))] diff --git a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs index fbdc1ac7e..83f41d9c0 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs @@ -4,11 +4,9 @@ using System.Net; using Duende.Bff.Configuration; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints.Management; -public class ManagementBasePathTests(ITestOutputHelper output) : BffTestBase(output) +public class ManagementBasePathTests : BffTestBase { [Theory] [InlineData(Constants.ManagementEndpoints.Login, HttpStatusCode.Redirect)] diff --git a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs index a2420ba90..684510229 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs @@ -10,14 +10,12 @@ using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints.Management; public class UserEndpointTests : BffTestBase { - public UserEndpointTests(ITestOutputHelper output) : base(output) => + public UserEndpointTests() : base() => Bff.OnConfigureApp += app => { // Setup a login endpoint that allows you to simulate signing in as a specific diff --git a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs index ce4f7a370..18306181e 100644 --- a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs @@ -14,7 +14,6 @@ using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; using Microsoft.AspNetCore.Authentication; using Microsoft.IdentityModel.Protocols.OpenIdConnect; -using Xunit.Abstractions; using Yarp.ReverseProxy.Forwarder; using Yarp.ReverseProxy.Transforms; using Yarp.ReverseProxy.Transforms.Builder; @@ -24,7 +23,7 @@ namespace Duende.Bff.Tests.Endpoints; public class RemoteEndpointTests : BffTestBase { - public RemoteEndpointTests(ITestOutputHelper output) : base(output) + public RemoteEndpointTests() : base() { Bff.OnConfigureServices += services => { diff --git a/bff/test/Bff.Tests/Endpoints/WireupTests.cs b/bff/test/Bff.Tests/Endpoints/WireupTests.cs index cf12338d4..433cb845d 100644 --- a/bff/test/Bff.Tests/Endpoints/WireupTests.cs +++ b/bff/test/Bff.Tests/Endpoints/WireupTests.cs @@ -3,11 +3,9 @@ using System.Net; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Endpoints; -public class WireupTests(ITestOutputHelper output) : BffTestBase(output) +public class WireupTests : BffTestBase { [Fact] public async Task Without_auto_wireup_management_endpoints_are_not_mapped() diff --git a/bff/test/Bff.Tests/Endpoints/YarpTests.cs b/bff/test/Bff.Tests/Endpoints/YarpTests.cs index 4d1d99791..dd36b1866 100644 --- a/bff/test/Bff.Tests/Endpoints/YarpTests.cs +++ b/bff/test/Bff.Tests/Endpoints/YarpTests.cs @@ -7,14 +7,13 @@ using Duende.Bff.DynamicFrontends; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; -using Xunit.Abstractions; using Yarp.ReverseProxy.Configuration; namespace Duende.Bff.Tests.Endpoints; public class YarpTests : BffTestBase { - public YarpTests(ITestOutputHelper output) : base(output) => + public YarpTests() : base() => Bff.OnConfigureApp += app => { app.MapReverseProxy(proxyApp => diff --git a/bff/test/Bff.Tests/EntityFramework/SessionIntegrationTests.cs b/bff/test/Bff.Tests/EntityFramework/SessionIntegrationTests.cs index 6b8ff8ec5..242471542 100644 --- a/bff/test/Bff.Tests/EntityFramework/SessionIntegrationTests.cs +++ b/bff/test/Bff.Tests/EntityFramework/SessionIntegrationTests.cs @@ -6,11 +6,9 @@ using Duende.Bff.EntityFramework.Internal; using Duende.Bff.SessionManagement.SessionStore; using Duende.Bff.Tests.TestInfra; using Microsoft.EntityFrameworkCore; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.BffHostBuilder; -public class HostBuilder_SessionTests(ITestOutputHelper output) : BffTestBase(output) +public class HostBuilder_SessionTests : BffTestBase { private string _databaseName = Guid.NewGuid().ToString(); @@ -167,7 +165,7 @@ public class HostBuilder_SessionTests(ITestOutputHelper output) : BffTestBase(ou }; IdentityServer.AddClient(The.ClientId, Bff.Url()); - var exception = await Should.ThrowAsync(InitializeAsync); + var exception = await Should.ThrowAsync(() => InitializeAsync().AsTask()); exception.Message.ShouldBe("No IUserSessionStoreCleanup is registered. Did you add session storage, such as EntityFramework?"); } diff --git a/bff/test/Bff.Tests/EntityFramework/UserSessionStoreTests.cs b/bff/test/Bff.Tests/EntityFramework/UserSessionStoreTests.cs index e60334508..0a5ce24cb 100644 --- a/bff/test/Bff.Tests/EntityFramework/UserSessionStoreTests.cs +++ b/bff/test/Bff.Tests/EntityFramework/UserSessionStoreTests.cs @@ -8,7 +8,6 @@ using Duende.Bff.Tests.TestInfra; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using UserSessionDb; -using Xunit.Abstractions; namespace Duende.Bff.EntityFramework.Tests; @@ -25,8 +24,9 @@ public class UserSessionStoreTests : IAsyncLifetime private UserSessionKey invalidUserSessionKey => new UserSessionKey(The.PartitionKey, UserKey.Parse("wrong")); - public UserSessionStoreTests(ITestOutputHelper output) + public UserSessionStoreTests() { + var output = TestContext.Current.TestOutputHelper!; var services = new ServiceCollection(); _fakeHttpContextAccessor = new FakeHttpContextAccessor(); _dbFilePath = Path.Combine(Path.GetTempPath(), $"test-{Guid.NewGuid():N}.sqlite"); @@ -839,12 +839,12 @@ public class UserSessionStoreTests : IAsyncLifetime }); } - public async Task InitializeAsync() => + public async ValueTask InitializeAsync() => // Ensure the database is created and migrations are applied await _database.Database.MigrateAsync(); - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { // Close all open SQLite connections used by EF var dbConn = _database.Database.GetDbConnection(); diff --git a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs index fc5ba7b58..7663c5f3f 100644 --- a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs @@ -5,13 +5,11 @@ using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.AspNetCore.HttpOverrides; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Headers; public class ApiAndBffUseForwardedHeaders : BffTestBase, IAsyncLifetime { - public ApiAndBffUseForwardedHeaders(ITestOutputHelper output) : base(output) + public ApiAndBffUseForwardedHeaders() : base() { Bff.OnConfigureApp += app => { diff --git a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs index 2e8a19ef0..7f02f662f 100644 --- a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs @@ -5,13 +5,11 @@ using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.AspNetCore.HttpOverrides; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.Headers; public class ApiUseForwardedHeaders : BffTestBase { - public ApiUseForwardedHeaders(ITestOutputHelper output) : base(output) + public ApiUseForwardedHeaders() : base() { Bff.OnConfigureBff += bff => bff.AddRemoteApis(); diff --git a/bff/test/Bff.Tests/Headers/GeneralTests.cs b/bff/test/Bff.Tests/Headers/GeneralTests.cs index 5d350d7d0..37e066bcb 100644 --- a/bff/test/Bff.Tests/Headers/GeneralTests.cs +++ b/bff/test/Bff.Tests/Headers/GeneralTests.cs @@ -6,12 +6,11 @@ using Duende.Bff.AccessTokenManagement; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; -using Xunit.Abstractions; using ApiHost = Duende.Bff.Tests.TestInfra.ApiHost; namespace Duende.Bff.Tests.Headers; -public class GeneralTests(ITestOutputHelper output) : BffTestBase(output) +public class GeneralTests : BffTestBase { [Theory, MemberData(nameof(AllSetups))] public async Task local_endpoint_should_receive_standard_headers(BffSetupType setup) diff --git a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs index 426eb7db6..cb381ed83 100644 --- a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs +++ b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs @@ -6,8 +6,6 @@ using Duende.Bff.Internal; using Duende.Bff.Tests.TestInfra; using Duende.Bff.Yarp; using Microsoft.Extensions.Logging.Abstractions; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; /// @@ -17,7 +15,7 @@ public class IAccessTokenRetriever_Extensibility_tests : BffTestBase { private ContextCapturingAccessTokenRetriever _customAccessTokenReceiver { get; } = new(NullLogger.Instance); - public IAccessTokenRetriever_Extensibility_tests(ITestOutputHelper output) : base(output) + public IAccessTokenRetriever_Extensibility_tests() : base() { IdentityServer.AddClient(The.ClientId, Bff.Url()); Bff.OnConfigureBff += bff => bff diff --git a/bff/test/Bff.Tests/LicensingTests.cs b/bff/test/Bff.Tests/LicensingTests.cs index a96a98b3d..53695b9f3 100644 --- a/bff/test/Bff.Tests/LicensingTests.cs +++ b/bff/test/Bff.Tests/LicensingTests.cs @@ -3,11 +3,9 @@ using Duende.Bff.Licensing; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; - namespace Duende.Bff.Tests; -public class LicensingTests(ITestOutputHelper output) : BffTestBase(output) +public class LicensingTests : BffTestBase { [Fact] public async Task Given_no_license_then_error_log() diff --git a/bff/test/Bff.Tests/MultiFrontend/FrontendSelectorTests.cs b/bff/test/Bff.Tests/MultiFrontend/FrontendSelectorTests.cs index 0b5146bb9..12c33b2b1 100644 --- a/bff/test/Bff.Tests/MultiFrontend/FrontendSelectorTests.cs +++ b/bff/test/Bff.Tests/MultiFrontend/FrontendSelectorTests.cs @@ -6,7 +6,6 @@ using Duende.Bff.Configuration; using Duende.Bff.DynamicFrontends; using Duende.Bff.DynamicFrontends.Internal; using Duende.Bff.Tests.TestInfra; -using Xunit.Abstractions; using TestLoggerProvider = Duende.Bff.Tests.TestFramework.TestLoggerProvider; namespace Duende.Bff.Tests.MultiFrontend; @@ -19,8 +18,9 @@ public class FrontendSelectorTests private static readonly TestData The = new(); internal TestDataBuilder Some => new(The); private readonly StringBuilder _logMessages = new(); + private readonly ITestOutputHelper _output = TestContext.Current.TestOutputHelper!; - public FrontendSelectorTests(ITestOutputHelper output) + public FrontendSelectorTests() { _frontendCollection = new(plugins: [], bffConfiguration: TestOptionsMonitor.Create(new BffConfiguration()), @@ -28,7 +28,7 @@ public class FrontendSelectorTests ); var testLoggerProvider = new TestLoggerProvider((s) => { - output.WriteLine(s); + _output.WriteLine(s); _logMessages.AppendLine(s); }, "", forceToWriteOutput: true); var loggerFactory = new LoggerFactory([testLoggerProvider]); diff --git a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs index 4d90a7c54..cdf0de833 100644 --- a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs @@ -6,16 +6,13 @@ using Duende.Bff.SessionManagement.TicketStore; using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; -using Xunit.Abstractions; - - namespace Duende.Bff.Tests.SessionManagement; public class CookieSlidingTests : BffTestBase { private InMemoryUserSessionStore _sessionStore => (InMemoryUserSessionStore)Bff.Resolve(); - public CookieSlidingTests(ITestOutputHelper output) : base(output) => + public CookieSlidingTests() : base() => Bff.OnConfigureBff += bff => bff.AddServerSideSessions(); diff --git a/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs b/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs index d28b8a052..90dc5f9d2 100644 --- a/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs @@ -3,11 +3,9 @@ using Duende.Bff.Tests.TestInfra; using Duende.IdentityServer.Stores; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.SessionManagement; -public class RevokeRefreshTokenTests(ITestOutputHelper output) : BffTestBase(output) +public class RevokeRefreshTokenTests : BffTestBase { [Theory, MemberData(nameof(AllSetups))] public async Task logout_should_revoke_refreshtoken(BffSetupType setup) diff --git a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs index 1a9c150e2..8e51b2ab5 100644 --- a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs @@ -5,13 +5,11 @@ using Duende.Bff.DynamicFrontends; using Duende.Bff.SessionManagement.SessionStore; using Duende.Bff.Tests.TestInfra; using Microsoft.AspNetCore.Authentication.Cookies; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.SessionManagement; public class ServerSideTicketStoreTests : BffTestBase { - public ServerSideTicketStoreTests(ITestOutputHelper output) : base(output) => + public ServerSideTicketStoreTests() : base() => Bff.OnConfigureBff += bff => { bff.AddServerSideSessions(); diff --git a/bff/test/Bff.Tests/TestInfra/BffTestBase.cs b/bff/test/Bff.Tests/TestInfra/BffTestBase.cs index 3d46073d8..6fc564f93 100644 --- a/bff/test/Bff.Tests/TestInfra/BffTestBase.cs +++ b/bff/test/Bff.Tests/TestInfra/BffTestBase.cs @@ -5,8 +5,6 @@ using System.Security.Claims; using Duende.Bff.DynamicFrontends; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.TestInfra; public abstract class BffTestBase : IAsyncDisposable @@ -22,9 +20,9 @@ public abstract class BffTestBase : IAsyncDisposable private readonly List _frontendBuffer = new(); - protected BffTestBase(ITestOutputHelper output) + protected BffTestBase() { - Context = new TestHostContext(output); + Context = new TestHostContext(TestContext.Current.TestOutputHelper!); IdentityServer = new IdentityServerTestHost(Context); The = Context.The; @@ -131,7 +129,7 @@ public abstract class BffTestBase : IAsyncDisposable protected IdentityServerTestHost IdentityServer { get; } protected SimulatedInternet Internet => Context.Internet; - public virtual async Task InitializeAsync() + public virtual async ValueTask InitializeAsync() { if (_initialized) { @@ -177,7 +175,7 @@ public abstract class BffTestBase : IAsyncDisposable GC.SuppressFinalize(this); } - public async Task DisposeAsync() => await ((IAsyncDisposable)this).DisposeAsync(); + public async ValueTask DisposeAsync() => await ((IAsyncDisposable)this).DisposeAsync(); protected void AddOrUpdateFrontend(BffFrontend frontend) { diff --git a/bff/test/Bff.Tests/TestInfra/TestHostContext.cs b/bff/test/Bff.Tests/TestInfra/TestHostContext.cs index c84f94985..01ee6bd82 100644 --- a/bff/test/Bff.Tests/TestInfra/TestHostContext.cs +++ b/bff/test/Bff.Tests/TestInfra/TestHostContext.cs @@ -3,8 +3,6 @@ using System.Diagnostics; using System.Text; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.TestInfra; public record TestHostContext(ITestOutputHelper OutputHelper) diff --git a/bff/test/Bff.Tests/TestInfra/TestInfraTests.cs b/bff/test/Bff.Tests/TestInfra/TestInfraTests.cs index a4bc702f8..7de13de53 100644 --- a/bff/test/Bff.Tests/TestInfra/TestInfraTests.cs +++ b/bff/test/Bff.Tests/TestInfra/TestInfraTests.cs @@ -3,11 +3,9 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Xunit.Abstractions; - namespace Duende.Bff.Tests.TestInfra; -public class TestInfraTests(ITestOutputHelper output) : BffTestBase(output) +public class TestInfraTests : BffTestBase { [Fact] public async Task Can_login_to_identity_server()