Skip to content

feat: kpipe-test module — TestStream<T> for Docker-free pipeline testing#231

Open
eschizoid wants to merge 2 commits into
mainfrom
feat/kpipe-test-module
Open

feat: kpipe-test module — TestStream<T> for Docker-free pipeline testing#231
eschizoid wants to merge 2 commits into
mainfrom
feat/kpipe-test-module

Conversation

@eschizoid

Copy link
Copy Markdown
Owner

What

The top adoption-friction item from the roadmap (P2 #1): testing a KPipe pipeline no longer requires Testcontainers/Docker or a hand-rolled MockConsumer harness.

final var captured = new CapturingSink<Map<String, Object>>();
try (final var driver = TestStream.<Map<String, Object>>builder(JsonFormat.INSTANCE)
    .pipe(addTimestamp)
    .filter(active)
    .toCustom(captured)
    .build()) {
  driver.send(record1);
  driver.send(record2);
  driver.flush();
  assertEquals(List.of(...), captured.captured());
}

Drive model (per the roadmap's recorded decision): a real KPipeConsumer over a seeded MockConsumer — tests exercise the production dispatcher/offset/sink paths, not a simulation. Default SEQUENTIAL, PARALLEL/KEY_ORDERED overridable.

  • Deterministic flush(): polled → accounted (processed+errors+inFlight) → drain, with post-drain re-read; AssertionError with metrics diagnostic on timeout — no sleeps, no flakes.
  • Batch v1: size-flush + shutdown-flush (age trigger deliberately disabled — virtual-clock is the recorded follow-up).
  • CapturingSink<T> — thread-safe, snapshot captured(), no assertion DSL (per the roadmap decision: users bring AssertJ/JUnit).
  • Full compile artifact lib/kpipe-test, JPMS module io.github.eschizoid.kpipe.test, wired into settings/BOM/publishing like siblings.

Tests

29 new, all Docker-free: the PLAN ergonomics sketch verbatim, ordering, operator chaining, filter semantics, operator-throw/malformed/null error paths, throwing error handler, PARALLEL & KEY_ORDERED delivery, lifecycle/builder validation, batch flush semantics, concurrent captures. Full :lib:kpipe-consumer:test suite green on the branch (392/392, exercises #229's PendingOffsetSet).

Notes

  • Additive-only extensions to the sketch surface (peek, withProcessingMode, errors(), etc.) — needed by the mandated error-path tests.
  • Pre-existing gap left untouched: kpipe-tracing-otel/kpipe-schema-registry-confluent missing from the BOM.
  • Docs (README module catalog + CLAUDE.md) being added to this branch before merge.

… Docker-free pipeline tests

New published module lib/kpipe-test (io.github.eschizoid.kpipe.test, JPMS module of the
same name) implementing the PLAN P2 surface:

- TestStream<T>: MockConsumer-backed driver around a real KPipeConsumer (PLAN drive-model
  option b), builder(format) → pipe/filter/peek/toCustom/toBatch → build() → send/sendRaw →
  flush() → close(). SEQUENTIAL by default so capture order matches send order;
  withProcessingMode overrides for PARALLEL / KEY_ORDERED.
- Deterministic flush(): waits until every sent record is polled, terminal (processed /
  filtered / failed) or batch-buffered, and the dispatcher in-flight count has drained
  (waitForInFlightDrain + metrics accounting), so assertions never race the consumer thread.
- Batch v1 semantics per PLAN: size-triggered flushes observable after flush(), trailing
  partial batch drains on close() (shutdown-flush); no age-based flush (policy age cap set
  beyond test scale).
- CapturingSink<T>: thread-safe capture with immutable captured() snapshots; no assertion
  DSL by design.
- errors() records every ProcessingError (operator throw, malformed payload, null value)
  ahead of any user error handler; metrics() exposes the consumer metric snapshot.

Wired into settings.gradle.kts and the BOM; build.gradle.kts and module-info.java modeled
on the sibling format modules, publishing via the existing :lib subprojects machinery.

29 new Docker-free tests, including the PLAN target-ergonomics sketch verbatim, filter and
error paths, batch size/shutdown flush, and non-sequential modes.
@eschizoid

Copy link
Copy Markdown
Owner Author

@copilot please review

- README: kpipe-test row in the module catalog, and a "Testing your
  pipeline" subsection under Testing showing the TestStream +
  CapturingSink flow (deterministic flush, filter/error visibility);
  the existing docker-compose walkthrough moves under an
  "Integration testing against a real broker" heading.
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
461 1 460 0
View the top 1 failed test(s) by shortest run time
io.github.eschizoid.kpipe.consumer.KPipeCircuitBreakerIntegrationTest::sustainedBatchFailuresTripBreaker()
Stack Traces | 5.03s run time
org.opentest4j.AssertionFailedError: batch failures must trip the breaker and pause the consumer ==> expected: <true> but was: <false>
	at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:232)
	at io.github.eschizoid.kpipe.consumer.KPipeCircuitBreakerIntegrationTest.sustainedBatchFailuresTripBreaker(KPipeCircuitBreakerIntegrationTest.java:110)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant