UNPKG

node-os-utils

Version:

Advanced cross-platform operating system monitoring utilities with TypeScript support

188 lines 8.4 kB
"use strict"; 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