Initial commit
This commit is contained in:
207
tests/http-smoke.test.mjs
Normal file
207
tests/http-smoke.test.mjs
Normal file
@@ -0,0 +1,207 @@
|
||||
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 });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user