Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

End-to-end tests: apply the database migrations once per run, not once per test file (#235)

* End-to-end tests: apply the database migrations once per run, not once per test file
test-bot authored 1 parent ac745d7commit f26063a6885338b8b5af2945826b5376b326a0d0Browse files
16 files changed+68−16
Files (16)
modifiedapps/diffinery/test/e2e/accounts.test.mjs+2−1View file
@@ -16,6 +16,7 @@
1616 import { createServer } from "node:net";
1717 import { test, before, after } from "node:test";
1818 import assert from "node:assert/strict";
19+import { migratedState } from "./d1-state.mjs";
1920
2021 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2122 const work = mkdtempSync(join(tmpdir(), "diffinery-accounts-"));
@@ -128,7 +129,7 @@
128129 base = `http://127.0.0.1:${port}`;
129130 const persist = join(work, "state");
130131 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
131- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
132+ migratedState(APP, persist);
132133 const at = new Date().toISOString();
133134 const hoursAgo = (h) => new Date(Date.now() - h * 3600_000).toISOString();
134135 const later = new Date(Date.now() + 30 * 86400_000).toISOString();
modifiedapps/diffinery/test/e2e/agentic.test.mjs+2−1View file
@@ -15,6 +15,7 @@
1515 import { createServer } from "node:net";
1616 import { test, before, after } from "node:test";
1717 import assert from "node:assert/strict";
18+import { migratedState } from "./d1-state.mjs";
1819
1920 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2021 const work = mkdtempSync(join(tmpdir(), "diffinery-agentic-e2e-"));
@@ -86,7 +87,7 @@
8687 const port = await freePort();
8788 base = `http://127.0.0.1:${port}`;
8889 const persist = join(work, "state");
89- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
90+ migratedState(APP, persist);
9091 dev = spawn("pnpm", ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--var", `MASTER_KEY:${randomBytes(32).toString("base64")}`, "--show-interactive-dev-session=false"], {
9192 cwd: APP,
9293 env: { ...process.env, CI: "1", WRANGLER_SEND_METRICS: "false" },
modifiedapps/diffinery/test/e2e/agents-harness.mjs+2−1View file
@@ -12,6 +12,7 @@
1212 import { createServer as httpServer } from "node:http";
1313 import { before, after } from "node:test";
1414 import assert from "node:assert/strict";
15+import { migratedState } from "./d1-state.mjs";
1516
1617 export const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1718 export const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -190,7 +191,7 @@
190191 const port = await freePort();
191192 base = `http://127.0.0.1:${port}`;
192193 const persist = join(work, "state");
193- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
194+ migratedState(APP, persist);
194195 // A second person, signed in with a session: not the terminal's opener, whatever their role.
195196 {
196197 const at = new Date().toISOString();
addedapps/diffinery/test/e2e/d1-state.mjs+37−0View file
@@ -1,0 +1,37 @@
1+// A fresh local database for an end-to-end test's `wrangler dev --persist-to` directory, with
2+// every migration applied.
3+//
4+// `wrangler d1 migrations apply --local` takes about 20 s (most of a test file's start), and
5+// every file used to pay it. The first call in a run applies the migrations once, the same way,
6+// into a template in the OS temp directory; every call then copies that template, which takes
7+// milliseconds. The template's name carries a hash of the migrations, the Wrangler config and
8+// Wrangler's version, so a change to any of them builds a new one. It is built in a directory
9+// of its own and renamed into place, so test files starting side by side never copy half of one.
10+import { execFileSync } from "node:child_process";
11+import { cpSync, existsSync, readdirSync, readFileSync, renameSync, rmSync } from "node:fs";
12+import { tmpdir } from "node:os";
13+import { createHash, randomBytes } from "node:crypto";
14+import { createRequire } from "node:module";
15+import { join } from "node:path";
16+
17+/** Copies a database with every migration applied into `persist` (the `--persist-to` directory). */
18+export function migratedState(app, persist) {
19+ const migrations = join(app, "migrations");
20+ const hash = createHash("sha256");
21+ for (const name of readdirSync(migrations).sort()) hash.update(`${name}\0`).update(readFileSync(join(migrations, name))).update("\0");
22+ hash.update(readFileSync(join(app, "wrangler.jsonc")));
23+ hash.update(createRequire(join(app, "package.json"))("wrangler/package.json").version);
24+ const template = join(tmpdir(), `diffinery-e2e-d1-${hash.digest("hex").slice(0, 16)}`);
25+ if (!existsSync(template)) {
26+ const building = `${template}.building-${process.pid}-${randomBytes(4).toString("hex")}`;
27+ execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", building], { cwd: app, stdio: "pipe", env: { ...process.env, CI: "1" } });
28+ try {
29+ renameSync(building, template);
30+ } catch (e) {
31+ // Another test file finished the same template first.
32+ if (!existsSync(template)) throw e;
33+ rmSync(building, { recursive: true, force: true });
34+ }
35+ }
36+ cpSync(template, persist, { recursive: true });
37+}
modifiedapps/diffinery/test/e2e/e2e.test.mjs+2−1View file
@@ -19,6 +19,7 @@
1919 import { test, before, after } from "node:test";
2020 import assert from "node:assert/strict";
2121 import { fakeGitHub, lfsObject } from "./fake-github.mjs";
22+import { migratedState } from "./d1-state.mjs";
2223
2324 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2425 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -178,7 +179,7 @@
178179 const port = await freePort();
179180 base = `http://127.0.0.1:${port}`;
180181 const persist = join(work, "state");
181- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
182+ migratedState(APP, persist);
182183 // Until the web UI exists, run the same app through the API-only entry.
183184 const entry = existsSync(join(APP, "src/web/routes.tsx")) ? [] : ["test/e2e/entry.ts"];
184185 const out = openSync(devLogFile, "a");
modifiedapps/diffinery/test/e2e/early-access.test.mjs+2−1View file
@@ -20,6 +20,7 @@
2020 import { request as httpRequest } from "node:http";
2121 import { test, after } from "node:test";
2222 import assert from "node:assert/strict";
23+import { migratedState } from "./d1-state.mjs";
2324
2425 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2526 const work = mkdtempSync(join(tmpdir(), "diffinery-early-access-e2e-"));
@@ -92,7 +93,7 @@
9293 const session = (account, cookie) => `INSERT INTO sessions (id, account_id, method, created_at, last_seen_at, expires_at) VALUES ('${hash(cookie)}', '${account}', 'passkey', '${at}', '${at}', '${later}')`;
9394 const seed = [person("u-root", "root", "root@example.com", 1), person("u-ann", "ann", "ann@example.com", 0), token("t-root", "u-root", T.root), token("t-ann", "u-ann", T.ann), session("u-root", S.root), session("u-ann", S.ann)];
9495 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
95- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
96+ migratedState(APP, persist);
9697 wrangler("d1", "execute", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist, "--command", seed.join("; "));
9798 const args = ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--show-interactive-dev-session=false"];
9899 const dev = spawn("pnpm", args, { cwd: APP, env: { ...process.env, CI: "1", WRANGLER_SEND_METRICS: "false" }, stdio: ["ignore", "pipe", "pipe"], detached: true });
modifiedapps/diffinery/test/e2e/email.test.mjs+2−1View file
@@ -21,6 +21,7 @@
2121 import { test, before, after } from "node:test";
2222 import assert from "node:assert/strict";
2323 import { chromium } from "playwright";
24+import { migratedState } from "./d1-state.mjs";
2425
2526 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2627 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -128,7 +129,7 @@
128129 const port = await freePort();
129130 base = `http://127.0.0.1:${port}`;
130131 const persist = join(work, "state");
131- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
132+ migratedState(APP, persist);
132133 dev = spawn("pnpm", ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--var", `MASTER_KEY:${randomBytes(32).toString("base64")}`, "--var", `MAIL_EVENTS_SECRET:${eventsSecret}`, "--show-interactive-dev-session=false"], {
133134 cwd: APP,
134135 env: { ...process.env, CI: "1", WRANGLER_SEND_METRICS: "false" },
modifiedapps/diffinery/test/e2e/graphql.test.mjs+2−1View file
@@ -15,6 +15,7 @@
1515 import { createServer } from "node:net";
1616 import { test, before, after } from "node:test";
1717 import assert from "node:assert/strict";
18+import { migratedState } from "./d1-state.mjs";
1819
1920 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2021 const work = mkdtempSync(join(tmpdir(), "diffinery-graphql-e2e-"));
@@ -43,7 +44,7 @@
4344 const later = new Date(Date.now() + 30 * 86400_000).toISOString();
4445 const person = (id, login) => `INSERT INTO accounts (id, login, kind, name, email, status, site_admin, created_at) VALUES ('${id}', '${login}', 'user', '${login}', '${login}@example.com', 'active', 0, '${at}')`;
4546 const token = (id, account, t, scope) => `INSERT INTO tokens (id, account_id, name, token_hash, prefix, scopes, expires_at, created_at) VALUES ('${id}', '${account}', 'e2e', '${hash(t)}', '${t.slice(0, 10)}', '["${scope}"]', '${later}', '${at}')`;
46- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
47+ migratedState(APP, persist);
4748 wrangler("d1", "execute", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist, "--command", [person("u-ann", "ann"), person("u-bob", "bob"), token("t-ann", "u-ann", T.ann, "admin"), token("t-anr", "u-ann", T.annRead, "read"), token("t-bob", "u-bob", T.bob, "admin")].join("; "));
4849 // No fixed dev identity (DEV_AUTH empty), so a request without a token is anonymous.
4950 dev = spawn("pnpm", ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--var", "DEV_AUTH:", "--show-interactive-dev-session=false"], {
modifiedapps/diffinery/test/e2e/moderation.test.mjs+2−1View file
@@ -17,6 +17,7 @@
1717 import { createServer } from "node:net";
1818 import { test, before, after } from "node:test";
1919 import assert from "node:assert/strict";
20+import { migratedState } from "./d1-state.mjs";
2021
2122 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2223 const work = mkdtempSync(join(tmpdir(), "diffinery-moderation-"));
@@ -89,7 +90,7 @@
8990 base = `http://127.0.0.1:${port}`;
9091 const persist = join(work, "state");
9192 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
92- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
93+ migratedState(APP, persist);
9394 const at = new Date().toISOString();
9495 const later = new Date(Date.now() + 30 * 86400_000).toISOString();
9596 const account = (id, login, kind) => `INSERT INTO accounts (id, login, kind, name, status, created_at) VALUES ('${id}', '${login}', '${kind}', '${login}', 'active', '${at}')`;
modifiedapps/diffinery/test/e2e/oauth.test.mjs+2−1View file
@@ -18,6 +18,7 @@
1818 import { test, before, after } from "node:test";
1919 import assert from "node:assert/strict";
2020 import { chromium } from "playwright";
21+import { migratedState } from "./d1-state.mjs";
2122
2223 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2324 const work = mkdtempSync(join(tmpdir(), "diffinery-oauth-"));
@@ -58,7 +59,7 @@
5859 const port = await freePort();
5960 base = `http://localhost:${port}`;
6061 persist = join(work, "state");
61- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
62+ migratedState(APP, persist);
6263 const at = new Date().toISOString();
6364 const later = new Date(Date.now() + 86400_000).toISOString();
6465 sql(
modifiedapps/diffinery/test/e2e/passkeys.test.mjs+3−2View file
@@ -21,6 +21,7 @@
2121 import { test, before, after } from "node:test";
2222 import assert from "node:assert/strict";
2323 import { chromium } from "playwright";
24+import { migratedState } from "./d1-state.mjs";
2425
2526 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2627 const work = mkdtempSync(join(tmpdir(), "diffinery-passkeys-"));
@@ -97,7 +98,7 @@
9798 base = `http://localhost:${port}`;
9899 const persist = join(work, "state");
99100 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
100- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
101+ migratedState(APP, persist);
101102 const at = new Date().toISOString();
102103 const later = new Date(Date.now() + 86400_000).toISOString();
103104 wrangler(
@@ -462,7 +463,7 @@
462463 const port = await freePort();
463464 const site = `http://localhost:${port}`;
464465 const persist = join(work, "signup-state");
465- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
466+ migratedState(APP, persist);
466467 const open = spawn(
467468 "pnpm",
468469 ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${site}`, "--var", `MASTER_KEY:${MASTER_KEY}`, "--var", "SIGNUP:open", "--show-interactive-dev-session=false"],
modifiedapps/diffinery/test/e2e/registry.test.mjs+2−1View file
@@ -17,6 +17,7 @@
1717 import { createServer } from "node:net";
1818 import { test, before, after } from "node:test";
1919 import assert from "node:assert/strict";
20+import { migratedState } from "./d1-state.mjs";
2021
2122 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2223 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -134,7 +135,7 @@
134135 base = `http://127.0.0.1:${port}`;
135136 host = `127.0.0.1:${port}`;
136137 const persist = join(work, "state");
137- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
138+ migratedState(APP, persist);
138139 const at = new Date().toISOString();
139140 const later = new Date(Date.now() + 30 * 86400_000).toISOString();
140141 const seed = [
modifiedapps/diffinery/test/e2e/review.test.mjs+2−1View file
@@ -19,6 +19,7 @@
1919 import { createServer as httpServer } from "node:http";
2020 import { test, before, after } from "node:test";
2121 import assert from "node:assert/strict";
22+import { migratedState } from "./d1-state.mjs";
2223
2324 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2425 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -156,7 +157,7 @@
156157 const port = await freePort();
157158 base = `http://127.0.0.1:${port}`;
158159 const persist = join(work, "state");
159- execFileSync("pnpm", ["exec", "wrangler", "d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
160+ migratedState(APP, persist);
160161 const vars = { PUBLIC_URL: base, MASTER_KEY: randomBytes(32).toString("base64"), SANDBOX_POOL_URL: `http://127.0.0.1:${poolPort}`, SANDBOX_POOL_SECRET: poolSecret, MODEL_UPSTREAM_ANTHROPIC: upstreamUrl, MODEL_UPSTREAM_OPENAI: upstreamUrl, MODEL_UPSTREAM_OPENROUTER: upstreamUrl };
161162 dev = spawn("pnpm", ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, ...Object.entries(vars).flatMap(([k, v]) => ["--var", `${k}:${v}`]), "--show-interactive-dev-session=false"], {
162163 cwd: APP,
modifiedapps/diffinery/test/e2e/security-txt.test.mjs+2−1View file
@@ -14,6 +14,7 @@
1414 import { createServer } from "node:net";
1515 import { test, after } from "node:test";
1616 import assert from "node:assert/strict";
17+import { migratedState } from "./d1-state.mjs";
1718
1819 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1920 const work = mkdtempSync(join(tmpdir(), "diffinery-securitytxt-e2e-"));
@@ -34,7 +35,7 @@
3435 const base = `http://127.0.0.1:${port}`;
3536 const persist = join(work, name);
3637 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
37- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
38+ migratedState(APP, persist);
3839 if (seed.length) wrangler("d1", "execute", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist, "--command", seed.join("; "));
3940 const args = ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--show-interactive-dev-session=false"];
4041 for (const [k, v] of Object.entries(vars)) args.push("--var", `${k}:${v}`);
modifiedapps/diffinery/test/e2e/security.test.mjs+2−1View file
@@ -34,6 +34,7 @@
3434 import { createServer as createHttpServer } from "node:http";
3535 import { test, before, after } from "node:test";
3636 import assert from "node:assert/strict";
37+import { migratedState } from "./d1-state.mjs";
3738
3839 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
3940 const work = mkdtempSync(join(tmpdir(), "diffinery-security-"));
@@ -135,7 +136,7 @@
135136 base = `http://127.0.0.1:${port}`;
136137 const persist = join(work, "state");
137138 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
138- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
139+ migratedState(APP, persist);
139140 const at = new Date().toISOString();
140141 const later = new Date(Date.now() + 30 * 86400_000).toISOString();
141142 const account = (id, login, kind, status, owner = null) => `INSERT INTO accounts (id, login, kind, name, status, owner_id, created_at) VALUES ('${id}', '${login}', '${kind}', '${login}', '${status}', ${owner ? `'${owner}'` : "NULL"}, '${at}')`;
modifiedapps/diffinery/test/e2e/status.test.mjs+2−1View file
@@ -13,6 +13,7 @@
1313 import { createServer } from "node:net";
1414 import { test, after } from "node:test";
1515 import assert from "node:assert/strict";
16+import { migratedState } from "./d1-state.mjs";
1617
1718 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1819 const work = mkdtempSync(join(tmpdir(), "diffinery-status-e2e-"));
@@ -33,7 +34,7 @@
3334 const base = `http://127.0.0.1:${port}`;
3435 const persist = join(work, name);
3536 const wrangler = (...args) => execFileSync("pnpm", ["exec", "wrangler", ...args], { cwd: APP, stdio: "pipe", env: { ...process.env, CI: "1" } });
36- wrangler("d1", "migrations", "apply", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist);
37+ migratedState(APP, persist);
3738 if (seed.length) wrangler("d1", "execute", "diffinery-dev", "--local", "-e", "dev", "--persist-to", persist, "--command", seed.join("; "));
3839 const args = ["exec", "wrangler", "dev", "-e", "dev", "--ip", "127.0.0.1", "--port", String(port), "--inspector-port", String(await freePort()), "--persist-to", persist, "--var", `PUBLIC_URL:${base}`, "--show-interactive-dev-session=false"];
3940 for (const [k, v] of Object.entries(vars)) args.push("--var", `${k}:${v}`);