148 lines
4.7 KiB
JavaScript
148 lines
4.7 KiB
JavaScript
// tests/contract/guanghu-shell.test.js
|
|
// 🌊 光湖语言壳 · 契约测试
|
|
|
|
'use strict';
|
|
|
|
const { execFileSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const ROOT = path.resolve(__dirname, '../..');
|
|
const SHELL_PATH = path.join(ROOT, '.github/scripts/guanghu-shell.js');
|
|
const STATUS_PATH = path.join(ROOT, '.github/brain/shell-status.json');
|
|
const ERROR_LOG_PATH = path.join(ROOT, '.github/brain/shell-errors.json');
|
|
|
|
function runShell(agentId, action, detail) {
|
|
const args = [SHELL_PATH, agentId, action];
|
|
if (detail) args.push(detail);
|
|
try {
|
|
const output = execFileSync('node', args, {
|
|
cwd: ROOT,
|
|
encoding: 'utf8',
|
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
});
|
|
return { exitCode: 0, stdout: output, stderr: '' };
|
|
} catch (e) {
|
|
return { exitCode: e.status, stdout: e.stdout || '', stderr: e.stderr || '' };
|
|
}
|
|
}
|
|
|
|
function readStatus() {
|
|
return JSON.parse(fs.readFileSync(STATUS_PATH, 'utf8'));
|
|
}
|
|
|
|
function readErrors() {
|
|
return JSON.parse(fs.readFileSync(ERROR_LOG_PATH, 'utf8'));
|
|
}
|
|
|
|
function resetState() {
|
|
fs.writeFileSync(STATUS_PATH, '{}');
|
|
fs.writeFileSync(ERROR_LOG_PATH, '[]');
|
|
}
|
|
|
|
describe('🌊 光湖语言壳 · Guanghu Shell v1.0', () => {
|
|
|
|
beforeEach(() => {
|
|
resetState();
|
|
});
|
|
|
|
afterAll(() => {
|
|
resetState();
|
|
});
|
|
|
|
describe('① 身份校验层', () => {
|
|
test('已注册Agent(定时型)允许通行', () => {
|
|
const r = runShell('AG-ZY-013', 'enter');
|
|
expect(r.exitCode).toBe(0);
|
|
expect(r.stdout).toContain('定时型Agent');
|
|
expect(r.stdout).toContain('允许通行');
|
|
});
|
|
|
|
test('已注册Agent(事件触发型)允许通行', () => {
|
|
const r = runShell('AG-ZY-002', 'enter');
|
|
expect(r.exitCode).toBe(0);
|
|
expect(r.stdout).toContain('事件触发型Agent');
|
|
expect(r.stdout).toContain('允许通行');
|
|
});
|
|
|
|
test('未注册Agent被拒绝', () => {
|
|
const r = runShell('AG-FAKE-999', 'enter');
|
|
expect(r.exitCode).toBe(1);
|
|
expect(r.stderr).toContain('身份不明');
|
|
});
|
|
|
|
test('缺少参数时退出码为1', () => {
|
|
const r = runShell('AG-ZY-001', '');
|
|
expect(r.exitCode).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('② 状态注册层', () => {
|
|
test('enter 记录启动状态', () => {
|
|
runShell('AG-ZY-001', 'enter');
|
|
const status = readStatus();
|
|
expect(status['AG-ZY-001']).toBeDefined();
|
|
expect(status['AG-ZY-001'].currentState).toBe('running');
|
|
expect(status['AG-ZY-001'].lastEnter).toBeDefined();
|
|
expect(status['AG-ZY-001'].runs).toHaveLength(1);
|
|
expect(status['AG-ZY-001'].runs[0].result).toBeNull();
|
|
});
|
|
|
|
test('exit 记录完成状态', () => {
|
|
runShell('AG-ZY-001', 'enter');
|
|
runShell('AG-ZY-001', 'exit', 'completed successfully');
|
|
const status = readStatus();
|
|
expect(status['AG-ZY-001'].currentState).toBe('completed');
|
|
expect(status['AG-ZY-001'].lastExit).toBeDefined();
|
|
expect(status['AG-ZY-001'].runs[0].result).toBe('success');
|
|
expect(status['AG-ZY-001'].runs[0].detail).toBe('completed successfully');
|
|
});
|
|
|
|
test('error 记录异常状态', () => {
|
|
runShell('AG-ZY-058', 'enter');
|
|
runShell('AG-ZY-058', 'error', 'test failure');
|
|
const status = readStatus();
|
|
expect(status['AG-ZY-058'].currentState).toBe('error');
|
|
expect(status['AG-ZY-058'].lastError).toBeDefined();
|
|
expect(status['AG-ZY-058'].runs[0].result).toBe('error');
|
|
});
|
|
|
|
test('多次运行保留最近10条', () => {
|
|
for (let i = 0; i < 12; i++) {
|
|
runShell('AG-ZY-001', 'enter');
|
|
runShell('AG-ZY-001', 'exit');
|
|
}
|
|
const status = readStatus();
|
|
expect(status['AG-ZY-001'].runs.length).toBeLessThanOrEqual(10);
|
|
});
|
|
});
|
|
|
|
describe('③ 异常兑底层', () => {
|
|
test('未注册Agent异常写入错误日志', () => {
|
|
runShell('AG-FAKE-999', 'enter');
|
|
const errors = readErrors();
|
|
expect(errors.length).toBeGreaterThanOrEqual(1);
|
|
const last = errors[errors.length - 1];
|
|
expect(last.agentId).toBe('AG-FAKE-999');
|
|
expect(last.error).toContain('UNREGISTERED');
|
|
expect(last.timestamp).toBeDefined();
|
|
});
|
|
|
|
test('error action 写入错误日志', () => {
|
|
runShell('AG-ZY-013', 'error', 'something broke');
|
|
const errors = readErrors();
|
|
const last = errors[errors.length - 1];
|
|
expect(last.agentId).toBe('AG-ZY-013');
|
|
expect(last.error).toBe('something broke');
|
|
});
|
|
|
|
test('错误日志最多保留100条', () => {
|
|
for (let i = 0; i < 105; i++) {
|
|
runShell('AG-FAKE-999', 'enter');
|
|
}
|
|
const errors = readErrors();
|
|
expect(errors.length).toBeLessThanOrEqual(100);
|
|
});
|
|
});
|
|
});
|