Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

testkit

Broker fixtures for the acceptance suite. Every milestone is verified against a real broker in a container — there are no mocked brokers in this workspace, by rule — and this crate is what makes that affordable.

publish = false.

Module map

FileLinesWhat
config.rs616BrokerConfig, Security, SaslMechanism, SaslUser
image.rs291the container image and its environment
kafka.rs233single_broker, cluster, and the _with variants
harness.rs173the Cluster trait and ExternalCluster
error.rs58fixture errors

The usual shapes

use testkit::{BrokerConfig, SaslMechanism, Security};

async fn example() -> testkit::Result<()> {
// The common case.
let broker = testkit::single_broker().await?;
let addr = broker.bootstrap_csv();

// Three nodes, for anything replica-aware.
let cluster = testkit::cluster(3).await?;

// Or configured.
let sasl = testkit::single_broker_with(
    BrokerConfig::new()
        .with_security(Security::SaslPlaintext)
        .with_mechanism(SaslMechanism::Plain)
        .with_user("alice", "alice-pw"),
)
.await?;
Ok(())
}

apache/kafka:4.3.1 in KRaft mode.

Tests take &dyn Cluster, never a concrete type

This is the crate's most important design decision and it is not abstraction for its own sake.

kaas-lib is the natural conformance harness for the kaas broker, and that only works if the acceptance suite can be pointed at something other than apache/kafka:4.3.1 without touching a single test. A hardcoded image in the fixtures would quietly foreclose that — not with an error, but by making the alternative expensive enough that nobody does it.

use std::fmt;
trait Cluster: fmt::Debug + Send + Sync {
    /// Bootstrap addresses reachable from the *test process* — for container
    /// fixtures the host-mapped port, not the in-container one.
    fn bootstrap(&self) -> &[String];
    fn nodes(&self) -> usize;
    // …plus exec, for driving the Kafka shell tools inside a node
}

ExternalCluster is the other half of the bargain: it makes "point the suite at a broker that is already running" a supported mode today, so the seam gets exercised rather than rotting into a trait nobody has implemented twice.

exec matters more than it looks

exec(node, argv) runs a command inside a fixture node, and several fixtures are generated by the Kafka shell tools rather than by a Rust client.

The group-kinds fixture is the reason. rdkafka cannot create a KIP-932 share group — librdkafka has no share-group support at all — so no Rust client in the workspace can generate that fixture. The apache/kafka image already ships kafka-console-consumer.sh and kafka-console-share-consumer.sh, and driving those through exec reaches every group kind with zero build dependencies.

The config builder exists from the start

single_broker_with(BrokerConfig) was built before anything needed it, because three later milestones do: SASL_PLAINTEXT/PLAIN and SASL_SSL/SCRAM-SHA-512 brokers, an authorizer-enabled broker for ACLs, and aggressive compaction settings for the backward-scan test.

The same argument applies to cluster(3). Retrofitting multi-broker fixtures after the fact is painful, and leader spread, log dirs and reassignment are not observable on one broker.

Start reading at harness.rs — it is short, and its module docs state the conformance-harness argument in full.