Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Microsoft.Extensions.DependencyInjection;

using XtremeIdiots.Portal.Repository.Abstractions.Interfaces.V1;
using XtremeIdiots.Portal.Repository.Api.Client.V1;

namespace XtremeIdiots.Portal.Server.Events.Processor.App.Tests.Startup;

/// <summary>
/// Startup-time DI resolution tests for the Repository API client registration used by the
/// Processor App. These tests replicate the production registration in
/// <c>Program.cs</c> and prove the container can build and resolve every typed sub-client
/// the app depends on (e.g. <see cref="IAdminActionsApi"/>). They exercise real DI
/// resolution rather than inspecting option flags so that any regression in the
/// <c>services.AddRepositoryApiClient(...)</c> composition — such as the
/// <c>WithCaching(c =&gt; c.UseLibraryDefaults())</c> policy expression rejection that
/// crashed portal-sync / portal-repository-func on Repository 4.2.21 — is caught here
/// before it reaches production.
/// </summary>
public class RepositoryApiClientRegistrationTests
{
private const string BaseUrl = "https://repository-api.test.local";
private const string Audience = "api://repository-api-test";

[Fact]
public void ProductionRegistration_BuildsAndResolvesRepositoryClient()

Check warning on line 25 in src/XtremeIdiots.Portal.Server.Events.Processor.App.Tests/Startup/RepositoryApiClientRegistrationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Missing XML comment for publicly visible type or member 'RepositoryApiClientRegistrationTests.ProductionRegistration_BuildsAndResolvesRepositoryClient()'

See more on https://sonarcloud.io/project/issues?id=frasermolyneux_portal-server-events&issues=AZ_EWTAtxR8TZER3NnEi&open=AZ_EWTAtxR8TZER3NnEi&pullRequest=53
{
var provider = BuildProductionServiceProvider();
using var scope = provider.CreateScope();

var repositoryClient = scope.ServiceProvider.GetRequiredService<IRepositoryApiClient>();

Assert.NotNull(repositoryClient);
}

[Fact]
public void ProductionRegistration_ResolvesAdminActionsSubClient()

Check warning on line 36 in src/XtremeIdiots.Portal.Server.Events.Processor.App.Tests/Startup/RepositoryApiClientRegistrationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Missing XML comment for publicly visible type or member 'RepositoryApiClientRegistrationTests.ProductionRegistration_ResolvesAdminActionsSubClient()'

See more on https://sonarcloud.io/project/issues?id=frasermolyneux_portal-server-events&issues=AZ_EWTAtxR8TZER3NnEj&open=AZ_EWTAtxR8TZER3NnEj&pullRequest=53
{
var provider = BuildProductionServiceProvider();
using var scope = provider.CreateScope();

var repositoryClient = scope.ServiceProvider.GetRequiredService<IRepositoryApiClient>();
IAdminActionsApi adminActions = repositoryClient.AdminActions.V1;

Check warning on line 42 in src/XtremeIdiots.Portal.Server.Events.Processor.App.Tests/Startup/RepositoryApiClientRegistrationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

use 'var' instead of explicit type

See more on https://sonarcloud.io/project/issues?id=frasermolyneux_portal-server-events&issues=AZ_EWTAtxR8TZER3NnEm&open=AZ_EWTAtxR8TZER3NnEm&pullRequest=53

Assert.NotNull(adminActions);
Assert.NotNull(scope.ServiceProvider.GetRequiredService<IVersionedAdminActionsApi>());
}

[Fact]
public void ProductionRegistration_ResolvesRepresentativeSubClients()

Check warning on line 49 in src/XtremeIdiots.Portal.Server.Events.Processor.App.Tests/Startup/RepositoryApiClientRegistrationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Missing XML comment for publicly visible type or member 'RepositoryApiClientRegistrationTests.ProductionRegistration_ResolvesRepresentativeSubClients()'

See more on https://sonarcloud.io/project/issues?id=frasermolyneux_portal-server-events&issues=AZ_EWTAtxR8TZER3NnEk&open=AZ_EWTAtxR8TZER3NnEk&pullRequest=53
{
var provider = BuildProductionServiceProvider();
using var scope = provider.CreateScope();

var repositoryClient = scope.ServiceProvider.GetRequiredService<IRepositoryApiClient>();

// Every sub-client the processor actually calls at runtime must be resolvable.
// Touching .V1 on each versioned facade forces the DI graph for the underlying
// typed client to be materialised — which is where the client-side caching
// policy composition failure surfaces on start-up.
Assert.NotNull(repositoryClient.AdminActions.V1);
Assert.NotNull(repositoryClient.Players.V1);
Assert.NotNull(repositoryClient.GameServers.V1);
Assert.NotNull(repositoryClient.GameServersEvents.V1);
Assert.NotNull(repositoryClient.GameServersStats.V1);
Assert.NotNull(repositoryClient.ChatMessages.V1);
Assert.NotNull(repositoryClient.Maps.V1);
Assert.NotNull(repositoryClient.ConnectedPlayers.V1);
Assert.NotNull(repositoryClient.RecentPlayers.V1);
Assert.NotNull(repositoryClient.GlobalConfigurations.V1);
Assert.NotNull(repositoryClient.GameServerConfigurations.V1);
Assert.NotNull(repositoryClient.LiveStatus.V1);
}

private static ServiceProvider BuildProductionServiceProvider()
{
var services = new ServiceCollection();

// Mirror the Repository API client registration in
// src/XtremeIdiots.Portal.Server.Events.Processor.App/Program.cs.
// Any deviation here (in particular re-introducing consumer-side WithCaching)
// must also be applied to Program.cs.
services.AddRepositoryApiClient(options => options
.WithBaseUrl(BaseUrl)
.WithEntraIdAuthentication(Audience));

Check warning on line 84 in src/XtremeIdiots.Portal.Server.Events.Processor.App.Tests/Startup/RepositoryApiClientRegistrationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Expression value is never used

See more on https://sonarcloud.io/project/issues?id=frasermolyneux_portal-server-events&issues=AZ_EWTAtxR8TZER3NnEl&open=AZ_EWTAtxR8TZER3NnEl&pullRequest=53

return services.BuildServiceProvider(validateScopes: true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@

services.AddRepositoryApiClient(options => options
.WithBaseUrl(configuration["RepositoryApi:BaseUrl"] ?? throw new InvalidOperationException("RepositoryApi:BaseUrl is required"))
.WithEntraIdAuthentication(configuration["RepositoryApi:ApplicationAudience"] ?? throw new InvalidOperationException("RepositoryApi:ApplicationAudience is required"))
.WithCaching(c => c.UseLibraryDefaults()));
.WithEntraIdAuthentication(configuration["RepositoryApi:ApplicationAudience"] ?? throw new InvalidOperationException("RepositoryApi:ApplicationAudience is required")));

services.AddServersApiClient(options => options
.WithBaseUrl(configuration["ServersIntegrationApi:BaseUrl"] ?? throw new InvalidOperationException("ServersIntegrationApi:BaseUrl is required"))
Expand Down
Loading