163 lines
5.5 KiB
JavaScript
163 lines
5.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { DatabaseSync } from "node:sqlite";
|
|
import test from "node:test";
|
|
import {
|
|
derivePairingProgress,
|
|
OWNED_PAIRING_PROGRESS_SQL,
|
|
} from "../db/pairing.ts";
|
|
|
|
const NOW = "2026-08-12T12:00:00.000Z";
|
|
|
|
function row(overrides = {}) {
|
|
return {
|
|
id: "pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
status: "waiting",
|
|
expires_at: "2026-08-12T12:10:00.000Z",
|
|
claimed_host_id: null,
|
|
claimed_at: null,
|
|
last_claim_attempt_at: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test("derives honest waiting, terminal, and claimed pairing progress", () => {
|
|
assert.equal(derivePairingProgress(row(), NOW).status, "waiting");
|
|
assert.equal(
|
|
derivePairingProgress(
|
|
row({ expires_at: "2026-08-12T12:00:00.000Z" }),
|
|
NOW,
|
|
).status,
|
|
"expired",
|
|
);
|
|
assert.equal(derivePairingProgress(row({ status: "locked" }), NOW).status, "locked");
|
|
assert.equal(derivePairingProgress(row({ status: "cancelled" }), NOW).status, "cancelled");
|
|
assert.deepEqual(
|
|
derivePairingProgress(
|
|
row({
|
|
status: "claimed",
|
|
claimed_host_id: "host_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
claimed_at: "2026-08-12T12:01:00.000Z",
|
|
}),
|
|
NOW,
|
|
),
|
|
{
|
|
id: "pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
status: "claimed",
|
|
expiresAt: "2026-08-12T12:10:00.000Z",
|
|
claimedHostId: "host_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
claimedAt: "2026-08-12T12:01:00.000Z",
|
|
claimAttemptState: "not_seen",
|
|
lastClaimAttemptAt: null,
|
|
},
|
|
);
|
|
assert.throws(
|
|
() => derivePairingProgress(row({ status: "claimed" }), NOW),
|
|
/incomplete_claimed_pairing_progress/,
|
|
);
|
|
assert.throws(
|
|
() => derivePairingProgress(row({ status: "unexpected" }), NOW),
|
|
/unknown_pairing_progress_status/,
|
|
);
|
|
});
|
|
|
|
test("distinguishes an unseen request from a safe owner-visible claim attempt signal", () => {
|
|
assert.deepEqual(
|
|
derivePairingProgress(row(), NOW),
|
|
{
|
|
id: "pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
status: "waiting",
|
|
expiresAt: "2026-08-12T12:10:00.000Z",
|
|
claimedHostId: null,
|
|
claimedAt: null,
|
|
claimAttemptState: "not_seen",
|
|
lastClaimAttemptAt: null,
|
|
},
|
|
);
|
|
assert.deepEqual(
|
|
derivePairingProgress(
|
|
row({ last_claim_attempt_at: "2026-08-12T11:59:00.000Z" }),
|
|
NOW,
|
|
),
|
|
{
|
|
id: "pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
status: "waiting",
|
|
expiresAt: "2026-08-12T12:10:00.000Z",
|
|
claimedHostId: null,
|
|
claimedAt: null,
|
|
claimAttemptState: "seen",
|
|
lastClaimAttemptAt: "2026-08-12T11:59:00.000Z",
|
|
},
|
|
);
|
|
assert.equal(
|
|
derivePairingProgress(row({ last_claim_attempt_at: "bad-time" }), NOW)
|
|
.claimAttemptState,
|
|
"invalid",
|
|
);
|
|
assert.equal(
|
|
derivePairingProgress(
|
|
row({ last_claim_attempt_at: "2026-08-12T12:06:00.000Z" }),
|
|
NOW,
|
|
).claimAttemptState,
|
|
"invalid",
|
|
);
|
|
});
|
|
|
|
test("queries pairing progress only through the owning account", () => {
|
|
const db = new DatabaseSync(":memory:");
|
|
db.exec(`
|
|
CREATE TABLE pairing_requests (
|
|
id TEXT PRIMARY KEY, account_id TEXT NOT NULL, status TEXT NOT NULL,
|
|
expires_at TEXT NOT NULL, claimed_host_id TEXT, claimed_at TEXT
|
|
);
|
|
CREATE TABLE pairing_claim_attempts (
|
|
pairing_request_id TEXT NOT NULL, created_at TEXT NOT NULL
|
|
);
|
|
INSERT INTO pairing_requests VALUES
|
|
('pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'acct_a', 'waiting',
|
|
'2026-08-12T12:10:00.000Z', NULL, NULL);
|
|
INSERT INTO pairing_claim_attempts VALUES
|
|
('pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', '2026-08-12T11:59:00.000Z');
|
|
`);
|
|
const query = db.prepare(OWNED_PAIRING_PROGRESS_SQL);
|
|
assert.equal(
|
|
query.get("pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "acct_a").status,
|
|
"waiting",
|
|
);
|
|
assert.equal(
|
|
query.get("pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "acct_a")
|
|
.last_claim_attempt_at,
|
|
"2026-08-12T11:59:00.000Z",
|
|
);
|
|
assert.equal(
|
|
query.get("pair_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "acct_b"),
|
|
undefined,
|
|
);
|
|
db.close();
|
|
});
|
|
|
|
test("polls the owner-only no-store endpoint and clears one-time state at a terminal result", async () => {
|
|
const [route, repository, form, stateModel, plan] = await Promise.all([
|
|
readFile(new URL("../app/api/hosts/pairing/route.ts", import.meta.url), "utf8"),
|
|
readFile(new URL("../db/repository.ts", import.meta.url), "utf8"),
|
|
readFile(new URL("../app/dashboard/hosts/new/PairingForm.tsx", import.meta.url), "utf8"),
|
|
readFile(new URL("../docs/state-model.md", import.meta.url), "utf8"),
|
|
readFile(new URL("../docs/implementation-plan.md", import.meta.url), "utf8"),
|
|
]);
|
|
assert.match(route, /export async function GET/);
|
|
assert.match(route, /getCloudViewer/);
|
|
assert.match(route, /getOwnedPairingProgress/);
|
|
assert.match(route, /cache-control": "no-store/);
|
|
assert.match(repository, /OWNED_PAIRING_PROGRESS_SQL/);
|
|
assert.match(form, /pairing_id=\$\{encodeURIComponent\(pairingId!\)\}/);
|
|
assert.match(form, /\{ cache: "no-store" \}/);
|
|
assert.match(form, /window\.setTimeout\(poll, 2_000\)/);
|
|
assert.match(form, /Cloud 已收到请求,但尚未认领/);
|
|
assert.match(form, /尚未收到注册请求/);
|
|
assert.match(form, /当前码有效时无需反复生成/);
|
|
assert.match(form, /setCompletion[\s\S]*setPairing\(null\)/);
|
|
assert.match(form, /一次性配对码已经从页面状态中清除/);
|
|
assert.match(stateModel, /账户所有者可以轮询自己创建的配对状态/);
|
|
assert.match(plan, /自动确认认领、过期、锁定或取消/);
|
|
});
|