diff --git a/src/Yavsc.Org.Tests/Controllers/ClientControllerCollectionTests.cs b/src/Yavsc.Org.Tests/Controllers/ClientControllerCollectionTests.cs index fe6bc2fc..cf18970e 100644 --- a/src/Yavsc.Org.Tests/Controllers/ClientControllerCollectionTests.cs +++ b/src/Yavsc.Org.Tests/Controllers/ClientControllerCollectionTests.cs @@ -110,6 +110,77 @@ public class ClientControllerCollectionTests : IClassFixture(); + var row = db.ClientRedirectUris + .FirstOrDefault(r => r.RedirectUri == newUri); + if (row is not null) + { + db.ClientRedirectUris.Remove(row); + db.SaveChanges(); + } + } + } + [Fact] public async Task AddRedirectUri_POST_appends_to_database() { @@ -206,6 +277,164 @@ public class ClientControllerCollectionTests : IClassFixture BisectClientDbId() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + return db.Clients.Single(c => c.ClientId == TargetClientId).Id; + } + + [Fact] + public async Task Bisect_RedirectUris_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.RedirectUris) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.RedirectUris); + } + + [Fact] + public async Task Bisect_PostLogoutRedirectUris_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.PostLogoutRedirectUris) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.PostLogoutRedirectUris); + } + + [Fact] + public async Task Bisect_AllowedScopes_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.AllowedScopes) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.AllowedScopes); + } + + [Fact] + public async Task Bisect_AllowedGrantTypes_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.AllowedGrantTypes) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.AllowedGrantTypes); + } + + [Fact] + public async Task Bisect_AllowedCorsOrigins_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.AllowedCorsOrigins) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.AllowedCorsOrigins); + } + + [Fact] + public async Task Bisect_IdentityProviderRestrictions_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.IdentityProviderRestrictions) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.IdentityProviderRestrictions); + } + + [Fact] + public async Task Bisect_Claims_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.Claims) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.Claims); + } + + [Fact] + public async Task Bisect_Properties_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.Properties) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.Properties); + } + + [Fact] + public async Task Bisect_ClientSecrets_alone() + { + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .Include(c => c.ClientSecrets) + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + Assert.NotNull(client!.ClientSecrets); + } + + [Fact] + public async Task Bisect_baseline_no_include() + { + // Sanity check : la query de base (sans Include) doit passer. + // Si celle-ci échoue, le problème n'est pas un Include. + await using var scope = _factory.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var id = await BisectClientDbId(); + var client = await db.Clients + .SingleOrDefaultAsync(c => c.Id == id, TestContext.Current.CancellationToken); + Assert.NotNull(client); + } + private static string? ExtractAntiforgeryToken(string html) { const string marker = "name=\"__RequestVerificationToken\""; diff --git a/src/Yavsc.Org/Controllers/Administration/ClientController.Collections.cs b/src/Yavsc.Org/Controllers/Administration/ClientController.Collections.cs index b31ec0c3..5569bf77 100644 --- a/src/Yavsc.Org/Controllers/Administration/ClientController.Collections.cs +++ b/src/Yavsc.Org/Controllers/Administration/ClientController.Collections.cs @@ -287,6 +287,7 @@ public partial class ClientController private async Task LoadClientAsync(int id) => await dbContext.Clients + .AsSplitQuery() .Include(c => c.RedirectUris) .Include(c => c.PostLogoutRedirectUris) .Include(c => c.AllowedScopes)