222 lines
7.4 KiB
JavaScript
222 lines
7.4 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createHash } from "node:crypto";
|
|
import { createServer } from "node:http";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
|
|
import {
|
|
applyBossAgentOtaUpdate,
|
|
checkBossAgentOtaUpdate,
|
|
getBossAgentOtaRunnerConfig,
|
|
} from "../local-agent/boss-agent-ota-runner.mjs";
|
|
|
|
function listen(server, host = "127.0.0.1") {
|
|
return new Promise((resolve, reject) => {
|
|
server.once("error", reject);
|
|
server.listen(0, host, () => {
|
|
server.off("error", reject);
|
|
resolve(server.address().port);
|
|
});
|
|
});
|
|
}
|
|
|
|
function sha256(buffer) {
|
|
return createHash("sha256").update(buffer).digest("hex");
|
|
}
|
|
|
|
test("boss-agent ota runner derives config from local-agent config", () => {
|
|
const config = getBossAgentOtaRunnerConfig({}, {
|
|
bossAgentOtaEnabled: true,
|
|
bossAgentVersion: "20260516194026",
|
|
bossAgentInstallRoot: "/tmp/boss-agent/current",
|
|
bossAgentOtaDownloadDir: "/tmp/boss-agent/updates",
|
|
bossAgentOtaCheckIntervalMs: 12345,
|
|
bossAgentOtaAutoInstall: true,
|
|
});
|
|
|
|
assert.equal(config.enabled, true);
|
|
assert.equal(config.currentVersion, "20260516194026");
|
|
assert.equal(config.installRoot, "/tmp/boss-agent/current");
|
|
assert.equal(config.downloadDir, "/tmp/boss-agent/updates");
|
|
assert.equal(config.checkIntervalMs, 12345);
|
|
assert.equal(config.autoInstall, true);
|
|
});
|
|
|
|
test("boss-agent ota runner checks, downloads, verifies, and stages a mac runtime package", async () => {
|
|
const tmp = await mkdtemp(path.join(os.tmpdir(), "boss-agent-ota-runner-"));
|
|
const packageBuffer = Buffer.from("boss-agent mac runtime zip", "utf8");
|
|
const packageHash = sha256(packageBuffer);
|
|
const requestLog = [];
|
|
|
|
const server = createServer((request, response) => {
|
|
requestLog.push({
|
|
url: request.url,
|
|
token: request.headers["x-boss-device-token"],
|
|
});
|
|
if (request.url?.startsWith("/api/v1/boss-agent/ota?")) {
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({
|
|
ok: true,
|
|
currentVersion: "20260501000000",
|
|
hasUpdate: true,
|
|
latest: {
|
|
version: "20260516194026",
|
|
fileName: "boss-agent-mac-latest.zip",
|
|
sizeBytes: packageBuffer.length,
|
|
sha256: packageHash,
|
|
downloadUrl: "/api/v1/boss-agent/ota/package",
|
|
updatedAt: "2026-05-16T11:40:26.000Z",
|
|
},
|
|
}));
|
|
return;
|
|
}
|
|
if (request.url?.startsWith("/api/v1/boss-agent/ota/package")) {
|
|
response.writeHead(200, {
|
|
"content-type": "application/zip",
|
|
"content-length": String(packageBuffer.length),
|
|
"x-boss-agent-ota-sha256": packageHash,
|
|
});
|
|
response.end(packageBuffer);
|
|
return;
|
|
}
|
|
response.writeHead(404, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ ok: false }));
|
|
});
|
|
|
|
try {
|
|
const port = await listen(server);
|
|
const localConfig = {
|
|
controlPlaneUrl: `http://127.0.0.1:${port}`,
|
|
deviceId: "mac-studio",
|
|
token: "device-token",
|
|
bossAgentOtaEnabled: true,
|
|
bossAgentVersion: "20260501000000",
|
|
bossAgentOtaDownloadDir: path.join(tmp, "updates"),
|
|
bossAgentInstallRoot: path.join(tmp, "current"),
|
|
};
|
|
const runtime = {};
|
|
|
|
const status = await checkBossAgentOtaUpdate(localConfig, runtime);
|
|
assert.equal(status.hasUpdate, true);
|
|
assert.equal(status.latest.version, "20260516194026");
|
|
assert.equal(requestLog.at(0)?.token, "device-token");
|
|
assert.match(requestLog.at(0)?.url ?? "", /deviceId=mac-studio/);
|
|
assert.match(requestLog.at(0)?.url ?? "", /currentVersion=20260501000000/);
|
|
|
|
const result = await applyBossAgentOtaUpdate(localConfig, runtime, {
|
|
launchInstaller: false,
|
|
});
|
|
assert.equal(result.status, "staged");
|
|
assert.equal(result.version, "20260516194026");
|
|
assert.equal(result.sha256, packageHash);
|
|
assert.match(result.archivePath, /boss-agent-mac-latest\.zip$/);
|
|
assert.equal(await readFile(result.archivePath, "utf8"), "boss-agent mac runtime zip");
|
|
const installInfo = await stat(path.join(result.stageDir, "install.command"));
|
|
assert.equal(installInfo.isFile(), true);
|
|
assert.equal(runtime.lastBossAgentOtaApply.status, "staged");
|
|
} finally {
|
|
server.close();
|
|
await rm(tmp, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("boss-agent ota runner reports up-to-date when latest equals current version", async () => {
|
|
const server = createServer((request, response) => {
|
|
if (request.url?.startsWith("/api/v1/boss-agent/ota?")) {
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({
|
|
ok: true,
|
|
currentVersion: "20260516201125",
|
|
hasUpdate: false,
|
|
latest: {
|
|
version: "20260516201125",
|
|
fileName: "boss-agent-mac-latest.zip",
|
|
sizeBytes: 1,
|
|
sha256: "0".repeat(64),
|
|
downloadUrl: "/api/v1/boss-agent/ota/package",
|
|
updatedAt: "2026-05-16T12:11:30.842Z",
|
|
},
|
|
}));
|
|
return;
|
|
}
|
|
response.writeHead(404);
|
|
response.end();
|
|
});
|
|
|
|
try {
|
|
const port = await listen(server);
|
|
const status = await checkBossAgentOtaUpdate(
|
|
{
|
|
controlPlaneUrl: `http://127.0.0.1:${port}`,
|
|
deviceId: "macbook-air",
|
|
token: "device-token",
|
|
bossAgentOtaEnabled: true,
|
|
bossAgentVersion: "20260516201125",
|
|
},
|
|
{},
|
|
);
|
|
|
|
assert.equal(status.hasUpdate, false);
|
|
assert.equal(status.message, "BOSS_AGENT_OTA_UP_TO_DATE");
|
|
assert.equal(status.latest.version, "20260516201125");
|
|
} finally {
|
|
server.close();
|
|
}
|
|
});
|
|
|
|
test("boss-agent ota runner rejects a package with mismatched checksum", async () => {
|
|
const tmp = await mkdtemp(path.join(os.tmpdir(), "boss-agent-ota-bad-checksum-"));
|
|
const packageBuffer = Buffer.from("tampered", "utf8");
|
|
|
|
const server = createServer((request, response) => {
|
|
if (request.url?.startsWith("/api/v1/boss-agent/ota?")) {
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({
|
|
ok: true,
|
|
currentVersion: "20260501000000",
|
|
hasUpdate: true,
|
|
latest: {
|
|
version: "20260516194026",
|
|
fileName: "boss-agent-mac-latest.zip",
|
|
sizeBytes: packageBuffer.length,
|
|
sha256: "0".repeat(64),
|
|
downloadUrl: "/api/v1/boss-agent/ota/package",
|
|
updatedAt: "2026-05-16T11:40:26.000Z",
|
|
},
|
|
}));
|
|
return;
|
|
}
|
|
if (request.url?.startsWith("/api/v1/boss-agent/ota/package")) {
|
|
response.writeHead(200, { "content-type": "application/zip" });
|
|
response.end(packageBuffer);
|
|
return;
|
|
}
|
|
response.writeHead(404);
|
|
response.end();
|
|
});
|
|
|
|
try {
|
|
const port = await listen(server);
|
|
const result = await applyBossAgentOtaUpdate(
|
|
{
|
|
controlPlaneUrl: `http://127.0.0.1:${port}`,
|
|
deviceId: "mac-studio",
|
|
token: "device-token",
|
|
bossAgentOtaEnabled: true,
|
|
bossAgentVersion: "20260501000000",
|
|
bossAgentOtaDownloadDir: path.join(tmp, "updates"),
|
|
bossAgentInstallRoot: path.join(tmp, "current"),
|
|
},
|
|
{},
|
|
{ launchInstaller: false },
|
|
);
|
|
|
|
assert.equal(result.status, "failed");
|
|
assert.equal(result.error, "BOSS_AGENT_OTA_CHECKSUM_MISMATCH");
|
|
} finally {
|
|
server.close();
|
|
await rm(tmp, { recursive: true, force: true });
|
|
}
|
|
});
|