using System.Net; using System.Net.Http.Json; using BigRegister.Api.Contracts; using BigRegister.Domain.Features; using Microsoft.AspNetCore.Mvc.Testing; namespace BigRegister.Tests; /// WP-47: runtime feature flags — catalog in code, admin-toggled, server-enforced. public class FeatureFlagTests(TestWebApplicationFactory factory) : IClassFixture { private readonly HttpClient _client = factory.CreateClient(); private HttpRequestMessage Admin(HttpMethod method, string path, object? body = null) { var req = new HttpRequestMessage(method, path) { Headers = { { "X-Role", "admin" } } }; if (body is not null) req.Content = JsonContent.Create(body); return req; } [Fact] public void The_catalog_has_unique_keys() { var keys = FeatureFlags.Catalog.Select(f => f.Key).ToList(); Assert.Equal(keys.Count, keys.Distinct().Count()); Assert.All(FeatureFlags.Catalog, f => Assert.False(string.IsNullOrWhiteSpace(f.Key))); } [Fact] public async Task Get_flags_returns_the_catalog() { var flags = await _client.GetFromJsonAsync>("/api/v1/flags"); Assert.Contains(flags!, f => f.Key == FeatureFlags.InschrijvingOpen); } [Fact] public async Task Toggling_is_admin_only_and_an_unknown_key_is_404() { // Non-admin (no X-Role → drafter) may not toggle. var denied = await _client.PutAsJsonAsync( $"/api/v1/admin/flags/{FeatureFlags.InschrijvingOpen}", new { enabled = false }); Assert.Equal(HttpStatusCode.Forbidden, denied.StatusCode); // Admin, unknown flag → 404. var unknown = await _client.SendAsync(Admin(HttpMethod.Put, "/api/v1/admin/flags/does-not-exist", new { enabled = true })); Assert.Equal(HttpStatusCode.NotFound, unknown.StatusCode); } [Fact] public async Task Closing_inschrijving_blocks_a_registratie_then_reopening_allows_it() { try { // Off → POST /aanvragen for a registratie is refused. (await _client.SendAsync(Admin(HttpMethod.Put, $"/api/v1/admin/flags/{FeatureFlags.InschrijvingOpen}", new { enabled = false }))) .EnsureSuccessStatusCode(); var blocked = await _client.PostAsJsonAsync("/api/v1/aanvragen", new { type = "registratie" }); Assert.Equal(HttpStatusCode.Forbidden, blocked.StatusCode); // On → allowed again. (await _client.SendAsync(Admin(HttpMethod.Put, $"/api/v1/admin/flags/{FeatureFlags.InschrijvingOpen}", new { enabled = true }))) .EnsureSuccessStatusCode(); var ok = await _client.PostAsJsonAsync("/api/v1/aanvragen", new { type = "registratie" }); Assert.Equal(HttpStatusCode.Created, ok.StatusCode); } finally { // Leave the flag on (shared DB across this class). await _client.SendAsync(Admin(HttpMethod.Put, $"/api/v1/admin/flags/{FeatureFlags.InschrijvingOpen}", new { enabled = true })); } } }