64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { test } from "node:test";
|
|
import { type LlamaSwapConfig } from "../src/lib/util";
|
|
import { MetricsPoller } from "../src/lib/metrics-poller";
|
|
import { parseGpuMetrics } from "../src/lib/metrics-parser";
|
|
|
|
const FIXTURE = readFileSync(new URL("./fixtures/metrics.txt", import.meta.url), "utf8");
|
|
const FIXTURE2 = FIXTURE
|
|
.replace(/llamaswap_gpu_util_percent\{id="0"[^}]*\} 100/, 'llamaswap_gpu_util_percent{id="0",name="RTX PRO 6000"} 30')
|
|
.replace(/llamaswap_gpu_util_percent\{id="1"[^}]*\} 100/, 'llamaswap_gpu_util_percent{id="1",name="RTX PRO 6000"} 50')
|
|
.replace(/llamaswap_gpu_util_percent\{id="2"[^}]*\} 100/, 'llamaswap_gpu_util_percent{id="2",name="RTX 5090"} 80');
|
|
|
|
function stubFetch(bodies: string[]) {
|
|
let i = 0;
|
|
return async () => bodies[Math.min(i++, bodies.length - 1)];
|
|
}
|
|
|
|
const CFG: LlamaSwapConfig = { baseUrl: "http://test" };
|
|
|
|
test("poller stores per-GPU history and computes aggregates", async () => {
|
|
const poller = new MetricsPoller(CFG, 5000, stubFetch([FIXTURE, FIXTURE2]));
|
|
await poller.tick();
|
|
await poller.tick();
|
|
|
|
assert.equal(poller.getValue("0", "util_percent"), 30);
|
|
assert.deepEqual(poller.getHistory("0", "util_percent"), [100, 30]);
|
|
|
|
const allUtil = poller.getValue("all", "util_percent");
|
|
assert.ok(allUtil !== undefined);
|
|
assert.ok(Math.abs(allUtil - (30 + 50 + 80) / 3) < 1e-9);
|
|
|
|
const allTemp = poller.getValue("all", "temperature");
|
|
assert.equal(allTemp, 64);
|
|
|
|
const allPower = poller.getValue("all", "power");
|
|
assert.ok(allPower !== undefined);
|
|
assert.ok(Math.abs(allPower - (316.56 + 336.17 + 377.28)) < 1e-9);
|
|
|
|
assert.deepEqual(poller.gpus().map((g) => g.id), ["0", "1", "2"]);
|
|
assert.equal(poller.gpus()[2].name, "NVIDIA GeForce RTX 5090");
|
|
});
|
|
|
|
test("poller ring buffer caps at 60 samples", async () => {
|
|
const poller = new MetricsPoller(CFG, 5000, stubFetch([FIXTURE]));
|
|
for (let i = 0; i < 70; i++) await poller.tick();
|
|
assert.equal(poller.getHistory("0", "fan").length, 60);
|
|
});
|
|
|
|
test("poller reports offline after a fetch failure and recovers", async () => {
|
|
let fail = true;
|
|
const fetchFn = async () => {
|
|
if (fail) throw new Error("boom");
|
|
return FIXTURE;
|
|
};
|
|
const poller = new MetricsPoller(CFG, 5000, fetchFn);
|
|
await poller.tick();
|
|
assert.equal(poller.isOffline(), true);
|
|
fail = false;
|
|
await poller.tick();
|
|
assert.equal(poller.isOffline(), false);
|
|
assert.ok(poller.getValue("0", "util_percent") !== undefined);
|
|
});
|