tests/urgency.test.js
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: GPL-3.0-or-later
/**
* Urgency is not severity.
*
* Severity says how bad a finding is; urgency says whether a human has to act
* on it now. Feedback that started this (Mastodon, @netappblackbox): "a RAID
* scrub summary or one corrected media error is routine, a broken disk with no
* spare is a 3am call... grade by 'does this need a human in the next hour',
* not by distance from normal, otherwise everything reads critical and people
* stop looking."
*
* So: the set is explicit (a code joins it after review, never because its
* severity happens to be high), an unknown code can never be "now", and the
* report shows the whole set instead of one action. The score is untouched.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { urgencyOf, needsYouNow } from "../src/severities.js";
import { renderReport, renderTodo } from "../src/report.js";
const f = (code, severity, extra = {}) => ({ id: 1, check: code.split("/")[0], code, severity, title: `${code} (${severity})`, detail: null, evidence: null, fix: `fix ${code}`, ...extra });
test("urgency: data-loss grades are 'now'", () => {
assert.equal(urgencyOf(f("raid/degraded", "high")), "now");
assert.equal(urgencyOf(f("disk/full", "high")), "now");
assert.equal(urgencyOf(f("smart/failing", "high")), "now");
assert.equal(urgencyOf(f("hardware/ecc", "high")), "now", "an uncorrected error is data loss");
});
test("urgency: the same code one grade down is 'watch', not 'now'", () => {
assert.equal(urgencyOf(f("disk/full", "medium")), "watch", "90% full is this week, not this hour");
assert.equal(urgencyOf(f("hardware/ecc", "medium")), "watch", "repeated corrected errors are a watch item");
assert.equal(urgencyOf(f("hardware/ecc", "info")), "fyi", "one corrected error is routine");
});
test("urgency: informational findings are never urgent", () => {
assert.equal(urgencyOf(f("updates/pending", "info")), "fyi");
assert.equal(urgencyOf(f("flatpak/pending", "info")), "fyi");
});
test("urgency: an unknown (plugin) code is never 'now'", () => {
// The safety property: "now" is opt-in per code. A finding from a plugin,
// however alarming its own wording, cannot claim a deadline this project
// never reviewed for it.
assert.equal(urgencyOf(f("myplugin/whatever", "high")), "watch");
assert.equal(urgencyOf(f("raid/scrub-stuck", "high")), "watch");
});
test("urgency: a certificate with days left is a deadline, not 'next hour'", () => {
// The cost of an expiring cert is a step at expiry, not a slope now: seven
// days out you schedule the renewal, you do not drop what you are doing. It
// is a watch item with a date, and the finding text carries the date.
assert.equal(urgencyOf(f("certs/critical", "high")), "watch");
});
test("urgency: --todo puts the 'now' set first, whatever order it arrived in", () => {
const findings = [
f("certs/critical", "high"), // arrives first in report order, but has a date
f("disk/full", "high"), // a deadline now
f("services/failed", "medium"),
];
const lines = renderTodo(findings)
.split("\n")
.filter((l) => /^\d+\./.test(l));
assert.match(lines[0], /disk\/full/, `first step should be the urgent one, got: ${lines[0]}`);
assert.match(lines[1], /certs\/critical/);
assert.match(lines[2], /services\/failed/);
});
test("urgency: needsYouNow returns the whole set, in report order", () => {
const findings = [
f("disk/full", "high"),
f("services/failed", "medium"),
f("raid/degraded", "high"),
f("hardware/ecc", "info"),
];
assert.deepEqual(needsYouNow(findings).map((x) => x.code), ["disk/full", "raid/degraded"]);
assert.deepEqual(needsYouNow([]), []);
});
test("urgency: the report shows every 'now' finding, not just the first", async () => {
const findings = [
f("disk/full", "high", { fix: "Free space." }),
f("raid/degraded", "high", { fix: "Replace the disk." }),
f("updates/pending", "medium"),
];
const report = await renderReport(findings, {
system: { distro: "Bazzite 44", kernel: "6.1.0", cores: 8, uptime: "1h" },
score: 62,
});
assert.match(report, /NEEDS YOU NOW/);
assert.match(report, /#1 disk\/full \(high\)/);
assert.match(report, /#2 raid\/degraded \(high\)/);
});
test("urgency: a single 'now' finding needs no second callout (START HERE covers it)", async () => {
const findings = [f("disk/full", "high", { fix: "Free space." }), f("updates/pending", "medium")];
const report = await renderReport(findings, {
system: { distro: "Bazzite 44", kernel: "6.1.0", cores: 8, uptime: "1h" },
score: 77,
});
assert.match(report, /START HERE/);
assert.ok(!/NEEDS YOU NOW/.test(report), "one finding is already the START HERE line");
});
test("urgency: changing urgency never changes the score", async () => {
// The score is the run-over-run memory; urgency must not re-grade it.
const findings = [f("raid/degraded", "high", { severity: "high", code: "raid/degraded" })];
const report = await renderReport(findings, {
system: { distro: "x", kernel: "y", cores: 1, uptime: "0h" },
score: 85,
scoreBreakdown: [{ code: "raid/degraded", severity: "high", title: "raid", penalty: 15 }],
});
assert.match(report, /health 85\/100/);
assert.match(report, /85\/100 = 100 −15 raid\/degraded/);
});