using System.Net.Http.Json; using BigRegister.Api.Contracts; using BigRegister.Api.Data; using BigRegister.Domain.Authorization; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; namespace BigRegister.Tests; /// Wraps but returns a DIFFERENT case id than the /// underlying Aanvraag.Id — reproduces exactly what OpenZaakZaakSource does in /// production (the FE-facing case id from ListCases is the ZGW zaak's own uuid, not /// ApplicationStore's primary key) without needing a live OpenZaak, so the besluit /// endpoint's Referentie-based resolution (the fix below) gets coverage on every push. file sealed class IdMismatchZaakSource : IZaakSource { private readonly LocalZaakSource inner = new(); private static ApplicationSummaryDto Rekey(ApplicationSummaryDto dto) => dto with { Id = $"zaak-{dto.Id}" }; public IReadOnlyList ListCases(DateTimeOffset now) => inner.ListCases(now).Select(Rekey).ToList(); public IReadOnlyList ListMyCases(ZorgverlenerCaller caller, DateTimeOffset now) => inner.ListMyCases(caller, now).Select(Rekey).ToList(); public (string Referentie, AanvraagStatusDto Status, string? ZaakUrl) CreateZaak( Aanvraag aanvraag, DateTimeOffset now, CallerIdentity caller) => inner.CreateZaak(aanvraag, now, caller); public void RecordBesluit(Aanvraag aanvraag, Besluit besluit, string? toelichting, DateTimeOffset now, CallerIdentity caller) => inner.RecordBesluit(aanvraag, besluit, toelichting, now, caller); } /// /// Regression for a real, live-repro'd bug: recording a besluit from the behandelportal always /// 404'd against a real OpenZaak. Root cause — POST /beoordeling/{id}/besluit looked /// id up directly in ApplicationStore (its own primary key), but id is /// whatever IZaakSource.ListCases handed the FE; under OpenZaakZaakSource that's /// the ZGW zaak's own uuid, a different value entirely. Fixed by resolving the case through /// the same ListCases seak the GET sibling () already uses, /// then to the local Aanvraag via its Referentie (ApplicationStore.GetByReferentie) /// — the one identifier stable across both sources. /// reproduces the id divergence without a live OpenZaak. /// public class BeoordelingIdMismatchTests { private static WebApplicationFactory Factory() { var dbPath = Path.Combine(Path.GetTempPath(), $"bigregister-id-mismatch-{Guid.NewGuid():N}.db"); return new WebApplicationFactory().WithWebHostBuilder(builder => builder .UseSetting("ConnectionStrings:AppDb", $"Data Source={dbPath}") .ConfigureTestServices(services => services.AddSingleton())); } private static HttpRequestMessage Behandelaar(HttpMethod method, string path, object? body = null) { var req = new HttpRequestMessage(method, path); req.Headers.Add("X-Medewerker", "medewerker-1"); if (body is not null) req.Content = JsonContent.Create(body); return req; } [Fact] public async Task Besluit_resolves_by_referentie_when_the_case_id_differs_from_the_local_aanvraag_id() { using var factory = Factory(); using var client = factory.CreateClient(); var created = await client.PostAsJsonAsync("/api/v1/applications", new { type = "registratie" }); var app = (await created.Content.ReadFromJsonAsync())!; var submit = await client.PostAsJsonAsync($"/api/v1/applications/{app.Id}/submit", new { diplomaHerkomst = "handmatig" }); submit.EnsureSuccessStatusCode(); var werkvoorraad = await client.SendAsync(Behandelaar(HttpMethod.Get, "/api/v1/werkvoorraad")); var items = (await werkvoorraad.Content.ReadFromJsonAsync>())!; var caseId = Assert.Single(items).Id; // Sanity: the id divergence this test exists for is real, not accidentally absent. Assert.NotEqual(app.Id, caseId); var res = await client.SendAsync(Behandelaar(HttpMethod.Post, $"/api/v1/beoordeling/{caseId}/besluit", new { besluit = "Afwijzen", toelichting = "onvolledig" })); res.EnsureSuccessStatusCode(); var body = (await res.Content.ReadFromJsonAsync())!; Assert.Equal("Afgewezen", body.Status.Tag); } }