OpenWriterControle/evals/agents/openagent/run-tests.js
darrenhinde cc96acc50e feat: add 5 essential workflow tests and reorganize with agents/ structure
- Add 5 workflow tests (task, context loading, stop-on-failure, conversational)
- Add 1 shared test (agent-agnostic approval gate)
- Reorganize: opencode/ → agents/ for clearer structure
- Rename: sdk-tests/ → tests/ for simplicity
- Update test runner paths to new structure
- Add comprehensive documentation (test plan, guides, migration)
- Update all documentation with new paths

Total: 13 tests (was 6, added 7)
Coverage: +31% workflow compliance
All tests passing: 11/11 (100%)
2025-11-22 15:20:59 +00:00

230 lines
6.7 KiB
JavaScript

/**
* OpenAgent Synthetic Test Runner
*
* Loads synthetic test sessions, runs evaluators, compares actual vs expected results
*/
const fs = require('fs');
const path = require('path');
// Import framework from evals/framework
const {
ApprovalGateEvaluator,
ContextLoadingEvaluator,
DelegationEvaluator,
ToolUsageEvaluator
} = require('../../framework/dist');
// Mock SessionInfo for synthetic tests
function createMockSessionInfo(testId) {
return {
id: `synthetic_${testId}`,
version: '1.0',
title: `Synthetic Test: ${testId}`,
time: {
created: Date.now(),
updated: Date.now()
}
};
}
// Load test cases
function loadTestCases(testsDir) {
const testCases = [];
const categories = fs.readdirSync(testsDir);
for (const category of categories) {
const categoryPath = path.join(testsDir, category);
if (!fs.statSync(categoryPath).isDirectory()) continue;
const tests = fs.readdirSync(categoryPath);
for (const testName of tests) {
const testPath = path.join(categoryPath, testName);
if (!fs.statSync(testPath).isDirectory()) continue;
const timelinePath = path.join(testPath, 'timeline.json');
const expectedPath = path.join(testPath, 'expected.json');
if (fs.existsSync(timelinePath) && fs.existsSync(expectedPath)) {
testCases.push({
id: testName,
category,
timeline: JSON.parse(fs.readFileSync(timelinePath, 'utf-8')),
expected: JSON.parse(fs.readFileSync(expectedPath, 'utf-8'))
});
}
}
}
return testCases;
}
// Compare actual vs expected
function compareResults(actual, expected, evaluatorName) {
const issues = [];
// Check passed
if (actual.passed !== expected.passed) {
issues.push(` ✗ Passed mismatch: got ${actual.passed}, expected ${expected.passed}`);
}
// Check score
if (actual.score !== expected.score) {
issues.push(` ✗ Score mismatch: got ${actual.score}, expected ${expected.score}`);
}
// Check violation count
if (actual.violations.length !== expected.violation_count) {
issues.push(` ✗ Violation count: got ${actual.violations.length}, expected ${expected.violation_count}`);
}
// Check violation types (if violations exist)
if (expected.violations && expected.violations.length > 0) {
for (const expectedViolation of expected.violations) {
const found = actual.violations.some(v =>
v.type === expectedViolation.type &&
v.severity === expectedViolation.severity
);
if (!found) {
issues.push(` ✗ Missing violation: ${expectedViolation.type} (${expectedViolation.severity})`);
}
}
}
return issues;
}
// Run single test
async function runTest(testCase) {
console.log(`\n${'='.repeat(80)}`);
console.log(`TEST: ${testCase.id}`);
console.log(`Category: ${testCase.category}`);
console.log(`Description: ${testCase.expected.description}`);
console.log('='.repeat(80));
const sessionInfo = createMockSessionInfo(testCase.id);
const timeline = testCase.timeline;
// Create evaluators
const evaluators = {
ApprovalGateEvaluator: new ApprovalGateEvaluator(),
ContextLoadingEvaluator: new ContextLoadingEvaluator(),
DelegationEvaluator: new DelegationEvaluator(),
ToolUsageEvaluator: new ToolUsageEvaluator()
};
const results = {};
const allIssues = [];
// Run each evaluator
for (const [name, evaluator] of Object.entries(evaluators)) {
console.log(`\nRunning ${name}...`);
const actual = await evaluator.evaluate(timeline, sessionInfo);
const expected = testCase.expected.expected_results[name];
results[name] = actual;
// Display actual results
console.log(` Status: ${actual.passed ? '✓ PASS' : '✗ FAIL'}`);
console.log(` Score: ${actual.score}/100`);
console.log(` Violations: ${actual.violations.length}`);
if (actual.violations.length > 0) {
actual.violations.forEach(v => {
console.log(` - [${v.severity.toUpperCase()}] ${v.type}: ${v.message}`);
});
}
// Compare with expected
const issues = compareResults(actual, expected, name);
if (issues.length > 0) {
console.log(`\n ❌ ISSUES FOUND:`);
issues.forEach(issue => console.log(issue));
allIssues.push(...issues.map(i => `${name}: ${i}`));
} else {
console.log(` ✅ Matches expected behavior`);
}
}
// Overall test result
const testPassed = allIssues.length === 0;
console.log(`\n${'─'.repeat(80)}`);
console.log(`TEST RESULT: ${testPassed ? '✅ PASS' : '❌ FAIL'}`);
if (!testPassed) {
console.log(`\nIssues (${allIssues.length}):`);
allIssues.forEach(issue => console.log(` ${issue}`));
}
return {
id: testCase.id,
passed: testPassed,
issues: allIssues,
results
};
}
// Main
async function main() {
console.log('='.repeat(80));
console.log('OPENAGENT SYNTHETIC TEST SUITE');
console.log('='.repeat(80));
const testsDir = path.join(__dirname, 'tests');
const testCases = loadTestCases(testsDir);
console.log(`\nFound ${testCases.length} test cases:\n`);
testCases.forEach((tc, idx) => {
console.log(` ${idx + 1}. ${tc.category}/${tc.id}`);
});
// Run all tests
const testResults = [];
for (const testCase of testCases) {
const result = await runTest(testCase);
testResults.push(result);
}
// Summary
console.log('\n\n' + '='.repeat(80));
console.log('TEST SUMMARY');
console.log('='.repeat(80));
const passedCount = testResults.filter(r => r.passed).length;
const failedCount = testResults.length - passedCount;
const passRate = Math.round((passedCount / testResults.length) * 100);
console.log(`\nTotal Tests: ${testResults.length}`);
console.log(`Passed: ${passedCount} (${passRate}%)`);
console.log(`Failed: ${failedCount} (${100 - passRate}%)`);
console.log(`\nTest Results:`);
testResults.forEach((result, idx) => {
const status = result.passed ? '✅' : '❌';
console.log(` ${status} ${result.id}`);
if (!result.passed) {
console.log(` Issues: ${result.issues.length}`);
}
});
if (failedCount > 0) {
console.log(`\n${'='.repeat(80)}`);
console.log('FAILED TESTS - DETAILED ISSUES');
console.log('='.repeat(80));
testResults.filter(r => !r.passed).forEach(result => {
console.log(`\n${result.id}:`);
result.issues.forEach(issue => console.log(` ${issue}`));
});
}
console.log('\n' + '='.repeat(80));
console.log(`FINAL RESULT: ${failedCount === 0 ? '✅ ALL TESTS PASSED' : '❌ SOME TESTS FAILED'}`);
console.log('='.repeat(80));
process.exit(failedCount > 0 ? 1 : 0);
}
main().catch(error => {
console.error('Error running tests:', error);
process.exit(1);
});