setup and mock fixes

This commit is contained in:
master
2026-02-21 20:14:23 +02:00
parent 1edce73165
commit a29f438f53
29 changed files with 1624 additions and 721 deletions

View File

@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http.Json;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.Platform.WebService.Tests;
public sealed class SeedEndpointsTests : IClassFixture<PlatformWebApplicationFactory>
{
private readonly PlatformWebApplicationFactory _factory;
public SeedEndpointsTests(PlatformWebApplicationFactory factory)
{
_factory = factory;
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SeedDemo_WhenDisabled_ReturnsServiceUnavailableProblem()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-seed-disabled-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "seed-tester");
var response = await client.PostAsJsonAsync(
"/api/v1/admin/seed-demo",
new { dryRun = true },
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Demo seeding is disabled", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SeedDemo_WhenModuleFilterMixesAllAndSpecific_ReturnsBadRequestProblem()
{
using WebApplicationFactory<Program> enabledFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, config) =>
{
config.AddInMemoryCollection(new Dictionary<string, string?>
{
["STELLAOPS_ENABLE_DEMO_SEED"] = "true",
});
});
});
using var client = enabledFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-seed-invalid-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "seed-tester");
var response = await client.PostAsJsonAsync(
"/api/v1/admin/seed-demo",
new
{
dryRun = true,
modules = new[] { "all", "policy" },
},
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Invalid module filter", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SeedDemo_WhenConnectionMissing_ReturnsServiceUnavailableProblem()
{
using WebApplicationFactory<Program> enabledFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, config) =>
{
config.AddInMemoryCollection(new Dictionary<string, string?>
{
["STELLAOPS_ENABLE_DEMO_SEED"] = "true",
});
});
});
using var client = enabledFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-seed-missing-conn-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "seed-tester");
var response = await client.PostAsJsonAsync(
"/api/v1/admin/seed-demo",
new { dryRun = true },
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Database connection unavailable", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SeedDemo_WhenUnauthenticated_ReturnsUnauthorized()
{
using WebApplicationFactory<Program> unauthenticatedFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication(RejectingAuthHandler.SchemeName)
.AddScheme<AuthenticationSchemeOptions, RejectingAuthHandler>(
RejectingAuthHandler.SchemeName, _ => { });
services.PostConfigureAll<AuthenticationOptions>(options =>
{
options.DefaultAuthenticateScheme = RejectingAuthHandler.SchemeName;
options.DefaultChallengeScheme = RejectingAuthHandler.SchemeName;
options.DefaultScheme = RejectingAuthHandler.SchemeName;
});
services.RemoveAll<IAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DenyAllAuthorizationHandler>();
});
});
using var client = unauthenticatedFactory.CreateClient();
var response = await client.PostAsJsonAsync(
"/api/v1/admin/seed-demo",
new { dryRun = true },
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SeedDemo_WhenAuthorizationFails_ReturnsForbidden()
{
using WebApplicationFactory<Program> forbiddenFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.RemoveAll<IAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DenyAllAuthorizationHandler>();
});
});
using var client = forbiddenFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-seed-forbidden-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "seed-tester");
var response = await client.PostAsJsonAsync(
"/api/v1/admin/seed-demo",
new { dryRun = true },
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
private sealed class RejectingAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public const string SchemeName = "SeedRejectingScheme";
public RejectingAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
}
private sealed class DenyAllAuthorizationHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
return Task.CompletedTask;
}
}
}