node-os-utils
Version:
Advanced cross-platform operating system monitoring utilities with TypeScript support
188 lines • 8.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const base_monitor_1 = require("../../../src/core/base-monitor");
const errors_1 = require("../../../src/types/errors");
function createAdapterStub() {
return {
getPlatform: () => 'test',
isSupported: (feature) => feature !== 'unsupported.feature',
executeCommand: async () => ({
stdout: '',
stderr: '',
exitCode: 0,
platform: 'test',
executionTime: 0,
command: ''
}),
readFile: async () => '',
fileExists: async () => true,
getCPUInfo: async () => ({}),
getCPUUsage: async () => ({ overall: 10 }),
getCPUTemperature: async () => ([]),
getMemoryInfo: async () => ({ total: 1, available: 1 }),
getMemoryUsage: async () => ({}),
getDiskInfo: async () => ({}),
getDiskIO: async () => ({}),
getNetworkInterfaces: async () => ({}),
getNetworkStats: async () => ({}),
getProcesses: async () => ({}),
getProcessInfo: async () => ({}),
getSystemInfo: async () => ({}),
getSystemLoad: async () => ({ load1: 0.1, load5: 0.2, load15: 0.3 }),
getDiskUsage: async () => ({}),
getDiskStats: async () => ({}),
getMounts: async () => ({}),
getFileSystems: async () => ({}),
getNetworkConnections: async () => ({}),
getDefaultGateway: async () => ({}),
getProcessList: async () => ({}),
killProcess: async () => true,
getProcessOpenFiles: async () => [],
getProcessEnvironment: async () => ({}),
getSystemUptime: async () => ({}),
getSystemUsers: async () => ([]),
getSystemServices: async () => ([]),
getSupportedFeatures: () => ({
cpu: { info: true, usage: true, temperature: true, frequency: true, cache: true, perCore: true, cores: true },
memory: { info: true, usage: true, swap: true, pressure: true, detailed: true, virtual: true },
disk: { info: true, io: true, health: true, smart: true, filesystem: true, usage: true, stats: true, mounts: true, filesystems: true },
network: { interfaces: true, stats: true, connections: true, bandwidth: true, gateway: true },
process: { list: true, details: true, tree: true, monitor: true, info: true, kill: true, openFiles: true, environment: true },
system: { info: true, load: true, uptime: true, users: true, services: true }
})
};
}
class TestMonitor extends base_monitor_1.BaseMonitor {
constructor(adapter) {
super(adapter, { cacheTTL: 20 });
this.callCount = 0;
}
getDefaultConfig() {
return {
cacheEnabled: true,
cacheTTL: 10
};
}
async info() {
this.callCount += 1;
return this.createSuccessResult({ value: this.callCount });
}
async cachedOperation() {
return this.executeWithCache('test', async () => {
this.callCount += 1;
return { value: this.callCount };
}, 50);
}
handleErrorPublic(error) {
return this.handleError(error);
}
validateFeature(feature) {
this.validatePlatformSupport(feature);
}
}
describe('BaseMonitor', () => {
it('executeWithCache 命中缓存时返回 cached 结果', async () => {
const monitor = new TestMonitor(createAdapterStub());
const first = await monitor.cachedOperation();
const second = await monitor.cachedOperation();
(0, chai_1.expect)(first.success).to.be.true;
if (!first.success) {
throw new Error('expected success');
}
(0, chai_1.expect)(first.cached).to.be.false;
(0, chai_1.expect)(first.data.value).to.equal(1);
(0, chai_1.expect)(second.success).to.be.true;
if (!second.success) {
throw new Error('expected success');
}
(0, chai_1.expect)(second.cached).to.be.true;
(0, chai_1.expect)(second.data.value).to.equal(first.data.value);
});
it('withCaching(false) 会禁用缓存', async () => {
const monitor = new TestMonitor(createAdapterStub());
monitor.withCaching(false);
const first = await monitor.cachedOperation();
const second = await monitor.cachedOperation();
(0, chai_1.expect)(first.success).to.be.true;
if (!first.success) {
throw new Error('expected success');
}
(0, chai_1.expect)(first.cached).to.be.false;
(0, chai_1.expect)(second.success).to.be.true;
if (!second.success) {
throw new Error('expected success');
}
(0, chai_1.expect)(second.cached).to.be.false;
(0, chai_1.expect)(second.data.value).to.equal(first.data.value + 1);
});
it('monitor 方法会触发回调并可取消订阅', async () => {
const monitor = new TestMonitor(createAdapterStub());
const values = [];
await new Promise((resolve) => {
const subscription = monitor.monitor(10, (data) => {
values.push(data.value);
subscription.unsubscribe();
resolve();
});
});
(0, chai_1.expect)(values).to.have.lengthOf(1);
(0, chai_1.expect)(monitor.getActiveSubscriptions()).to.equal(0);
});
it('handleError 会将错误包装成 MonitorError', () => {
const monitor = new TestMonitor(createAdapterStub());
monitor.on('error', () => undefined);
const result = monitor.handleErrorPublic(new Error('boom'));
(0, chai_1.expect)(result.success).to.be.false;
if (result.success) {
throw new Error('expected failure');
}
(0, chai_1.expect)(result.error).to.be.instanceOf(errors_1.MonitorError);
(0, chai_1.expect)(result.error.code).to.equal(errors_1.ErrorCode.COMMAND_FAILED);
});
it('validatePlatformSupport 在不支持的功能上抛出异常', () => {
const monitor = new TestMonitor(createAdapterStub());
(0, chai_1.expect)(() => monitor.validateFeature('unsupported.feature')).to.throw(errors_1.MonitorError);
});
it('destroy 会清理订阅与缓存', async () => {
const monitor = new TestMonitor(createAdapterStub());
await monitor.cachedOperation();
monitor.monitor(5, () => undefined);
(0, chai_1.expect)(monitor.getActiveSubscriptions()).to.equal(1);
monitor.destroy();
(0, chai_1.expect)(monitor.getActiveSubscriptions()).to.equal(0);
(0, chai_1.expect)(monitor.getCacheStats()?.size).to.equal(0);
});
});
describe('BaseMonitor.warnDegradation — Deno 兼容性降级警告', () => {
let originalWarn;
let warnCalls;
beforeEach(() => {
// 重置静态 Set(访问私有静态属性)
base_monitor_1.BaseMonitor.warnedDegradations?.clear();
originalWarn = console.warn;
warnCalls = [];
console.warn = (...args) => { warnCalls.push(args.join(' ')); };
});
afterEach(() => {
console.warn = originalWarn;
base_monitor_1.BaseMonitor.warnedDegradations?.clear();
});
it('T024: 相同 key 首次调用时应触发 console.warn', () => {
base_monitor_1.BaseMonitor.warnDegradation('cpu.command_failed', 'PowerShell WMI 不可用');
(0, chai_1.expect)(warnCalls).to.have.lengthOf(1);
(0, chai_1.expect)(warnCalls[0]).to.include('[node-os-utils]');
(0, chai_1.expect)(warnCalls[0]).to.include('cpu');
});
it('T024: 相同 key 第二次调用时不应重复触发 console.warn', () => {
base_monitor_1.BaseMonitor.warnDegradation('cpu.command_failed', 'PowerShell WMI 不可用');
base_monitor_1.BaseMonitor.warnDegradation('cpu.command_failed', 'PowerShell WMI 不可用');
(0, chai_1.expect)(warnCalls).to.have.lengthOf(1);
});
it('T024: 不同 key 应各自独立触发一次 console.warn', () => {
base_monitor_1.BaseMonitor.warnDegradation('cpu.command_failed', 'CPU 降级');
base_monitor_1.BaseMonitor.warnDegradation('memory.command_failed', 'Memory 降级');
(0, chai_1.expect)(warnCalls).to.have.lengthOf(2);
});
});
//# sourceMappingURL=base-monitor.test.js.map