test(acceptance): document-termijn verloopt (both branches) (refs #102)
BDD for S-10a: a registration parked at WachtOpDocumenten expires to VERLOPEN when the 30-day timer fires, and does NOT expire when documents arrive first. Drives the real RegistratieVerlopenProcessor + ExpireRegistrationWorker against an in-memory Flowable stand-in, mirroring the escalation feature. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,57 @@ public sealed class InMemoryEscalatieClient : IBeoordelingEscalatieClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>An in-memory Flowable stand-in for the document-timeout scenario (S-10a): it models one
|
||||
/// WachtOpDocumenten wait per process instance — whether it is still open and the registration it
|
||||
/// correlates to — and the RegistratieVerlopen jobs the interrupting 30-day boundary timer parks. It
|
||||
/// drives the timeout worker's behaviour without a running Flowable; the timer firing live is the
|
||||
/// verify-domain check.</summary>
|
||||
public sealed class InMemoryDocumentTimeoutClient : IRegistratieVerlopenClient
|
||||
{
|
||||
private sealed class Wait
|
||||
{
|
||||
public required RegistrationId RegistrationId { get; init; }
|
||||
public bool IsWaiting { get; set; } = true;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, Wait> _waits = [];
|
||||
private readonly List<RegistratieVerlopenJob> _parked = [];
|
||||
private int _seq;
|
||||
|
||||
/// <summary>A registration parks at WachtOpDocumenten, waiting for the citizen's documents.</summary>
|
||||
public string ParkWaitingForDocuments(RegistrationId registrationId)
|
||||
{
|
||||
var pid = $"pi-{++_seq}";
|
||||
_waits[pid] = new Wait { RegistrationId = registrationId };
|
||||
return pid;
|
||||
}
|
||||
|
||||
/// <summary>The documents arrive before the timer fires: the wait task closes, so the interrupting
|
||||
/// timer no longer fires (mirrors the Workflow Client completing WachtOpDocumenten).</summary>
|
||||
public void ReceiveDocuments(string processInstanceId) => _waits[processInstanceId].IsWaiting = false;
|
||||
|
||||
/// <summary>The 30-day interrupting boundary timer fires: if still waiting, it cancels the wait and
|
||||
/// parks a RegistratieVerlopen job carrying the correlated registration id. A no-op if the documents
|
||||
/// already arrived (the wait/timer race, §8.6).</summary>
|
||||
public void FireDocumentTimer(string processInstanceId)
|
||||
{
|
||||
var wait = _waits[processInstanceId];
|
||||
if (!wait.IsWaiting)
|
||||
return;
|
||||
wait.IsWaiting = false;
|
||||
_parked.Add(new RegistratieVerlopenJob($"job-{++_seq}", wait.RegistrationId));
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<RegistratieVerlopenJob>> AcquireRegistratieVerlopenJobsAsync(int maxJobs, CancellationToken ct = default)
|
||||
=> Task.FromResult<IReadOnlyList<RegistratieVerlopenJob>>(_parked.Take(maxJobs).ToList());
|
||||
|
||||
public Task CompleteRegistratieVerlopenJobAsync(string jobId, CancellationToken ct = default)
|
||||
{
|
||||
_parked.RemoveAll(j => j.JobId == jobId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>An in-memory registration store for the domain acceptance scenario.</summary>
|
||||
public sealed class InMemoryRegistrationStore : IRegistrationStore
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user