v5.0.0
renamed-and-rewiredThe library is now Wiretap: new coordinates, pass-through mode, and declarative fixture seeding.
Highlights
- 01
Wiretap, under new coordinates
Read the guide →io.gitlab.guisseppe:spring-kafka-test-utilsbecomesio.typecheck:wiretap-spring-boot, with renamed packages, a renamed annotation (@EnableWiretapKafkaBroker) and a renamed property prefix (wiretap.test.*). Mechanical to migrate, and deliberately without compatibility shims. - 02
Pass-through mode
Read the guide →wiretap.test.mode=passthroughpoints the whole harness at a broker you already run — Testcontainers, docker compose, a local Kafka — while topics, seeding, listener readiness, assertions and per-method cleanup all keep working. - 03
Declarative seeding with @KafkaSeed
Declare the records a test starts from in a
Read the guide →.jsonor.ndjsonfixture, with${placeholder}resolution, typed bindings and built-ins like${#uuid}and${#now-P1D}. Class seeds are re-applied after every cleanup. - 04
Broker wiring survives a shadowing @ContextConfiguration
A test class that declared its own
Read the guide →@ContextConfigurationused to lose the entire broker wiring. A context customizer now applies the initializer additively, so the broker, the properties and the topics are there either way.
Migrate with AI
Paste this into your coding agent after installing the skill pack. It scopes the work to this release and keeps the agent on the documented API.
You are migrating this repository from io.gitlab.guisseppe:spring-kafka-test-utils 4.x to io.typecheck:wiretap-spring-boot:5.0.0 (the same library, rebranded as wiretap). Make these changes:
1. Dependency: replace io.gitlab.guisseppe:spring-kafka-test-utils with io.typecheck:wiretap-spring-boot version 5.0.0 (test scope). Optionally import io.typecheck:wiretap-bom:5.0.0 in dependencyManagement.
2. Imports: io.gitlab.guisseppe.spring.kafka.test.utils.assertions.* -> io.typecheck.wiretap.core.assertions.*. Other io.gitlab.guisseppe.spring.kafka.test.utils.* -> io.typecheck.wiretap.core.* (KafkaTestPublisher, KafkaTopicReader, KafkaTestAwait, KafkaTestLatch, TopicCleaner) or io.typecheck.wiretap.spring.* (the annotation, KafkaTestListeners, and the renamed classes: SharedKafkaProperties -> WiretapTestProperties, SharedKafkaBrokerHolder -> WiretapBrokerHolder, SharedKafkaObjectMapper -> WiretapObjectMapper). The Jackson serializer pair is internal in both versions - nothing to migrate.
3. Annotation: @SharedKafkaBroker -> @EnableWiretapKafkaBroker (attributes topics() and partitions() unchanged).
4. Properties: rename every spring.kafka.test.<key> to wiretap.test.<key> (topics, topics-file, partitions, mock-schema-registry.enabled, object-mapper-bean-name, listeners.ready-timeout, bean-overrides.enabled, bean-overrides.consumer.auto-offset-reset, bean-overrides.consumer.group-id-suffix, bean-overrides.consumer.unique-group-ids). Do NOT touch Spring's own keys: spring.kafka.bootstrap-servers, any other spring.kafka.*, spring.embedded.kafka.brokers, logging.level.*.
5. Renamed literals (only if your tests reference them): object-mapper bean sharedKafkaTestObjectMapper -> wiretapTestObjectMapper; mock schema registry URL mock://shared-kafka-test -> mock://wiretap.
6. Removed API: overloads taking EmbeddedKafkaBroker on KafkaTestPublisher/KafkaTopicReader/KafkaAssertions are gone. Pass bootstrap servers explicitly (broker.getBrokersAsString()) or use the implicit no-servers forms. Keyless publish with explicit servers: KafkaTestPublisher.sendValue(servers, topic, value) or send(servers, topic, null, value). @Autowired EmbeddedKafkaBroker still works.
7. Verify: rg -n "io\.gitlab\.guisseppe|SharedKafkaBroker|spring\.kafka\.test\.|shared-kafka-test" src pom.xml build.gradle* must return nothing; rg -n "spring\.kafka\." should still show your unchanged Spring config. Run the full test suite.
Do it in one commit; 4.x and 5.0 cannot be mixed in one suite. After migrating, consider new 5.0.0 features: wiretap.test.mode=passthrough (run against Testcontainers or a local broker) and @KafkaSeed fixture seeding with ${placeholder} support.Full notes
Breaking changes
- Maven coordinates changed from
io.gitlab.guisseppe:spring-kafka-test-utilstoio.typecheck:wiretap-spring-boot. Releases up to 4.1.2 remain available under the old coordinates. - Packages renamed:
io.gitlab.guisseppe.spring.kafka.test.utils.assertions.*toio.typecheck.wiretap.core.assertions.*, the rest of the engine toio.typecheck.wiretap.core.*, and the Spring integration (the annotation,KafkaTestListeners) toio.typecheck.wiretap.spring.*. @SharedKafkaBrokerrenamed to@EnableWiretapKafkaBroker; itstopics()andpartitions()attributes are unchanged.- Every
spring.kafka.test.<key>property renamed towiretap.test.<key>. Spring's own keys —spring.kafka.*,spring.embedded.kafka.brokers,logging.level.*— are untouched. - Removed the overloads taking an
EmbeddedKafkaBrokerfromKafkaTestPublisher,KafkaTopicReaderandKafkaAssertions. Pass a bootstrap-servers address (broker.getBrokersAsString()) or use the implicit no-servers forms; injecting theEmbeddedKafkaBrokerbean still works in embedded mode. - Renamed literals: the default object-mapper bean is
wiretapTestObjectMapper(wassharedKafkaTestObjectMapper) and the mock schema registry URL ismock://wiretap(wasmock://shared-kafka-test). - No compatibility shims are published: there is no deprecated annotation alias, no
spring.kafka.test.*fallback and no re-exported packages, so 4.x and 5.0 cannot be mixed in one test suite.
Added
@KafkaSeed— repeatable declarative topic seeding on a test class or method, plus the suite-levelwiretap.test.seed.locationsandwiretap.test.seed.modeproperties. Fixtures are.jsonarrays or.ndjsonstreams in an envelope (key/value/headers, including tombstones) or bare-value shorthand form. AddingavroSchema = "classpath:….avsc"publishes that seed's fixtures Avro-encoded against the mock schema registry: values convert from plain JSON toGenericRecords (unions written as the plain value ornull,bytes/fixedbase64,enuma symbol string, logical types passed through, schema defaults applied), while keys stay strings, headers are untouched and a null value is still a real tombstone. Suite-level seed locations stay JSON-only.- Placeholder resolution for seed fixtures:
${name}, inline defaults${name:default}, the$${...}escape, and the built-ins${#uuid},${#now},${#now±<ISO-8601 offset>}and${#today}— resolved per occurrence, with whole-value bindings keeping their JSON type andSeedPlaceholdersproviders resolved as Spring beans when the context declares them. - Pass-through mode:
wiretap.test.mode,wiretap.test.passthrough.bootstrap-serversandwiretap.test.passthrough.allow-remoterun the harness against a cluster wiretap did not start, with no embedded broker, nospring.embedded.kafka.brokersand no JVM system properties published. io.typecheck:wiretap-bomfor aligning the versions of wiretap's own modules; it manages only wiretap artifacts, never third-party versions.- The build is now a monorepo of a Spring-free
wiretap-coreengine and thewiretap-spring-bootintegration, so the publisher, reader, await helpers and assertions no longer depend on Spring. KafkaTestPublisher.sendValue(bootstrapServers, topic, value)— the named form of a keyless publish at an explicit address, which the three-argumentsendsignature cannot express.- An evaluation lane — a never-published
wiretap-evaluationmodule that runs the harness against real Kafka brokers (Testcontainers locally, service containers in CI) across the supported broker lines, so divergence from a real cluster is caught in review.
Fixed
- A test class that directly declares
@ContextConfigurationno longer loses the broker wiring contributed by@EnableWiretapKafkaBroker. Such contexts previously came up with no broker bean, nospring.kafka.bootstrap-serversand no topics, and failed on the first Kafka interaction; aContextCustomizerFactorynow applies the initializer additively, and the initializer is idempotent when both routes fire. - Closed a race in the topic ledger where a topic could be treated as created while it was still being created. Creation now runs through a two-phase claim: a topic counts as created only once the creator commits, concurrent callers wait for that commit (in ascending name order, so overlapping topic sets cannot deadlock), a rolled-back claim returns the topic to absent, and the commit is recorded against the cluster address it happened on.
- A test class whose own
@ContextConfigurationshadows the annotation resolves its mode and pass-through address once, at wiring time. Supplyingwiretap.test.modeorwiretap.test.passthrough.bootstrap-serversvia@DynamicPropertySourceon such a class now fails fast — those values arrive after the context customizer has already wired the broker — with a message pointing at@TestPropertySource,@SpringBootTest(properties)or application properties, rather than silently splitting the mode between components.
Security
- Pass-through mode refuses a non-loopback target unless
wiretap.test.passthrough.allow-remote=true. The guard is a restriction on the form of the configured address —localhost, any127.0.0.0/8address,::1— and performs no DNS resolution, deliberately, so its verdict depends on reviewable configuration rather than on the machine running the test. - Per-method cleanup on a cluster wiretap does not own is limited to the topics wiretap created or seeded on that cluster. Both halves of that ledger are recorded against the bootstrap address they happened on, and the cluster is never enumerated to discover what to delete.
- Consumer-group deletion in pass-through mode is narrowed to groups carrying wiretap's unique group-id suffix; with suffixing disabled, no consumer group is deleted at all.