/** * @file Tests server/lib/autostart.js (Settings → About's "Start AgentHub * automatically"): off by default, on writes + enables a unit for this server * without starting it, off disables without stopping, and a foreign unit is * never touched. Also the bootstrap's half: `writeUserService({enable:false})` * leaves the enabled state alone. systemctl is faked; HOME is a temp dir. * @author Nguyễn Ngọc Trí Vĩ */ const { describe, it, beforeEach, after } = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const TMP_HOME = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-autostart-")); const prevHome = process.env.HOME; process.env.HOME = TMP_HOME; const svc = require("../../scripts/systemd-service"); const autostart = require("../lib/autostart"); svc.enableLinger = () => true; // the real one runs loginctl, outside the seam let calls = []; let enabled = false; beforeEach(() => { calls = []; enabled = false; fs.rmSync(svc.unitPath("agenthub"), { force: true }); svc.__setExecImpl((args) => { if (args[0] === "--version") return { status: 0 }; calls.push(args.join(" ")); if (args[0] === "is-enabled") return { status: 0, stdout: enabled ? "enabled\n" : "disabled\n" }; if (args[0] === "enable") enabled = true; if (args[0] === "disable") enabled = false; return { status: 0 }; }); }); after(() => { svc.__reset(); if (prevHome === undefined) delete process.env.HOME; else process.env.HOME = prevHome; fs.rmSync(TMP_HOME, { recursive: true, force: true }); }); const linuxOnly = { skip: process.platform !== "linux" ? "systemd is Linux-only" : false }; const startsOrStops = (c) => /^(start|stop|restart)\b|--now/.test(c); describe("autostart", linuxOnly, () => { it("is off with no unit, and turning it off writes nothing", () => { assert.equal(autostart.status().enabled, false); autostart.setEnabled(false); assert.equal(fs.existsSync(svc.unitPath("agenthub")), false); }); it("on writes a unit for this server and enables it, starting nothing", () => { const res = autostart.setEnabled(true); assert.equal(res.enabled, true); const body = fs.readFileSync(svc.unitPath("agenthub"), "utf8"); assert.match( body, new RegExp(`^WorkingDirectory=${path.resolve(__dirname, "..", "..")}$`, "m") ); assert.ok(calls.includes("enable agenthub.service")); assert.ok(!calls.some(startsOrStops), JSON.stringify(calls)); }); it("off disables our unit and keeps it, stopping nothing", () => { autostart.setEnabled(true); calls = []; const res = autostart.setEnabled(false); assert.equal(res.enabled, false); assert.ok(calls.includes("disable agenthub.service")); assert.ok(!calls.some(startsOrStops), JSON.stringify(calls)); assert.ok(fs.existsSync(svc.unitPath("agenthub"))); }); it("refuses a unit it did not write", () => { fs.mkdirSync(path.dirname(svc.unitPath("agenthub")), { recursive: true }); fs.writeFileSync(svc.unitPath("agenthub"), "[Service]\nExecStart=/opt/mine\n", "utf8"); assert.equal(autostart.status().foreign, true); assert.throws(() => autostart.setEnabled(true), { code: "EFOREIGN" }); assert.equal( fs.readFileSync(svc.unitPath("agenthub"), "utf8"), "[Service]\nExecStart=/opt/mine\n" ); }); it("writeUserService({enable:false}) repoints without enabling — the bootstrap's off path", () => { svc.writeUserService({ name: "agenthub", description: "x", workingDir: "/plugin/root", execStart: "/usr/bin/node /plugin/root/server/index.js", enable: false, }); assert.ok(!calls.some((c) => c.startsWith("enable")), JSON.stringify(calls)); assert.equal(svc.unitIsEnabled("agenthub"), false); }); });