All releases

v5.0.2

clean-teardown

An interrupt from your test harness no longer turns into a mystery Kafka failure — and no client close can hang the test JVM.

Highlights

  • 01

    Interrupts are named, not laundered

    An interrupt arriving from elsewhere in a run — a preemptive @Timeout, assertTimeoutPreemptively, a cancelled Awaitility poller — used to surface as a baffling InterruptException three frames deep in your code, or silently as a produce that never happened. wiretap never interrupts a thread; it now fails at the interrupt site with a diagnostic that names the likely origin, and warns the moment a test worker thread arrives already interrupted.

  • 02

    The topic reader survives cancellation

    await().untilAsserted(assertThatTopic(...)) cancels its poll thread with an interrupt when the outer wait times out. The reader now closes its consumer cleanly under a set flag instead of aborting mid-leave-group and leaking one consumer per retry — and still propagates the interrupt the caller's machinery needs to see.

  • 03

    No client close can hang the test JVM

    Every Kafka client wiretap opens now closes with a bound (producer 30s, AdminClient and consumer 10s), so an unresponsive broker — or a call abandoned by an interrupt — can no longer stall a test for the client's unbounded default. Each close is best-effort, so a close failure never masks the operation's own result.

Full notes

Changed

  • An interrupt that lands during per-method cleanup now surfaces as an afterEach failure (and the class's declared seed state is not reapplied for that method on the interrupted thread) rather than passing silently. This is intended — a compromised thread should fail loudly and locally — but is a visible behavior change for suites that run under a preemptive timeout which fires during cleanup.

Fixed

  • Interrupt-flag hygiene: TopicCleaner no longer swallows InterruptException during per-method cleanup (which, because that exception re-sets the interrupt flag, used to hand a poisoned thread to the next test and make its first blocking Kafka call fail instantly). It now fails at the interrupt site with a diagnostic naming the likely origin, and preserves the flag as the harness's signal.
  • KafkaTopicReader closes its consumer interrupt-or-not — the flag is taken off for a bounded close and restored exactly as found — so a cancelled read (e.g. an Awaitility timeout) no longer leaks a consumer per retry; a diagnostic names the cancellation, including the footgun that wiretap reads already wait internally, so an outer await shorter than the read window is guaranteed to interrupt it.
  • The broker-facing assertions (exists(), doesNotExist(), hasPartitionCount()) preserve the interrupt flag when failing on interruption instead of discarding it.
  • The JUnit extension warns at beforeAll/beforeEach when the test worker thread arrives already interrupted, naming the common origins — so the root cause is greppable in the log instead of surfacing as a Kafka error deep in user code.
  • Bounded client closes throughout: KafkaTestPublisher's producer close (behind every send/sendValue/sendBatch, previously unbounded at Long.MAX_VALUE) is now 30s, and WiretapTopicProvisioner's AdminClient close (the per-test-class startup path, previously unbounded at ~365 days) is now 10s. An unresponsive broker can no longer hang the test JVM at these sites.