forked from xiongyuxing/tiku-backend.net
115 lines
4.4 KiB
C#
115 lines
4.4 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Tiku.Application.Tenancy;
|
|
using Tiku.Domain.Tenancy;
|
|
using Tiku.Infrastructure.Persistence;
|
|
using Tiku.IntegrationTests.Api;
|
|
|
|
namespace Tiku.IntegrationTests;
|
|
|
|
public sealed class TenantDomainLifecycleTests
|
|
{
|
|
[Fact]
|
|
public async Task Domain_becomes_active_only_after_dns_and_tls_are_ready()
|
|
{
|
|
await using var factory = new ApiTestFactory(
|
|
domainOwnershipVerifier: new FakeOwnershipVerifier(true),
|
|
domainGatewayProvisioner: new FakeGatewayProvisioner(true));
|
|
var tenantId = Guid.NewGuid();
|
|
var domainId = Guid.NewGuid();
|
|
await factory.SeedAsync(
|
|
new Tenant
|
|
{
|
|
Id = tenantId,
|
|
Slug = "tenant-a",
|
|
Name = "Tenant A",
|
|
Status = TenantStatus.Active,
|
|
Mode = TenantMode.Saas
|
|
},
|
|
new TenantDomain
|
|
{
|
|
Id = domainId,
|
|
TenantId = tenantId,
|
|
Host = "learn.tenant-a.example",
|
|
DomainType = TenantDomainType.Custom,
|
|
Status = TenantDomainStatus.Pending,
|
|
VerificationToken = "verification-token"
|
|
});
|
|
|
|
using (var scope = factory.CreateSystemScope("Process domain lifecycle"))
|
|
{
|
|
var processed = await scope.ServiceProvider
|
|
.GetRequiredService<ITenantDomainLifecycleService>()
|
|
.ProcessPendingAsync();
|
|
Assert.Equal(1, processed);
|
|
}
|
|
|
|
using var verificationScope = factory.CreateSystemScope();
|
|
var domain = await verificationScope.ServiceProvider.GetRequiredService<TikuDbContext>()
|
|
.TenantDomains.SingleAsync(item => item.Id == domainId);
|
|
Assert.Equal(TenantDomainStatus.Active, domain.Status);
|
|
Assert.NotNull(domain.DnsVerifiedAt);
|
|
Assert.NotNull(domain.TlsReadyAt);
|
|
Assert.Null(domain.LastFailureReason);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Missing_gateway_configuration_keeps_domain_pending()
|
|
{
|
|
await using var factory = new ApiTestFactory(
|
|
domainOwnershipVerifier: new FakeOwnershipVerifier(true),
|
|
domainGatewayProvisioner: new FakeGatewayProvisioner(false, configured: false));
|
|
var tenantId = Guid.NewGuid();
|
|
var domainId = Guid.NewGuid();
|
|
await factory.SeedAsync(
|
|
new Tenant
|
|
{
|
|
Id = tenantId,
|
|
Slug = "tenant-a",
|
|
Name = "Tenant A",
|
|
Status = TenantStatus.Active,
|
|
Mode = TenantMode.Saas
|
|
},
|
|
new TenantDomain
|
|
{
|
|
Id = domainId,
|
|
TenantId = tenantId,
|
|
Host = "pending.tenant-a.example",
|
|
Status = TenantDomainStatus.Pending,
|
|
VerificationToken = "verification-token"
|
|
});
|
|
|
|
using (var scope = factory.CreateSystemScope("Process pending domain"))
|
|
{
|
|
await scope.ServiceProvider.GetRequiredService<ITenantDomainLifecycleService>().ProcessPendingAsync();
|
|
}
|
|
|
|
using var verificationScope = factory.CreateSystemScope();
|
|
var domain = await verificationScope.ServiceProvider.GetRequiredService<TikuDbContext>()
|
|
.TenantDomains.SingleAsync(item => item.Id == domainId);
|
|
Assert.Equal(TenantDomainStatus.Pending, domain.Status);
|
|
Assert.NotNull(domain.DnsVerifiedAt);
|
|
Assert.Contains("not configured", domain.LastFailureReason, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private sealed class FakeOwnershipVerifier(bool verified) : IDomainOwnershipVerifier
|
|
{
|
|
public Task<DomainOwnershipResult> VerifyAsync(
|
|
string host,
|
|
string verificationToken,
|
|
CancellationToken cancellationToken = default) =>
|
|
Task.FromResult(new DomainOwnershipResult(verified, true, verified ? null : "DNS failed"));
|
|
}
|
|
|
|
private sealed class FakeGatewayProvisioner(bool ready, bool configured = true) : IDomainGatewayProvisioner
|
|
{
|
|
public Task<DomainGatewayResult> EnsureTlsAsync(
|
|
string host,
|
|
CancellationToken cancellationToken = default) =>
|
|
Task.FromResult(new DomainGatewayResult(
|
|
ready,
|
|
configured,
|
|
ready ? null : configured ? "TLS pending" : "Gateway is not configured"));
|
|
}
|
|
}
|