Skip to main content

Core Concepts

ConsumedRecord<V>โ€‹

The only data type that crosses layer boundaries. It is the universal output of the transport layer and the universal input of the assertion layer.

@Value
public class ConsumedRecord<V> {
String source; // topic name
int partition;
long offset;
String key;
V value; // String for raw, GenericRecord for Avro
long timestamp;
Headers headers;

static <V> ConsumedRecord<V> fromKafkaRecord(ConsumerRecord<String, V> record) { ... }
MatchedRecord toMatchedRecord() { ... }
}

MatchedRecordโ€‹

Deduplication token, represents a record that has already been claimed by a consumer step. It holds topic + partition + offset + key + timestamp and is stored in the static deduplication registry.

MatchedRecord deliberately excludes processedTime from equals/hashCode so that two records from the same Kafka partition+offset are always considered the same, regardless of when they were processed.


MatchContextโ€‹

Immutable context object passed to a RecordMatcher. Built by AbstractKafkaConsumer.buildMatchContext() from the ConsumerContext.

@Value @Builder
public class MatchContext {
String matchMethod;
List<String> matchFilePaths; // replaces old matchFilePath (String)
List<String> excludedFields; // defaults to emptyList()
boolean strictMatching;
String matchKey;
String matchValue;

// Convenience, for single-record matchers
public String getMatchFilePath() {
return matchFilePaths != null && !matchFilePaths.isEmpty()
? matchFilePaths.get(0) : null;
}
}

MatchResultโ€‹

Returned by every RecordMatcher. Carries a pass/fail flag plus the diff, expected, and actual strings for failure reporting.

@Value
public class MatchResult {
boolean passed;
String diff;
String expected;
String actual;

static MatchResult pass() { ... }
static MatchResult fail(String diff, String expected, String actual) { ... }
}

ConsumerContext<K, V>โ€‹

Immutable builder that configures a consumer operation. Built by ConsumerValidationService in ktestify-cucumber from DataTable values.

Key fields:

FieldTypeDescription
topicTopicThe output topic (must be OUTPUT type โ€” validated in builder)
matchMethodStringOne of the ConfigConstants.method* values
matchFilePathsList<String>Expected file paths (single or batch)
excludedFieldsList<String>Field names to ignore in comparison
expectedRecordKeyStringKey filter โ€” record must match this key
readTimeoutlongMilliseconds
consumerDeltaTimelongMilliseconds (DataTable seconds ร— 1000)
isBatchConsumerbooleanEnables batch fetch mode
batchSizeintNumber of records to collect in batch mode

Topicโ€‹

@Data @Builder
public class Topic {
String topicName;
String topicAlias;
String topicNamespace;
Topic.Type topicType; // INPUT or OUTPUT

// Returns "namespace.topicName" or just "topicName" if no namespace
String getNamespacedTopic() { ... }
}

RecordMatcherFactoryโ€‹

Pure static factory, no DI, no singleton. Resolves the right RecordMatcher implementation based on matchMethod and whether the consumer is raw or Avro.

RecordMatcherFactory.forRaw("matchFile") โ†’ FileRecordMatcher
RecordMatcherFactory.forAvro("matchFile") โ†’ AvroFileRecordMatcher
RecordMatcherFactory.forRaw("matchXML") โ†’ XmlRecordMatcher
RecordMatcherFactory.forAvro("matchXML") โ†’ throws ConsumerException โ† not supported

See Built-in matchers โ†’ for the full mapping table.


Dynamic variable systemโ€‹

All file reads go through FileUtils.getFileContent(path), which transparently calls DynamicVariableProcessor.process(content) before returning. To add a new variable type:

  1. Implement DynamicVariable interface.
  2. Register it in DynamicVariableFactory.
  3. No changes needed to FileUtils or DynamicVariableProcessor.

See Dynamic variables โ†’ for the full list of built-in types.