S-09b: Approval flow — temp admin endpoint + status transition to projection #77

Merged
not merged 13 commits from feat/75-approval-flow into main 2026-07-14 09:05:00 +00:00
Showing only changes of commit b672132ed4 - Show all commits

View File

@@ -8,6 +8,7 @@ namespace EventSubscriber.Tests;
public sealed class NotificationProjectorTests public sealed class NotificationProjectorTests
{ {
private const string ZaakUrl = "http://openzaak:8000/zaken/api/v1/zaken/11111111-1111-1111-1111-111111111111"; private const string ZaakUrl = "http://openzaak:8000/zaken/api/v1/zaken/11111111-1111-1111-1111-111111111111";
private const string StatusUrl = "http://openzaak:8000/zaken/api/v1/statussen/22222222-2222-2222-2222-222222222222";
private readonly InMemoryNotificationLog _log = new(); private readonly InMemoryNotificationLog _log = new();
private readonly InMemoryProjectionStore _store = new(); private readonly InMemoryProjectionStore _store = new();
@@ -17,6 +18,10 @@ public sealed class NotificationProjectorTests
private static Notification ZaakCreated(string url = ZaakUrl) private static Notification ZaakCreated(string url = ZaakUrl)
=> new("zaken", "zaak", "create", new Uri(url)); => new("zaken", "zaak", "create", new Uri(url));
// A status-set notification: resourceUrl is the status resource, hoofdObject is the zaak it belongs to.
private static Notification StatusSet(string zaakUrl = ZaakUrl, string statusUrl = StatusUrl)
=> new("zaken", "status", "create", new Uri(statusUrl), new Uri(zaakUrl));
[Fact] [Fact]
public async Task creating_a_zaak_writes_one_row_with_status_ingediend() public async Task creating_a_zaak_writes_one_row_with_status_ingediend()
{ {
@@ -62,16 +67,53 @@ public sealed class NotificationProjectorTests
[Theory] [Theory]
[InlineData("documenten", "enkelvoudiginformatieobject", "create")] // wrong kanaal + resource [InlineData("documenten", "enkelvoudiginformatieobject", "create")] // wrong kanaal + resource
[InlineData("documenten", "zaak", "create")] // wrong kanaal only [InlineData("documenten", "zaak", "create")] // wrong kanaal only
[InlineData("zaken", "status", "create")] // wrong resource only
[InlineData("zaken", "zaak", "update")] // wrong actie [InlineData("zaken", "zaak", "update")] // wrong actie
[InlineData("zaken", "zaak", "destroy")] // wrong actie [InlineData("zaken", "zaak", "destroy")] // wrong actie
public async Task only_a_zaken_zaak_create_notification_is_projected(string kanaal, string resource, string actie) [InlineData("zaken", "status", "update")] // a status change we ignore
[InlineData("zaken", "resultaat", "create")] // not a status we project
public async Task an_unrelated_notification_is_not_projected(string kanaal, string resource, string actie)
{ {
await Projector().HandleAsync(new Notification(kanaal, resource, actie, new Uri(ZaakUrl))); await Projector().HandleAsync(new Notification(kanaal, resource, actie, new Uri(ZaakUrl)));
Assert.Empty(await _store.AllAsync()); Assert.Empty(await _store.AllAsync());
} }
[Fact]
public async Task setting_a_status_projects_ingeschreven_keyed_on_the_zaak_not_the_status()
{
await Projector().HandleAsync(StatusSet());
var entry = Assert.Single(await _store.AllAsync());
// Keyed on the zaak (hoofdObject), not the status resource URL.
Assert.Equal("11111111-1111-1111-1111-111111111111", entry.Id);
Assert.Equal(RegistrationStatus.Ingeschreven, entry.Status);
}
[Fact]
public async Task approving_updates_the_existing_zaak_row_from_ingediend_to_ingeschreven()
{
var projector = Projector();
await projector.HandleAsync(ZaakCreated());
await projector.HandleAsync(StatusSet());
var entry = Assert.Single(await _store.AllAsync());
Assert.Equal("11111111-1111-1111-1111-111111111111", entry.Id);
Assert.Equal(RegistrationStatus.Ingeschreven, entry.Status);
}
[Fact]
public async Task rebuild_reproduces_the_approved_status()
{
var projector = Projector();
await projector.HandleAsync(ZaakCreated());
await projector.HandleAsync(StatusSet());
await projector.RebuildAsync();
var entry = Assert.Single(await _store.AllAsync());
Assert.Equal(RegistrationStatus.Ingeschreven, entry.Status);
}
[Fact] [Fact]
public async Task rebuild_clears_stale_rows_and_repopulates_from_the_notification_log() public async Task rebuild_clears_stale_rows_and_repopulates_from_the_notification_log()
{ {