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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ jobs:
run: npx playwright install --with-deps chromium
- name: Exercise real paid browser storage and recovery
working-directory: ant-core/browser-tests
# This step compiles only the pinned node, which runs the code of a
# node release so this client is tested against older nodes. Each new
# stable toolchain can add warnings to that old code (Rust 1.99
# deprecated `fetch_update`), which are not this repository's to fix,
# so they must not fail the build here.
env:
RUSTFLAGS: ""
run: npm test

test-unit:
Expand Down
17 changes: 13 additions & 4 deletions ant-core/browser-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,19 @@ The test starts seven real ant-nodes and an isolated Anvil chain, then uses
Chromium's real WebRTC implementation. `ANT_NODE_DIR` overrides the default
sibling `ant-node-web-support` checkout. CI checks out the exact browser-enabled
node revision in [`node-revision`](node-revision); use that revision locally to
reproduce CI. This integration pin is separate from the native `ant-node`
registry dependency, which has no git `rev`. Update the pin only with a passing
paid browser integration run against the replacement. Anvil must be installed
and available on PATH.
reproduce CI. Without `ANT_NODE_DIR`, the devnet refuses to start unless the
sibling checkout is that revision without tracked edits, and builds it with
`--locked`. The pin runs the same code as a node release already on the
network, so the suite checks this client against older nodes. It is currently
`26129a26`, the ant-node `main` commit that adds only the Rust 1.99 fixes to
the 0.21.0 release: its one runtime change renames `fetch_update` to
`try_update`, the same method. CI builds the pin without `-D warnings`, because
each new toolchain can add warnings to an old release. This integration pin is
separate from the native `ant-node` registry dependency, which has no git
`rev`. Update the pin only with a passing paid browser integration run against
the replacement. In CI, the run fails unless every test ran and passed:
`run-guard.js` fails a run with a skipped or unfinished test, and `.only` is
rejected. Anvil must be installed and available on PATH.

The harness authenticates through `BrowserNetworkClient.connect()` and retains
that pool for the upload, makes one batched storage payment,
Expand Down
2 changes: 1 addition & 1 deletion ant-core/browser-tests/node-revision
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c092f225877b3058eccbc47e2082fc44750ed2b5
26129a2611cac08f9f53a557f91fb8806b40a1cc
3 changes: 2 additions & 1 deletion ant-core/browser-tests/playwright.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from "@playwright/test";
export default defineConfig({
testDir: ".", testMatch: "*.spec.js", workers: 1, timeout: 300_000, reporter: "line",
testDir: ".", testMatch: "*.spec.js", workers: 1, timeout: 300_000, forbidOnly: !!process.env.CI,
reporter: [["line"], ["./run-guard.js"]],
use: { browserName: "chromium", headless: true, baseURL: "http://127.0.0.1:35173",
launchOptions: { args: ["--force-fieldtrials=WebRTC-NoSdpMangleUfrag/Enabled/"] } },
webServer: [
Expand Down
19 changes: 19 additions & 0 deletions ant-core/browser-tests/run-guard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Fails an otherwise passing run unless every discovered test ran in Chromium and passed.
// Playwright alone exits 0 when tests are skipped, so a skipped test could leave the suite green
// without exercising the pinned nodes.
export default class RunGuard {
onBegin(_, suite) { this.tests = suite.allTests(); }
onEnd(result) {
// `--list` reports the discovered tests without running them, so there is nothing to check.
if (result.status !== "passed" || process.argv.includes("--list")) return;
const tests = this.tests ?? [];
const missed = tests.filter(test => test.results.at(-1)?.status !== "passed");
if (tests.length > 0 && missed.length === 0) {
console.log(`Run guard: all ${tests.length} tests ran and passed`);
return;
}
console.error(tests.length === 0 ? "Run guard: no tests ran"
: `Run guard: ${missed.length} of ${tests.length} tests did not pass: ${missed.map(test => test.title).join("; ")}`);
return { status: "failed" };
}
}
27 changes: 23 additions & 4 deletions ant-core/browser-tests/start-devnet.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import { spawn } from "node:child_process";
import { mkdtemp, rm } from "node:fs/promises";
import { execFileSync, spawn } from "node:child_process";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { resolve, join } from "node:path";
const directory = await mkdtemp(join(tmpdir(), "ant-core-browser-test-"));
const node = resolve(process.env.ANT_NODE_DIR ?? "../../../ant-node-web-support");
const child = spawn("cargo", ["run", "--manifest-path", join(node, "Cargo.toml"), "--bin", "ant-devnet", "--",
const cargo = ["run", "--manifest-path", join(node, "Cargo.toml"), "--bin", "ant-devnet"];
// Without an explicit ANT_NODE_DIR the suite runs exactly the pinned node: that revision, without tracked edits,
// on its own lockfile.
if (!process.env.ANT_NODE_DIR) {
const pinned = (await readFile("node-revision", "utf8")).trim();
const git = (...args) => execFileSync("git", ["-C", node, ...args], { encoding: "utf8", stdio: "pipe" }).trim();
let problem;
try {
const revision = git("rev-parse", "HEAD");
if (revision !== pinned) problem = `is at ${revision}, not the pinned ${pinned}`;
else if (git("status", "--porcelain", "--untracked-files=no") !== "") problem = `has tracked edits to the pinned ${pinned}`;
} catch { problem = `is not a git checkout of the pinned ${pinned}`; }
if (problem) {
console.error(`${node} ${problem}: check out node-revision there or set ANT_NODE_DIR`);
process.exit(1);
}
console.log(`Starting ant-devnet from the pinned node ${pinned}`);
cargo.push("--locked");
}
const directory = await mkdtemp(join(tmpdir(), "ant-core-browser-test-"));
const child = spawn("cargo", [...cargo, "--",
"--nodes", "7", "--data-dir", directory, "--base-port", "33000", "--webrtc-direct", "--webrtc-direct-base-port", "34000",
"--serve-port", "35000", "--enable-evm"], { stdio: "inherit" });
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => child.kill("SIGINT"));
Expand Down
Loading