node-os-utils
Version:
Advanced cross-platform operating system monitoring utilities with TypeScript support
190 lines • 8.89 kB
JavaScript
;
/**
* CommandExecutor单元测试
* 测试命令执行器的核心功能和错误处理
*/
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const command_executor_1 = require("../../../src/utils/command-executor");
const errors_1 = require("../../../src/types/errors");
describe('CommandExecutor Unit Tests', function () {
let executor;
beforeEach(function () {
executor = new command_executor_1.CommandExecutor('test-platform', {
timeout: 5000,
encoding: 'utf8'
});
});
describe('基本命令执行', function () {
it('应该能够执行简单的系统命令', async function () {
// 使用跨平台兼容的命令
const command = process.platform === 'win32' ? 'echo hello' : 'echo "hello"';
const result = await executor.execute(command);
(0, chai_1.expect)(result.stdout.trim()).to.equal('hello');
(0, chai_1.expect)(result.stderr).to.equal('');
(0, chai_1.expect)(result.exitCode).to.equal(0);
(0, chai_1.expect)(result.platform).to.equal('test-platform');
(0, chai_1.expect)(result.command).to.equal(command);
(0, chai_1.expect)(result.executionTime).to.be.a('number');
});
it('应该正确处理命令执行失败', async function () {
try {
await executor.execute('nonexistent-command-12345');
// 如果没有抛出错误,则测试失败
chai_1.expect.fail('应该抛出错误');
}
catch (error) {
(0, chai_1.expect)(error).to.be.an('error');
// 检查是否是MonitorError
if (error.code) {
(0, chai_1.expect)(error.code).to.be.oneOf(['COMMAND_FAILED', 'FILE_NOT_FOUND']);
}
}
});
it('应该正确处理有stderr输出但成功的命令', async function () {
// 某些命令会向stderr输出信息但仍然成功
const command = process.platform === 'win32'
? 'echo error>&2 & echo success'
: 'echo "error" >&2; echo "success"';
const result = await executor.execute(command);
(0, chai_1.expect)(result.stdout.trim()).to.include('success');
(0, chai_1.expect)(result.exitCode).to.equal(0);
});
});
describe('超时处理', function () {
it('应该在超时后终止命令', async function () {
this.timeout(3000); // 设置测试超时
const shortTimeout = new command_executor_1.CommandExecutor('test-platform', { timeout: 100 });
// 创建一个会运行较长时间的命令
const command = process.platform === 'win32'
? 'ping -n 10 127.0.0.1'
: 'sleep 5';
try {
await shortTimeout.execute(command);
chai_1.expect.fail('应该抛出超时错误');
}
catch (error) {
(0, chai_1.expect)(error).to.be.an('error');
if (error.code) {
(0, chai_1.expect)(error.code).to.equal('TIMEOUT');
}
}
});
});
describe('输出处理', function () {
it('应该正确处理大量输出', async function () {
// 生成大量输出的命令
const command = process.platform === 'win32'
? 'for /L %i in (1,1,10) do @echo Line %i'
: 'for i in {1..10}; do echo "Line $i"; done';
const result = await executor.execute(command);
const lines = result.stdout.trim().split('\n');
(0, chai_1.expect)(lines.length).to.be.at.least(5); // 至少有一些行
(0, chai_1.expect)(result.exitCode).to.equal(0);
});
it('应该正确处理空输出', async function () {
const command = process.platform === 'win32' ? 'echo.' : 'true';
const result = await executor.execute(command);
(0, chai_1.expect)(result.exitCode).to.equal(0);
});
});
describe('平台特定命令', function () {
it('应该能够执行平台特定的系统信息命令', async function () {
let command;
switch (process.platform) {
case 'darwin':
command = 'uname -s';
break;
case 'linux':
command = 'uname -s';
break;
case 'win32':
command = 'ver';
break;
default:
this.skip();
return;
}
const result = await executor.execute(command);
(0, chai_1.expect)(result.stdout).to.be.a('string');
(0, chai_1.expect)(result.stdout.length).to.be.greaterThan(0);
(0, chai_1.expect)(result.exitCode).to.equal(0);
});
});
describe('配置选项', function () {
it('应该使用自定义配置', async function () {
const customExecutor = new command_executor_1.CommandExecutor('custom-platform', {
timeout: 1000,
encoding: 'utf8'
});
const command = process.platform === 'win32' ? 'echo test' : 'echo "test"';
const result = await customExecutor.execute(command);
(0, chai_1.expect)(result.stdout.trim()).to.equal('test');
(0, chai_1.expect)(result.platform).to.equal('custom-platform');
});
});
describe('并发执行', function () {
it('应该能够并发执行多个命令', async function () {
const commands = [
process.platform === 'win32' ? 'echo 1' : 'echo "1"',
process.platform === 'win32' ? 'echo 2' : 'echo "2"',
process.platform === 'win32' ? 'echo 3' : 'echo "3"'
];
const promises = commands.map(cmd => executor.execute(cmd));
const results = await Promise.all(promises);
results.forEach((result, index) => {
(0, chai_1.expect)(result.stdout.trim()).to.equal((index + 1).toString());
(0, chai_1.expect)(result.exitCode).to.equal(0);
});
});
});
describe('流式执行', function () {
it('应该在禁用 shell 时正确处理包含空格的命令', async function () {
const script = 'console.log("stream output")';
const command = executor.buildCommand(process.execPath, ['-e', script]);
const chunks = [];
const result = await executor.executeStream(command, (data) => {
chunks.push(data);
}, { shell: false });
(0, chai_1.expect)(result.exitCode).to.equal(0);
(0, chai_1.expect)(chunks.join('')).to.contain('stream output');
});
});
});
describe('CommandExecutor — Deno 兼容性:非标准异常处理', function () {
it('T023: 应将字符串类型的非标准异常统一捕获为 MonitorError(COMMAND_FAILED)', async function () {
const executor = new command_executor_1.CommandExecutor('test-platform');
const internal = executor;
// 模拟 Deno 兼容层抛出非 Error 实例(字符串)
internal.executeWithTimeout = async () => {
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw 'Deno compat layer: exec failed unexpectedly';
};
try {
await executor.execute('echo test');
chai_1.expect.fail('应该抛出错误');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(errors_1.MonitorError);
(0, chai_1.expect)(error.code).to.equal(errors_1.ErrorCode.COMMAND_FAILED);
}
});
it('T023: 应将自定义对象类型的非标准异常统一捕获为 MonitorError(COMMAND_FAILED)', async function () {
const executor = new command_executor_1.CommandExecutor('test-platform');
const internal = executor;
// 模拟 Deno 兼容层抛出普通对象(非 Error 实例)
internal.executeWithTimeout = async () => {
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw { message: 'DENO_EXEC_ERROR', code: 'ERR_DENO_COMPAT' };
};
try {
await executor.execute('echo test');
chai_1.expect.fail('应该抛出错误');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(errors_1.MonitorError);
(0, chai_1.expect)(error.code).to.equal(errors_1.ErrorCode.COMMAND_FAILED);
}
});
});
//# sourceMappingURL=command-executor.test.js.map