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
4 changes: 4 additions & 0 deletions runner/pipeline/demo-routes-version.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ globalThis.fetch = async (input, init) => {
if (url.startsWith("https://login.invalid") && init?.headers?.Authorization === "Bearer test-token") {
return Response.json({ email: AUTHOR, sub: "u1" });
}
// A PR build looks up the PR's current commit (DEV-3338).
if (url.startsWith("https://pkg.pr.new/") && init?.method === "HEAD") {
return new Response(null, { headers: { "x-commit-key": "handsontable:handsontable:abc1234" } });
}
// Anything else is a test escaping its sandbox. A throw inside
// authenticate's try/catch reads as 401, inside fetchVersionCatalog as 502 —
// both fail the asserting test loudly instead of reaching a live registry.
Expand Down
47 changes: 42 additions & 5 deletions runner/pipeline/fixtures/worker-harness.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export function parseDemosInsert(sql, binds) {
*/
export function fakeD1(seedRows = [], seedTokens = [], { buildCacheHit = true } = {}) {
const writes = [];
// The build_cache keys asked for, in order — the only observable of what a
// build is keyed on, since the fake answers every lookup alike.
const cacheLookups = [];
const demos = new Map(seedRows.map((row) => [row.id, row]));
const tokens = new Map(seedTokens.map((row) => [row.id, { ...row }]));
const prepare = (sql) => {
Expand All @@ -60,8 +63,13 @@ export function fakeD1(seedRows = [], seedTokens = [], { buildCacheHit = true }
// and so a route that forgets to write a change cannot appear to.
return row ? { ...row } : null;
}
if (/FROM demos WHERE id = \?/.test(sql)) return demos.get(binds[0]) ?? null;
if (/FROM demos WHERE id = \?/.test(sql)) {
// A copy, as D1 returns: a caller holding a row must not see later writes.
const row = demos.get(binds[0]);
return row ? { ...row } : null;
}
if (/FROM build_cache/.test(sql)) {
cacheLookups.push(binds[0]);
return buildCacheHit ? { r2_prefix: "demos/_prior-identical-build/" } : null;
}
return null;
Expand All @@ -71,7 +79,7 @@ export function fakeD1(seedRows = [], seedTokens = [], { buildCacheHit = true }
const inserted = parseDemosInsert(sql, binds);
if (inserted) demos.set(inserted.id, inserted);
applyTokenWrite(tokens, sql, binds);
return { success: true, meta: {} };
return { success: true, meta: { changes: applyPrRefreshWrite(demos, sql, binds) } };
},
async all() {
if (/FROM api_tokens ORDER BY created_at DESC/.test(sql)) {
Expand All @@ -85,7 +93,36 @@ export function fakeD1(seedRows = [], seedTokens = [], { buildCacheHit = true }
});
return { bind: (...binds) => bound(binds), ...bound([]) };
};
return { db: { prepare }, writes, demos, tokens };
return { db: { prepare }, writes, demos, tokens, cacheLookups };
}

/**
* Apply the PR-refresh claim (pr-refresh.ts) and its undo to the `demos` map,
* honouring the claim's WHERE clause and answering `meta.changes` — the claim is
* only atomic because of that condition, so a fake that always applied it would
* pass a double-scheduling bug.
*/
function applyPrRefreshWrite(demos, sql, binds) {
if (/UPDATE demos SET build_status='building', build_error=NULL, ht_attempt_sha=\?/.test(sql)) {
// Each condition applies only while the SQL still says it.
const [sha, now, id, staleBefore, notSha, version] = binds;
const row = demos.get(id);
const staleClause = /build_status!='building' OR updated_at<\?/.test(sql);
const busy = row?.build_status === "building" && !(staleClause && row.updated_at < staleBefore);
const retry = /COALESCE\(ht_attempt_sha,''\)!=\?/.test(sql) && (row?.ht_attempt_sha ?? "") === notSha;
const moved = /AND ht_version=\?/.test(sql) && row?.ht_version !== version;
if (!row || busy || retry || moved) return 0;
Object.assign(row, { build_status: "building", build_error: null, ht_attempt_sha: sha, updated_at: now });
return 1;
}
if (/UPDATE demos SET build_status=\?, ht_attempt_sha=\?, updated_at=\? WHERE id=\?/.test(sql)) {
const [status, sha, updatedAt, id] = binds;
const row = demos.get(id);
if (!row) return 0;
Object.assign(row, { build_status: status, ht_attempt_sha: sha, updated_at: updatedAt });
return 1;
}
return undefined;
}

/**
Expand Down Expand Up @@ -238,7 +275,7 @@ export const AUTHOR = "dev@handsontable.com";
* under test on the browser routes.
*/
export function makeEnv(seedRows = [], seedTokens = [], seedArtifacts = {}, opts = {}) {
const { db, writes, demos, tokens } = fakeD1(seedRows, seedTokens, opts);
const { db, writes, demos, tokens, cacheLookups } = fakeD1(seedRows, seedTokens, opts);
const artifacts = fakeR2(seedArtifacts);
const buildJobs = fakeBuildJobs();
const env = {
Expand All @@ -256,7 +293,7 @@ export function makeEnv(seedRows = [], seedTokens = [], seedArtifacts = {}, opts
// Not the production host, so the Sentry gate in index.ts stays inert.
PREVIEW_HOST: "localhost:8787",
};
return { env, writes, demos, artifacts, tokens, scheduled: buildJobs.scheduled };
return { env, writes, demos, artifacts, tokens, cacheLookups, scheduled: buildJobs.scheduled };
}

export const ctx = {
Expand Down
12 changes: 11 additions & 1 deletion runner/pipeline/mcp-routes.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,17 @@ test("an MCP rebuild derives the bare ref from a pkg.pr.new-pinned payload and r
// package.json asks for (bare ref in D1, exact URL in the snapshot), and the
// sentinel is repaired rather than re-stored.
const { env, writes, artifacts } = makeEnv([demoRow({ ht_version: "latest" })]);
const res = await worker.fetch(patchRequest("abc123", { files: filesWith(PR_URL) }), env, ctx);
// The build looks up the PR's current commit (DEV-3338); answer it here, not over the network.
const realFetch = globalThis.fetch;
globalThis.fetch = async (url, init) => String(url).startsWith("https://pkg.pr.new/")
? new Response(null, { headers: { "x-commit-key": "handsontable:handsontable:abc1234" } })
: realFetch(url, init);
let res;
try {
res = await worker.fetch(patchRequest("abc123", { files: filesWith(PR_URL) }), env, ctx);
} finally {
globalThis.fetch = realFetch;
}
assert.equal(res.status, 200);
const body = await res.json();
assert.equal(body.rebuilt, true);
Expand Down
Loading
Loading