test(acl): approval writes the RegisterRecord to Objecten (refs #149)
Ports and failing tests for the Objecten hop, ahead of the implementation: - IRegisterRecordGateway + RegisterRecord — the Application-side port; the record mirrors the objecttype schema registered in S-18c (ADR-0027). - AclService takes the port but does not yet call it, so the approval test fails on an empty upsert list. - ObjectenGateway is a shell throwing NotImplementedException; its tests pin the contract: resolve the objecttype by name, search by data attribute, POST when absent / PATCH when present, static Token auth per API, the CRS headers the geo API requires, and a surfaced error body. Also splits S-19 (#20) into #149/#150 in BACKLOG.md — the approval-side write and the projection re-sourcing are independently deployable (CLAUDE.md §13).
This commit is contained in:
+6
-1
@@ -287,12 +287,17 @@ Split into independently deployable sub-slices (CLAUDE.md §13):
|
|||||||
- **S-18b** (#140, ✅) · Objecten API up in compose, wired to Objecttypen. Depends on S-18a.
|
- **S-18b** (#140, ✅) · Objecten API up in compose, wired to Objecttypen. Depends on S-18a.
|
||||||
- **S-18c** (#141, ✅) · RegisterRecord objecttype defined + registered (public-safe JSON schema). Depends on S-18a/b.
|
- **S-18c** (#141, ✅) · RegisterRecord objecttype defined + registered (public-safe JSON schema). Depends on S-18a/b.
|
||||||
|
|
||||||
### S-19 · ACL extension: write register-record to Objecten on approval
|
### S-19 · ACL extension: write register-record to Objecten on approval *(split — #20 closed)*
|
||||||
|
|
||||||
**Outcome:** Approval path writes the canonical register record to Objecten, not OpenZaak eigenschappen. Projection now sourced from Objecten events.
|
**Outcome:** Approval path writes the canonical register record to Objecten, not OpenZaak eigenschappen. Projection now sourced from Objecten events.
|
||||||
|
|
||||||
**ADR required:** "Why Objecten holds the register, OpenZaak holds the process."
|
**ADR required:** "Why Objecten holds the register, OpenZaak holds the process."
|
||||||
|
|
||||||
|
Split into independently deployable sub-slices (CLAUDE.md §13):
|
||||||
|
|
||||||
|
- **S-19a** (#149) · ACL writes the `RegisterRecord` to Objecten on approval, idempotently, alongside the ZGW eindstatus. Carries the ADR.
|
||||||
|
- **S-19b** (#150) · Read projection sourced from Objecten instead of NRC zaak events. Depends on S-19a.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Iteration 5 — Data governance module *(milestone: `Iteration 5 — Data Governance`)*
|
## Iteration 5 — Data governance module *(milestone: `Iteration 5 — Data Governance`)*
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ namespace Acl.Application;
|
|||||||
|
|
||||||
/// <summary>The ACL's single operation: open a zaak from a domain payload,
|
/// <summary>The ACL's single operation: open a zaak from a domain payload,
|
||||||
/// default-filling the ZGW-mandatory fields (ADR-0003).</summary>
|
/// default-filling the ZGW-mandatory fields (ADR-0003).</summary>
|
||||||
public sealed class AclService(IZaakGateway gateway, IDefaultFillStore fill, IZaaktypeCatalog catalog, IClock clock)
|
public sealed class AclService(
|
||||||
|
IZaakGateway gateway,
|
||||||
|
IRegisterRecordGateway register,
|
||||||
|
IDefaultFillStore fill,
|
||||||
|
IZaaktypeCatalog catalog,
|
||||||
|
IClock clock)
|
||||||
{
|
{
|
||||||
public async Task<Uri> OpenZaakAsync(DomainRegistration registration, CancellationToken ct = default)
|
public async Task<Uri> OpenZaakAsync(DomainRegistration registration, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
namespace Acl.Application;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Port to the Objecten API, which holds the authoritative register record (S-19a, ADR-0028).
|
||||||
|
/// Implemented in Infrastructure — as with ZGW, the ACL is the only code that talks to the
|
||||||
|
/// upstream Common Ground module (§8.1).
|
||||||
|
/// </summary>
|
||||||
|
public interface IRegisterRecordGateway
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Write the register record for a registration, creating it if absent and updating it if it
|
||||||
|
/// already exists. Idempotent on <see cref="RegisterRecord.Id"/>: a replayed approval updates
|
||||||
|
/// the existing object instead of creating a second one (§8.6).
|
||||||
|
/// </summary>
|
||||||
|
Task UpsertAsync(RegisterRecord record, CancellationToken ct = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The public-safe register record, matching the <c>RegisterRecord</c> objecttype schema registered
|
||||||
|
/// in S-18c (ADR-0027). No bsn, no name — the register is world-readable.
|
||||||
|
/// </summary>
|
||||||
|
public sealed record RegisterRecord(string Id, string Status, string? Reference);
|
||||||
|
|
||||||
|
/// <summary>The register statuses the RegisterRecord objecttype's schema allows (ADR-0027).</summary>
|
||||||
|
public static class RegisterRecordStatus
|
||||||
|
{
|
||||||
|
public const string Ingediend = "INGEDIEND";
|
||||||
|
|
||||||
|
public const string Ingeschreven = "INGESCHREVEN";
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Acl.Application;
|
||||||
|
|
||||||
|
namespace Acl.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>The only code that talks to the Objecten API (ADR-0028).</summary>
|
||||||
|
public sealed class ObjectenGateway(HttpClient http, ObjectenOptions options, IClock clock) : IRegisterRecordGateway
|
||||||
|
{
|
||||||
|
public Task UpsertAsync(RegisterRecord record, CancellationToken ct = default) =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Acl.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connection + credential config for the Objecten and Objecttypen APIs. Both authenticate with a
|
||||||
|
/// static <c>Authorization: Token …</c> (they are not ZGW JWT APIs), so there is no client-id/secret
|
||||||
|
/// pair as with OpenZaak.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ObjectenOptions
|
||||||
|
{
|
||||||
|
public required Uri BaseUrl { get; init; }
|
||||||
|
public required string Token { get; init; }
|
||||||
|
|
||||||
|
/// <summary>Objecttypen API root — the ACL resolves the objecttype URL + version from it by name
|
||||||
|
/// rather than pinning a seed-time UUID in config (same reasoning as ADR-0021).</summary>
|
||||||
|
public required Uri ObjecttypenBaseUrl { get; init; }
|
||||||
|
public required string ObjecttypenToken { get; init; }
|
||||||
|
|
||||||
|
/// <summary>The objecttype the register record is written as (S-18c registers "RegisterRecord").</summary>
|
||||||
|
public required string ObjecttypeName { get; init; }
|
||||||
|
}
|
||||||
@@ -75,6 +75,17 @@ public class AclServiceTests
|
|||||||
Task.FromResult(Zaaktypen);
|
Task.FromResult(Zaaktypen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class FakeRegisterRecordGateway : IRegisterRecordGateway
|
||||||
|
{
|
||||||
|
public readonly List<RegisterRecord> Upserted = [];
|
||||||
|
|
||||||
|
public Task UpsertAsync(RegisterRecord record, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
Upserted.Add(record);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static AclDefaults Defaults() => new()
|
private static AclDefaults Defaults() => new()
|
||||||
{
|
{
|
||||||
Bronorganisatie = "517439943",
|
Bronorganisatie = "517439943",
|
||||||
@@ -88,7 +99,10 @@ public class AclServiceTests
|
|||||||
new(new DefaultFillSettings(d.Bronorganisatie, d.VerantwoordelijkeOrganisatie, d.Vertrouwelijkheidaanduiding));
|
new(new DefaultFillSettings(d.Bronorganisatie, d.VerantwoordelijkeOrganisatie, d.Vertrouwelijkheidaanduiding));
|
||||||
|
|
||||||
private static AclService ServiceWith(FakeGateway gateway, AclDefaults defaults, DateOnly today) =>
|
private static AclService ServiceWith(FakeGateway gateway, AclDefaults defaults, DateOnly today) =>
|
||||||
new(gateway, FillFrom(defaults), new CachedZaaktypeCatalog(gateway, defaults), new FixedClock(today));
|
ServiceWith(gateway, new FakeRegisterRecordGateway(), defaults, today);
|
||||||
|
|
||||||
|
private static AclService ServiceWith(FakeGateway gateway, FakeRegisterRecordGateway register, AclDefaults defaults, DateOnly today) =>
|
||||||
|
new(gateway, register, FillFrom(defaults), new CachedZaaktypeCatalog(gateway, defaults), new FixedClock(today));
|
||||||
|
|
||||||
private sealed class FixedClock(DateOnly today) : IClock
|
private sealed class FixedClock(DateOnly today) : IClock
|
||||||
{
|
{
|
||||||
@@ -161,10 +175,42 @@ public class AclServiceTests
|
|||||||
public async Task Approving_a_null_zaak_is_rejected_without_touching_the_gateway()
|
public async Task Approving_a_null_zaak_is_rejected_without_touching_the_gateway()
|
||||||
{
|
{
|
||||||
var gateway = new FakeGateway();
|
var gateway = new FakeGateway();
|
||||||
var service = ServiceWith(gateway, Defaults(), new DateOnly(2026, 6, 4));
|
var register = new FakeRegisterRecordGateway();
|
||||||
|
var service = ServiceWith(gateway, register, Defaults(), new DateOnly(2026, 6, 4));
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentNullException>(() => service.ApproveZaakAsync(null!));
|
await Assert.ThrowsAsync<ArgumentNullException>(() => service.ApproveZaakAsync(null!));
|
||||||
Assert.Null(gateway.Approved);
|
Assert.Null(gateway.Approved);
|
||||||
|
Assert.Empty(register.Upserted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Approving_a_zaak_writes_the_register_record_to_objecten(/* S-19a */)
|
||||||
|
{
|
||||||
|
var gateway = new FakeGateway();
|
||||||
|
var register = new FakeRegisterRecordGateway();
|
||||||
|
var service = ServiceWith(gateway, register, Defaults(), new DateOnly(2026, 6, 4));
|
||||||
|
|
||||||
|
await service.ApproveZaakAsync(new Uri("http://openzaak/zaken/api/v1/zaken/abc"));
|
||||||
|
|
||||||
|
var record = Assert.Single(register.Upserted);
|
||||||
|
// The record is keyed on the zaak id — the same key the read projection rows carry (S-19b).
|
||||||
|
Assert.Equal("abc", record.Id);
|
||||||
|
Assert.Equal("INGESCHREVEN", record.Status);
|
||||||
|
// The public-safe reference comes from the zaak's identificatie, never from the domain payload.
|
||||||
|
Assert.Equal("REG-FROM-ZAAK", record.Reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Cancelling_a_zaak_writes_no_register_record(/* S-19a */)
|
||||||
|
{
|
||||||
|
var gateway = new FakeGateway();
|
||||||
|
var register = new FakeRegisterRecordGateway();
|
||||||
|
var service = ServiceWith(gateway, register, Defaults(), new DateOnly(2026, 6, 4));
|
||||||
|
|
||||||
|
await service.CancelZaakAsync(new Uri("http://openzaak/zaken/api/v1/zaken/abc"));
|
||||||
|
|
||||||
|
// Only an approval enters the register; a cancelled zaak never becomes a register record.
|
||||||
|
Assert.Empty(register.Upserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using Acl.Application;
|
||||||
|
using Acl.Infrastructure;
|
||||||
|
|
||||||
|
namespace Acl.Tests;
|
||||||
|
|
||||||
|
public class ObjectenGatewayTests
|
||||||
|
{
|
||||||
|
private sealed class StubHandler(Func<HttpRequestMessage, Task<HttpResponseMessage>> onSend)
|
||||||
|
: HttpMessageHandler
|
||||||
|
{
|
||||||
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct)
|
||||||
|
=> onSend(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FixedClock(DateOnly today) : IClock
|
||||||
|
{
|
||||||
|
public DateOnly Today { get; } = today;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record Sent(HttpMethod Method, Uri Uri, string? Body, string? Auth, string? ContentCrs, string? AcceptCrs);
|
||||||
|
|
||||||
|
private const string ObjecttypeUrl = "http://objecttypen:8000/api/v2/objecttypes/ot-1";
|
||||||
|
|
||||||
|
private static ObjectenGateway Gateway(List<Sent> sent, Func<HttpRequestMessage, HttpResponseMessage> respond) =>
|
||||||
|
new(
|
||||||
|
new HttpClient(new StubHandler(async req =>
|
||||||
|
{
|
||||||
|
sent.Add(new Sent(
|
||||||
|
req.Method,
|
||||||
|
req.RequestUri!,
|
||||||
|
req.Content is null ? null : await req.Content.ReadAsStringAsync(),
|
||||||
|
req.Headers.Authorization?.ToString(),
|
||||||
|
req.Content?.Headers.TryGetValues("Content-Crs", out var c) == true ? string.Join(",", c!) : null,
|
||||||
|
req.Headers.TryGetValues("Accept-Crs", out var a) ? string.Join(",", a) : null));
|
||||||
|
return respond(req);
|
||||||
|
})),
|
||||||
|
new ObjectenOptions
|
||||||
|
{
|
||||||
|
BaseUrl = new("http://objecten:8000"),
|
||||||
|
Token = "objecten-token",
|
||||||
|
ObjecttypenBaseUrl = new("http://objecttypen:8000"),
|
||||||
|
ObjecttypenToken = "objecttypen-token",
|
||||||
|
ObjecttypeName = "RegisterRecord",
|
||||||
|
},
|
||||||
|
new FixedClock(new DateOnly(2026, 6, 4)));
|
||||||
|
|
||||||
|
// The Objecttypen lookup (by name) and the Objecten search (by data attribute) that precede every
|
||||||
|
// write. `respondToWrite` decides what the POST/PATCH returns.
|
||||||
|
private static HttpResponseMessage Route(HttpRequestMessage req, object[] existingObjects) =>
|
||||||
|
req.RequestUri!.AbsolutePath.StartsWith("/api/v2/objecttypes", StringComparison.Ordinal)
|
||||||
|
? new HttpResponseMessage(HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Content = JsonContent.Create(new
|
||||||
|
{
|
||||||
|
results = new[]
|
||||||
|
{
|
||||||
|
new { url = "http://objecttypen:8000/api/v2/objecttypes/other", name = "SomethingElse", versions = new[] { "…/versions/1" } },
|
||||||
|
new { url = ObjecttypeUrl, name = "RegisterRecord", versions = new[] { "…/versions/1", "…/versions/2" } },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
: req.Method == HttpMethod.Get
|
||||||
|
? new HttpResponseMessage(HttpStatusCode.OK) { Content = JsonContent.Create(new { results = existingObjects }) }
|
||||||
|
: new HttpResponseMessage(HttpStatusCode.Created) { Content = JsonContent.Create(new { url = "http://objecten:8000/api/v2/objects/obj-1" }) };
|
||||||
|
|
||||||
|
private static RegisterRecord Record() => new("zaak-uuid-1", RegisterRecordStatus.Ingeschreven, "REG-2026-0001");
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Creates_the_object_when_none_exists_for_the_registration()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
|
||||||
|
await Gateway(sent, req => Route(req, [])).UpsertAsync(Record());
|
||||||
|
|
||||||
|
var write = sent.Single(s => s.Method == HttpMethod.Post && s.Uri.AbsolutePath == "/api/v2/objects");
|
||||||
|
Assert.Contains($"\"type\":\"{ObjecttypeUrl}\"", write.Body);
|
||||||
|
Assert.Contains("\"typeVersion\":2", write.Body);
|
||||||
|
Assert.Contains("\"id\":\"zaak-uuid-1\"", write.Body);
|
||||||
|
Assert.Contains("\"status\":\"INGESCHREVEN\"", write.Body);
|
||||||
|
Assert.Contains("\"reference\":\"REG-2026-0001\"", write.Body);
|
||||||
|
Assert.Contains("\"startAt\":\"2026-06-04\"", write.Body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Updates_the_existing_object_instead_of_creating_a_second_one()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
object[] existing = [new { uuid = "obj-9", url = "http://objecten:8000/api/v2/objects/obj-9" }];
|
||||||
|
|
||||||
|
await Gateway(sent, req => Route(req, existing)).UpsertAsync(Record());
|
||||||
|
|
||||||
|
Assert.DoesNotContain(sent, s => s.Method == HttpMethod.Post && s.Uri.AbsolutePath == "/api/v2/objects");
|
||||||
|
var write = sent.Single(s => s.Method == HttpMethod.Patch);
|
||||||
|
Assert.Equal("http://objecten:8000/api/v2/objects/obj-9", write.Uri.ToString());
|
||||||
|
Assert.Contains("\"status\":\"INGESCHREVEN\"", write.Body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Searches_objecten_for_the_registration_id_within_the_objecttype()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
|
||||||
|
await Gateway(sent, req => Route(req, [])).UpsertAsync(Record());
|
||||||
|
|
||||||
|
var search = sent.Single(s => s.Method == HttpMethod.Get && s.Uri.AbsolutePath == "/api/v2/objects");
|
||||||
|
Assert.Contains("type=" + Uri.EscapeDataString(ObjecttypeUrl), search.Uri.Query);
|
||||||
|
Assert.Contains("data_attrs=id__exact__zaak-uuid-1", search.Uri.Query);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Authenticates_with_the_static_token_of_each_api()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
|
||||||
|
await Gateway(sent, req => Route(req, [])).UpsertAsync(Record());
|
||||||
|
|
||||||
|
Assert.All(
|
||||||
|
sent.Where(s => s.Uri.AbsolutePath.StartsWith("/api/v2/objecttypes", StringComparison.Ordinal)),
|
||||||
|
s => Assert.Equal("Token objecttypen-token", s.Auth));
|
||||||
|
Assert.All(
|
||||||
|
sent.Where(s => s.Uri.AbsolutePath.StartsWith("/api/v2/objects", StringComparison.Ordinal)),
|
||||||
|
s => Assert.Equal("Token objecten-token", s.Auth));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sends_the_geo_crs_headers_the_objecten_api_requires()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
|
||||||
|
await Gateway(sent, req => Route(req, [])).UpsertAsync(Record());
|
||||||
|
|
||||||
|
var objects = sent.Where(s => s.Uri.AbsolutePath.StartsWith("/api/v2/objects", StringComparison.Ordinal)).ToList();
|
||||||
|
Assert.All(objects, s => Assert.Equal("EPSG:4326", s.AcceptCrs));
|
||||||
|
Assert.All(objects.Where(s => s.Body is not null), s => Assert.Equal("EPSG:4326", s.ContentCrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Resolves_the_objecttype_once_and_reuses_it_across_writes()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
var gateway = Gateway(sent, req => Route(req, []));
|
||||||
|
|
||||||
|
await gateway.UpsertAsync(Record());
|
||||||
|
await gateway.UpsertAsync(Record() with { Id = "zaak-uuid-2" });
|
||||||
|
|
||||||
|
Assert.Single(sent, s => s.Uri.AbsolutePath.StartsWith("/api/v2/objecttypes", StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Fails_loudly_when_the_objecttype_is_not_registered()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
var gateway = Gateway(sent, _ => new HttpResponseMessage(HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Content = JsonContent.Create(new { results = Array.Empty<object>() }),
|
||||||
|
});
|
||||||
|
|
||||||
|
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => gateway.UpsertAsync(Record()));
|
||||||
|
Assert.Contains("RegisterRecord", error.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Surfaces_the_objecten_error_body_when_a_write_is_rejected()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
var gateway = Gateway(sent, req => req.Method == HttpMethod.Post && req.RequestUri!.AbsolutePath == "/api/v2/objects"
|
||||||
|
? new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("{\"detail\":\"schema mismatch\"}") }
|
||||||
|
: Route(req, []));
|
||||||
|
|
||||||
|
var error = await Assert.ThrowsAsync<HttpRequestException>(() => gateway.UpsertAsync(Record()));
|
||||||
|
Assert.Contains("schema mismatch", error.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Rejects_a_null_record_without_calling_objecten()
|
||||||
|
{
|
||||||
|
var sent = new List<Sent>();
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<ArgumentNullException>(() => Gateway(sent, req => Route(req, [])).UpsertAsync(null!));
|
||||||
|
Assert.Empty(sent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ public sealed class EenZaakOpenenSteps
|
|||||||
{
|
{
|
||||||
var fill = new InMemoryDefaultFillStore(new DefaultFillSettings(
|
var fill = new InMemoryDefaultFillStore(new DefaultFillSettings(
|
||||||
_defaults!.Bronorganisatie, _defaults.VerantwoordelijkeOrganisatie, _defaults.Vertrouwelijkheidaanduiding));
|
_defaults!.Bronorganisatie, _defaults.VerantwoordelijkeOrganisatie, _defaults.Vertrouwelijkheidaanduiding));
|
||||||
var service = new AclService(_gateway, fill, new CachedZaaktypeCatalog(_gateway, _defaults!), new FixedClock(_today));
|
var service = new AclService(_gateway, new InMemoryRegisterRecordGateway(), fill, new CachedZaaktypeCatalog(_gateway, _defaults!), new FixedClock(_today));
|
||||||
_returnedUrl = await service.OpenZaakAsync(_registration!);
|
_returnedUrl = await service.OpenZaakAsync(_registration!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,3 +53,16 @@ public sealed class InMemoryZaakGateway : IZaakGateway
|
|||||||
=> Task.FromResult<IReadOnlyList<ZaaktypeSummary>>(
|
=> Task.FromResult<IReadOnlyList<ZaaktypeSummary>>(
|
||||||
[new ZaaktypeSummary("BIG-REGISTRATIE", "BIG-registratie", ResolvedZaaktypeUrl)]);
|
[new ZaaktypeSummary("BIG-REGISTRATIE", "BIG-registratie", ResolvedZaaktypeUrl)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>An in-memory stand-in for the Objecten API (S-19a): records the register records the ACL
|
||||||
|
/// writes on approval, so a scenario can assert on them without a running Objecten.</summary>
|
||||||
|
public sealed class InMemoryRegisterRecordGateway : IRegisterRecordGateway
|
||||||
|
{
|
||||||
|
public List<RegisterRecord> Upserted { get; } = [];
|
||||||
|
|
||||||
|
public Task UpsertAsync(RegisterRecord record, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
Upserted.Add(record);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user