Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91e9d77f46 |
No files matched your search
@@ -0,0 +1,150 @@
|
|||||||
|
// @vitest-environment node
|
||||||
|
|
||||||
|
import { Response } from "undici";
|
||||||
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.hoisted(() => {
|
||||||
|
process.env.CI = "true";
|
||||||
|
process.env.NODE_ENV = "test";
|
||||||
|
process.env.SECRET_ENCRYPTION_KEY = "0".repeat(64);
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock("@homarr/core/infrastructure/http", () => ({
|
||||||
|
fetchWithTrustedCertificatesAsync: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@homarr/core/infrastructure/logs", () => ({
|
||||||
|
createLogger: () => ({
|
||||||
|
debug: vi.fn(),
|
||||||
|
info: vi.fn(),
|
||||||
|
warn: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||||
|
|
||||||
|
import type { IntegrationSecret } from "../../base/types";
|
||||||
|
import { UnraidIntegration } from "../unraid-integration";
|
||||||
|
|
||||||
|
const TEST_URL = "https://unraid.example.com";
|
||||||
|
const mockFetch = vi.mocked(fetchWithTrustedCertificatesAsync);
|
||||||
|
|
||||||
|
const createIntegration = (secrets: IntegrationSecret[] = []) =>
|
||||||
|
new UnraidIntegration({
|
||||||
|
id: "test-unraid",
|
||||||
|
name: "Test Unraid",
|
||||||
|
url: TEST_URL,
|
||||||
|
externalUrl: null,
|
||||||
|
decryptedSecrets: secrets.length ? secrets : [{ kind: "apiKey", value: "secret-api-key" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const graphqlResponse = (data: unknown) => ({
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockGraphQL = (data: unknown) => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
new Response(JSON.stringify(graphqlResponse(data)), {
|
||||||
|
status: 200,
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GiB = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
const systemInfoResponse = {
|
||||||
|
metrics: {
|
||||||
|
cpu: {
|
||||||
|
percentTotal: 10,
|
||||||
|
cpus: [{ percentTotal: 10 }, { percentTotal: 10 }],
|
||||||
|
},
|
||||||
|
memory: {
|
||||||
|
available: 20 * GiB,
|
||||||
|
used: 12 * GiB,
|
||||||
|
free: 10 * GiB,
|
||||||
|
total: 32 * GiB,
|
||||||
|
percentTotal: 37.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
array: {
|
||||||
|
state: "STARTED",
|
||||||
|
capacity: {
|
||||||
|
disks: {
|
||||||
|
free: 100,
|
||||||
|
total: 200,
|
||||||
|
used: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
disks: [
|
||||||
|
{
|
||||||
|
name: "disk1",
|
||||||
|
size: 200 * 1024 * 1024,
|
||||||
|
fsFree: 100 * 1024 * 1024,
|
||||||
|
fsUsed: 100 * 1024 * 1024,
|
||||||
|
status: "DISK_OK",
|
||||||
|
temp: 38,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
devices: {
|
||||||
|
network: [
|
||||||
|
{
|
||||||
|
speed: 1000,
|
||||||
|
dhcp: true,
|
||||||
|
model: "eth0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
os: {
|
||||||
|
platform: "linux",
|
||||||
|
distro: "Unraid",
|
||||||
|
release: "7.3.2",
|
||||||
|
uptime: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
cpu: {
|
||||||
|
manufacturer: "Intel",
|
||||||
|
brand: "Intel Core i5",
|
||||||
|
cores: 4,
|
||||||
|
threads: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("UnraidIntegration", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("computes used memory from metrics.memory.total - available instead of layout sizes", async () => {
|
||||||
|
mockGraphQL(systemInfoResponse);
|
||||||
|
const integration = createIntegration();
|
||||||
|
|
||||||
|
const result = await integration.getSystemInfoAsync();
|
||||||
|
|
||||||
|
expect(result.memUsedInBytes).toBe(12 * GiB);
|
||||||
|
expect(result.memAvailableInBytes).toBe(20 * GiB);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("never reports negative used memory when available exceeds total", async () => {
|
||||||
|
mockGraphQL({
|
||||||
|
...systemInfoResponse,
|
||||||
|
metrics: {
|
||||||
|
...systemInfoResponse.metrics,
|
||||||
|
memory: {
|
||||||
|
...systemInfoResponse.metrics.memory,
|
||||||
|
available: 40 * GiB,
|
||||||
|
total: 32 * GiB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const integration = createIntegration();
|
||||||
|
|
||||||
|
const result = await integration.getSystemInfoAsync();
|
||||||
|
|
||||||
|
expect(result.memUsedInBytes).toBe(0);
|
||||||
|
expect(result.memAvailableInBytes).toBe(32 * GiB);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -47,8 +47,12 @@ export class UnraidIntegration extends Integration implements ISystemHealthMonit
|
|||||||
cpuUtilizationNormalized = cpuUtilization / cpuCount;
|
cpuUtilizationNormalized = cpuUtilization / cpuCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalMemory = systemInfo.info.memory.layout.reduce((acc, layout) => layout.size + acc, 0);
|
// metrics.memory.* is documented as bytes (see MemoryUtilization schema), unlike
|
||||||
const usedMemory = totalMemory * (systemInfo.metrics.memory.percentTotal / 100);
|
// info.memory.layout[].size, which can be reported in KiB on some Unraid versions and caused a
|
||||||
|
// 1024x under-reporting of used RAM. total - available matches Unraid's percentTotal calculation.
|
||||||
|
|
||||||
|
const totalMemory = systemInfo.metrics.memory.total;
|
||||||
|
const usedMemory = Math.max(totalMemory - systemInfo.metrics.memory.available, 0);
|
||||||
const uptime = dayjs(systemInfo.info.os.uptime);
|
const uptime = dayjs(systemInfo.info.os.uptime);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -143,11 +147,6 @@ export class UnraidIntegration extends Integration implements ISystemHealthMonit
|
|||||||
brand,
|
brand,
|
||||||
cores,
|
cores,
|
||||||
threads
|
threads
|
||||||
},
|
|
||||||
memory {
|
|
||||||
layout {
|
|
||||||
size
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,13 +60,6 @@ export const unraidSystemInfoSchema = z.object({
|
|||||||
cores: z.number(),
|
cores: z.number(),
|
||||||
threads: z.number(),
|
threads: z.number(),
|
||||||
}),
|
}),
|
||||||
memory: z.object({
|
|
||||||
layout: z.array(
|
|
||||||
z.object({
|
|
||||||
size: z.number(),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user