import { beforeEach, test } from "node:test"; import assert from "node:assert/strict"; import path from "node:path"; import { tmpdir } from "node:os"; import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { blockDeviceName, detectLocationHealth, minCounterIntervalMs, resetHealthDetector, } from "./storageVolumes"; import { applyHealthTimings, countersVerdict, parseBlockStat } from "./storageHealth"; // Run with: // pnpm --filter yt-dlp-transcript-common exec tsx --test lib/storageHealthCounters.test.ts // // THE COUNTERS DETECTOR. No test stalls a real drive: findmnt is a fake that // names a device, and /sys/class/block is a temp directory whose `stat` files // the test writes — a stalled device is one whose in-flight count stays up // while its completions stand still. beforeEach(() => { resetHealthDetector(); applyHealthTimings(); }); // A real line from this machine's /sys/class/block//stat (17 fields). const LINE = "368126412 135952867 36463191157 80435430 29670281 46781260 4001255365 167469727 0 44151394 253218297 877589 0 861936568 4100450 578669 1212688"; test("the stat line: reads + writes (+ discards + flushes) completed, and requests in flight", () => { // Fields 1, 5, 12 and 16 completed; field 9 in flight. assert.deepEqual(parseBlockStat(LINE), { completed: 368126412 + 29670281 + 877589 + 578669, inFlight: 0, }); // A long flush alone moves completions: not a stall. const before = parseBlockStat("10 0 0 0 5 0 0 0 1 0 0 0 0 0 0 7 0"); const after = parseBlockStat("10 0 0 0 5 0 0 0 1 0 0 0 0 0 0 8 0"); assert.equal(countersVerdict(before!, after!), "ok"); // An 11-field line from an older kernel parses the same way. assert.deepEqual(parseBlockStat("10 0 0 0 5 0 0 0 3 0 0\n"), { completed: 15, inFlight: 3 }); assert.equal(parseBlockStat(""), null); assert.equal(parseBlockStat("1 2 3"), null); assert.equal(parseBlockStat("a b c d e f g h i"), null); }); test("the verdict over a pair of samples", () => { const s = (completed: number, inFlight: number) => ({ completed, inFlight }); // In flight at both, nothing completed between: stalled. assert.equal(countersVerdict(s(100, 2), s(100, 5)), "stalled"); // Completions moved: slow, perhaps, but answering. assert.equal(countersVerdict(s(100, 2), s(101, 2)), "ok"); // Nothing in flight at either end: idle. assert.equal(countersVerdict(s(100, 0), s(100, 0)), "ok"); assert.equal(countersVerdict(s(100, 0), s(100, 4)), "ok"); assert.equal(countersVerdict(s(100, 4), s(100, 0)), "ok"); }); test("a mount source's device name: a partition, a bind or subvolume suffix, nothing that is not /dev", async () => { assert.equal(await blockDeviceName("/dev/no-such-disk1"), "no-such-disk1"); assert.equal(await blockDeviceName("/dev/no-such-disk2[/@home]"), "no-such-disk2"); assert.equal(await blockDeviceName("tmpfs"), null); assert.equal(await blockDeviceName("server:/export"), null); assert.equal(await blockDeviceName(""), null); }); // ── the detector end to end, with a fake findmnt and a fake /sys ──────────── const FAKE_FINDMNT = `#!/usr/bin/env node import { readFileSync } from "node:fs"; import path from "node:path"; const c = JSON.parse(readFileSync(path.join(import.meta.dirname, "control.json"), "utf8")); if (c.sleepMs) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, c.sleepMs); if (c.exit) process.exit(c.exit); process.stdout.write(JSON.stringify({ filesystems: [{ source: c.source, uuid: c.uuid ?? null }] }) + "\\n"); `; type H = { root: string; bins: { findmntBin: string }; sys: string; control: (c: Record) => Promise; counters: (device: string, completed: number, inFlight: number) => Promise; }; async function withHarness(fn: (h: H) => Promise): Promise { const dir = await mkdtemp(path.join(tmpdir(), "ttb-counters-")); try { const bin = path.join(dir, "fake-findmnt.mjs"); await writeFile(bin, FAKE_FINDMNT); await chmod(bin, 0o755); const root = path.join(dir, "media"); await mkdir(root); const sys = path.join(dir, "sys-block"); await fn({ root, bins: { findmntBin: bin }, sys, control: (c) => writeFile(path.join(dir, "control.json"), JSON.stringify(c)), counters: async (device, completed, inFlight) => { await mkdir(path.join(sys, device), { recursive: true }); // Reads `completed`, writes 0, in flight `inFlight`, the rest zero. await writeFile( path.join(sys, device, "stat"), `${completed} 0 0 0 0 0 0 0 ${inFlight} 0 0 0 0 0 0 0 0\n`, ); }, }); } finally { await rm(dir, { recursive: true, force: true }); } } const loc = (root: string, uuid?: string) => ({ id: "usb", root, ...(uuid ? { volume: { uuid, mountpoint: root, relPath: "" } } : {}), }); test("counters: first sample no verdict; stuck → stalled; two clean samples; each pass apart", async () => { await withHarness(async (h) => { await h.control({ source: "/dev/fakedisk1", uuid: "u-1" }); const at = (i: number) => ({ sysBlockDir: h.sys, now: i * 15_000 }); await h.counters("fakedisk1", 100, 2); assert.deepEqual(await detectLocationHealth(loc(h.root, "u-1"), h.bins, at(1)), { answer: null, detector: "counters", device: "fakedisk1", }); // Still two in flight, nothing completed in 15 s. await h.counters("fakedisk1", 100, 2); const stuck = await detectLocationHealth(loc(h.root, "u-1"), h.bins, at(2)); assert.equal(stuck.answer, "stalled"); assert.equal(stuck.detector, "counters"); assert.match(String(stuck.cause), /^its disk \(fakedisk1\) had 2 request\(s\) in flight and completed none in 15 s$/); // It drains: nothing in flight. await h.counters("fakedisk1", 140, 0); assert.equal((await detectLocationHealth(loc(h.root, "u-1"), h.bins, at(3))).answer, "ok"); // Busy and moving: still ok. await h.counters("fakedisk1", 190, 3); assert.equal((await detectLocationHealth(loc(h.root, "u-1"), h.bins, at(4))).answer, "ok"); }); }); test("counters: a second sample sooner than the minimum interval gives no verdict and keeps the first", async () => { await withHarness(async (h) => { await h.control({ source: "/dev/fakedisk1" }); await h.counters("fakedisk1", 100, 2); await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 0 }); const soon = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: minCounterIntervalMs() - 1, }); assert.equal(minCounterIntervalMs(), 10_000); assert.equal(soon.answer, null); // Compared with the FIRST sample, not the refused one. const later = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 15_000, }); assert.equal(later.answer, "stalled"); }); }); test("counters: the minimum spacing follows the pass interval (storage.health.passIntervalMs)", async () => { await withHarness(async (h) => { await h.control({ source: "/dev/fakedisk1" }); await h.counters("fakedisk1", 100, 2); // A pass every 8 s: samples 4 s apart are compared (8 − 5 = 3 s, floored // at half the interval), which the default 15 s pass would refuse. applyHealthTimings({ passIntervalMs: 8_000 }); assert.equal(minCounterIntervalMs(), 4_000); await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 0 }); const early = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 3_999, }); assert.equal(early.answer, null); const due = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 4_000, }); assert.equal(due.answer, "stalled"); // A pass every 5 minutes: 10 s, as at the default. applyHealthTimings({ passIntervalMs: 300_000 }); assert.equal(minCounterIntervalMs(), 10_000); }); }); test("no device → the child stat, and the verdict says so", async () => { await withHarness(async (h) => { const opts = { sysBlockDir: h.sys, now: 0 }; // A tmpfs or network source names no block device. await h.control({ source: "tmpfs" }); assert.deepEqual(await detectLocationHealth(loc(h.root), h.bins, opts), { answer: "ok", detector: "stat", }); // findmnt cannot say (no such path, a container without it). await h.control({ exit: 1 }); assert.equal((await detectLocationHealth(loc(h.root), h.bins, opts)).detector, "stat"); assert.equal( (await detectLocationHealth(loc(path.join(h.root, "gone")), h.bins, opts)).answer, "absent", ); // A device with no /sys entry. await h.control({ source: "/dev/nodisk9" }); assert.equal((await detectLocationHealth(loc(h.root), h.bins, opts)).detector, "stat"); // A root whose filesystem is not the location's recorded volume. await h.counters("fakedisk1", 1, 0); await h.control({ source: "/dev/fakedisk1", uuid: "someone-else" }); assert.equal( (await detectLocationHealth(loc(h.root, "u-1"), h.bins, opts)).detector, "stat", ); // No findmnt binary at all. assert.equal( ( await detectLocationHealth( loc(h.root), { findmntBin: path.join(h.root, "no-findmnt") }, opts, ) ).detector, "stat", ); }); }); test("a device already named is read without findmnt; findmnt again only when its /sys entry stops reading", async () => { await withHarness(async (h) => { await h.control({ source: "/dev/fakedisk1" }); await h.counters("fakedisk1", 100, 2); await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 0 }); // findmnt now hangs: it is not asked, the known device is read. await h.control({ sleepMs: 5_000, source: "/dev/fakedisk1" }); const started = Date.now(); const v = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 15_000, timeoutMs: 300, }); assert.ok(Date.now() - started < 250, "no findmnt was run"); assert.equal(v.detector, "counters"); assert.equal(v.answer, "stalled"); // The device is gone from /sys (replugged under another name): findmnt is // asked again — here it does not answer, so no device, and the child stat. await rm(path.join(h.sys, "fakedisk1"), { recursive: true }); const again = await detectLocationHealth(loc(h.root), h.bins, { sysBlockDir: h.sys, now: 30_000, timeoutMs: 300, }); assert.equal(again.detector, "stat"); // The detector's samples are on globalThis (the pass and a Refresh run in // different module copies and compare against one previous sample). assert.ok(globalThis.__yttHealthDetector__); }); });