Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
import { describe, expect, it, vi } from "@suaveplan/testing/runner";
import { SqliteError } from "../errors/index.js";
import { createWasmDriver } from "./wasm-driver.js";
// Injectable worker factory avoids spawning real Workers in Node/Vitest environment
function makeWorkerFactory(
handler: (
msg: unknown,
post: (data: unknown) => void
) => void | Promise<void>
): () => Worker {
return () => {
let onmessage: ((ev: MessageEvent) => void) | null = null;
let onerror: ((ev: ErrorEvent) => void) | null = null;
const post = (data: unknown) => {
if (onmessage) {
onmessage({ data } as MessageEvent);
}
};
const worker = {
get onmessage() {
return onmessage;
},
set onmessage(fn: ((ev: MessageEvent) => void) | null) {
onmessage = fn;
},
get onerror() {
return onerror;
},
set onerror(fn: ((ev: ErrorEvent) => void) | null) {
onerror = fn;
},
postMessage: (msg: unknown) => {
void Promise.resolve().then(() => handler(msg, post));
},
terminate: vi.fn(),
};
return worker as unknown as Worker;
};
}
function makeSuccessWorker(): () => Worker {
return makeWorkerFactory((msg, post) => {
const m = msg as {
type: string;
id: number;
sql?: string;
params?: unknown[];
};
if (m.type === "init") {
post({ id: m.id, ok: true, result: { type: "ready" } });
} else if (m.type === "query") {
post({ id: m.id, ok: true, result: [["value1"], ["value2"]] });
} else if (m.type === "execute") {
post({ id: m.id, ok: true, result: { rowsAffected: 1 } });
} else if (m.type === "close") {
post({ id: m.id, ok: true, result: { type: "closed" } });
}
});
}
describe("createWasmDriver", () => {
it("creates driver and resolves on successful init", {
timeout: 30000,
}, async () => {
const { db, close } = await createWasmDriver(
undefined,
makeSuccessWorker()
);
expect(db).toBeDefined();
await close();
});
it("query returns rows from worker", { timeout: 30000 }, async () => {
const { db, close } = await createWasmDriver(
undefined,
makeSuccessWorker()
);
const rows = await db.query("SELECT * FROM t");
expect(rows).toEqual([["value1"], ["value2"]]);
await close();
});
it("execute returns rowsAffected from worker", {
timeout: 30000,
}, async () => {
const { db, close } = await createWasmDriver(
undefined,
makeSuccessWorker()
);
const result = await db.execute("INSERT INTO t VALUES (?)", [1]);
expect(result.rowsAffected).toBe(1);
await close();
});
it("close() is idempotent", { timeout: 30000 }, async () => {
const { close } = await createWasmDriver(
undefined,
makeSuccessWorker()
);
await close();
await expect(close()).resolves.toBeUndefined();
});
it("rejects pending requests when close() is called", {
timeout: 30000,
}, async () => {
let postFn: ((data: unknown) => void) | null = null;
const slowWorker = makeWorkerFactory((msg, post) => {
const m = msg as { type: string; id: number };
if (m.type === "init") {
post({ id: m.id, ok: true, result: { type: "ready" } });
} else if (m.type === "close") {
post({ id: m.id, ok: true, result: { type: "closed" } });
}
// query messages hang — capture postFn for manual resolution
if (m.type === "query") {
postFn = post;
}
});
const { db, close } = await createWasmDriver(undefined, slowWorker);
// Fire a query that will hang — capture the promise
const queryPromise = db.query("SELECT 1");
// Ensure the query is actually sent before closing
await Promise.resolve();
// close() should drain pending
await close();
// The hanging query should now reject
await expect(queryPromise).rejects.toBeInstanceOf(SqliteError);
// Suppress unused variable warning
void postFn;
});
it("throws SqliteError on worker init failure", {
timeout: 30000,
}, async () => {
const failWorker = makeWorkerFactory((msg, post) => {
const m = msg as { type: string; id: number };
if (m.type === "init") {
post({
id: m.id,
ok: false,
error: "sqlite-wasm init failed: load error",
});
} else if (m.type === "close") {
post({ id: m.id, ok: true, result: { type: "closed" } });
}
});
await expect(
createWasmDriver(undefined, failWorker)
).rejects.toBeInstanceOf(SqliteError);
await expect(
createWasmDriver(undefined, failWorker)
).rejects.toMatchObject({ code: "SQLITE.DRIVER_INIT_FAILED" });
});
it("worker error event rejects pending requests", {
timeout: 30000,
}, async () => {
let fireError: ((ev: ErrorEvent) => void) | null = null;
const hangingWorker = makeWorkerFactory((msg, post) => {
const m = msg as { type: string; id: number };
if (m.type === "init") {
post({ id: m.id, ok: true, result: { type: "ready" } });
}
// query messages hang — worker "crashes" below
});
const patchedFactory = () => {
const worker = hangingWorker();
Object.defineProperty(worker, "onerror", {
set: (fn: (ev: ErrorEvent) => void) => {
fireError = fn;
},
get: () => fireError,
configurable: true,
});
return worker;
};
const { db } = await createWasmDriver(undefined, patchedFactory);
const queryPromise = db.query("SELECT 1");
await Promise.resolve();
// Simulate worker crash — onerror should reject all pending promises
fireError?.({ message: "Worker crashed" } as ErrorEvent);
await expect(queryPromise).rejects.toBeInstanceOf(SqliteError);
});
});