Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions ct-runner/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@
positional.push(a);
}
}
if (positional.length !== 1) usageError("expected exactly one <suite.wasm> argument");
if (positional.length !== 1) {
usageError("expected exactly one <suite.wasm> argument");
}
if (out === undefined) usageError("--out <results.jsonl> is required");
return {
suitePath: positional[0],
Expand All @@ -121,9 +123,11 @@
};
}

async function loadImportsModule(path: string): Promise<Record<string, unknown>> {
async function loadImportsModule(
path: string,
): Promise<Record<string, unknown>> {
const mod = await import(
path.startsWith(".") || path.startsWith("/")

Check warning on line 130 in ct-runner/src/main.ts

View workflow job for this annotation

GitHub Actions / core (ubuntu-24.04)

unable to analyze dynamic import

Check warning on line 130 in ct-runner/src/main.ts

View workflow job for this annotation

GitHub Actions / core (ubuntu-24.04-arm)

unable to analyze dynamic import
? new URL(path, `file://${Deno.cwd()}/`).href
: path
);
Expand All @@ -142,15 +146,18 @@
* `polyengine-translator-shim.wasm` asset instead. */
async function loadTranslator(explicit?: string): Promise<Translator> {
const fromEnv = Deno.env.get("POLYENGINE_TRANSLATOR");
const path = explicit ?? (fromEnv !== undefined && fromEnv !== "" ? fromEnv : undefined);
const path = explicit ??
(fromEnv !== undefined && fromEnv !== "" ? fromEnv : undefined);
if (path !== undefined) {
let bytes: Uint8Array;
try {
bytes = await Deno.readFile(path);
} catch (e) {
console.error(
`error: cannot read translator wasm at ${path}` +
` (${explicit !== undefined ? "--translator" : "POLYENGINE_TRANSLATOR"}): ${e}`,
` (${
explicit !== undefined ? "--translator" : "POLYENGINE_TRANSLATOR"
}): ${e}`,
);
Deno.exit(1);
}
Expand Down
6 changes: 1 addition & 5 deletions ct-runner/src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
// provider, never composing wasm for L2. See src/run-suite.ts for the case
// loop and src/context.ts for the host resource.

export {
type RunCounts,
runSuite,
type RunSuiteOptions,
} from "./run-suite.ts";
export { type RunCounts, runSuite, type RunSuiteOptions } from "./run-suite.ts";

export {
analyzeImports,
Expand Down
48 changes: 27 additions & 21 deletions ct-runner/src/run-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ import {
type ComponentArtifacts,
instantiate,
} from "@polyengine/runtime/embedder";
import { Trap, ComponentException } from "@polyengine/protocol";
import { ComponentException, Trap } from "@polyengine/protocol";
import { Context, testContextImportRecord } from "./context.ts";
import { analyzeImports, requireImportsResolved } from "./import-analysis.ts";
import {
applies,
firstExcluding,
loadTagsInventory,
tagsOf,
} from "./tags.ts";
import { requireImportsResolved } from "./import-analysis.ts";
import { applies, firstExcluding, loadTagsInventory, tagsOf } from "./tags.ts";

/**
* The suite's `tests` interface id (wit/tests.wit `interface tests`, v0.1.0).
Expand Down Expand Up @@ -310,12 +305,15 @@ export async function runSuite(
}
if (!applies(tags, missing)) {
counts.na++;
opts.emit(JSON.stringify({
case: name,
status: "not-applicable",
detail: firstExcluding(tags, missing),
"diagnostics-complete": true,
}), i);
opts.emit(
JSON.stringify({
case: name,
status: "not-applicable",
detail: firstExcluding(tags, missing),
"diagnostics-complete": true,
}),
i,
);
opts.log?.(`${name} … not-applicable`);
continue;
}
Expand All @@ -329,11 +327,14 @@ export async function runSuite(
// `only <filter>` detail — no other fields.
if (!isSelected) {
counts.deselected++;
opts.emit(JSON.stringify({
case: name,
status: "deselected",
detail: `only ${opts.only}`,
}), i);
opts.emit(
JSON.stringify({
case: name,
status: "deselected",
detail: `only ${opts.only}`,
}),
i,
);
opts.log?.(`${name} … deselected`);
continue;
}
Expand Down Expand Up @@ -479,8 +480,13 @@ export async function runSuite(
return counts;
}

// deno-lint-ignore no-explicit-any
async function findByName(list: any[], name: string, hint?: number): Promise<any> {
async function findByName(
// deno-lint-ignore no-explicit-any
list: any[],
name: string,
hint?: number,
// deno-lint-ignore no-explicit-any
): Promise<any> {
// Same-index fast path. Enumeration order is a hint, not a contract: real
// suites enumerate deterministically, so the re-enumerated case is
// virtually always at its census index — one name() round-trip instead of
Expand Down
4 changes: 3 additions & 1 deletion ct-runner/tests/cli_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ Deno.test({
name: "cli: POLYENGINE_TRANSLATOR env is honored",
ignore: !ready,
fn: async () => {
const { code, lines } = await runCli([], { POLYENGINE_TRANSLATOR: TRANSLATOR });
const { code, lines } = await runCli([], {
POLYENGINE_TRANSLATOR: TRANSLATOR,
});
assertEq(code, 1);
assertEq(lines!.length, 1 + 6 + 1);
},
Expand Down
10 changes: 8 additions & 2 deletions ct-runner/tests/e2e_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

import { assertEq } from "../../runtime/tests/support/asserts.ts";
import { runSuite } from "../src/mod.ts";
import { artifactsOf, FULL_RUN_COUNTS, haveFixture, TEST_SUITE_WASM } from "./support.ts";
import {
artifactsOf,
FULL_RUN_COUNTS,
haveFixture,
TEST_SUITE_WASM,
} from "./support.ts";

const ready = await haveFixture(TEST_SUITE_WASM);

Expand Down Expand Up @@ -139,7 +144,8 @@ Deno.test({
});

Deno.test({
name: "e2e: freshCases=false still runs to completion (single shared instance)",
name:
"e2e: freshCases=false still runs to completion (single shared instance)",
ignore: !ready,
fn: async () => {
const artifacts = await artifactsOf(TEST_SUITE_WASM);
Expand Down
8 changes: 6 additions & 2 deletions ct-runner/tests/golden_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@

import { assertEq } from "../../runtime/tests/support/asserts.ts";
import { runSuite } from "../src/mod.ts";
import { artifactsOf, FULL_RUN_COUNTS, haveFixture, TEST_SUITE_WASM } from "./support.ts";
import {
artifactsOf,
FULL_RUN_COUNTS,
haveFixture,
TEST_SUITE_WASM,
} from "./support.ts";

const ready = await haveFixture(TEST_SUITE_WASM);

/** Strip nondeterministic fields for a byte-stable comparison. */
// deno-lint-ignore no-explicit-any
function normalize(line: string): string {
const v = JSON.parse(line);
if (v.suite?.["artifact-sha256"]) v.suite["artifact-sha256"] = "<sha256>";
Expand Down
9 changes: 7 additions & 2 deletions ct-runner/tests/import_analysis_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import {
MissingImportsError,
requireImportsResolved,
} from "../src/import-analysis.ts";
import { TEST_CONTEXT_INTERFACE, testContextImportRecord } from "../src/context.ts";
import {
TEST_CONTEXT_INTERFACE,
testContextImportRecord,
} from "../src/context.ts";
import { artifactsOf, haveFixture, TEST_SUITE_WASM } from "./support.ts";

const ready = await haveFixture(TEST_SUITE_WASM);
Expand Down Expand Up @@ -89,7 +92,9 @@ Deno.test({
assertEq(
analysis.missing.some((m) => m.includes("polymorph:websocket")),
true,
`expected a polymorph:websocket leaf among: ${analysis.missing.join(", ")}`,
`expected a polymorph:websocket leaf among: ${
analysis.missing.join(", ")
}`,
);

let threw: unknown;
Expand Down
5 changes: 4 additions & 1 deletion ct-runner/tests/schema_validation_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ function checkProvenance(p: unknown): void {
if (
p !== null && typeof p === "object" && "limit-exceeded" in (p as object)
) {
assertEq(typeof (p as { "limit-exceeded": unknown })["limit-exceeded"], "string");
assertEq(
typeof (p as { "limit-exceeded": unknown })["limit-exceeded"],
"string",
);
return;
}
throw new Error(`unrecognized provenance shape: ${JSON.stringify(p)}`);
Expand Down
8 changes: 6 additions & 2 deletions ct-runner/tests/shard_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@

import { assertEq } from "../../runtime/tests/support/asserts.ts";
import { runSuite } from "../src/mod.ts";
import { artifactsOf, FULL_RUN_COUNTS, haveFixture, TEST_SUITE_WASM } from "./support.ts";
import {
artifactsOf,
FULL_RUN_COUNTS,
haveFixture,
TEST_SUITE_WASM,
} from "./support.ts";

function assert(cond: boolean, msg = ""): void {
if (!cond) throw new Error(msg || "assertion failed");
}

/** Strip `duration-ms` (nondeterministic wall-clock) for stable comparison,
* same normalization golden_test.ts applies. */
// deno-lint-ignore no-explicit-any
function normalize(line: string): string {
const v = JSON.parse(line);
if (typeof v["duration-ms"] === "number") delete v["duration-ms"];
Expand Down
11 changes: 9 additions & 2 deletions ct-runner/tests/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,19 @@ export function artifactsOfBytes(
return { plan, componentBytes, adapters };
}

export const TEST_SUITE_WASM = "examples/guests/build/test-suite.component.wasm";
export const TEST_SUITE_WASM =
"examples/guests/build/test-suite.component.wasm";

/** `runSuite`'s tally for an unfiltered, untagged run of TEST_SUITE_WASM
* (4 pass, 1 fail, 1 skip; nothing gated or deselected). Tests whose
* subject is not the counts assert this whole; tests ABOUT `only`/tags
* spell out their own. */
export const FULL_RUN_COUNTS: RunCounts = {
passed: 4, failed: 1, skipped: 1, na: 0, deselected: 0, selected: 6, total: 6,
passed: 4,
failed: 1,
skipped: 1,
na: 0,
deselected: 0,
selected: 6,
total: 6,
};
28 changes: 22 additions & 6 deletions ct-runner/tests/tags_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
applies,
collectTagsSections,
firstExcluding,
loadTagsInventory,
parseTagsRecords,
TAGS_SECTION,
tagsOf,
Expand Down Expand Up @@ -113,13 +112,27 @@ Deno.test("tags: scanner finds nested core-module sections and repairs newlines"
// module) plus the concatenation/newline-repair path (inventory.rs).
const coreCustom = customSection(TAGS_SECTION, enc.encode("m/core hsm"));
const core = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // core preamble
0x00,
0x61,
0x73,
0x6d,
0x01,
0x00,
0x00,
0x00, // core preamble
...coreCustom,
]);
const moduleSection = new Uint8Array([0x01, ...leb(core.length), ...core]);
const componentCustom = customSection(TAGS_SECTION, enc.encode("m/comp\n"));
const component = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x0d, 0x00, 0x01, 0x00, // component preamble
0x00,
0x61,
0x73,
0x6d,
0x0d,
0x00,
0x01,
0x00, // component preamble
...moduleSection,
...componentCustom,
]);
Expand All @@ -145,7 +158,8 @@ const RECORDS = "suite/basic/pass\n" +
"suite/nested/deep/leaf\n";

Deno.test({
name: "tags e2e: missing feature schedules the requiring case out (N/A row exact)",
name:
"tags e2e: missing feature schedules the requiring case out (N/A row exact)",
ignore: !ready,
fn: async () => {
const bytes = withTags((await readArtifact(TEST_SUITE_WASM))!, RECORDS);
Expand Down Expand Up @@ -186,7 +200,8 @@ Deno.test({
});

Deno.test({
name: "tags e2e: gating is on whenever an inventory exists (decline case N/As)",
name:
"tags e2e: gating is on whenever an inventory exists (decline case N/As)",
ignore: !ready,
fn: async () => {
const bytes = withTags((await readArtifact(TEST_SUITE_WASM))!, RECORDS);
Expand Down Expand Up @@ -283,7 +298,8 @@ Deno.test({
});

Deno.test({
name: "tags e2e: --missing without an inventory refuses (no silent feature-blind run)",
name:
"tags e2e: --missing without an inventory refuses (no silent feature-blind run)",
ignore: !ready,
fn: async () => {
const bytes = (await readArtifact(TEST_SUITE_WASM))!; // no section
Expand Down
14 changes: 9 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ check: fmt-check lint build test-rust
cd wasi && deno task check
cd ct-runner && deno task check

# Runtime formatting; generated files are excluded by runtime/deno.json.
# The five published packages are formatter- and lint-clean (`deno fmt`,
# `deno lint`, stock rules). Generated artifacts are excluded per package in
# its deno.json (runtime's bindgen snapshots and fixture output). harness,
# examples, and tools are not shipped and are not gated.
shipped := "protocol runtime translator wasi ct-runner"

# Fix with `cd <pkg> && deno fmt`.
fmt-check:
cd runtime && deno fmt --check
for p in {{shipped}}; do (cd $p && deno fmt --check) || exit 1; done

# The runtime package is lint-clean (`deno lint`, stock rules; generated
# artifacts excluded in runtime/deno.json alongside fmt).
lint:
cd runtime && deno lint
for p in {{shipped}}; do (cd $p && deno lint) || exit 1; done

# ----- builders ---------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion protocol/deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@polyengine/protocol",
"version": "0.3.1",
"version": "0.3.2",
"exports": {
".": "./src/mod.ts"
},
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@
// which is a worse footgun than brand-based recognition would create.

import {
COMPONENT_EXCEPTION,
defineBrand,
DROPPED,
hasBrand,
INVALID_HANDLE,
PEER_TRAPPED,
STREAM_PRODUCER,
TRAP,
COMPONENT_EXCEPTION,
} from "./brands.ts";

/** A WIT `result<T, E>` err value, branded. `payload` is shaped per the value table. */
Expand Down
8 changes: 7 additions & 1 deletion protocol/src/handles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
// lib.dom/lib.esnext ambient types (`ReadableStream`, `Uint8Array`,
// `PromiseLike`, `AsyncIterable`, `Iterable`).

import { ERROR_CONTEXT, FUTURE, hasBrand, STREAM, STREAM_WRITER } from "./brands.ts";
import {
ERROR_CONTEXT,
FUTURE,
hasBrand,
STREAM,
STREAM_WRITER,
} from "./brands.ts";

/** `Chunk<u8>` is a `Uint8Array`; every other element type chunks as `T[]`. */
export type Chunk<T> = T extends number ? Uint8Array | T[] : T[];
Expand Down
Loading
Loading