Skip to content

test(producer): pin KafkaMessageSink error paths#192

Merged
eschizoid merged 2 commits into
mainfrom
test/kafka-message-sink-error-paths
Jun 18, 2026
Merged

test(producer): pin KafkaMessageSink error paths#192
eschizoid merged 2 commits into
mainfrom
test/kafka-message-sink-error-paths

Conversation

@eschizoid

Copy link
Copy Markdown
Owner

Summary

Closes a criticality-6 coverage gap on KafkaMessageSink: the existing tests only covered happy paths. This PR adds three tests that pin the error-path contract — no production code changes.

Invariants pinned

  • acceptPropagatesProducerExceptionAsRuntime — when the underlying Kafka Producer.send(record, callback) throws a KafkaException synchronously (serialization failure, authorization failure, buffer exhaustion with max.block.ms=0, etc.), the sink must propagate the exception unwrapped, not catch-and-log. The async-callback failure path is the only "log and swallow" path the sink documents (per the class javadoc); synchronous throws are surfaced so upstream sink error handling (MessageProcessorRegistry.withSinkErrorHandling) can see them. Pins §12 (no-silent-failures doctrine).

  • acceptOnClosedProducerThrows — per Kafka's Producer contract, calling send(...) on a closed producer throws IllegalStateException("Cannot perform operation after producer has been closed"). The sink does not pre-check producer state and does not swallow this exception — it propagates so pipeline error handlers can route or fail loudly.

  • ofStaticFactoryWithNullKeyAccepted — the KafkaMessageSink.of(producer, topic, valueMapper, tracer) factory produces a sink whose key path is null. Verifies the resulting ProducerRecord has a null key (Kafka allows null keys; partition assignment falls back to the configured partitioner — round-robin / sticky for the default).

Test plan

  • ./gradlew :lib:kpipe-producer:test — 7 tests in KafkaMessageSinkTest all green
  • Full producer module test suite — green
  • No production code changes — pure test addition

Closes a criticality-6 coverage gap: the existing tests only exercised
happy paths. Add three tests that pin the error contract:

- acceptPropagatesProducerExceptionAsRuntime: synchronous KafkaException
  from Producer.send must propagate (no silent log-and-swallow). The
  async-callback failure log is the only documented "swallow" path; sync
  throws are surfaced so upstream sink error handling can see them (§12).
- acceptOnClosedProducerThrows: when the underlying producer is closed,
  Kafka throws IllegalStateException from send. The sink does not pre-
  check and does not swallow — it propagates so pipeline error handlers
  can react.
- ofStaticFactoryWithNullKeyAccepted: the of(...) factory must produce a
  null-keyed ProducerRecord (Kafka allows null keys for round-robin /
  sticky partitioning).
@eschizoid

Copy link
Copy Markdown
Owner Author

@copilot please review

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.60%. Comparing base (eb21492) to head (b4ddf67).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #192      +/-   ##
============================================
- Coverage     77.64%   77.60%   -0.04%     
+ Complexity      732      731       -1     
============================================
  Files            68       68              
  Lines          2800     2800              
  Branches        346      346              
============================================
- Hits           2174     2173       -1     
  Misses          465      465              
- Partials        161      162       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Three Javadoc blocks referenced §12 — replaced with direct wording per
the saved feedback (no spec/section refs in code comments).

Also renamed `acceptPropagatesProducerExceptionAsRuntime` →
`acceptPropagatesProducerExceptionUnwrapped`. The body asserts the
original `KafkaException` propagates verbatim via `assertSame`, so
"Unwrapped" matches the actual invariant; "AsRuntime" implied a rewrap
that doesn't happen.
@eschizoid

Copy link
Copy Markdown
Owner Author

@copilot please review

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