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:
| Field | Type | Description |
|---|---|---|
topic | Topic | The output topic (must be OUTPUT type โ validated in builder) |
matchMethod | String | One of the ConfigConstants.method* values |
matchFilePaths | List<String> | Expected file paths (single or batch) |
excludedFields | List<String> | Field names to ignore in comparison |
expectedRecordKey | String | Key filter โ record must match this key |
readTimeout | long | Milliseconds |
consumerDeltaTime | long | Milliseconds (DataTable seconds ร 1000) |
isBatchConsumer | boolean | Enables batch fetch mode |
batchSize | int | Number 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:
- Implement
DynamicVariableinterface. - Register it in
DynamicVariableFactory. - No changes needed to
FileUtilsorDynamicVariableProcessor.
See Dynamic variables โ for the full list of built-in types.