Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
onDiagnosticEvent,
resetDiagnosticEventsForTest,
type DiagnosticEventPayload,
} from "../infra/diagnostic-events.js";
import { emitDiagnosticMemorySample, resetDiagnosticMemoryForTest } from "./diagnostic-memory.js";
function memoryUsage(overrides: Partial<NodeJS.MemoryUsage>): NodeJS.MemoryUsage {
return {
rss: 100,
heapTotal: 80,
heapUsed: 40,
external: 10,
arrayBuffers: 5,
...overrides,
};
}
describe("diagnostic memory", () => {
beforeEach(() => {
resetDiagnosticEventsForTest();
resetDiagnosticMemoryForTest();
});
afterEach(() => {
resetDiagnosticEventsForTest();
resetDiagnosticMemoryForTest();
});
it("emits memory samples with byte counts", () => {
const events: DiagnosticEventPayload[] = [];
const stop = onDiagnosticEvent((event) => events.push(event));
emitDiagnosticMemorySample({
now: 1000,
uptimeMs: 123,
memoryUsage: memoryUsage({ rss: 4096, heapUsed: 1024 }),
});
stop();
expect(events).toMatchObject([
{
type: "diagnostic.memory.sample",
uptimeMs: 123,
memory: {
rssBytes: 4096,
heapUsedBytes: 1024,
},
},
]);
});
it("emits pressure when RSS crosses a threshold", () => {
const events: DiagnosticEventPayload[] = [];
const stop = onDiagnosticEvent((event) => events.push(event));
emitDiagnosticMemorySample({
now: 1000,
memoryUsage: memoryUsage({ rss: 2000 }),
thresholds: {
rssWarningBytes: 1000,
rssCriticalBytes: 3000,
pressureRepeatMs: 60_000,
},
});
stop();
expect(events).toContainEqual(
expect.objectContaining({
type: "diagnostic.memory.pressure",
level: "warning",
reason: "rss_threshold",
thresholdBytes: 1000,
}),
);
});
it("can check pressure without recording an idle memory sample", () => {
const events: DiagnosticEventPayload[] = [];
const stop = onDiagnosticEvent((event) => events.push(event));
emitDiagnosticMemorySample({
now: 1000,
emitSample: false,
memoryUsage: memoryUsage({ rss: 2000 }),
thresholds: {
rssWarningBytes: 1000,
rssCriticalBytes: 3000,
pressureRepeatMs: 60_000,
},
});
stop();
expect(events.map((event) => event.type)).toEqual(["diagnostic.memory.pressure"]);
});
it("emits pressure when RSS grows quickly", () => {
const events: DiagnosticEventPayload[] = [];
const stop = onDiagnosticEvent((event) => events.push(event));
emitDiagnosticMemorySample({
now: 1000,
memoryUsage: memoryUsage({ rss: 1000 }),
thresholds: {
rssWarningBytes: 10_000,
heapUsedWarningBytes: 10_000,
rssGrowthWarningBytes: 500,
growthWindowMs: 10_000,
},
});
emitDiagnosticMemorySample({
now: 2000,
memoryUsage: memoryUsage({ rss: 1700 }),
thresholds: {
rssWarningBytes: 10_000,
heapUsedWarningBytes: 10_000,
rssGrowthWarningBytes: 500,
growthWindowMs: 10_000,
},
});
stop();
expect(events).toContainEqual(
expect.objectContaining({
type: "diagnostic.memory.pressure",
level: "warning",
reason: "rss_growth",
rssGrowthBytes: 700,
windowMs: 1000,
}),
);
});
it("throttles repeated pressure events by reason and level", () => {
const events: DiagnosticEventPayload[] = [];
const stop = onDiagnosticEvent((event) => events.push(event));
for (const now of [1000, 2000]) {
emitDiagnosticMemorySample({
now,
memoryUsage: memoryUsage({ rss: 2000 }),
thresholds: {
rssWarningBytes: 1000,
rssCriticalBytes: 3000,
pressureRepeatMs: 60_000,
},
});
}
stop();
expect(events.filter((event) => event.type === "diagnostic.memory.pressure")).toHaveLength(1);
});
});
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland
|
|