@synet/shell-exec
Version:
Safe shell command execution with Unit Architecture - foundation component for MetaDev
174 lines (148 loc) • 6.53 kB
text/typescript
/**
* @synet/shell-exec - Basic Unit Tests
*
* Tests for the ShellExecUnit to verify consciousness-based command execution.
* These are minimal 80/20 tests to validate core functionality.
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { ShellExecUnit } from '../src/index.js';
describe('ShellExecUnit', () => {
let shellExec: ShellExecUnit;
beforeEach(() => {
shellExec = ShellExecUnit.create({
defaultTimeout: 5000,
maxConcurrent: 2
});
});
describe('Consciousness Features', () => {
it('should have proper identity (whoami)', () => {
const identity = shellExec.whoami();
expect(identity).toContain('ShellExecUnit');
expect(identity).toContain('v1.0.0');
});
it('should provide help information', () => {
// Should not throw - help() logs to console
expect(() => shellExec.help()).not.toThrow();
});
it('should expose teaching contract', () => {
const teaching = shellExec.teach();
expect(teaching.unitId).toBe('shell-exec');
expect(teaching.capabilities).toBeDefined();
expect(teaching.schema).toBeDefined();
expect(teaching.validator).toBeDefined();
});
});
describe('Command Validation', () => {
it('should validate safe commands', async () => {
const result = await shellExec.execute('validate', 'echo "test"') as { valid: boolean; reason: string; suggestions: string[] };
expect(result.valid).toBe(true);
expect(result.reason).toContain('safety checks');
});
it('should block dangerous commands', async () => {
const result = await shellExec.execute('validate', 'rm -rf /packages/shell-exec/node_modules') as { valid: boolean; reason: string; suggestions: string[] };
expect(result.valid).toBe(false);
expect(result.reason).toContain('blocked');
expect(result.suggestions).toBeInstanceOf(Array);
});
it('should block unknown commands', async () => {
const result = await shellExec.execute('validate', 'dangerous-unknown-command') as { valid: boolean; reason: string; suggestions: string[] };
expect(result.valid).toBe(false);
expect(result.reason).toContain('not in allowed list');
});
});
describe('Command Execution', () => {
it('should execute simple echo command', async () => {
const result = await shellExec.execute('exec', 'echo "Hello SYNET"') as { exitCode: number; stdout: string; duration: number; command: string };
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain('Hello SYNET');
expect(result.duration).toBeGreaterThan(0);
expect(result.command).toBe('echo "Hello SYNET"');
});
it('should capture stderr for failing commands', async () => {
// Try to run a command that should fail
const result = await shellExec.execute('exec', 'node -e "process.exit(1)"') as { exitCode: number; killed: boolean };
expect(result.exitCode).toBe(1);
expect(result.killed).toBe(false);
});
it('should handle command timeout', async () => {
// This might be slow, testing timeout mechanism
try {
const result = await shellExec.execute('exec', 'sleep 10', { timeout: 100 }) as { killed: boolean };
expect(result.killed).toBe(true);
} catch (error) {
// Some systems might throw error on timeout, that's also acceptable
expect(error).toBeDefined();
}
}, 10000);
});
describe('Execution History', () => {
it('should track execution history', async () => {
await shellExec.execute('exec', 'echo "test1"');
await shellExec.execute('exec', 'echo "test2"');
const history = await shellExec.execute('getHistory') as Array<{ command: string }>;
expect(history.length).toBeGreaterThanOrEqual(2);
expect(history[0].command).toContain('echo');
});
it('should track running processes', async () => {
const processes = await shellExec.execute('getRunningProcesses') as number[];
expect(processes).toBeInstanceOf(Array);
// Should be empty when no processes running
expect(processes.length).toBe(0);
});
});
describe('Unit Architecture Integration', () => {
it('should inherit base Unit capabilities', () => {
expect(shellExec.getCapabilities()).toBeInstanceOf(Array);
expect(shellExec.getCapabilities()).toContain('exec');
expect(shellExec.getCapabilities()).toContain('validate');
});
it('should support capability checking', () => {
expect(shellExec.can('exec')).toBe(true);
expect(shellExec.can('validate')).toBe(true);
expect(shellExec.can('nonexistent')).toBe(false);
});
it('should have valid schema for exec command', () => {
expect(shellExec.hasSchema('exec')).toBe(true);
const schema = shellExec.getSchema('exec');
expect(schema).toBeDefined();
expect(schema?.name).toBe('exec');
});
});
});
describe('ShellExecUnit Factory', () => {
it('should create unit with default config', () => {
const unit = ShellExecUnit.create();
expect(unit).toBeInstanceOf(ShellExecUnit);
expect(unit.whoami()).toContain('ShellExecUnit');
});
it('should create unit with custom config', () => {
const unit = ShellExecUnit.create({
defaultTimeout: 1000,
maxConcurrent: 1,
allowedCommands: ['echo', 'pwd']
});
expect(unit).toBeInstanceOf(ShellExecUnit);
});
});
describe('MetaDev Integration Scenarios', () => {
let shellExec: ShellExecUnit;
beforeEach(() => {
shellExec = ShellExecUnit.create();
});
it('should handle npm commands (MetaDev build scenario)', async () => {
const result = await shellExec.execute('exec', 'npm --version') as { exitCode: number; stdout: string };
expect(result.exitCode).toBe(0);
expect(result.stdout).toMatch(/\d+\.\d+\.\d+/); // Version format
});
it('should handle node commands (MetaDev execution scenario)', async () => {
const result = await shellExec.execute('exec', 'node --version') as { exitCode: number; stdout: string };
expect(result.exitCode).toBe(0);
expect(result.stdout).toMatch(/v\d+\.\d+\.\d+/); // Node version format
});
it('should handle pwd command (MetaDev directory checks)', async () => {
const result = await shellExec.execute('exec', 'pwd') as { exitCode: number; stdout: string };
expect(result.exitCode).toBe(0);
expect(result.stdout).toBeTruthy();
expect(result.stdout.length).toBeGreaterThan(0);
});
});