Lifecycle

Core lifecycle

The entry points and lifecycle components that make the shared test broker work.

@EnableWiretapKafkaBroker

Package: io.typecheck.wiretap.spring

Add this annotation to a Spring test class to opt into the shared embedded broker — or, with wiretap.test.mode=passthrough, into the same harness against a cluster you already run.

PropertyDefaultDescription
topics
String[]
{}Extra topics to create for that test class.
partitions
int
1Partition count for topics declared in topics.
Java
@SpringBootTest
@EnableWiretapKafkaBroker(topics = {"orders", "payments"}, partitions = 2)
class OrderFlowIT {
}

WiretapExtension

The JUnit Jupiter extension behind @EnableWiretapKafkaBroker:

  • makes the broker under test available before the class runs, and re-registers the engine's address per test class so a cached passthrough context stays correct when an embedded class ran in between
  • creates annotation topics for non-Spring-managed tests
  • applies class-scoped seeds when the class starts and method-level @KafkaSeeds before each test
  • triggers cleanup after each test method, then re-applies the seeds that survive it

WiretapContextInitializer

The Spring context initializer behind @EnableWiretapKafkaBroker:

  • resolves the mode first, so an unknown wiretap.test.mode, a missing passthrough address or a non-loopback target without the opt-in fails before a broker is started or a topic created
  • embedded: starts (or reuses) the shared broker. Passthrough: points the engine at your cluster and never asks for an embedded broker at all
  • creates topics declared through @EnableWiretapKafkaBroker(topics = ...) before auto-starting listener containers subscribe
  • reads topic definitions from Spring properties
  • loads YAML or JSON topic files when wiretap.test.topics-file is set
  • validates topic files against the bundled JSON Schema before creating topics
  • injects spring.kafka.bootstrap-servers, wiretap.test.active and the resolved wiretap.test.mode
  • optionally wires the mock schema registry URL (both modes)
  • optionally adjusts application Kafka client beans while preserving names, retargeted at whichever cluster is in play
  • registers the default wiretapTestObjectMapper bean when the context has none
  • embedded only: publishes spring.embedded.kafka.brokers and registers the EmbeddedKafkaBroker singleton

initialize is idempotent, and a context whose refresh fails releases its registration rather than looking wired. See Passthrough mode for what the initializer deliberately does not do when wiretap does not own the broker.

WiretapContextCustomizerFactory

The annotation's @ContextConfiguration(initializers = ...) is not the only route into a context, because Spring lets a directly declared @ContextConfiguration on a test class win over the initializers contributed by composed annotations. A co-resident test library — or a hand-added one — used to drop the entire broker wiring that way: no broker bean, no spring.kafka.bootstrap-servers, no topics, and a failure on the first Kafka interaction.

A ContextCustomizerFactory, discovered from META-INF/spring.factories, now applies the initializer additively to every context carrying @EnableWiretapKafkaBroker — inherited from a superclass or wrapped in a composed annotation included — and publishes the annotation's topics so they exist before listener containers start. When both routes fire for one context, the second is a no-op.

Properties
wiretap.test.topics=orders,payments,notifications
wiretap.test.partitions=2
wiretap.test.mock-schema-registry.enabled=true

For per-topic partition counts, use a YAML or JSON topic file:

Properties
wiretap.test.topics-file=classpath:kafka-topics.yml
YAML
topics:
  - name: "orders"
    partitions: 4
  - name: "payments"
    partitions: 2

WiretapBrokerHolder

Singleton holder for the shared embedded broker, and the source of the implicit address used by the no-servers overloads in KafkaTopicReader, KafkaTestPublisher and the assertions. In passthrough mode the holder is bypassed entirely — the engine is pointed at your cluster instead, so nothing in that path can start a broker.

PropertyDefaultDescription
getBroker()—Returns the shared broker, starting it on first use.
getBootstrapServers()—Returns the broker address as host:port.
createTopicsIfAbsent(Collection<String>, int)—Creates topics that have not already been created.
createTopicsIfAbsent(Map<String, Integer>)—Creates topics with per-topic partition counts.
getCreatedTopics()—Returns the set of topics created through the holder.
Java
String bootstrapServers = WiretapBrokerHolder.getBootstrapServers();

TopicCleaner

Package: io.typecheck.wiretap.core. Used internally after each test method; which method runs depends on who owns the broker.

PropertyDefaultDescription
cleanAll(String bootstrapServers)—Purges records from every non-internal topic and deletes every consumer group. This enumerates the cluster, so it is only ever used for the embedded broker wiretap owns outright.
cleanTopics(String bootstrapServers, Collection<String> topics, String consumerGroupIdSuffix)—Purges records from exactly those topics and deletes only the consumer groups whose id carries the suffix. Nothing outside topics is touched and the cluster is never enumerated to discover what to clean — this is the passthrough path.