1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Loads a module for its test.mjs: its build, module.json and session record. handle() runs it under runModule
// with module.json's calls and anyRecords, like a real host, and fails the test when the module makes a call
// outside its session's scope (atlibs' own scopeAllows). respond(call) answers { ok, output } or { ok: false, error };
// http (runModule's allowlist) and fetch (its requests: (url, init) -> Response) serve com.fedfork.exec.http.fetch.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { scopeAllows } from "../../atlibs/javascript/src/oauth/index.js";
import { runModule } from "../../atlibs/javascript/src/run-module/index.js";
import { did, load, now } from "../../atlibs/rust/src/harness.mjs";
export { did, now };
const root = new URL("../", import.meta.url);
const json = (path) => JSON.parse(readFileSync(new URL(path, root), "utf8"));
export async function loadModule(name) {
const spec = json(`modules/${name}/module.json`);
const scope = json(`records/${spec.session}.json`).clientMetadata.scope;
const loaded = await load(new URL(`target/wasm32-unknown-unknown/release/${name.replaceAll("-", "_")}.wasm`, root));
async function handle(entry, input, { respond, budget, http, fetch } = {}) {
const ctx = { wasm: { run: async ({ entry, input }) => loaded.run(entry, { ...input, now }) }, http: { fetch: fetch ?? (async (url) => assert.fail(`no fetch for ${url}`)) } };
const outside = [];
const call = async (nsid, request) => {
if (!scopeAllows(scope, nsid, request)) outside.push({ nsid, ...request });
const answer = await respond({ nsid, ...request });
if (answer?.ok === false) throw new Error(answer.error ?? "call failed");
return answer?.output;
};
const ran = await runModule(ctx, { module: loaded.module, calls: spec.calls, anyRecords: spec.anyRecords, http: spec.http }, entry, { did, ...input }, call, { budget, http });
assert.deepEqual(outside, [], "calls outside the module's calls or session scope");
return ran;
}
return { ...loaded, spec, scope, handle };
}
/** No imports, and an export per action. */
export function abiTest(test, { module, spec }) {
test("module has no imports and exports every action", () => {
assert.equal(WebAssembly.Module.imports(module).length, 0);
const names = WebAssembly.Module.exports(module).map((e) => e.name);
for (const name of ["memory", "alloc", ...spec.actions.map((a) => a.entry)]) assert.ok(names.includes(name), name);
});
}