chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
import {
|
||||
type RealtimeRunRow,
|
||||
serializeRunRow,
|
||||
} from "~/services/realtime/electricStreamProtocol.server";
|
||||
import { type RunListFilter } from "~/services/realtime/runReader.server";
|
||||
import { RealtimeShadowComparator } from "~/services/realtime/shadowCompare.server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
function sampleRow(overrides: Partial<RealtimeRunRow> = {}): RealtimeRunRow {
|
||||
return {
|
||||
id: "run_a",
|
||||
taskIdentifier: "my-task",
|
||||
createdAt: new Date("2026-06-07T09:00:00.000Z"),
|
||||
updatedAt: new Date("2026-06-07T10:05:30.123Z"),
|
||||
startedAt: null,
|
||||
delayUntil: null,
|
||||
queuedAt: null,
|
||||
expiredAt: null,
|
||||
completedAt: null,
|
||||
friendlyId: "run_friendly_a",
|
||||
number: 7,
|
||||
isTest: true,
|
||||
status: "EXECUTING",
|
||||
usageDurationMs: 1234,
|
||||
costInCents: 0.55,
|
||||
baseCostInCents: 0.25,
|
||||
ttl: "1h",
|
||||
payload: '{"hello":"world"}',
|
||||
payloadType: "application/json",
|
||||
metadata: null,
|
||||
metadataType: "application/json",
|
||||
output: null,
|
||||
outputType: "application/json",
|
||||
runTags: ["a", "b"],
|
||||
error: null,
|
||||
realtimeStreams: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const UP_TO_DATE = { headers: { control: "up-to-date" } };
|
||||
|
||||
function insert(value: Record<string, string | null>) {
|
||||
return { key: `"public"."TaskRun"/"${value.id}"`, value, headers: { operation: "insert" } };
|
||||
}
|
||||
|
||||
function makeComparator(
|
||||
rowsById: Record<string, RealtimeRunRow | null>,
|
||||
resolvedIds: string[] = []
|
||||
) {
|
||||
return new RealtimeShadowComparator({
|
||||
runReader: {
|
||||
getRunById: async (_env: string, id: string) => rowsById[id] ?? null,
|
||||
hydrateByIds: async (_env: string, ids: string[]) =>
|
||||
ids.map((id) => rowsById[id]).filter((row): row is RealtimeRunRow => Boolean(row)),
|
||||
} as any,
|
||||
runListResolver: { resolveMatchingRunIds: async (_f: RunListFilter) => resolvedIds } as any,
|
||||
});
|
||||
}
|
||||
|
||||
describe("RealtimeShadowComparator serialization", () => {
|
||||
it("counts a faithful re-serialization as a match", async () => {
|
||||
const row = sampleRow();
|
||||
const body = JSON.stringify([insert(serializeRunRow(row)), UP_TO_DATE]);
|
||||
const cmp = makeComparator({ run_a: row });
|
||||
|
||||
const out = await cmp.compare({
|
||||
feed: "run",
|
||||
electricBody: body,
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
});
|
||||
|
||||
expect(out.serializationMatched).toBe(1);
|
||||
expect(out.serializationDiverged).toBe(0);
|
||||
expect(out.serializationSkew).toBe(0);
|
||||
expect(out.diffs).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not flag semantically-equivalent but differently-encoded values", async () => {
|
||||
const row = sampleRow();
|
||||
// Electric encodes bool as "true" (native uses "t"), a number with a trailing
|
||||
// zero, and a timestamp without millis — all equal after decoding.
|
||||
const value = {
|
||||
...serializeRunRow(row),
|
||||
isTest: "true",
|
||||
costInCents: "0.5500",
|
||||
createdAt: "2026-06-07T09:00:00",
|
||||
};
|
||||
const body = JSON.stringify([insert(value), UP_TO_DATE]);
|
||||
const cmp = makeComparator({ run_a: row });
|
||||
|
||||
const out = await cmp.compare({
|
||||
feed: "run",
|
||||
electricBody: body,
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
});
|
||||
|
||||
expect(out.serializationMatched).toBe(1);
|
||||
expect(out.serializationDiverged).toBe(0);
|
||||
});
|
||||
|
||||
it("flags a genuine column divergence (same version)", async () => {
|
||||
const row = sampleRow();
|
||||
const value = { ...serializeRunRow(row), payload: '{"hello":"TAMPERED"}' };
|
||||
const body = JSON.stringify([insert(value), UP_TO_DATE]);
|
||||
const cmp = makeComparator({ run_a: row });
|
||||
|
||||
const out = await cmp.compare({
|
||||
feed: "run",
|
||||
electricBody: body,
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
});
|
||||
|
||||
expect(out.serializationDiverged).toBe(1);
|
||||
expect(out.serializationMatched).toBe(0);
|
||||
expect(out.diffs).toEqual([
|
||||
{
|
||||
runId: "run_a",
|
||||
column: "payload",
|
||||
electric: '{"hello":"TAMPERED"}',
|
||||
native: '{"hello":"world"}',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("treats DEQUEUED/EXECUTING as equivalent (legacy status rewrite)", async () => {
|
||||
const row = sampleRow({ status: "EXECUTING" });
|
||||
const value = { ...serializeRunRow(row), status: "DEQUEUED" };
|
||||
const body = JSON.stringify([insert(value), UP_TO_DATE]);
|
||||
const cmp = makeComparator({ run_a: row });
|
||||
|
||||
const out = await cmp.compare({
|
||||
feed: "run",
|
||||
electricBody: body,
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
});
|
||||
|
||||
expect(out.serializationDiverged).toBe(0);
|
||||
expect(out.serializationMatched).toBe(1);
|
||||
});
|
||||
|
||||
it("records skew when the row advanced between emit and refetch", async () => {
|
||||
const row = sampleRow();
|
||||
// Electric emitted an older version; the refetched row is newer.
|
||||
const value = {
|
||||
...serializeRunRow(sampleRow({ updatedAt: new Date("2026-06-07T10:00:00.000Z") })),
|
||||
};
|
||||
const body = JSON.stringify([insert(value), UP_TO_DATE]);
|
||||
const cmp = makeComparator({ run_a: row });
|
||||
|
||||
const out = await cmp.compare({
|
||||
feed: "run",
|
||||
electricBody: body,
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
});
|
||||
|
||||
expect(out.serializationSkew).toBe(1);
|
||||
expect(out.serializationMatched).toBe(0);
|
||||
expect(out.serializationDiverged).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("RealtimeShadowComparator membership", () => {
|
||||
const filter: RunListFilter = {
|
||||
organizationId: "org_1",
|
||||
projectId: "proj_1",
|
||||
environmentId: "env_1",
|
||||
tags: ["t"],
|
||||
createdAtAfter: new Date("2026-06-06T00:00:00.000Z"),
|
||||
limit: 1000,
|
||||
};
|
||||
|
||||
function bodyFor(ids: string[]) {
|
||||
const msgs = ids.map((id) => insert(serializeRunRow(sampleRow({ id }))));
|
||||
return JSON.stringify([...msgs, UP_TO_DATE]);
|
||||
}
|
||||
|
||||
it("matches when Electric's set equals the native resolver's set", async () => {
|
||||
const cmp = makeComparator({ a: sampleRow({ id: "a" }), b: sampleRow({ id: "b" }) }, [
|
||||
"a",
|
||||
"b",
|
||||
]);
|
||||
const out = await cmp.compare({
|
||||
feed: "runs",
|
||||
electricBody: bodyFor(["a", "b"]),
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
membershipFilter: filter,
|
||||
});
|
||||
expect(out.membershipMatch).toBe(true);
|
||||
expect(out.missingInNative).toEqual([]);
|
||||
expect(out.extraInNative).toEqual([]);
|
||||
});
|
||||
|
||||
it("reports rows missing from / extra in the native resolution", async () => {
|
||||
const cmp = makeComparator(
|
||||
{ a: sampleRow({ id: "a" }), b: sampleRow({ id: "b" }) },
|
||||
["a", "c"] // native missing b, has extra c
|
||||
);
|
||||
const out = await cmp.compare({
|
||||
feed: "runs",
|
||||
electricBody: bodyFor(["a", "b"]),
|
||||
environment: { id: "env_1" },
|
||||
skipColumns: [],
|
||||
isInitialSnapshot: true,
|
||||
membershipFilter: filter,
|
||||
});
|
||||
expect(out.membershipMatch).toBe(false);
|
||||
expect(out.missingInNative).toEqual(["b"]);
|
||||
expect(out.extraInNative).toEqual(["c"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user