Initial Commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* §16 conformance proof — the worker-proxy package consumes the
|
||||
* `@suaveplan/api-worker-rpc` contract directly (client + server +
|
||||
* MessagePort transport). This test exercises the canonical
|
||||
* `runWorkerRpcConformance` harness with a minimal handler set to
|
||||
* prove the consumer is wire-compatible end-to-end (request frame,
|
||||
* response frame, abort propagation) using the same port transport
|
||||
* the package builds on top of in `src/main-side` / `src/worker-side`.
|
||||
*/
|
||||
import { afterEach, describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { runWorkerRpcConformance } from "../../../api-worker-rpc/src/testing/conformance.js";
|
||||
|
||||
const handles: Array<{ dispose(): void }> = [];
|
||||
afterEach(() => {
|
||||
while (handles.length > 0) handles.pop()?.dispose();
|
||||
});
|
||||
|
||||
describe("api-worker-rpc contract conformance (consumer-side)", () => {
|
||||
it("round-trips a request through the canonical harness", {
|
||||
timeout: 5000,
|
||||
}, async () => {
|
||||
const h = runWorkerRpcConformance(() => ({
|
||||
echo: (params: ReadonlyArray<unknown>) => params[0],
|
||||
}));
|
||||
handles.push(h);
|
||||
const result = await h.client.call<number>("echo", [42]);
|
||||
expect(result).toBe(42);
|
||||
});
|
||||
|
||||
it("surfaces UNKNOWN_METHOD from the server", {
|
||||
timeout: 5000,
|
||||
}, async () => {
|
||||
const h = runWorkerRpcConformance(() => ({}));
|
||||
handles.push(h);
|
||||
await expect(h.client.call("missing", [])).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { createDbProxyHarness } from "../../src/testing/testing.js";
|
||||
|
||||
/**
|
||||
* End-to-end conformance smoke. The full `runDbAdapterConformance`
|
||||
* harness lives in `@suaveplan/api-db` (Stage 4); this file pins the
|
||||
* scenarios that downstream adapters MUST observe through the proxy
|
||||
* surface so the proxy's protocol is locked before Stage-4 work
|
||||
* starts.
|
||||
*/
|
||||
describe("db-proxy conformance against in-memory adapter", () => {
|
||||
it("CRUD round-trip via the proxy", { timeout: 5000 }, async () => {
|
||||
const h = createDbProxyHarness();
|
||||
try {
|
||||
expect(h.client.engine).toBe("sqlite");
|
||||
const inserted = await h.client.execute("INSERT a", { v: 1 });
|
||||
expect(inserted.rowsAffected).toBe(1);
|
||||
const rows =
|
||||
await h.client.query<ReadonlyArray<unknown>>("SELECT *");
|
||||
expect(rows).toEqual([{ v: 1 }]);
|
||||
const deleted = await h.client.execute("DELETE a");
|
||||
expect(deleted.rowsAffected).toBe(1);
|
||||
} finally {
|
||||
await h.client.close();
|
||||
h.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("transaction commit persists; rollback path runs", {
|
||||
timeout: 5000,
|
||||
}, async () => {
|
||||
const h = createDbProxyHarness();
|
||||
try {
|
||||
await h.client.transaction?.(async (tx) => {
|
||||
await tx.execute("INSERT a", { v: 1 });
|
||||
});
|
||||
expect(h.db.rows.get("a")).toEqual({ v: 1 });
|
||||
await expect(
|
||||
h.client.transaction?.(async (tx) => {
|
||||
await tx.execute("INSERT b", { v: 2 });
|
||||
throw new Error("rollback me");
|
||||
})
|
||||
).rejects.toThrow("rollback me");
|
||||
} finally {
|
||||
await h.client.close();
|
||||
h.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("cursor: 1000-row stream yields incrementally", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const h = createDbProxyHarness({
|
||||
seed: Array.from(
|
||||
{ length: 1000 },
|
||||
(_, i) => [String(i), { i }] as const
|
||||
),
|
||||
});
|
||||
try {
|
||||
const t0 = Date.now();
|
||||
let firstRowAt = -1;
|
||||
let count = 0;
|
||||
for await (const _row of h.client.cursor("SELECT-CURSOR *")) {
|
||||
if (count === 0) firstRowAt = Date.now() - t0;
|
||||
count += 1;
|
||||
}
|
||||
expect(count).toBe(1000);
|
||||
expect(firstRowAt).toBeGreaterThanOrEqual(0);
|
||||
} finally {
|
||||
await h.client.close();
|
||||
h.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("prepared statement round-trips", { timeout: 5000 }, async () => {
|
||||
const h = createDbProxyHarness({ seed: [["a", { v: 1 }]] });
|
||||
try {
|
||||
const stmt = await h.client.prepare?.("SELECT *");
|
||||
expect(stmt).toBeDefined();
|
||||
if (stmt === undefined) throw new Error("prepare returned");
|
||||
expect(Array.isArray(await stmt.execute())).toBe(true);
|
||||
await stmt.finalize();
|
||||
} finally {
|
||||
await h.client.close();
|
||||
h.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("close is observable on the main side", { timeout: 5000 }, async () => {
|
||||
const h = createDbProxyHarness();
|
||||
try {
|
||||
await h.client.close();
|
||||
expect(h.db.closed()).toBe(true);
|
||||
} finally {
|
||||
h.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user