Class TestOutboxRecordCaptor

java.lang.Object
com.aim2be.platform.test.TestOutboxRecordCaptor

public class TestOutboxRecordCaptor extends Object
In-memory captor that records every OutboxRecord written during a test. Replaces the JPA-backed repository in test scope so consumers can assert against emitted events without standing up Postgres.

Assertion methods follow AssertJ-style naming and produce diagnostic messages including the observed status distribution so failures point directly at the divergence (e.g. "Expected exactly 1 PENDING record but found 2; statuses observed: [PENDING x1, SENT x1]").

Status-at-capture semantics (R2 fix): assertions use the status that the row carried at capture(OutboxRecord) time, NOT the live status of the underlying OutboxRecord reference. The in-memory repository mutates rows in-place during markSent / markFailureAttempt, so a captor that reads record.getStatus() at assertion time would observe SENT/FAILED for rows captured AT save time as PENDING — spuriously failing assertEmittedExactly(N, PENDING) after a full publish cycle. The captor stores a snapshot of the status alongside the reference; listEmitted() still returns the live references for callers that want post-mutation introspection.

Thread-safety: the captor uses an internal ConcurrentLinkedQueue, so concurrent calls to capture(OutboxRecord) from multiple writer threads are safe. Tests that assert ordering across concurrent producers MUST still pin a single executor to avoid scheduler non-determinism in the visible sequence.

Wired by OutboxTestAutoConfiguration when AutoConfigureOutbox is present on a test class.

  • Constructor Details

    • TestOutboxRecordCaptor

      public TestOutboxRecordCaptor()
  • Method Details

    • listEmitted

      public List<OutboxRecord> listEmitted()
      Returns every record captured during the test, in insertion order. The returned references are the LIVE records — callers that need post-mutation introspection (e.g. asserting the in-memory repo flipped a row to SENT) read from here. For status assertions against the insertion-time state, use assertEmittedExactly(int, OutboxRecord.Status) which uses the snapshot status (R2 fix).
      Returns:
      immutable list snapshot; non-null
    • assertEmittedExactly

      public void assertEmittedExactly(int expectedCount, OutboxRecord.Status expectedStatus)
      Asserts that exactly expectedCount records were emitted with expectedStatus at capture time. Throws AssertionError with a diagnostic message listing the observed status distribution (also at capture time) when the assertion fails.
      Parameters:
      expectedCount - required number of matching records
      expectedStatus - required status for each matched record; non-null
      Throws:
      AssertionError - when the captor did not record exactly expectedCount entries with expectedStatus at capture time
    • assertNoEmissions

      public void assertNoEmissions()
      Asserts that the captor recorded zero emissions. Common after negative-path tests (e.g., transaction rolled back; nothing was supposed to land in the outbox).
      Throws:
      AssertionError - when the captor recorded one or more emissions
    • clear

      public void clear()
      Clears all captured records. Convenience for tests that share a Spring context across methods (rare; isolated contexts are preferred).