thalos-service/tests/Thalos.Service.Application.UnitTests/RuntimeWiringTests.cs
José René White Enciso 96c53d9dab feat(thalos-service): add canonical session flows
Why: provide service-side canonical login/refresh orchestration for session-based web auth.

What: add session contracts, refresh token codec with provider-agnostic secret boundary, grpc session methods, DI wiring, tests, and docs.

Rule: preserve thalos identity ownership and keep transport adapters at service edge.
2026-03-08 14:48:35 -06:00

116 lines
5.0 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using BuildingBlock.Identity.Contracts.Conventions;
using BuildingBlock.Identity.Contracts.Requests;
using Thalos.Service.Application.Adapters;
using Thalos.Service.Application.DependencyInjection;
using Thalos.Service.Application.Grpc;
using Thalos.Service.Application.UseCases;
using BuildingIssueRequest = BuildingBlock.Identity.Contracts.Requests.IssueIdentityTokenRequest;
using BuildingPolicyRequest = BuildingBlock.Identity.Contracts.Requests.EvaluateIdentityPolicyRequest;
using StartSessionRequest = Thalos.Service.Identity.Abstractions.Contracts.StartIdentitySessionRequest;
using SessionRefreshRequest = Thalos.Service.Identity.Abstractions.Contracts.RefreshIdentitySessionRequest;
namespace Thalos.Service.Application.UnitTests;
public class RuntimeWiringTests
{
[Fact]
public async Task AddThalosServiceRuntime_WhenInvoked_ResolvesUseCases()
{
var services = new ServiceCollection();
services.AddThalosServiceRuntime();
using var provider = services.BuildServiceProvider();
var issueTokenUseCase = provider.GetRequiredService<IIssueIdentityTokenUseCase>();
var startSessionUseCase = provider.GetRequiredService<IStartIdentitySessionUseCase>();
var refreshSessionUseCase = provider.GetRequiredService<IRefreshIdentitySessionUseCase>();
var evaluatePolicyUseCase = provider.GetRequiredService<IEvaluateIdentityPolicyUseCase>();
var tokenResponse = await issueTokenUseCase.HandleAsync(new BuildingIssueRequest("user-1", "tenant-1"));
var policyResponse = await evaluatePolicyUseCase.HandleAsync(
new BuildingPolicyRequest("user-1", "tenant-1", "identity.token.issue"));
var startSessionResponse = await startSessionUseCase.HandleAsync(
new StartSessionRequest("user-1", "tenant-1"));
var refreshSessionResponse = await refreshSessionUseCase.HandleAsync(
new SessionRefreshRequest(startSessionResponse.RefreshToken, "corr-rt-1"));
Assert.Equal("user-1:tenant-1:token", tokenResponse.Token);
Assert.Equal(1800, tokenResponse.ExpiresInSeconds);
Assert.True(policyResponse.IsAllowed);
Assert.Equal("user-1", startSessionResponse.SubjectId);
Assert.Equal("tenant-1", startSessionResponse.TenantId);
Assert.NotEmpty(startSessionResponse.RefreshToken);
Assert.Equal("user-1", refreshSessionResponse.SubjectId);
Assert.Equal("tenant-1", refreshSessionResponse.TenantId);
Assert.NotEmpty(refreshSessionResponse.RefreshToken);
}
[Fact]
public async Task AddThalosServiceRuntime_WhenSubjectMissing_ReturnsEmptyToken()
{
var services = new ServiceCollection();
services.AddThalosServiceRuntime();
using var provider = services.BuildServiceProvider();
var issueTokenUseCase = provider.GetRequiredService<IIssueIdentityTokenUseCase>();
var tokenResponse = await issueTokenUseCase.HandleAsync(
new BuildingIssueRequest("missing-user", "tenant-1"));
Assert.Equal(string.Empty, tokenResponse.Token);
Assert.Equal(0, tokenResponse.ExpiresInSeconds);
}
[Fact]
public async Task AddThalosServiceRuntime_WhenAzureProviderUsed_IssuesProviderToken()
{
var services = new ServiceCollection();
services.AddThalosServiceRuntime();
using var provider = services.BuildServiceProvider();
var issueTokenUseCase = provider.GetRequiredService<IIssueIdentityTokenUseCase>();
var tokenResponse = await issueTokenUseCase.HandleAsync(
new BuildingIssueRequest(
string.Empty,
"tenant-2",
IdentityAuthProvider.AzureAd,
"azure-id-token"));
Assert.StartsWith("azure:", tokenResponse.Token);
Assert.True(tokenResponse.ExpiresInSeconds > 0);
}
[Fact]
public void IdentityPolicyGrpcContractAdapter_WhenMapped_PreservesValues()
{
var adapter = new IdentityPolicyGrpcContractAdapter();
var useCaseRequest = new BuildingPolicyRequest("user-2", "tenant-2", "identity.policy.evaluate");
var grpcContract = adapter.ToGrpc(useCaseRequest);
var roundtrip = adapter.FromGrpc(grpcContract);
Assert.Equal("user-2", roundtrip.SubjectId);
Assert.Equal("tenant-2", roundtrip.TenantId);
Assert.Equal("identity.policy.evaluate", roundtrip.PermissionCode);
}
[Fact]
public void IdentityPolicyGrpcContractAdapter_WhenFromGrpc_UsesExpectedContractShape()
{
var adapter = new IdentityPolicyGrpcContractAdapter();
var contract = new EvaluateIdentityPolicyGrpcContract(
"subject-9",
"tenant-9",
"identity.token.issue",
IdentityAuthProvider.Google.ToString());
var request = adapter.FromGrpc(contract);
Assert.Equal("subject-9", request.SubjectId);
Assert.Equal("tenant-9", request.TenantId);
Assert.Equal("identity.token.issue", request.PermissionCode);
Assert.Equal(IdentityAuthProvider.Google, request.Provider);
}
}