using Big.Application; using Big.Infrastructure; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace Big.Tests; // S-14 (#15): the escalation drain loop. Mirrors OpenZaakJobProcessor — acquire the parked // BeoordelingEscaleren jobs, reassign each instance's Beoordelen task to teamlead, then complete the // job. A job whose reassignment fails is logged and left un-completed for Flowable to redeliver (§8.6). public class BeoordelingEscalatieProcessorTests { /// A fake escalation client: scripts the jobs to acquire, records reassignments and /// completions, and can be told to throw on reassigning a given instance. private sealed class FakeEscalatieClient(params EscalatieJob[] jobs) : IBeoordelingEscalatieClient { public int AcquireCount { get; private set; } public List Reassigned { get; } = []; public List Completed { get; } = []; public string? ThrowOnInstance { get; set; } public Task> AcquireBeoordelingEscalatieJobsAsync(int maxJobs, CancellationToken ct = default) { AcquireCount++; return Task.FromResult>(jobs.Take(maxJobs).ToList()); } public Task ReassignBeoordelingToTeamleadAsync(string processInstanceId, CancellationToken ct = default) { if (processInstanceId == ThrowOnInstance) throw new InvalidOperationException("reassign failed"); Reassigned.Add(processInstanceId); return Task.CompletedTask; } public Task CompleteBeoordelingEscalatieJobAsync(string jobId, CancellationToken ct = default) { Completed.Add(jobId); return Task.CompletedTask; } } [Fact] public async Task Acquires_an_escalation_reassigns_to_teamlead_and_completes_the_job() { var client = new FakeEscalatieClient(new EscalatieJob("job-9", "pi-1")); var acquired = await new BeoordelingEscalatieProcessor( client, NullLogger.Instance).PumpOnceAsync(5); Assert.Equal(1, acquired); Assert.Equal("pi-1", Assert.Single(client.Reassigned)); Assert.Equal("job-9", Assert.Single(client.Completed)); } [Fact] public async Task A_failing_reassign_is_left_uncompleted_for_flowable_to_redeliver() { var client = new FakeEscalatieClient(new EscalatieJob("job-9", "pi-1")) { ThrowOnInstance = "pi-1" }; var logger = new CapturingLogger(); var acquired = await new BeoordelingEscalatieProcessor(client, logger).PumpOnceAsync(5); Assert.Equal(1, acquired); Assert.Empty(client.Completed); var error = Assert.Single(logger.Entries, e => e.Level == LogLevel.Error); Assert.Contains("job-9", error.Message); } [Fact] public async Task Does_nothing_but_poll_when_there_are_no_escalations() { var client = new FakeEscalatieClient(); var acquired = await new BeoordelingEscalatieProcessor( client, NullLogger.Instance).PumpOnceAsync(5); Assert.Equal(0, acquired); Assert.Equal(1, client.AcquireCount); Assert.Empty(client.Completed); } }