HerregistratieReminderSweep reminds every due inscription, persists the flag so a re-fire is a no-op, and returns the reminded ids. Stubbed to an empty result so the new tests fail; green implements the sweep. Adds a FixedClock TimeProvider fake so the sweep is deterministic without a testing package. refs #18
149 lines
6.0 KiB
C#
149 lines
6.0 KiB
C#
using Big.Application;
|
|
using Big.Domain;
|
|
|
|
namespace Big.Tests;
|
|
|
|
/// <summary>An in-memory <see cref="IRegistrationStore"/> for the application-layer tests. Upserts
|
|
/// keyed on the registration id, mirroring the production store (kept distinct from the production
|
|
/// <c>InMemoryRegistrationStore</c> so tests can seed and inspect save counts).</summary>
|
|
internal sealed class FakeRegistrationStore : IRegistrationStore
|
|
{
|
|
private readonly Dictionary<RegistrationId, Registration> _byId = [];
|
|
|
|
public int SaveCount { get; private set; }
|
|
|
|
public Task SaveAsync(Registration registration, CancellationToken ct = default)
|
|
{
|
|
SaveCount++;
|
|
_byId[registration.Id] = registration;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task<Registration?> GetAsync(RegistrationId id, CancellationToken ct = default)
|
|
=> Task.FromResult(_byId.GetValueOrDefault(id));
|
|
|
|
public Task<Registration?> FindOpenByBsnAsync(string bsn, CancellationToken ct = default)
|
|
=> Task.FromResult(_byId.Values.FirstOrDefault(r =>
|
|
r.Bsn == bsn && r.Status is RegistrationStatus.Ingediend or RegistrationStatus.InBehandeling));
|
|
|
|
public Task<IReadOnlyList<Registration>> FindDueForHerregistratieReminderAsync(
|
|
DateTimeOffset asOf, CancellationToken ct = default)
|
|
=> Task.FromResult<IReadOnlyList<Registration>>(
|
|
_byId.Values.Where(r => r.HerregistratieReminderDue(asOf)).ToList());
|
|
|
|
public void Seed(Registration registration) => _byId[registration.Id] = registration;
|
|
}
|
|
|
|
/// <summary>A fake Workflow Client that records the registration it was asked to start a process for
|
|
/// and returns a fixed process-instance id. An optional callback runs at start time, letting a test
|
|
/// assert ordering (e.g. that the registration was persisted before the process started).</summary>
|
|
internal sealed class FakeWorkflowClient(string processInstanceId = "proc-1", Action<RegistrationId>? onStart = null)
|
|
: IWorkflowClient
|
|
{
|
|
public RegistrationId? StartedFor { get; private set; }
|
|
public DiplomaOrigin? StartedWithOrigin { get; private set; }
|
|
public string? WithdrawnProcessInstanceId { get; private set; }
|
|
public string? CompletedDocumentWaitFor { get; private set; }
|
|
|
|
public Task<string> StartRegistrationProcessAsync(
|
|
RegistrationId registrationId, DiplomaOrigin diplomaOrigin, CancellationToken ct = default)
|
|
{
|
|
onStart?.Invoke(registrationId);
|
|
StartedFor = registrationId;
|
|
StartedWithOrigin = diplomaOrigin;
|
|
return Task.FromResult(processInstanceId);
|
|
}
|
|
|
|
public Task WithdrawProcessAsync(string processInstanceId, CancellationToken ct = default)
|
|
{
|
|
WithdrawnProcessInstanceId = processInstanceId;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task CompleteDocumentWaitAsync(string processInstanceId, CancellationToken ct = default)
|
|
{
|
|
CompletedDocumentWaitFor = processInstanceId;
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
/// <summary>A fake user-task client for the werkbak/decision use cases: returns a scripted set of
|
|
/// open beoordeling tasks and records claim/complete calls.</summary>
|
|
internal sealed class FakeUserTaskClient(IReadOnlyList<BeoordelingTask> open) : IUserTaskClient
|
|
{
|
|
public (string TaskId, string Behandelaar)? Claimed { get; private set; }
|
|
public (string TaskId, BeoordelingsBesluit Besluit)? Completed { get; private set; }
|
|
|
|
public Task<IReadOnlyList<BeoordelingTask>> GetOpenBeoordelingenAsync(CancellationToken ct = default)
|
|
=> Task.FromResult(open);
|
|
|
|
public Task ClaimAsync(string taskId, string behandelaar, CancellationToken ct = default)
|
|
{
|
|
Claimed = (taskId, behandelaar);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task CompleteBeoordelingAsync(string taskId, BeoordelingsBesluit besluit, CancellationToken ct = default)
|
|
{
|
|
Completed = (taskId, besluit);
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
/// <summary>A <see cref="TimeProvider"/> pinned to a fixed instant, so time-based use cases (the
|
|
/// herregistratie sweep, S-17) are deterministic without the TimeProvider.Testing package.</summary>
|
|
internal sealed class FixedClock(DateTimeOffset now) : TimeProvider
|
|
{
|
|
public override DateTimeOffset GetUtcNow() => now;
|
|
}
|
|
|
|
/// <summary>A fake ACL client that records the bsn it was asked to open a zaak for and returns a
|
|
/// fixed zaak URL.</summary>
|
|
internal sealed class FakeAclClient(Uri? zaakUrl = null) : IAclClient
|
|
{
|
|
public static readonly Uri DefaultZaakUrl = new("http://openzaak/zaken/api/v1/zaken/abc");
|
|
|
|
private readonly Uri _zaakUrl = zaakUrl ?? DefaultZaakUrl;
|
|
|
|
public string? OpenedForBsn { get; private set; }
|
|
public string? OpenedWithReference { get; private set; }
|
|
public int CallCount { get; private set; }
|
|
|
|
public Uri? ApprovedZaakUrl { get; private set; }
|
|
public int ApproveCallCount { get; private set; }
|
|
|
|
public Task<Uri> OpenZaakAsync(string bsn, string reference, CancellationToken ct = default)
|
|
{
|
|
CallCount++;
|
|
OpenedForBsn = bsn;
|
|
OpenedWithReference = reference;
|
|
return Task.FromResult(_zaakUrl);
|
|
}
|
|
|
|
public Task ApproveZaakAsync(Uri zaakUrl, CancellationToken ct = default)
|
|
{
|
|
ApproveCallCount++;
|
|
ApprovedZaakUrl = zaakUrl;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public (Uri ZaakUrl, byte[] Content, string FileName, string ContentType)? StoredDiploma { get; private set; }
|
|
public static readonly Uri DefaultDocumentUrl = new("http://openzaak/documenten/api/v1/enkelvoudiginformatieobjecten/doc");
|
|
|
|
public Task<Uri> StoreDiplomaAsync(Uri zaakUrl, byte[] content, string fileName, string contentType, CancellationToken ct = default)
|
|
{
|
|
StoredDiploma = (zaakUrl, content, fileName, contentType);
|
|
return Task.FromResult(DefaultDocumentUrl);
|
|
}
|
|
|
|
public Uri? CancelledZaakUrl { get; private set; }
|
|
public int CancelCallCount { get; private set; }
|
|
|
|
public Task CancelZaakAsync(Uri zaakUrl, CancellationToken ct = default)
|
|
{
|
|
CancelCallCount++;
|
|
CancelledZaakUrl = zaakUrl;
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|