tpmjs/packages/executor-test/src/runner.ts
Ajax Davis 32c6e097ed feat(executor): formalize Executor Protocol v1.0 with compliance testing
- Add EXECUTOR_SPECIFICATION.md with formal v1.0 protocol spec
- Add executor-openapi.yaml (OpenAPI 3.0 specification)
- Create @tpmjs/executor-test compliance test package (15 tests)
- Update Railway executor to v1.0 compliance (15/15 tests pass)
- Update Unsandbox executor to v1.0 compliance (15/15 tests pass)
- Update Vercel executor to v1.0 compliance
- Add /info endpoint with capability advertisement to all executors
- Add structured error codes (PACKAGE_NOT_FOUND, TOOL_NOT_FOUND, etc.)
- Add protocolVersion and implementationVersion to /health responses
- Add X-TPMJS-Protocol-Version header support
- Add EXECUTOR_COMPLIANCE.md with test results documentation
2026-02-04 02:09:08 +10:00

201 lines
5 KiB
TypeScript

import pc from 'picocolors';
import { runCoreTests } from './tests/core.js';
import { runStandardTests } from './tests/standard.js';
import type { ComplianceResult, TestSuite } from './types.js';
const VERSION = '0.1.0';
const PROTOCOL_VERSION = '1.0';
function printUsage(): void {
console.log(`
${pc.bold('TPMJS Executor Compliance Test')} v${VERSION}
${pc.dim('Usage:')}
npx @tpmjs/executor-test <executor-url> [options]
${pc.dim('Options:')}
--api-key <key> API key for authentication (Bearer token)
--json Output results as JSON
--verbose Show detailed test output
--help Show this help message
${pc.dim('Examples:')}
npx @tpmjs/executor-test https://my-executor.example.com
npx @tpmjs/executor-test https://my-executor.example.com --api-key sk-xxx
npx @tpmjs/executor-test https://my-executor.example.com --json
`);
}
function printBanner(target: string): void {
console.log();
console.log(pc.bold(`TPMJS Executor Compliance Test v${VERSION}`));
console.log(pc.dim(`Protocol Version: ${PROTOCOL_VERSION}`));
console.log(pc.dim(`Target: ${target}`));
console.log();
}
function printSuite(suite: TestSuite): void {
const levelLabel =
suite.level === 'core'
? pc.blue('Core')
: suite.level === 'standard'
? pc.yellow('Standard')
: pc.magenta('Extended');
console.log(`${levelLabel} ${pc.bold(suite.name)}:`);
for (const result of suite.results) {
const icon = result.passed ? pc.green('\u2713') : pc.red('\u2717');
const name = result.passed ? result.name : pc.red(result.name);
const duration = pc.dim(`(${result.durationMs}ms)`);
console.log(` ${icon} ${name} ${duration}`);
if (!result.passed && result.message) {
console.log(` ${pc.dim(result.message)}`);
}
}
console.log();
}
function printSummary(result: ComplianceResult): void {
const { summary } = result;
console.log(pc.bold('Summary:'));
console.log(
` Tests: ${pc.green(`${summary.passed} passed`)}, ${summary.failed > 0 ? pc.red(`${summary.failed} failed`) : `${summary.failed} failed`}, ${summary.totalTests} total`
);
console.log();
const coreStatus = summary.coreCompliant ? pc.green('PASS') : pc.red('FAIL');
const standardStatus = summary.standardCompliant
? pc.green('PASS')
: summary.coreCompliant
? pc.yellow('PARTIAL')
: pc.red('FAIL');
console.log(` Core Compliance: ${coreStatus}`);
console.log(` Standard Compliance: ${standardStatus}`);
console.log();
}
interface Options {
apiKey?: string;
json: boolean;
verbose: boolean;
}
function parseArgs(args: string[]): { url: string | null; options: Options } {
const options: Options = {
json: false,
verbose: false,
};
let url: string | null = null;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--help' || arg === '-h') {
printUsage();
process.exit(0);
}
if (arg === '--json') {
options.json = true;
continue;
}
if (arg === '--verbose' || arg === '-v') {
options.verbose = true;
continue;
}
if (arg === '--api-key') {
i++;
options.apiKey = args[i] ?? undefined;
continue;
}
if (!arg?.startsWith('-') && !url) {
url = arg ?? null;
}
}
return { url, options };
}
export async function run(args: string[]): Promise<void> {
const { url, options } = parseArgs(args);
if (!url) {
printUsage();
process.exit(1);
}
// Normalize URL
const target = url.replace(/\/$/, '');
if (!options.json) {
printBanner(target);
}
const suites: TestSuite[] = [];
// Run Core tests
if (!options.json) {
console.log(pc.dim('Running Core compliance tests...'));
console.log();
}
const coreSuite = await runCoreTests(target, options.apiKey);
suites.push(coreSuite);
if (!options.json) {
printSuite(coreSuite);
}
// Run Standard tests
if (!options.json) {
console.log(pc.dim('Running Standard compliance tests...'));
console.log();
}
const standardSuite = await runStandardTests(target, options.apiKey);
suites.push(standardSuite);
if (!options.json) {
printSuite(standardSuite);
}
// Calculate summary
const totalTests = suites.reduce((sum, s) => sum + s.results.length, 0);
const passed = suites.reduce((sum, s) => sum + s.results.filter((r) => r.passed).length, 0);
const failed = totalTests - passed;
const coreCompliant = coreSuite.results.every((r) => r.passed);
const standardCompliant = coreCompliant && standardSuite.results.every((r) => r.passed);
const result: ComplianceResult = {
target,
protocolVersion: PROTOCOL_VERSION,
timestamp: new Date().toISOString(),
suites,
summary: {
totalTests,
passed,
failed,
coreCompliant,
standardCompliant,
},
};
if (options.json) {
console.log(JSON.stringify(result, null, 2));
} else {
printSummary(result);
}
// Exit with error code if not compliant
process.exit(coreCompliant ? 0 : 1);
}