Files
quickdrop/tests/http-smoke.test.mjs
2026-08-07 22:13:25 -05:00

208 lines
6.4 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { access, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { execFile, spawn } from "node:child_process";
import { promisify } from "node:util";
try {
await access(".output/server/index.mjs");
} catch {
await promisify(execFile)("npm", ["run", "build"], { stdio: "inherit" });
}
const port = 19000 + Math.floor(Math.random() * 500);
const storage = await mkdtemp(join(tmpdir(), "quickdrop-http-"));
const child = spawn(process.execPath, [".output/server/index.mjs"], {
env: {
...process.env,
NITRO_HOST: "127.0.0.1",
NITRO_PORT: String(port),
AUTH_PASSCODE: "smoke-passcode",
AUTH_SECRET: "smoke-secret-for-tests",
QUICKDROP_STORAGE_DIR: storage,
},
stdio: "ignore",
});
async function request(url, init) {
return fetch(`http://127.0.0.1:${port}${url}`, init);
}
async function waitForServer() {
for (let attempt = 0; attempt < 50; attempt++) {
try {
const response = await request("/api/auth/session");
if (response.status === 200) return;
} catch {}
await new Promise((resolve) => setTimeout(resolve, 100));
}
throw new Error("built server did not start");
}
test("built server enforces auth and serves capability-only lease/chunk APIs", async () => {
try {
await waitForServer();
const reservationBody = JSON.stringify({
version: 2,
chunkSize: 8 * 1024 * 1024,
chunkCount: 1,
noncePrefix: "AQIDBAUGBwg",
expiresIn: "24h",
maxReads: 1,
});
assert.equal(
(
await request("/api/drops", {
method: "POST",
headers: { "content-type": "application/json" },
body: reservationBody,
})
).status,
401,
);
const login = await request("/api/auth/login", {
method: "POST",
headers: {
"content-type": "application/json",
origin: `http://127.0.0.1:${port}`,
},
body: JSON.stringify({ passcode: "smoke-passcode" }),
});
assert.equal(login.status, 204);
const cookie = login.headers.get("set-cookie").split(";", 1)[0];
const reserve = await request("/api/drops", {
method: "POST",
headers: {
"content-type": "application/json",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: reservationBody,
});
assert.equal(reserve.status, 201);
const created = await reserve.json();
const chunk = new Uint8Array(16);
const put = await request(`/api/drops/${created.id}/chunks/0`, {
method: "PUT",
headers: {
"content-type": "application/octet-stream",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: chunk,
});
assert.equal(put.status, 201);
const finalize = await request(`/api/drops/${created.id}/finalize`, {
method: "POST",
headers: {
"content-type": "application/octet-stream",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: new Uint8Array(17),
});
assert.equal(finalize.status, 200);
const descriptor = await request(`/api/drops/${created.id}`, {
headers: { "x-quickdrop-access": created.access },
});
assert.equal(descriptor.status, 200);
const first = await request(`/api/drops/${created.id}/leases`, {
method: "POST",
headers: { "x-quickdrop-access": created.access },
});
assert.equal(first.status, 201);
const lease = await first.json();
const second = await request(`/api/drops/${created.id}/leases`, {
method: "POST",
headers: { "x-quickdrop-access": created.access },
});
assert.equal(second.status, 410);
const reused = await request(`/api/drops/${created.id}/leases`, {
method: "POST",
headers: {
"x-quickdrop-access": created.access,
authorization: `Bearer ${lease.token}`,
},
});
assert.equal(reused.status, 200);
assert.equal((await reused.json()).token, lease.token);
const chunkGet = await request(`/api/drops/${created.id}/chunks/0`, {
headers: { authorization: `Bearer ${lease.token}` },
});
assert.equal(chunkGet.status, 200);
assert.equal((await chunkGet.arrayBuffer()).byteLength, 16);
const complete = await request(`/api/drops/${created.id}/complete`, {
method: "POST",
headers: { authorization: `Bearer ${lease.token}` },
});
assert.equal(complete.status, 204);
// Completion retries must also be idempotent when the drop remains (unlimited reads).
const unlimitedBody = JSON.stringify({
...JSON.parse(reservationBody),
maxReads: null,
});
const unlimitedReserve = await request("/api/drops", {
method: "POST",
headers: {
"content-type": "application/json",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: unlimitedBody,
});
assert.equal(unlimitedReserve.status, 201);
const unlimited = await unlimitedReserve.json();
assert.equal(
(
await request(`/api/drops/${unlimited.id}/chunks/0`, {
method: "PUT",
headers: {
"content-type": "application/octet-stream",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: chunk,
})
).status,
201,
);
assert.equal(
(
await request(`/api/drops/${unlimited.id}/finalize`, {
method: "POST",
headers: {
"content-type": "application/octet-stream",
cookie,
origin: `http://127.0.0.1:${port}`,
},
body: new Uint8Array(17),
})
).status,
200,
);
const unlimitedClaim = await request(`/api/drops/${unlimited.id}/leases`, {
method: "POST",
headers: { "x-quickdrop-access": unlimited.access },
});
assert.equal(unlimitedClaim.status, 201);
const unlimitedLease = await unlimitedClaim.json();
const completionInit = {
method: "POST",
headers: { authorization: `Bearer ${unlimitedLease.token}` },
};
assert.equal(
(await request(`/api/drops/${unlimited.id}/complete`, completionInit))
.status,
204,
);
assert.equal(
(await request(`/api/drops/${unlimited.id}/complete`, completionInit))
.status,
204,
);
} finally {
child.kill("SIGTERM");
await rm(storage, { recursive: true, force: true });
}
});