Add account based multiplayer hosting and bug report retention
This commit is contained in:
146
scripts/test-bug-retention-http.mjs
Normal file
146
scripts/test-bug-retention-http.mjs
Normal file
@@ -0,0 +1,146 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import sharp from "sharp";
|
||||
process.loadEnvFile(".env.local");
|
||||
const origin = new URL(process.argv[2] || "https://minegeo.vercel.app").origin;
|
||||
const db = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.SUPABASE_SECRET_KEY,
|
||||
{ auth: { persistSession: false, autoRefreshToken: false } },
|
||||
);
|
||||
const checked = (r) => {
|
||||
if (r.error) throw new Error(r.error.message);
|
||||
return r.data;
|
||||
};
|
||||
const cookies = new Map();
|
||||
let id;
|
||||
await mkdir(".data/retention-check", { recursive: true });
|
||||
async function api(path, body, expected = 200, stranger = false) {
|
||||
const response = await fetch(`${origin}/api/v1/bug-reports${path}`, {
|
||||
method: body === undefined ? "GET" : "POST",
|
||||
headers: {
|
||||
origin,
|
||||
"content-type": "application/json",
|
||||
cookie: stranger
|
||||
? ""
|
||||
: [...cookies].map(([k, v]) => `${k}=${v}`).join("; "),
|
||||
},
|
||||
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
||||
signal: AbortSignal.timeout(60000),
|
||||
});
|
||||
if (!stranger)
|
||||
for (const cookie of response.headers.getSetCookie()) {
|
||||
const part = cookie.split(";")[0],
|
||||
at = part.indexOf("=");
|
||||
cookies.set(part.slice(0, at), part.slice(at + 1));
|
||||
}
|
||||
const result = await response.json();
|
||||
assert.equal(response.status, expected, `${path}: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
}
|
||||
async function row() {
|
||||
return checked(
|
||||
await db.from("bug_reports").select("*").eq("id", id).maybeSingle(),
|
||||
);
|
||||
}
|
||||
async function waitFor(predicate, label) {
|
||||
for (let n = 0; n < 40; n++) {
|
||||
const current = await row();
|
||||
if (predicate(current)) return current;
|
||||
if (current?.cleanup_error) throw new Error(current.cleanup_error);
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
}
|
||||
throw new Error(`Timed out: ${label}`);
|
||||
}
|
||||
assert.equal((await api("")).ready, true);
|
||||
const created = await api("", {
|
||||
clientId: randomUUID(),
|
||||
title: `[Verification] Retention ${randomUUID()}`,
|
||||
description:
|
||||
"Automated temporary verification fixture for three-day report retention. This is not a real player bug.",
|
||||
displayName: "Support verification",
|
||||
pagePath: "/support",
|
||||
screenshot: true,
|
||||
});
|
||||
id = created.id;
|
||||
await writeFile(
|
||||
".data/retention-check/fixture.json",
|
||||
JSON.stringify({ id, cookies: [...cookies] }),
|
||||
);
|
||||
const image = await sharp({
|
||||
create: { width: 8, height: 8, channels: 3, background: "#334455" },
|
||||
})
|
||||
.png()
|
||||
.toBuffer();
|
||||
assert.equal(
|
||||
(
|
||||
await fetch(created.upload, {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "image/png" },
|
||||
body: image,
|
||||
})
|
||||
).ok,
|
||||
true,
|
||||
);
|
||||
await api(`/${id}/submit`, {});
|
||||
await waitFor((r) => r?.issue_synced, "Linear issue creation");
|
||||
await api(`/${id}/close`, {}, 404, true);
|
||||
const closed = await api(`/${id}/close`, {});
|
||||
assert.equal(closed.state, "done");
|
||||
assert.equal(
|
||||
Date.parse(closed.delete_after) - Date.parse(closed.closed_at),
|
||||
3 * 86400000,
|
||||
);
|
||||
assert.equal((await api(`/${id}/close`, {})).delete_after, closed.delete_after);
|
||||
await api(
|
||||
`/${id}/messages`,
|
||||
{ clientId: randomUUID(), text: "Blocked after closure" },
|
||||
409,
|
||||
);
|
||||
await waitFor((r) => r?.linear_done_synced, "Linear Done status");
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
fixture: id,
|
||||
checkpoint: "Done synchronized; three-day deadline and ownership verified",
|
||||
}),
|
||||
);
|
||||
// Accelerate only this journaled verification fixture; no real report is modified.
|
||||
const backdated = new Date(Date.now() - 3 * 86400000 - 60000).toISOString();
|
||||
checked(
|
||||
await db
|
||||
.from("bug_reports")
|
||||
.update({
|
||||
closed_at: backdated,
|
||||
delete_after: new Date(Date.now() - 60000).toISOString(),
|
||||
cleanup_run_id: null,
|
||||
cleanup_lease_until: null,
|
||||
status_checked_at: new Date().toISOString(),
|
||||
})
|
||||
.eq("id", id)
|
||||
.like("title", "[Verification] Retention %"),
|
||||
);
|
||||
await api(`/${id}/retry-cleanup`, {});
|
||||
await waitFor((r) => r === null, "both-system deletion");
|
||||
assert.equal(
|
||||
checked(await db.from("bug_report_messages").select("id").eq("report_id", id))
|
||||
.length,
|
||||
0,
|
||||
);
|
||||
assert.equal(
|
||||
checked(await db.storage.from("minegeo-support").list(id)).length,
|
||||
0,
|
||||
);
|
||||
await api(`/${id}`, undefined, 404);
|
||||
await writeFile(
|
||||
".data/retention-check/fixture.json",
|
||||
JSON.stringify({ id, deleted: true }),
|
||||
);
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
fixture: id,
|
||||
checkpoint:
|
||||
"Expired report, messages, screenshots and Linear issue deleted",
|
||||
}),
|
||||
);
|
||||
Reference in New Issue
Block a user