237 lines
9.4 KiB
TypeScript
237 lines
9.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "bun:test";
|
|
|
|
import {
|
|
classifyWorkbenchKafkaDebugReplayClientOverlay,
|
|
classifyWorkbenchKafkaDebugReplayResult,
|
|
completeWorkbenchKafkaDebugReplay,
|
|
createWorkbenchKafkaDebugReplayTracker,
|
|
markWorkbenchKafkaDebugReplayBarrierComplete,
|
|
markWorkbenchKafkaDebugReplayConsumerReady,
|
|
observeWorkbenchKafkaDebugReplayRecord,
|
|
recordWorkbenchKafkaDebugReplayDelivery
|
|
} from "./workbench-kafka-debug-replay-contract.ts";
|
|
|
|
const readyConsumer = { ready: true, groupId: "hwlab-debug-test" };
|
|
const deliveredCounts = {
|
|
scanned: 1,
|
|
barrierScanned: 1,
|
|
parsed: 1,
|
|
traceMatched: 1,
|
|
replayMatched: 1,
|
|
matched: 1,
|
|
delivered: 1,
|
|
clientReceived: 1,
|
|
decoded: 1,
|
|
applied: 1
|
|
};
|
|
|
|
test("isolated replay classifies an empty producer result", () => {
|
|
const result = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_empty",
|
|
traceId: "trc_empty",
|
|
producer: { invoked: false, sourceMatched: null },
|
|
consumer: readyConsumer,
|
|
counts: {},
|
|
terminalObserved: false
|
|
});
|
|
assert.deepEqual(result, {
|
|
ok: false,
|
|
phase: "producer",
|
|
code: "producer_not_invoked",
|
|
message: "No isolated debug producer was invoked for this replay."
|
|
});
|
|
});
|
|
|
|
test("isolated replay classifies matching events without terminal", () => {
|
|
const result = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_no_terminal",
|
|
traceId: "trc_no_terminal",
|
|
producer: { invoked: true, sourceMatched: true },
|
|
consumer: readyConsumer,
|
|
counts: deliveredCounts,
|
|
terminalObserved: false
|
|
});
|
|
assert.equal(result.code, "terminal_missing");
|
|
assert.equal(result.phase, "terminal");
|
|
});
|
|
|
|
test("isolated replay classifies production reducer rejection", () => {
|
|
const result = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_reducer_rejected",
|
|
traceId: "trc_reducer_rejected",
|
|
producer: { invoked: true, sourceMatched: true },
|
|
consumer: readyConsumer,
|
|
counts: { ...deliveredCounts, applied: 0 },
|
|
terminalObserved: true
|
|
});
|
|
assert.equal(result.code, "reducer_rejected");
|
|
assert.equal(result.phase, "client");
|
|
});
|
|
|
|
test("isolated replay classifies terminal completion", () => {
|
|
const result = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_complete",
|
|
traceId: "trc_complete",
|
|
producer: { invoked: true, sourceMatched: true },
|
|
consumer: readyConsumer,
|
|
counts: deliveredCounts,
|
|
terminalObserved: true
|
|
});
|
|
assert.deepEqual(result, {
|
|
ok: true,
|
|
phase: "terminal",
|
|
code: "terminal_complete",
|
|
message: "The isolated replay reached a terminal event."
|
|
});
|
|
});
|
|
|
|
test("isolated replay keeps source, filter, and decoder failures distinct", () => {
|
|
const sourceMissing = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_source_missing",
|
|
traceId: "trc_source_missing",
|
|
producer: { invoked: true, sourceMatched: false },
|
|
consumer: readyConsumer,
|
|
counts: { scanned: 2, barrierScanned: 2, parsed: 2, traceMatched: 0 },
|
|
terminalObserved: false
|
|
});
|
|
const filterMismatch = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_filter_mismatch",
|
|
traceId: "trc_filter_mismatch",
|
|
producer: { invoked: true, sourceMatched: true },
|
|
consumer: readyConsumer,
|
|
counts: { scanned: 2, barrierScanned: 2, parsed: 2, traceMatched: 2, replayMatched: 0 },
|
|
terminalObserved: false
|
|
});
|
|
const decoderRejected = classifyWorkbenchKafkaDebugReplayResult({
|
|
replayId: "rpl_decoder_rejected",
|
|
traceId: "trc_decoder_rejected",
|
|
producer: { invoked: true, sourceMatched: true },
|
|
consumer: readyConsumer,
|
|
counts: { ...deliveredCounts, decoded: 0, applied: 0 },
|
|
terminalObserved: true
|
|
});
|
|
assert.equal(sourceMissing.code, "source_trace_missing");
|
|
assert.equal(filterMismatch.code, "records_scanned_but_filter_mismatch");
|
|
assert.equal(decoderRejected.code, "decoder_rejected");
|
|
});
|
|
|
|
test("correlated replay requires seek, lastOffset, and complete unique batch cardinality", () => {
|
|
const complete = correlatedReplay();
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(complete).code, "terminal_complete");
|
|
|
|
const seekMissing = correlatedReplay({ barrier: { seekApplied: false, completed: true, lastOffsetObserved: true } });
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(seekMissing).code, "consumer_seek_not_applied");
|
|
|
|
const lastOffsetMissing = correlatedReplay({ barrier: { seekApplied: true, completed: false, lastOffsetObserved: false } });
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(lastOffsetMissing).code, "barrier_not_completed");
|
|
|
|
const middleOffsetMissing = correlatedReplay({
|
|
requestedOffsetRange: { partition: 0, firstOffset: "10", lastOffset: "12" },
|
|
producer: { invoked: true, sourceMatched: true, publishedCount: 3 }
|
|
});
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(middleOffsetMissing).code, "barrier_cardinality_mismatch");
|
|
|
|
const duplicateOffset = correlatedReplay({ rejectedByReason: { duplicate_offset: 1 } });
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(duplicateOffset).code, "barrier_duplicate_offset");
|
|
});
|
|
|
|
test("correlated replay fails typed parse, filter, delivery, and producer evidence loss", () => {
|
|
const parseLost = correlatedReplay({ counts: { ...correlatedCounts(), parsed: 1, traceMatched: 1, replayMatched: 1, matched: 1, delivered: 1 } });
|
|
const filterLost = correlatedReplay({ counts: { ...correlatedCounts(), traceMatched: 1, replayMatched: 1, matched: 1, delivered: 1 } });
|
|
const deliveryLost = correlatedReplay({ counts: { ...correlatedCounts(), delivered: 1 } });
|
|
const producerFalse = correlatedReplay({ producer: { invoked: false, sourceMatched: true, publishedCount: 2 } });
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(parseLost).code, "record_parse_rejected");
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(filterLost).code, "records_scanned_but_filter_mismatch");
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(deliveryLost).code, "sse_write_failed");
|
|
assert.equal(classifyWorkbenchKafkaDebugReplayResult(producerFalse).code, "producer_not_invoked");
|
|
});
|
|
|
|
test("server result declares client counts unavailable and client overlay reuses the pure classifier", () => {
|
|
const serverResult = {
|
|
...correlatedReplay(),
|
|
offsetRange: { requested: { partition: 0, firstOffset: "10", lastOffset: "11" } },
|
|
completionReason: "barrier",
|
|
classificationScope: "server",
|
|
requiresClientOverlay: true,
|
|
clientCounts: { available: false, received: null, decoded: null, applied: null }
|
|
};
|
|
const overlay = classifyWorkbenchKafkaDebugReplayClientOverlay(serverResult, { received: 2, decoded: 2, applied: 1 });
|
|
assert.equal(overlay.code, "reducer_rejected");
|
|
assert.equal(overlay.classificationScope, "client");
|
|
assert.equal(overlay.requiresClientOverlay, false);
|
|
assert.deepEqual(overlay.clientCounts, { available: true, received: 2, decoded: 2, applied: 1, source: "client-local-overlay" });
|
|
});
|
|
|
|
test("correlated tracker counts unique offsets and rejects a duplicate even after lastOffset", () => {
|
|
const tracker = createWorkbenchKafkaDebugReplayTracker({
|
|
mode: "correlated-v2",
|
|
replayId: "rpl_unique_offsets",
|
|
traceId: "trc_unique_offsets",
|
|
offsetRange: { partition: 0, firstOffset: "10", lastOffset: "11" },
|
|
producer: { invoked: true, sourceMatched: true, publishedCount: 2 }
|
|
});
|
|
markWorkbenchKafkaDebugReplayConsumerReady(tracker, { groupId: "hwlab-debug-unique", seekApplied: true });
|
|
const observation = (offset: string, duplicate = false) => ({
|
|
partition: 0,
|
|
offset,
|
|
duplicate,
|
|
inOffsetRange: true,
|
|
parsed: true,
|
|
filterMatches: { traceId: true, replayId: true },
|
|
matched: !duplicate
|
|
});
|
|
observeWorkbenchKafkaDebugReplayRecord(tracker, observation("10"));
|
|
observeWorkbenchKafkaDebugReplayRecord(tracker, observation("10", true));
|
|
observeWorkbenchKafkaDebugReplayRecord(tracker, observation("11"));
|
|
recordWorkbenchKafkaDebugReplayDelivery(tracker, { partition: 0, offset: "10", value: {} });
|
|
recordWorkbenchKafkaDebugReplayDelivery(tracker, { partition: 0, offset: "11", value: {} });
|
|
markWorkbenchKafkaDebugReplayBarrierComplete(tracker);
|
|
const result = completeWorkbenchKafkaDebugReplay(tracker, { reason: "barrier", terminalObserved: true });
|
|
assert.equal(result.counts.scanned, 3);
|
|
assert.equal(result.counts.barrierScanned, 2);
|
|
assert.equal(result.barrier.uniqueOffsetCount, 2);
|
|
assert.equal(result.rejectedByReason.duplicate_offset, 1);
|
|
assert.equal(result.code, "barrier_duplicate_offset");
|
|
assert.equal(result.classificationScope, "server");
|
|
assert.equal(result.requiresClientOverlay, true);
|
|
assert.deepEqual(result.clientCounts, {
|
|
available: false,
|
|
received: null,
|
|
decoded: null,
|
|
applied: null,
|
|
source: "client-local-overlay-required"
|
|
});
|
|
});
|
|
|
|
function correlatedReplay(overrides: Record<string, any> = {}) {
|
|
return {
|
|
mode: "correlated-v2",
|
|
replayId: "rpl_correlated",
|
|
traceId: "trc_correlated",
|
|
producer: { invoked: true, sourceMatched: true, publishedCount: 2 },
|
|
consumer: readyConsumer,
|
|
requestedOffsetRange: { partition: 0, firstOffset: "10", lastOffset: "11" },
|
|
barrier: { seekApplied: true, completed: true, lastOffsetObserved: true },
|
|
rejectedByReason: {},
|
|
counts: correlatedCounts(),
|
|
terminalObserved: true,
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
function correlatedCounts() {
|
|
return {
|
|
scanned: 2,
|
|
barrierScanned: 2,
|
|
parsed: 2,
|
|
traceMatched: 2,
|
|
replayMatched: 2,
|
|
matched: 2,
|
|
delivered: 2,
|
|
clientReceived: null,
|
|
decoded: null,
|
|
applied: null
|
|
};
|
|
}
|