Initial Commit
This commit is contained in:
182
packages/api-stack/api/api-sandbox-wasm-host-bridge/tests/fixtures/build-wasm.test.ts
vendored
Normal file
182
packages/api-stack/api/api-sandbox-wasm-host-bridge/tests/fixtures/build-wasm.test.ts
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { buildFixtureWasm, WITNESS_OFFSET } from "./build-wasm.js";
|
||||
|
||||
async function instantiate(bytes: Uint8Array) {
|
||||
const mod = await WebAssembly.compile(bytes);
|
||||
const instance = await WebAssembly.instantiate(mod, {});
|
||||
return instance.exports as Record<string, unknown> & {
|
||||
memory: WebAssembly.Memory;
|
||||
};
|
||||
}
|
||||
|
||||
describe("buildFixtureWasm", () => {
|
||||
it("compiles and exports the full ABI surface", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const bytes = buildFixtureWasm();
|
||||
const exports = await instantiate(bytes);
|
||||
const required = [
|
||||
"memory",
|
||||
"__suaveplan_alloc",
|
||||
"__suaveplan_free",
|
||||
"__suaveplan_handle_request",
|
||||
"__suaveplan_routes",
|
||||
"__suaveplan_start",
|
||||
"__suaveplan_dispose",
|
||||
];
|
||||
for (const name of required) {
|
||||
expect(exports[name]).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("default routes JSON decodes to a single GET route", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(buildFixtureWasm());
|
||||
const routes = exports.__suaveplan_routes as () => bigint;
|
||||
const packed = routes();
|
||||
const ptr = Number((packed >> 32n) & 0xffff_ffffn);
|
||||
const len = Number(packed & 0xffff_ffffn);
|
||||
const json = new TextDecoder().decode(
|
||||
new Uint8Array(exports.memory.buffer, ptr, len)
|
||||
);
|
||||
expect(JSON.parse(json)).toEqual([{ method: "GET", path: "/hello" }]);
|
||||
});
|
||||
|
||||
it("handle_request copies request bytes into the witness range", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(buildFixtureWasm());
|
||||
const alloc = exports.__suaveplan_alloc as (n: number) => number;
|
||||
const handle = exports.__suaveplan_handle_request as (
|
||||
p: number,
|
||||
l: number
|
||||
) => bigint;
|
||||
const payload = new TextEncoder().encode("hello-witness");
|
||||
const ptr = alloc(payload.length);
|
||||
new Uint8Array(exports.memory.buffer).set(payload, ptr);
|
||||
handle(ptr, payload.length);
|
||||
const witnessBytes = new Uint8Array(
|
||||
exports.memory.buffer,
|
||||
WITNESS_OFFSET,
|
||||
payload.length
|
||||
);
|
||||
expect(new TextDecoder().decode(witnessBytes)).toBe("hello-witness");
|
||||
});
|
||||
|
||||
it("clamps oversize requests to WITNESS_CAPACITY", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(buildFixtureWasm());
|
||||
const alloc = exports.__suaveplan_alloc as (n: number) => number;
|
||||
const handle = exports.__suaveplan_handle_request as (
|
||||
p: number,
|
||||
l: number
|
||||
) => bigint;
|
||||
const payload = new Uint8Array(2048).fill(0x41);
|
||||
const ptr = alloc(payload.length);
|
||||
new Uint8Array(exports.memory.buffer).set(payload, ptr);
|
||||
handle(ptr, payload.length);
|
||||
// First 1024 witness bytes are populated; reading the FULL
|
||||
// witness range should be all 0x41 (since the clamp wrote
|
||||
// exactly WITNESS_CAPACITY bytes, not more).
|
||||
const witness = new Uint8Array(
|
||||
exports.memory.buffer,
|
||||
WITNESS_OFFSET,
|
||||
1024
|
||||
);
|
||||
expect(witness.every((b) => b === 0x41)).toBe(true);
|
||||
});
|
||||
|
||||
it("allocAlwaysZero produces an alloc that returns 0", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ allocAlwaysZero: true })
|
||||
);
|
||||
const alloc = exports.__suaveplan_alloc as (n: number) => number;
|
||||
expect(alloc(16)).toBe(0);
|
||||
});
|
||||
|
||||
it("handlerTraps fixture traps via unreachable", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ handlerTraps: true })
|
||||
);
|
||||
const handle = exports.__suaveplan_handle_request as (
|
||||
p: number,
|
||||
l: number
|
||||
) => bigint;
|
||||
expect(() => handle(0, 0)).toThrow(WebAssembly.RuntimeError);
|
||||
});
|
||||
|
||||
it("startTraps + disposeTraps both surface as RuntimeError", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const startExports = await instantiate(
|
||||
buildFixtureWasm({ startTraps: true })
|
||||
);
|
||||
expect(() => (startExports.__suaveplan_start as () => void)()).toThrow(
|
||||
WebAssembly.RuntimeError
|
||||
);
|
||||
const disposeExports = await instantiate(
|
||||
buildFixtureWasm({ disposeTraps: true })
|
||||
);
|
||||
expect(() =>
|
||||
(disposeExports.__suaveplan_dispose as () => void)()
|
||||
).toThrow(WebAssembly.RuntimeError);
|
||||
});
|
||||
|
||||
it("routesTraps fixture traps __suaveplan_routes", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ routesTraps: true })
|
||||
);
|
||||
expect(() => (exports.__suaveplan_routes as () => bigint)()).toThrow(
|
||||
WebAssembly.RuntimeError
|
||||
);
|
||||
});
|
||||
|
||||
it("routesEmpty returns (0, 0)", { timeout: 30000 }, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ routesEmpty: true })
|
||||
);
|
||||
expect((exports.__suaveplan_routes as () => bigint)()).toBe(0n);
|
||||
});
|
||||
|
||||
it("handlerEmptyResponse returns (0, 0)", { timeout: 30000 }, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ handlerEmptyResponse: true })
|
||||
);
|
||||
const handle = exports.__suaveplan_handle_request as (
|
||||
p: number,
|
||||
l: number
|
||||
) => bigint;
|
||||
expect(handle(0, 0)).toBe(0n);
|
||||
});
|
||||
|
||||
it("dropExports omits the requested symbols", {
|
||||
timeout: 30000,
|
||||
}, async () => {
|
||||
const exports = await instantiate(
|
||||
buildFixtureWasm({ dropExports: ["__suaveplan_start"] })
|
||||
);
|
||||
expect(exports.__suaveplan_start).toBeUndefined();
|
||||
// Memory and the rest remain.
|
||||
expect(exports.memory).toBeInstanceOf(WebAssembly.Memory);
|
||||
});
|
||||
|
||||
it("rejects oversize routes JSON", { timeout: 5000 }, () => {
|
||||
expect(() =>
|
||||
buildFixtureWasm({ routesJson: "x".repeat(2048) })
|
||||
).toThrow(RangeError);
|
||||
});
|
||||
|
||||
it("rejects oversize response JSON", { timeout: 5000 }, () => {
|
||||
expect(() =>
|
||||
buildFixtureWasm({ responseJson: "x".repeat(2048) })
|
||||
).toThrow(RangeError);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user