126 lines
3.4 KiB
JavaScript
126 lines
3.4 KiB
JavaScript
// scenarios/repo-images.mjs — repo→custom worker image registry (REST CRUD).
|
|
// Spawn itself is NOT exercised here: it needs Docker, which the harness must
|
|
// not require (see spawn-validation.mjs).
|
|
|
|
import { rest } from "../lib.mjs";
|
|
|
|
export async function run(ctx) {
|
|
const { r, base, token } = ctx;
|
|
|
|
const unauth = await rest(base, null, "/api/repos");
|
|
r.check(
|
|
"GET /api/repos without token → 401",
|
|
unauth.status === 401,
|
|
`got ${unauth.status}`,
|
|
);
|
|
|
|
const empty = await rest(base, token, "/api/repos");
|
|
r.check(
|
|
"GET /api/repos on fresh daemon → 200 []",
|
|
empty.status === 200 &&
|
|
Array.isArray(empty.json) &&
|
|
empty.json.length === 0,
|
|
`got ${empty.status} ${empty.text}`,
|
|
);
|
|
|
|
const put = await rest(base, token, "/api/repos/lvmh/e2e/image", {
|
|
method: "PUT",
|
|
body: { image: "lvmh-worker-lvmh--e2e-ab12cd" },
|
|
});
|
|
r.check(
|
|
"PUT valid repo/image → 200 {ok:true}",
|
|
put.status === 200 && put.json?.ok === true,
|
|
`got ${put.status} ${put.text}`,
|
|
);
|
|
|
|
const putTagged = await rest(base, token, "/api/repos/lvmh/e2e2/image", {
|
|
method: "PUT",
|
|
body: { image: "lvmh-worker-lvmh--e2e2-ab12cd:1.0" },
|
|
});
|
|
r.check(
|
|
"PUT tagged image → 200",
|
|
putTagged.status === 200,
|
|
`got ${putTagged.status}`,
|
|
);
|
|
|
|
const list = await rest(base, token, "/api/repos");
|
|
const registrations = Array.isArray(list.json)
|
|
? list.json.filter((x) => x.repo === "lvmh/e2e" || x.repo === "lvmh/e2e2")
|
|
: [];
|
|
r.check(
|
|
"GET /api/repos lists both registrations",
|
|
list.status === 200 &&
|
|
registrations.length === 2 &&
|
|
registrations[0].repo === "lvmh/e2e" &&
|
|
registrations[0].image === "lvmh-worker-lvmh--e2e-ab12cd" &&
|
|
registrations[1].repo === "lvmh/e2e2" &&
|
|
registrations[1].image === "lvmh-worker-lvmh--e2e2-ab12cd:1.0",
|
|
`got ${list.status} ${list.text}`,
|
|
);
|
|
|
|
for (const image of ["evil-image", "", "lvmh-worker-", "LVMH-worker-x"]) {
|
|
const bad = await rest(base, token, "/api/repos/lvmh/e2e/image", {
|
|
method: "PUT",
|
|
body: { image },
|
|
});
|
|
r.check(
|
|
`PUT invalid image ${JSON.stringify(image)} → 400`,
|
|
bad.status === 400 && typeof bad.json?.error === "string",
|
|
`got ${bad.status} ${bad.text}`,
|
|
);
|
|
}
|
|
|
|
const badRepo = await rest(base, token, "/api/repos/noslash/image", {
|
|
method: "PUT",
|
|
body: { image: "lvmh-worker-x" },
|
|
});
|
|
r.check(
|
|
"PUT invalid repo → 400",
|
|
badRepo.status === 400,
|
|
`got ${badRepo.status}`,
|
|
);
|
|
|
|
const malformed = await fetch(`${base}/api/repos/lvmh/e2e/image`, {
|
|
method: "PUT",
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: "{not json",
|
|
});
|
|
r.check(
|
|
"PUT malformed JSON → 400",
|
|
malformed.status === 400,
|
|
`got ${malformed.status}`,
|
|
);
|
|
await malformed.text();
|
|
|
|
const del = await rest(base, token, "/api/repos/lvmh/e2e/image", {
|
|
method: "DELETE",
|
|
});
|
|
r.check(
|
|
"DELETE image → 200 {ok:true}",
|
|
del.status === 200 && del.json?.ok === true,
|
|
`got ${del.status}`,
|
|
);
|
|
|
|
const delAgain = await rest(base, token, "/api/repos/lvmh/e2e/image", {
|
|
method: "DELETE",
|
|
});
|
|
r.check(
|
|
"DELETE absent image → 200 (idempotent)",
|
|
delAgain.status === 200,
|
|
`got ${delAgain.status}`,
|
|
);
|
|
|
|
const after = await rest(base, token, "/api/repos");
|
|
const remaining = Array.isArray(after.json)
|
|
? after.json.filter((x) => x.repo === "lvmh/e2e")
|
|
: null;
|
|
r.check(
|
|
"GET after delete no longer lists lvmh/e2e",
|
|
after.status === 200 && remaining?.length === 0,
|
|
`got ${after.status} ${after.text}`,
|
|
);
|
|
}
|