@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// `ConusAI-Txid` (umbrella TS6.3): a write's answer carries the transaction id it committed under,
|
||||
// which the browser's live collections await before they let go of an optimistic row; a read, a
|
||||
// write that committed nothing and a refused write carry none. The kernel's caller is stubbed with
|
||||
// one that commits the way kit-data-kysely does inside a capture (`recordTxid` after the commit);
|
||||
// the capture itself is proven against a real Postgres in @conusai-kit/data-kysely's own gate.
|
||||
|
||||
import type { Principal } from "@conusai-kit/auth"
|
||||
import { AppError } from "@conusai-kit/core"
|
||||
import { recordTxid } from "@conusai-kit/data-kysely"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
|
||||
const route = (kind: "read" | "write", scope: "project" | "user" = "project") => ({
|
||||
module: "notes",
|
||||
kind,
|
||||
scope,
|
||||
permission: "notes.note.read",
|
||||
idempotent: false,
|
||||
tool: false,
|
||||
download: false,
|
||||
})
|
||||
|
||||
vi.mock("../apps/web/src/server/app", () => ({
|
||||
convexCapabilityStatus: async () => ({ ready: true }),
|
||||
webRuntime: () => ({
|
||||
registry: {
|
||||
router: {
|
||||
"notes.note.list": route("read"),
|
||||
"notes.note.create": route("write"),
|
||||
"notes.note.noop": route("write"),
|
||||
"notes.note.refused": route("write"),
|
||||
},
|
||||
},
|
||||
platform: { audit: { log: async () => undefined }, usage: { track: () => undefined } },
|
||||
observe: {
|
||||
span: (_name: string, _attributes: unknown, run: () => unknown) => run(),
|
||||
log: { info: () => undefined, error: () => undefined },
|
||||
captureException: () => undefined,
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
const principal: Principal = { actor: { userId: "u-txid" }, method: "bearer" } as Principal
|
||||
|
||||
vi.mock("../apps/web/src/server/request", () => ({
|
||||
requestContext: async () => ({
|
||||
principal,
|
||||
caller: {
|
||||
callByName: async (name: string) => {
|
||||
// Two commits, as a write with an outbox event in a second transaction makes: the higher wins.
|
||||
if (name === "notes.note.create") {
|
||||
await Promise.resolve()
|
||||
recordTxid("7001")
|
||||
recordTxid("7003")
|
||||
}
|
||||
if (name === "notes.note.refused") {
|
||||
recordTxid("9999")
|
||||
throw new AppError({ type: "/problems/conflict", title: "Conflict", status: 409, code: "conflict" })
|
||||
}
|
||||
return { ok: true }
|
||||
},
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
async function post(name: string): Promise<Response> {
|
||||
const { handle } = await import("../apps/web/src/server/router")
|
||||
return handle(
|
||||
new Request(`https://app.example.test/api/v1/${name}`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json", authorization: "Bearer stub" },
|
||||
body: JSON.stringify({ org: "o", workspace: "w", project: "p" }),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
describe("ConusAI-Txid", () => {
|
||||
it("is the highest transaction id a write committed", async () => {
|
||||
const answer = await post("notes.note.create")
|
||||
expect(answer.status).toBe(200)
|
||||
expect(answer.headers.get("conusai-txid")).toBe("7003")
|
||||
})
|
||||
|
||||
it("is absent from a read, from a write that committed nothing and from a refused write", async () => {
|
||||
expect((await post("notes.note.list")).headers.get("conusai-txid")).toBeNull()
|
||||
expect((await post("notes.note.noop")).headers.get("conusai-txid")).toBeNull()
|
||||
const refused = await post("notes.note.refused")
|
||||
expect(refused.status).toBe(409)
|
||||
expect(refused.headers.get("conusai-txid")).toBeNull()
|
||||
})
|
||||
|
||||
it("does not leak one request's id into the next", async () => {
|
||||
const [first, second] = await Promise.all([post("notes.note.create"), post("notes.note.noop")])
|
||||
expect(first.headers.get("conusai-txid")).toBe("7003")
|
||||
expect(second.headers.get("conusai-txid")).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user