diff --git a/tests/E2E Tests/AgentApplications/AgentApplicationsTests.csproj b/tests/E2E Tests/AgentApplications/AgentApplicationsTests.csproj index 959ef529b..741c3716f 100644 --- a/tests/E2E Tests/AgentApplications/AgentApplicationsTests.csproj +++ b/tests/E2E Tests/AgentApplications/AgentApplicationsTests.csproj @@ -16,8 +16,6 @@ - - @@ -27,6 +25,7 @@ + diff --git a/tests/E2E Tests/AgentApplications/GetFicAsyncTests.cs b/tests/E2E Tests/AgentApplications/GetFicAsyncTests.cs index 692679c8f..4bd10bdb6 100644 --- a/tests/E2E Tests/AgentApplications/GetFicAsyncTests.cs +++ b/tests/E2E Tests/AgentApplications/GetFicAsyncTests.cs @@ -6,9 +6,11 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Web; +using Microsoft.Identity.Web.Test.Common; namespace AgentApplicationsTests { + [Collection(nameof(TokenAcquirerFactorySingletonProtection))] public class GetFicAsyncTests { [Fact] diff --git a/tests/E2E Tests/WebAppUiTests/B2CWebAppCallsWebApiLocally.cs b/tests/E2E Tests/WebAppUiTests/B2CWebAppCallsWebApiLocally.cs index c5449e88a..f56861654 100644 --- a/tests/E2E Tests/WebAppUiTests/B2CWebAppCallsWebApiLocally.cs +++ b/tests/E2E Tests/WebAppUiTests/B2CWebAppCallsWebApiLocally.cs @@ -18,7 +18,7 @@ namespace WebAppUiTests #if !FROM_GITHUB_ACTION { // since these tests change environment variables we'd prefer it not run at the same time as other tests - [CollectionDefinition(nameof(UiTestNoParallelization), DisableParallelization = true)] + [Collection(nameof(UiTestNoParallelization))] public class B2CWebAppCallsWebApiLocally : IClassFixture { private const string KeyvaultEmailName = "IdWeb-B2C-user"; @@ -69,7 +69,7 @@ public async Task Susi_B2C_LocalAccount_TodoAppFunctionsCorrectlyAsync() IBrowserContext context = await browser.NewContextAsync(new BrowserNewContextOptions { IgnoreHTTPSErrors = true }); await context.Tracing.StartAsync(new() { Screenshots = true, Snapshots = true, Sources = true }); - Process? serviceProcess= null; + Process? serviceProcess = null; Process? clientProcess = null; try diff --git a/tests/E2E Tests/WebAppUiTests/TestingWebAppLocally.cs b/tests/E2E Tests/WebAppUiTests/TestingWebAppLocally.cs index d7e808340..cc017a952 100644 --- a/tests/E2E Tests/WebAppUiTests/TestingWebAppLocally.cs +++ b/tests/E2E Tests/WebAppUiTests/TestingWebAppLocally.cs @@ -18,7 +18,7 @@ namespace WebAppUiTests; #if !FROM_GITHUB_ACTION && !AZURE_DEVOPS_BUILD // Since this test affects Kestrel environment variables it can cause a race condition when run in parallel with other UI tests. -[CollectionDefinition(nameof(UiTestNoParallelization), DisableParallelization = true)] +[Collection(nameof(UiTestNoParallelization))] public class TestingWebAppLocally : IClassFixture { private const string UrlString = "https://localhost:5001/MicrosoftIdentity/Account/signin"; diff --git a/tests/E2E Tests/WebAppUiTests/UiTestHelpers.cs b/tests/E2E Tests/WebAppUiTests/UiTestHelpers.cs index 83fa322d4..74ca74d5e 100644 --- a/tests/E2E Tests/WebAppUiTests/UiTestHelpers.cs +++ b/tests/E2E Tests/WebAppUiTests/UiTestHelpers.cs @@ -360,7 +360,7 @@ internal static bool StartAndVerifyProcessesAreRunning(List { if (!UiTestHelpers.ProcessesAreAlive(processes.Values.ToList())) { - RestartProcesses(processes, processDataEntries , output); + RestartProcesses(processes, processDataEntries, output); } } @@ -384,7 +384,7 @@ static void RestartProcesses(Dictionary processes, List { private const uint GrpcPort = 5001; @@ -116,7 +116,7 @@ public async Task ChallengeUser_MicrosoftIdFlow_LocalApp_ValidEmailPasswordCreds _output.WriteLine("Starting web app sign-in flow using Todo List button after sign out."); await page.GetByRole(AriaRole.Link, new() { Name = "TodoList" }).ClickAsync(); await UiTestHelpers.SuccessiveLogin_MicrosoftIdFlow_ValidEmailPasswordAsync(page, email, labResponse.User.GetOrFetchPassword(), _output); - var todoLink = page.GetByRole(AriaRole.Link, new() { Name = "Create New" }); + var todoLink = page.GetByRole(AriaRole.Link, new() { Name = "Create New" }); await Assertions.Expect(todoLink).ToBeVisibleAsync(_assertVisibleOptions); _output.WriteLine("Web app sign-in flow successful using Todo List button after sign out."); @@ -226,7 +226,7 @@ public async Task ChallengeUser_MicrosoftIdFlow_LocalApp_ValidEmailPasswordCreds foreach (var process in processes) { #pragma warning disable CA1305 // Specify IFormatProvider - runningProcesses.AppendLine($"Is {process.Key} running: {UiTestHelpers.ProcessIsAlive(process.Value )}"); + runningProcesses.AppendLine($"Is {process.Key} running: {UiTestHelpers.ProcessIsAlive(process.Value)}"); #pragma warning restore CA1305 // Specify IFormatProvider } Assert.Fail(TC.WebAppCrashedString + " " + runningProcesses.ToString()); diff --git a/tests/E2E Tests/WebAppUiTests/WebAppIntegrationTests.cs b/tests/E2E Tests/WebAppUiTests/WebAppIntegrationTests.cs index 209008bee..5a685823a 100644 --- a/tests/E2E Tests/WebAppUiTests/WebAppIntegrationTests.cs +++ b/tests/E2E Tests/WebAppUiTests/WebAppIntegrationTests.cs @@ -10,9 +10,10 @@ using Xunit; namespace WebAppUiTests -{ #if !FROM_GITHUB_ACTION +{ + [Collection(nameof(UiTestNoParallelization))] public class WebAppIntegrationTests { const string UrlString = "https://webapptestmsidweb.azurewebsites.net/MicrosoftIdentity/Account/signin"; @@ -47,6 +48,6 @@ public async Task ChallengeUser_MicrosoftIdentityFlow_RemoteApp_ValidEmailPasswo } } -#endif //FROM_GITHUB_ACTION } } +#endif //FROM_GITHUB_ACTION diff --git a/tests/Microsoft.Identity.Web.Test/FmiTests.cs b/tests/Microsoft.Identity.Web.Test/FmiTests.cs index b79083566..da017010f 100644 --- a/tests/Microsoft.Identity.Web.Test/FmiTests.cs +++ b/tests/Microsoft.Identity.Web.Test/FmiTests.cs @@ -7,13 +7,14 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Client; +using Microsoft.Identity.Web.Test.Common; using Microsoft.Identity.Web.Test.Common.Mocks; using Microsoft.Identity.Web.TestOnly; using Xunit; namespace Microsoft.Identity.Web.Test { - [Collection("Run tests - serial")] + [Collection(nameof(TokenAcquirerFactorySingletonProtection))] public class FmiTests { [Fact] @@ -52,12 +53,12 @@ private TokenAcquirerFactory InitTokenAcquirerFactoryForFmi() options.ClientId = "urn:microsoft:identity:fmi"; options.ExtraQueryParameters = new Dictionary { - { "dc", "ESTS-PUB-SCUS-LZ1-FD000-TEST1" } + { "dc", "ESTS-PUB-SCUS-LZ1-FD000-TEST1" } }; options.ClientCredentials = [ new CredentialDescription() { SourceType = CredentialSource.ClientSecret, ClientSecret = "someSecret" - }]; + }]; }); // Add MockedHttpClientFactory diff --git a/tests/Microsoft.Identity.Web.Test/ManagedIdentityCaeTests.cs b/tests/Microsoft.Identity.Web.Test/ManagedIdentityCaeTests.cs index 6ea9ee5b5..d230814d1 100644 --- a/tests/Microsoft.Identity.Web.Test/ManagedIdentityCaeTests.cs +++ b/tests/Microsoft.Identity.Web.Test/ManagedIdentityCaeTests.cs @@ -9,6 +9,7 @@ using Microsoft.Identity.Web.TestOnly; using Xunit; using Microsoft.Identity.Web.Test; +using Microsoft.Identity.Web.Test.Common; using NSubstitute; using System.Collections.Generic; using System.Net.Http; @@ -20,7 +21,7 @@ namespace Microsoft.Identity.Web.Tests.Certificateless { - [Collection("Run tests - serial")] + [Collection(nameof(TokenAcquirerFactorySingletonProtection))] public class ManagedIdentityTests { private const string Scope = "https://management.azure.com/.default"; diff --git a/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs b/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs index f64c13a6b..5815eb5c7 100644 --- a/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs +++ b/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs @@ -9,10 +9,12 @@ using Microsoft.Extensions.Options; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Client; +using Microsoft.Identity.Web.Test.Common; using Xunit; namespace Microsoft.Identity.Web.Test { + [Collection(nameof(TokenAcquirerFactorySingletonProtection))] public class ServiceCollectionExtensionsTests { [Fact] diff --git a/tests/Microsoft.Identity.Web.Test/TokenAcquirerCollection.cs b/tests/Microsoft.Identity.Web.Test/TokenAcquirerCollection.cs deleted file mode 100644 index 3cdc7b182..000000000 --- a/tests/Microsoft.Identity.Web.Test/TokenAcquirerCollection.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Xunit; - -namespace Microsoft.Identity.Web.Tests -{ - /// - /// Disables parallel execution for every test-class that - /// is decorated with [Collection("Run tests - serial")]. - /// NOTE: tests that rely on TokenAcquirerFactory / TokenAcquisition (and the - /// IMsalHttpClientFactory mocks they spin-up) share several static / singleton - /// caches. If xUnit runs them in parallel those shared objects collide and the - /// mocks return the wrong handler, producing flaky failures. Putting them all - /// in this “serial” collection forces xUnit to execute them one-by-one. - /// Be cautious: only include tests that really need this, as this will impact - /// the overall test suite running time - /// - [CollectionDefinition("Run tests - serial", DisableParallelization = true)] - public sealed class TokenAcquirerCollection : ICollectionFixture - { - } -} diff --git a/tests/Microsoft.Identity.Web.Test/TokenAcquisitionTests.cs b/tests/Microsoft.Identity.Web.Test/TokenAcquisitionTests.cs index 2adb86e41..bc8ef2fd7 100644 --- a/tests/Microsoft.Identity.Web.Test/TokenAcquisitionTests.cs +++ b/tests/Microsoft.Identity.Web.Test/TokenAcquisitionTests.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Client; +using Microsoft.Identity.Web.Test.Common; using Microsoft.Identity.Web.Test.Common.Mocks; using Microsoft.Identity.Web.TestOnly; using Xunit; @@ -16,6 +17,7 @@ namespace Microsoft.Identity.Web.Test { + [Collection(nameof(TokenAcquirerFactorySingletonProtection))] public class TokenAcquisitionTests { private const string Tenant = "tenant"; @@ -61,10 +63,10 @@ public void TestManagedIdentityWithCommonTenantShouldNotCallResolveTenant() { // This test verifies that ResolveTenant is not called when using managed identity, // which prevents the IDW10405 error when tenant is "common" or "organizations" - + // The fix ensures that when ManagedIdentity is specified in tokenAcquisitionOptions, // ResolveTenant is skipped entirely, so this scenario should not throw - + // Create test options with managed identity var tokenOptions = new TokenAcquisitionOptions { @@ -73,15 +75,15 @@ public void TestManagedIdentityWithCommonTenantShouldNotCallResolveTenant() UserAssignedClientId = "test-client-id" } }; - - var mergedOptions = new MergedOptions - { + + var mergedOptions = new MergedOptions + { TenantId = Constants.Common // This would normally cause ResolveTenant to throw }; - + // This should not throw because ResolveTenant should not be called for managed identity scenarios // The actual method call would be tested in integration tests, but we can test the logic here - + // Verify that ResolveTenant still throws for non-managed identity scenarios var exception = Assert.Throws(() => TokenAcquisition.ResolveTenant(null, mergedOptions)); Assert.StartsWith(IDWebErrorMessage.ClientCredentialTenantShouldBeTenanted, exception.Message, StringComparison.Ordinal); @@ -134,9 +136,9 @@ private TokenAcquirerFactory InitTokenAcquirerFactory() options.TenantId = "f645ad92-e38d-4d1a-b510-d1b09a74a8ca"; options.ClientId = "idu773ld-e38d-jud3-45lk-d1b09a74a8ca"; options.ExtraQueryParameters = new Dictionary - { - { "dc", "ESTS-PUB-SCUS-LZ1-FD000-TEST1" } - }; + { + { "dc", "ESTS-PUB-SCUS-LZ1-FD000-TEST1" } + }; options.ClientCredentials = [ new CredentialDescription() { SourceType = CredentialSource.ClientSecret, ClientSecret = "someSecret"