evOo-local/packages/db/src/messaging-migration.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

57 lines
2.3 KiB
TypeScript

import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
const migrationSql = readFileSync(
join(
dirname(fileURLToPath(import.meta.url)),
"../prisma/migrations/20260901120000_messaging_surface/migration.sql",
),
"utf8",
);
/** Close-out predicate from the messaging_surface migration. */
function closeOutPending(
rows: Array<{ status: string; identityId: string | null; threadId: string | null }>,
) {
return rows.map((row) =>
row.status === "pending" && row.identityId === null && row.threadId === null
? { ...row, status: "failed" }
: row,
);
}
describe("messaging_surface outbound close-out", () => {
it("fails only pending rows that lack identityId and threadId", () => {
expect(migrationSql).toMatch(
/UPDATE "messaging_outbound"\s+SET "status" = 'failed'\s+WHERE "status" = 'pending'\s+AND "identityId" IS NULL\s+AND "threadId" IS NULL/,
);
expect(migrationSql).not.toMatch(
/UPDATE "messaging_outbound" SET "status" = 'failed' WHERE "status" = 'pending';/,
);
});
it("keeps identity-mapped DMs pending and fails unaddressable group/intro rows", () => {
const after = closeOutPending([
{ status: "pending", identityId: "ident-1", threadId: null },
{ status: "pending", identityId: null, threadId: null },
{ status: "pending", identityId: null, threadId: "sendblue:group:1" },
{ status: "sent", identityId: null, threadId: null },
]);
expect(after.map((row) => row.status)).toEqual(["pending", "failed", "pending", "sent"]);
});
});
describe("messaging_surface channel close-out", () => {
it("retires memberships of the legacy-prefixed channels", () => {
// The prefixed channels can never receive traffic again; leaving their
// members active would let a stale row answer the owner's next LEAVE.
expect(migrationSql).toMatch(
/UPDATE "messaging_channel_members" m\s+SET "status" = 'left'\s+FROM "messaging_channels" c\s+WHERE m\."channelId" = c\."id"\s+AND c\."threadId" LIKE 'legacy:%'\s+AND m\."status" IN \('invited', 'approved'\)/,
);
// Declined and already-left members keep their answer.
expect(migrationSql).not.toMatch(/UPDATE "messaging_channel_members" SET "status" = 'left';/);
});
});