IKHSAN
EN Read in EnglishID

homeio

Publik

Fork dari doctor-io/homeio

Branch
main
Commit terakhir
958d74616 Oktober 2026

metrics-history.test.ts

Buka raw
import { describe, expect, it, vi } from "vitest";

vi.mock("@/lib/server/modules/system/service", () => ({
  getSystemMetricsSnapshot: vi.fn(),
}));

import {
  HISTORY_SAMPLE_MS,
  createMetricsHistory,
  toHistoryPoint,
} from "@/lib/server/modules/system/metrics-history";
import type { MetricsHistoryPoint, SystemMetricsSnapshot } from "@/lib/shared/contracts/system";

const MINUTE = 60_000;
const START = Date.UTC(2026, 8, 27, 10, 0, 0);

function point(t: number, cpu: number | null, temperature: number | null = null): MetricsHistoryPoint {
  return {
    t,
    cpuPercent: cpu,
    memoryPercent: 50,
    temperatureCelsius: temperature,
    downloadMbps: 1,
    uploadMbps: 0.5,
    diskReadMBps: 2,
    diskWriteMBps: 1,
  };
}

describe("metrics history", () => {
  it("keeps one hour of 5 s samples and drops older ones", () => {
    const history = createMetricsHistory();
    const samples = (2 * 60 * 60 * 1000) / HISTORY_SAMPLE_MS;
    for (let i = 0; i < samples; i += 1) history.record(point(START + i * HISTORY_SAMPLE_MS, i % 100));

    const now = START + (samples - 1) * HISTORY_SAMPLE_MS;
    const hour = history.get("1h", now);

    expect(hour.intervalSeconds).toBe(5);
    expect(hour.points).toHaveLength(720);
    expect(hour.points[0].t).toBeGreaterThan(now - 60 * MINUTE);
    expect(hour.points.at(-1)?.t).toBe(now);
  });

  it("serves the last 15 minutes of the hour at the same 5 s resolution", () => {
    const history = createMetricsHistory();
    for (let i = 0; i < 720; i += 1) history.record(point(START + i * HISTORY_SAMPLE_MS, 1));

    const now = START + 719 * HISTORY_SAMPLE_MS;
    const quarter = history.get("15m", now);

    expect(quarter.intervalSeconds).toBe(5);
    expect(quarter.points).toHaveLength(180);
    expect(quarter.points[0].t).toBeGreaterThan(now - 15 * MINUTE);
  });

  it("averages each minute for the 24 h view and includes the minute in progress", () => {
    const history = createMetricsHistory();
    // First minute: 10, 20, 30. Second minute (in progress): 70.
    history.record(point(START, 10));
    history.record(point(START + 5_000, 20));
    history.record(point(START + 10_000, 30));
    history.record(point(START + MINUTE, 70));

    const day = history.get("24h", START + MINUTE + 1_000);

    expect(day.intervalSeconds).toBe(60);
    expect(day.points.map((p) => [p.t, p.cpuPercent])).toEqual([
      [START, 20],
      [START + MINUTE, 70],
    ]);
  });

  it("averages only the readings a host has, and keeps null when it has none", () => {
    const history = createMetricsHistory();
    history.record(point(START, null, 40));
    history.record(point(START + 5_000, 30, null));
    history.record(point(START + 10_000, 60, 50));

    const [minute] = history.get("24h", START + 20_000).points;

    expect(minute.cpuPercent).toBe(45);
    expect(minute.temperatureCelsius).toBe(45);

    const noSensor = createMetricsHistory();
    noSensor.record(point(START, 10, null));
    expect(noSensor.get("24h", START + 1_000).points[0].temperatureCelsius).toBeNull();
  });

  it("forgets minutes older than 24 hours", () => {
    const history = createMetricsHistory();
    for (let minute = 0; minute < 25 * 60; minute += 1) history.record(point(START + minute * MINUTE, 1));

    const now = START + (25 * 60 - 1) * MINUTE;
    const points = history.get("24h", now).points;

    expect(points.length).toBeLessThanOrEqual(24 * 60);
    expect(points[0].t).toBeGreaterThan(now - 24 * 60 * MINUTE);
  });

  it("maps a metrics snapshot and turns missing or invalid readings into null", () => {
    const snapshot = {
      cpu: { normalizedPercent: 12.5 },
      memory: { usedPercent: 40 },
      temperature: { mainCelsius: null },
      wifi: { downloadMbps: Number.NaN, uploadMbps: 2 },
      diskIo: { readMBps: 12, writeMBps: null },
    } as unknown as SystemMetricsSnapshot;

    expect(toHistoryPoint(snapshot, START)).toEqual({
      t: START,
      cpuPercent: 12.5,
      memoryPercent: 40,
      temperatureCelsius: null,
      downloadMbps: null,
      uploadMbps: 2,
      diskReadMBps: 12,
      diskWriteMBps: null,
    });
  });
});
byte
4.146
baris
122
Jenis
ts
Commit terakhir
16 Oktober 2026