/** * @file host-stats.test.js * @description Tests for server/lib/host-stats.js — the Server tab's hardware * snapshot and per-user CPU/memory attribution (`GET /api/host`). * @author Nguyễn Ngọc Trí Vĩ */ const { test } = require("node:test"); const assert = require("node:assert/strict"); const { hostStats, mountOf, __setDeps } = require("../lib/host-stats"); const linux = process.platform === "linux"; test("mountOf picks the longest mount point holding the path", () => { const list = [{ mount: "/" }, { mount: "/srv" }, { mount: "/srv/users" }]; assert.equal(mountOf(list, "/srv/users/alice"), "/srv/users"); assert.equal(mountOf(list, "/srv/usersx"), "/srv"); assert.equal(mountOf(list, "/home/x"), "/"); assert.equal(mountOf(list, null), null); }); test("hostStats reports hardware and attributes processes by uid", { skip: !linux }, async () => { const me = process.getuid(); __setDeps({ users: () => [ { id: 7, username: "zed" }, { id: 8, username: "idle" }, ], memberNameForUid: (uid) => (uid === me ? "zed" : null), laneOwner: () => null, homesRoot: () => "/", wait: () => new Promise((r) => setTimeout(r, 20)), }); const r = await hostStats(); assert.ok(r.cpu.cores > 0); assert.ok(r.memory.total > 0 && r.memory.used >= 0); assert.ok(Array.isArray(r.disks)); const zed = r.usage.groups.find((g) => g.key === "user:7"); assert.ok(zed.processes > 0, "this test's own process belongs to zed"); assert.ok(zed.memory > 0); assert.ok(zed.top.every((t) => typeof t.name === "string" && !("argv" in t))); const idle = r.usage.groups.find((g) => g.key === "user:8"); assert.deepEqual([idle.cpu, idle.memory, idle.processes], [0, 0, 0]); assert.equal( r.usage.groups.find((g) => g.key === "host"), undefined ); }); test( "a host process with a workspace's AGENTHUB_LANE_ID counts for its owner", { skip: !linux }, async () => { const { spawn } = require("node:child_process"); const child = spawn("sleep", ["5"], { env: { ...process.env, AGENTHUB_LANE_ID: "4242" } }); try { __setDeps({ users: () => [{ id: 3, username: "own" }], memberNameForUid: () => null, laneOwner: (id) => (id === 4242 ? 3 : null), wait: () => new Promise((r) => setTimeout(r, 20)), }); const r = await hostStats(); const own = r.usage.groups.find((g) => g.key === "user:3"); assert.ok(own.top.some((t) => t.pid === child.pid)); } finally { child.kill(); } } );