test: cover runner token lifecycle

This commit is contained in:
2026-04-29 22:00:50 +00:00
parent 6ebc0d96bb
commit 0ca0d367d3
+58 -17
View File
@@ -1,5 +1,6 @@
import { assert, assertEquals, assertRejects } from "jsr:@std/assert@^1.0.0";
import { RunnerAdmin } from "../../../uptime.link/ts_api/classes/runner-admin.ts";
import { RunnerCoordinator } from "../../../uptime.link/ts_api/classes/runner-coordinator.ts";
import { RunnerFileStore } from "../../../uptime.link/ts_api/classes/runner-file-store.ts";
import {
@@ -64,9 +65,15 @@ const main = async () => {
},
];
const coordinator = new RunnerCoordinator({
runners: [{ runnerId, token: runnerToken, labels: ["scenario:basic"] }],
const coordinator = new RunnerCoordinator();
const admin = new RunnerAdmin(coordinator);
const registration = admin.registerRunner({
runnerId,
token: runnerToken,
labels: ["scenario:basic"],
});
assertEquals(registration.runner.runnerId, runnerId);
assertEquals(registration.token, runnerToken);
const scheduler = new RunnerScheduler(coordinator, { now: () => 1000 });
const scheduleResult = scheduler.scheduleDueChecks(
createRunnerSchedulesFromMonitors(monitors),
@@ -132,6 +139,12 @@ const main = async () => {
pollIntervalMs: 1000,
});
await assertRejects(() => unauthorizedRunner.runOnce(), Error, "401");
await assertRunnerTokenLifecycle(
admin,
coordinator,
coordinatorServer.url,
runner,
);
console.log(`[${scenarioName}] Passed`);
} finally {
@@ -212,26 +225,54 @@ function assertMonitorStatusDerivation(
assertEquals(ingestor.getMonitorState("manual-degraded")?.status, "degraded");
}
async function assertRunnerTokenLifecycle(
adminArg: RunnerAdmin,
coordinatorArg: RunnerCoordinator,
instanceUrlArg: string,
staleRunnerArg: UptimeRunner,
): Promise<void> {
const rotated = adminArg.rotateRunnerToken(runnerId, "rotated-token");
assertEquals(rotated.token, "rotated-token");
assertEquals(adminArg.listRunners()[0].tokenPreview, "rotate...oken");
coordinatorArg.enqueueCheck({
id: "post-rotate-assumption",
type: "assumption",
assumedStatus: "ok",
metadata: {
monitorId: "post-rotate",
},
});
await assertRejects(() => staleRunnerArg.runOnce(), Error, "401");
const rotatedRunner = new UptimeRunner({
instanceUrl: instanceUrlArg,
runnerId,
token: rotated.token,
});
const rotatedResult = await rotatedRunner.runOnce();
assertEquals(rotatedResult.results.length, 1);
assertEquals(rotatedResult.results[0].status, "ok");
adminArg.disableRunner(runnerId);
assertEquals(adminArg.listRunners()[0].enabled, false);
await assertRejects(() => rotatedRunner.runOnce(), Error, "401");
adminArg.enableRunner(runnerId);
adminArg.setRunnerLabels(runnerId, ["scenario:basic", "role:external"]);
assertEquals(
adminArg.listRunners()[0].labels.includes("role:external"),
true,
);
}
async function assertSnapshotPersistence(
coordinatorArg: RunnerCoordinator,
targetUrlArg: string,
): Promise<void> {
const snapshotPath = await Deno.makeTempFile();
const store = new RunnerFileStore({
readTextFile: async () => {
try {
return await Deno.readTextFile(snapshotPath);
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
return undefined;
}
throw error;
}
},
writeTextFile: async (contentArg) => {
await Deno.writeTextFile(snapshotPath, contentArg);
},
});
const store = RunnerFileStore.fromDenoPath(snapshotPath);
try {
await store.save(coordinatorArg.getSnapshot());