03ecc9e29a
- Settings → About → "Start AgentHub automatically" (AutostartSettings.tsx,
GET/PUT /api/settings/autostart, server/lib/autostart.js). The switch is
the systemd --user unit's / LaunchAgent's enabled state: on writes a unit
for the running server when none exists and enables it, off disables it;
neither starts or stops the server. A foreign unit is never touched
(409 EFOREIGN)
- The plugin bootstrap no longer installs a unit on every install: it
installs or starts one only while the user has it enabled, and a rewrite
keeps the enabled state (writeUserService({ enable })). An install that
already had the unit enabled stays on. A stale-but-enabled unit beside a
live detached server is repointed, no longer started onto the bound port
- unitIsEnabled / setUnitEnabled in systemd-service.js and launchd-service.js
Also:
- fix(workspace): status bar no longer covers the chat box below md (#61)
104 lines
3.8 KiB
JavaScript
104 lines
3.8 KiB
JavaScript
/**
|
|
* @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ĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
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);
|
|
});
|
|
});
|