23f7624596
ADR-166 MCP Bridge Security Lock / Static-source security lock (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / Compose default binds loopback + Mongo has auth (push) Failing after 2s
CodeQL Advanced / Analyze (rust) (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / plugin-agent-federation bindHost default (push) Failing after 1s
ADR-166 MCP Bridge Security Lock / Runtime behavior — 401 + terminal gate + fail-closed (push) Failing after 4s
business-pods-smoke / smoke (push) Failing after 1s
all-plugins-smoke / smoke-all (push) Failing after 2s
CI/CD Pipeline / Security & Code Quality (push) Failing after 1s
CI/CD Pipeline / Test Suite (ubuntu-latest) (push) Failing after 1s
CI/CD Pipeline / Build & Package (macos-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (ubuntu-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (windows-latest) (push) Has been skipped
CI/CD Pipeline / Documentation & Examples (push) Failing after 1s
Clone Tracker (14-day rolling) / Snapshot clones for ruflo ecosystem (push) Failing after 1s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
federation-peer-rust / stable-noop (push) Failing after 1s
metaharness-ci / score (push) Failing after 1s
metaharness-ci / router-compat (push) Failing after 0s
metaharness-ci / similarity-tests (push) Failing after 0s
no-agentbbs-smoke / smoke-without-agentbbs (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (windows-latest) (push) Has been skipped
codex-integration-audit / Codex integration audit (push) Failing after 1s
helpers-manifest-guard / guard (push) Failing after 1s
🔗 Cross-Agent Integration Tests / 🤝 Agent Coordination Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🧠 Memory Sharing Integration (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🛡️ Fault Tolerance Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / ⚡ Performance Integration Tests (push) Has been skipped
metaharness-ci / mcp-scan (push) Failing after 1s
metaharness-ci / eject-dryrun (push) Failing after 1s
metaharness-ci / metaharness-real-data (push) Failing after 0s
no-cli-optdep-bloat-2561 / guard (push) Failing after 1s
no-metaharness-smoke / smoke-without-metaharness (push) Failing after 1s
no-phantom-agentic-flow-subpath / guard (push) Failing after 1s
🔄 Automated Rollback Manager / 🚨 Failure Detection (push) Failing after 1s
V3 CI/CD Pipeline / Plugin hooks smoke / ubuntu-latest / Node 22 (push) Failing after 1s
V3 CI/CD Pipeline / ruflo-graph-intelligence build + test smoke (#2044, ADR-123) (push) Failing after 1s
CVE Audit Gate / Audit root (critical-blocking) (push) Failing after 2s
cost-tracker-smoke / smoke (push) Failing after 3s
oia-audit-weekly / audit (push) Failing after 2s
ruflo-agent-smoke / ruflo-agent structural smoke (push) Failing after 1s
📊 Status Badges Update / 📊 Update Status Badges (push) Failing after 1s
V3 CI/CD Pipeline / Static regression guards (#2267 YAML + (push) Failing after 1s
V3 CI/CD Pipeline / Test V3 Packages (push) Failing after 0s
V3 CI/CD Pipeline / agent_execute provider routing smoke (#2042) (push) Failing after 0s
CVE Audit Gate / Audit v3 (critical-blocking) (push) Failing after 1s
federation-peer-rust / stable-native (push) Failing after 2s
🔗 Cross-Agent Integration Tests / 🚀 Integration Test Setup (push) Failing after 2s
neural-trader-smoke / runtime-smoke (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (macos-latest) (push) Has been skipped
V3 CI/CD Pipeline / Build V3 (ubuntu-latest) (push) Has been skipped
V3 CI/CD Pipeline / Type Check V3 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 24 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 22 (push) Failing after 2s
V3 CI/CD Pipeline / browser rvf create flag smoke (#2015) (push) Failing after 0s
V3 CI/CD Pipeline / Dependency review (#2046) (push) Has been skipped
V3 CI/CD Pipeline / Supply-chain audit (#2046) (push) Failing after 0s
V3 CI/CD Pipeline / witness marker drift smoke (#2021) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / kg-extract type-import classification smoke (#2049) (push) Failing after 0s
V3 CI/CD Pipeline / witness verify precondition smoke (#1880) (push) Failing after 2s
V3 CI/CD Pipeline / neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) (push) Failing after 0s
V3 CI/CD Pipeline / neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) (push) Failing after 0s
V3 CI/CD Pipeline / plugin-registry signature verification smoke (#1922, CWE-347) (push) Failing after 4s
V3 CI/CD Pipeline / memory stats legacy-DB smoke (#2120) (push) Failing after 4s
V3 CI/CD Pipeline / github deprecated actions smoke (#2089, ADR-127 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / graph query + pathfinder smoke (ADR-130 P2+P5) (push) Has been skipped
V3 CI/CD Pipeline / graph trajectory hooks smoke (ADR-130 P3) (push) Has been skipped
V3 CI/CD Pipeline / graph plugin adapter smoke (ADR-130 P4) (push) Has been skipped
V3 CI/CD Pipeline / graph benchmark (ADR-130 P6) (push) Has been skipped
V3 CI/CD Pipeline / statusline generator delegation smoke (#2195) (push) Failing after 1s
V3 CI/CD Pipeline / wizard init regression guard (#2206 (push) Failing after 1s
V3 CI/CD Pipeline / memory no-stray-db smoke (ADR-125 P7) (push) Failing after 1s
V3 CI/CD Pipeline / github-safe injection smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github actions pin smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github attribution opt-in smoke (#2089, ADR-127 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / pre-bash hook safety smoke (#2017) (push) Failing after 1s
V3 CI/CD Pipeline / Memory import smoke / ubuntu-latest (push) Failing after 0s
V3 CI/CD Pipeline / MCP protocol smoke / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / ruvllm WASM auto-init smoke (#2086) (push) Failing after 4s
V3 CI/CD Pipeline / MCP paired-tool round-trip smoke (#1889) (push) Failing after 1s
V3 CI/CD Pipeline / Plugin package install-safety (#1902/#1903/#1904) (push) Failing after 1s
V3 CI/CD Pipeline / Tool description discoverability (ADR-112) (push) Failing after 3s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (22) (push) Failing after 1s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (24) (push) Failing after 1s
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Vector-index dimension audit (#1947) (push) Failing after 0s
V3 CI/CD Pipeline / Hook-command install safety (#1921) (push) Failing after 1s
V3 CI/CD Pipeline / ToolOutputGuardrail smoke (ADR-131, (push) Failing after 1s
V3 CI/CD Pipeline / init-bundle invariants smoke (#2095, ADR-128 Phase 5) (push) Failing after 1s
V3 CI/CD Pipeline / wasm provider bridge smoke (ADR-129 P1) (push) Failing after 2s
V3 CI/CD Pipeline / wasm gallery CRUD smoke (ADR-129 P3) (push) Failing after 1s
V3 CI/CD Pipeline / wasm plugin bridge smoke (ADR-129 P4) (push) Failing after 0s
V3 CI/CD Pipeline / wasm compose smoke (ADR-129 P2) (push) Failing after 4s
V3 CI/CD Pipeline / graph schema smoke (ADR-130 P1) (push) Failing after 0s
Validate Marketplace / validate (push) Failing after 1s
🔍 Verification Pipeline / 🚀 Setup Verification (push) Failing after 1s
🔍 Verification Pipeline / 🛡️ Security Verification (push) Has been skipped
🔍 Verification Pipeline / 📝 Code Quality (push) Has been skipped
🔍 Verification Pipeline / 🧪 Test Verification (${{ matrix.os }}, Node ${{ matrix.node }}) (push) Has been skipped
🔍 Verification Pipeline / 🏗️ Build Verification (push) Has been skipped
🔍 Verification Pipeline / 📚 Documentation Verification (push) Has been skipped
CVE Audit Gate / High-severity report (warn only) (push) Has been cancelled
🔄 Automated Rollback Manager / 🔄 Execute Rollback (push) Has been cancelled
🔄 Automated Rollback Manager / ✅ Post-Rollback Verification (push) Has been cancelled
🔄 Automated Rollback Manager / 📊 Rollback Monitoring (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / windows-latest (push) Has been cancelled
🔄 Automated Rollback Manager / ⏳ Manual Rollback Approval (push) Has been cancelled
V3 CI/CD Pipeline / MCP protocol smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Memory import smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / ubuntu-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Publish to npm (alpha) (push) Has been cancelled
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / macos-latest / Node 22 (push) Has been cancelled
V3 CI/CD Pipeline / Plugin hooks smoke / macos-latest / Node 22 (push) Has been cancelled
CI/CD Pipeline / Deploy & Release (push) Has been cancelled
CI/CD Pipeline / CI Status (push) Has been cancelled
🔗 Cross-Agent Integration Tests / 📊 Integration Test Report (push) Has been cancelled
🔄 Automated Rollback Manager / 🔍 Pre-Rollback Validation (push) Has been cancelled
🔍 Verification Pipeline / ⚡ Performance Verification (push) Has been cancelled
🔍 Verification Pipeline / 📊 Verification Report (push) Has been cancelled
517 lines
17 KiB
TypeScript
517 lines
17 KiB
TypeScript
/**
|
|
* RuVector Integration Tests
|
|
*
|
|
* Tests for the main ruvector module exports and integration.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import {
|
|
isRuvectorAvailable,
|
|
getRuvectorVersion,
|
|
createQLearningRouter,
|
|
createASTAnalyzer,
|
|
createDiffClassifier,
|
|
createCoverageRouter,
|
|
QLearningRouter,
|
|
ASTAnalyzer,
|
|
DiffClassifier,
|
|
CoverageRouter,
|
|
// Graph analyzer exports (function-based API)
|
|
buildDependencyGraph,
|
|
analyzeGraph,
|
|
analyzeMinCutBoundaries,
|
|
analyzeModuleCommunities,
|
|
detectCircularDependencies,
|
|
exportToDot,
|
|
loadRuVector,
|
|
fallbackMinCut,
|
|
fallbackLouvain,
|
|
} from '../../src/ruvector/index.js';
|
|
|
|
// Mock all ruvector modules
|
|
vi.mock('@ruvector/core', () => ({
|
|
createQLearning: vi.fn(() => null),
|
|
version: '1.0.0',
|
|
}));
|
|
|
|
vi.mock('@ruvector/ast', () => ({
|
|
createASTAnalyzer: vi.fn(() => null),
|
|
}));
|
|
|
|
vi.mock('@ruvector/diff', () => ({
|
|
createDiffClassifier: vi.fn(() => null),
|
|
}));
|
|
|
|
vi.mock('@ruvector/coverage', () => ({
|
|
createCoverageRouter: vi.fn(() => null),
|
|
}));
|
|
|
|
vi.mock('@ruvector/wasm', () => ({
|
|
minCut: vi.fn(() => null),
|
|
louvain: vi.fn(() => null),
|
|
}));
|
|
|
|
describe('RuVector Module Exports', () => {
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('isRuvectorAvailable', () => {
|
|
it('should return boolean', async () => {
|
|
const result = await isRuvectorAvailable();
|
|
expect(typeof result).toBe('boolean');
|
|
});
|
|
|
|
it('returns true when ruvector resolves (mocked at top of file)', async () => {
|
|
// The top-level vi.mock('@ruvector/core', ...) makes the dynamic
|
|
// import inside isRuvectorAvailable resolve, so the value must be
|
|
// true. The previous test used vi.doMock to flip this at runtime,
|
|
// but vi.doMock is too late: the module graph is already resolved
|
|
// by the time the test handler runs (vi.mock is hoisted, vi.doMock
|
|
// is not). Pinning the *real* observable behavior here.
|
|
const result = await isRuvectorAvailable();
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getRuvectorVersion', () => {
|
|
it('should return version string or null', async () => {
|
|
const version = await getRuvectorVersion();
|
|
expect(version === null || typeof version === 'string').toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Factory Functions', () => {
|
|
it('should export createQLearningRouter', () => {
|
|
expect(typeof createQLearningRouter).toBe('function');
|
|
const router = createQLearningRouter();
|
|
expect(router).toBeInstanceOf(QLearningRouter);
|
|
});
|
|
|
|
it('should export createASTAnalyzer', () => {
|
|
expect(typeof createASTAnalyzer).toBe('function');
|
|
const analyzer = createASTAnalyzer();
|
|
expect(analyzer).toBeInstanceOf(ASTAnalyzer);
|
|
});
|
|
|
|
it('should export createDiffClassifier', () => {
|
|
expect(typeof createDiffClassifier).toBe('function');
|
|
const classifier = createDiffClassifier();
|
|
expect(classifier).toBeInstanceOf(DiffClassifier);
|
|
});
|
|
|
|
it('should export createCoverageRouter', () => {
|
|
expect(typeof createCoverageRouter).toBe('function');
|
|
const router = createCoverageRouter();
|
|
expect(router).toBeInstanceOf(CoverageRouter);
|
|
});
|
|
});
|
|
|
|
describe('Graph Analyzer Functions', () => {
|
|
it('should export buildDependencyGraph', () => {
|
|
expect(typeof buildDependencyGraph).toBe('function');
|
|
});
|
|
|
|
it('should export analyzeGraph', () => {
|
|
expect(typeof analyzeGraph).toBe('function');
|
|
});
|
|
|
|
it('should export analyzeMinCutBoundaries', () => {
|
|
expect(typeof analyzeMinCutBoundaries).toBe('function');
|
|
});
|
|
|
|
it('should export analyzeModuleCommunities', () => {
|
|
expect(typeof analyzeModuleCommunities).toBe('function');
|
|
});
|
|
|
|
it('should export detectCircularDependencies', () => {
|
|
expect(typeof detectCircularDependencies).toBe('function');
|
|
});
|
|
|
|
it('should export exportToDot', () => {
|
|
expect(typeof exportToDot).toBe('function');
|
|
});
|
|
|
|
it('should export loadRuVector', () => {
|
|
expect(typeof loadRuVector).toBe('function');
|
|
});
|
|
|
|
it('should export fallbackMinCut', () => {
|
|
expect(typeof fallbackMinCut).toBe('function');
|
|
});
|
|
|
|
it('should export fallbackLouvain', () => {
|
|
expect(typeof fallbackLouvain).toBe('function');
|
|
});
|
|
});
|
|
|
|
describe('Class Exports', () => {
|
|
it('should export QLearningRouter class', () => {
|
|
expect(QLearningRouter).toBeDefined();
|
|
const router = new QLearningRouter();
|
|
expect(router).toBeInstanceOf(QLearningRouter);
|
|
});
|
|
|
|
it('should export ASTAnalyzer class', () => {
|
|
expect(ASTAnalyzer).toBeDefined();
|
|
const analyzer = new ASTAnalyzer();
|
|
expect(analyzer).toBeInstanceOf(ASTAnalyzer);
|
|
});
|
|
|
|
it('should export DiffClassifier class', () => {
|
|
expect(DiffClassifier).toBeDefined();
|
|
const classifier = new DiffClassifier();
|
|
expect(classifier).toBeInstanceOf(DiffClassifier);
|
|
});
|
|
|
|
it('should export CoverageRouter class', () => {
|
|
expect(CoverageRouter).toBeDefined();
|
|
const router = new CoverageRouter();
|
|
expect(router).toBeInstanceOf(CoverageRouter);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('RuVector Integration Scenarios', () => {
|
|
describe('Code Analysis Workflow', () => {
|
|
it('should analyze TypeScript code and extract information', () => {
|
|
const analyzer = createASTAnalyzer();
|
|
const code = `
|
|
import { helper } from './utils';
|
|
|
|
export class UserService {
|
|
getUsers() {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function createUser(name: string) {
|
|
return { name };
|
|
}
|
|
`;
|
|
|
|
const analysis = analyzer.analyze(code, 'user-service.ts');
|
|
|
|
expect(analysis.language).toBe('typescript');
|
|
expect(analysis.classes.length).toBeGreaterThan(0);
|
|
expect(analysis.functions.length).toBeGreaterThan(0);
|
|
expect(analysis.imports).toContain('./utils');
|
|
expect(analysis.exports).toContain('UserService');
|
|
expect(analysis.exports).toContain('createUser');
|
|
});
|
|
});
|
|
|
|
describe('Diff Analysis Workflow', () => {
|
|
it('should analyze diff and provide classification', () => {
|
|
const classifier = createDiffClassifier();
|
|
const diff = `diff --git a/src/auth/login.ts b/src/auth/login.ts
|
|
--- a/src/auth/login.ts
|
|
+++ b/src/auth/login.ts
|
|
@@ -10,6 +10,10 @@ export async function login(username: string, password: string) {
|
|
const user = await findUser(username);
|
|
+
|
|
+ // Add rate limiting
|
|
+ if (await isRateLimited(username)) {
|
|
+ throw new Error('Too many attempts');
|
|
+ }
|
|
|
|
if (!user) {
|
|
throw new Error('User not found');
|
|
`;
|
|
|
|
const files = classifier.parseDiff(diff);
|
|
const analysis = classifier.classify(files);
|
|
|
|
expect(analysis.files.length).toBe(1);
|
|
expect(analysis.overall.impactLevel).toBe('critical'); // auth file
|
|
expect(analysis.overall.testingStrategy.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Coverage Routing Workflow', () => {
|
|
it('should route based on coverage and suggest improvements', () => {
|
|
const router = createCoverageRouter();
|
|
const coverageData = {
|
|
'src/critical/auth.ts': {
|
|
lineCoverage: 45,
|
|
branchCoverage: 30,
|
|
functionCoverage: 50,
|
|
statementCoverage: 45,
|
|
uncoveredLines: [10, 20, 30, 40, 50],
|
|
totalLines: 100,
|
|
coveredLines: 45,
|
|
},
|
|
'src/utils/helper.ts': {
|
|
lineCoverage: 90,
|
|
branchCoverage: 85,
|
|
functionCoverage: 95,
|
|
statementCoverage: 90,
|
|
uncoveredLines: [5],
|
|
totalLines: 50,
|
|
coveredLines: 45,
|
|
},
|
|
};
|
|
|
|
const report = router.parseCoverage(coverageData, 'json');
|
|
const result = router.route(report);
|
|
|
|
expect(result.action).toBe('prioritize'); // Low overall coverage
|
|
expect(result.targetFiles.length).toBeGreaterThan(0);
|
|
expect(result.gaps.length).toBeGreaterThan(0);
|
|
expect(report.uncoveredCritical.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Dependency Graph Workflow', () => {
|
|
it('should build graph using function-based API', async () => {
|
|
// The function-based API builds graphs from directories
|
|
// For testing without actual files, we test that the functions are callable
|
|
expect(typeof buildDependencyGraph).toBe('function');
|
|
expect(typeof analyzeGraph).toBe('function');
|
|
expect(typeof detectCircularDependencies).toBe('function');
|
|
expect(typeof exportToDot).toBe('function');
|
|
});
|
|
|
|
it('should detect circular dependencies in graphs', () => {
|
|
// Create a mock graph with circular dependency
|
|
const graph = {
|
|
nodes: new Map([
|
|
['a.ts', { id: 'a.ts', path: 'a.ts', name: 'a.ts', type: 'file', imports: ['./b'], exports: ['a'], size: 100 }],
|
|
['b.ts', { id: 'b.ts', path: 'b.ts', name: 'b.ts', type: 'file', imports: ['./a'], exports: ['b'], size: 100 }],
|
|
]),
|
|
edges: [
|
|
{ source: 'a.ts', target: 'b.ts', type: 'import', weight: 1 },
|
|
{ source: 'b.ts', target: 'a.ts', type: 'import', weight: 1 },
|
|
],
|
|
metadata: { rootDir: '.', totalFiles: 2, totalEdges: 2, buildTime: 0 },
|
|
};
|
|
|
|
const cycles = detectCircularDependencies(graph as any);
|
|
expect(Array.isArray(cycles)).toBe(true);
|
|
});
|
|
|
|
it('should export graph to DOT format using GraphAnalysisResult', () => {
|
|
// exportToDot takes GraphAnalysisResult, not DependencyGraph
|
|
const analysisResult = {
|
|
graph: {
|
|
nodes: new Map([
|
|
['a.ts', { id: 'a.ts', path: 'a.ts', name: 'a.ts', type: 'file', imports: [], exports: ['a'], size: 100 }],
|
|
]),
|
|
edges: [],
|
|
metadata: { rootDir: '.', totalFiles: 1, totalEdges: 0, buildTime: 0 },
|
|
},
|
|
circularDependencies: [],
|
|
statistics: { nodeCount: 1, edgeCount: 0, avgDegree: 0, maxDegree: 0, density: 0, componentCount: 1 },
|
|
};
|
|
|
|
const dot = exportToDot(analysisResult as any);
|
|
expect(dot).toContain('digraph');
|
|
});
|
|
});
|
|
|
|
describe('Q-Learning Task Routing Workflow', () => {
|
|
it('should learn and improve routing decisions', async () => {
|
|
const router = createQLearningRouter({
|
|
explorationInitial: 0.1, // Low exploration for predictable tests
|
|
});
|
|
|
|
// Train the router with feedback
|
|
router.update('implement user authentication', 'coder', 10.0);
|
|
router.update('write unit tests for auth', 'tester', 10.0);
|
|
router.update('review security of auth module', 'reviewer', 10.0);
|
|
router.update('design database schema', 'architect', 10.0);
|
|
|
|
// After training, router should make informed decisions
|
|
const coderDecision = router.route('implement new feature', false);
|
|
const testerDecision = router.route('write tests for feature', false);
|
|
|
|
expect(coderDecision.confidence).toBeGreaterThan(0);
|
|
expect(testerDecision.confidence).toBeGreaterThan(0);
|
|
expect(coderDecision.alternatives.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should persist and restore learning', () => {
|
|
const router1 = createQLearningRouter();
|
|
|
|
// Train router 1
|
|
router1.update('task1', 'coder', 10.0);
|
|
router1.update('task2', 'tester', 8.0);
|
|
|
|
// Export state
|
|
const exported = router1.export();
|
|
|
|
// Create new router and import
|
|
const router2 = createQLearningRouter();
|
|
router2.import(exported);
|
|
|
|
// Verify state was restored
|
|
expect(router2.getStats().qTableSize).toBe(router1.getStats().qTableSize);
|
|
});
|
|
});
|
|
|
|
describe('Combined Workflow', () => {
|
|
it('should use multiple analyzers together', () => {
|
|
// 1. Analyze code structure
|
|
const astAnalyzer = createASTAnalyzer();
|
|
const code = `
|
|
export function processOrder(order: Order) {
|
|
if (!order.items.length) {
|
|
throw new Error('Empty order');
|
|
}
|
|
return calculateTotal(order);
|
|
}
|
|
`;
|
|
const astAnalysis = astAnalyzer.analyze(code, 'order.ts');
|
|
|
|
// 2. Use function-based graph API with GraphAnalysisResult
|
|
const mockAnalysisResult = {
|
|
graph: {
|
|
nodes: new Map([
|
|
['order.ts', { id: 'order.ts', path: 'order.ts', name: 'order.ts', type: 'file', imports: ['./utils'], exports: astAnalysis.exports, size: 200 }],
|
|
['utils.ts', { id: 'utils.ts', path: 'utils.ts', name: 'utils.ts', type: 'file', imports: [], exports: ['calculateTotal'], size: 100 }],
|
|
]),
|
|
edges: [{ source: 'order.ts', target: 'utils.ts', type: 'import', weight: 1 }],
|
|
metadata: { rootDir: '.', totalFiles: 2, totalEdges: 1, buildTime: 0 },
|
|
},
|
|
circularDependencies: [],
|
|
statistics: { nodeCount: 2, edgeCount: 1, avgDegree: 0.5, maxDegree: 1, density: 0.5, componentCount: 1 },
|
|
};
|
|
const dotOutput = exportToDot(mockAnalysisResult as any);
|
|
|
|
// 3. Check coverage
|
|
const coverageRouter = createCoverageRouter();
|
|
const coverageReport = coverageRouter.parseCoverage({
|
|
'order.ts': {
|
|
lineCoverage: 60,
|
|
branchCoverage: 50,
|
|
functionCoverage: 100,
|
|
statementCoverage: 60,
|
|
uncoveredLines: [3, 4],
|
|
totalLines: 10,
|
|
coveredLines: 6,
|
|
},
|
|
}, 'json');
|
|
|
|
const coverageResult = coverageRouter.route(coverageReport);
|
|
|
|
// 4. Route to appropriate agent
|
|
const qRouter = createQLearningRouter();
|
|
qRouter.update('write tests for order processing', 'tester', 10.0);
|
|
const routeDecision = qRouter.route('add tests for order.ts', false);
|
|
|
|
// Verify integration
|
|
expect(astAnalysis.functions.length).toBeGreaterThan(0);
|
|
expect(mockAnalysisResult.graph.nodes.size).toBeGreaterThan(0);
|
|
expect(dotOutput).toContain('digraph');
|
|
expect(coverageResult.targetFiles.length).toBeGreaterThan(0);
|
|
expect(routeDecision.route).toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
it('should handle invalid inputs gracefully', () => {
|
|
const astAnalyzer = createASTAnalyzer();
|
|
expect(() => astAnalyzer.analyze('', 'empty.ts')).not.toThrow();
|
|
|
|
const diffClassifier = createDiffClassifier();
|
|
expect(() => diffClassifier.parseDiff('')).not.toThrow();
|
|
|
|
// Graph analyzer - detectCircularDependencies with proper structure
|
|
const emptyGraph = {
|
|
nodes: new Map(),
|
|
edges: [],
|
|
metadata: { rootDir: '.', totalFiles: 0, totalEdges: 0, buildTime: 0 },
|
|
};
|
|
expect(() => detectCircularDependencies(emptyGraph as any)).not.toThrow();
|
|
|
|
// exportToDot requires GraphAnalysisResult
|
|
const emptyAnalysisResult = {
|
|
graph: emptyGraph,
|
|
circularDependencies: [],
|
|
statistics: { nodeCount: 0, edgeCount: 0, avgDegree: 0, maxDegree: 0, density: 0, componentCount: 0 },
|
|
};
|
|
expect(() => exportToDot(emptyAnalysisResult as any)).not.toThrow();
|
|
|
|
const coverageRouter = createCoverageRouter();
|
|
expect(() => coverageRouter.parseCoverage({}, 'json')).not.toThrow();
|
|
|
|
const qRouter = createQLearningRouter();
|
|
expect(() => qRouter.route('')).not.toThrow();
|
|
});
|
|
|
|
it('should handle malformed data gracefully', () => {
|
|
const coverageRouter = createCoverageRouter();
|
|
|
|
// Invalid LCOV
|
|
expect(() => coverageRouter.parseCoverage('invalid lcov data', 'lcov')).not.toThrow();
|
|
|
|
// Invalid Cobertura
|
|
expect(() => coverageRouter.parseCoverage('<invalid>xml</invalid>', 'cobertura')).not.toThrow();
|
|
|
|
// Note: parseCoverage may throw for certain invalid inputs - that's expected behavior
|
|
// The key is that it handles valid formats properly
|
|
});
|
|
});
|
|
|
|
describe('Performance', () => {
|
|
it('should handle large graph operations efficiently', () => {
|
|
// Generate large mock graph
|
|
const nodes = new Map();
|
|
const graphEdges = [];
|
|
for (let i = 0; i < 100; i++) {
|
|
nodes.set(`module${i}/file.ts`, {
|
|
id: `module${i}/file.ts`,
|
|
path: `src/module${i}/file.ts`,
|
|
name: `file${i}.ts`,
|
|
type: 'file',
|
|
imports: i > 0 ? [`../module${i-1}/file`] : [],
|
|
exports: [`export${i}`],
|
|
size: 100,
|
|
});
|
|
if (i > 0) {
|
|
graphEdges.push({ source: `module${i}/file.ts`, target: `module${i-1}/file.ts`, type: 'import', weight: 1 });
|
|
}
|
|
}
|
|
|
|
const graph = {
|
|
nodes,
|
|
edges: graphEdges,
|
|
metadata: { rootDir: '.', totalFiles: 100, totalEdges: 99, buildTime: 0 },
|
|
};
|
|
const analysisResult = {
|
|
graph,
|
|
circularDependencies: [],
|
|
statistics: { nodeCount: 100, edgeCount: 99, avgDegree: 0.99, maxDegree: 1, density: 0.01, componentCount: 1 },
|
|
};
|
|
|
|
const startTime = performance.now();
|
|
const cycles = detectCircularDependencies(graph as any);
|
|
const dot = exportToDot(analysisResult as any);
|
|
const duration = performance.now() - startTime;
|
|
|
|
expect(nodes.size).toBe(100);
|
|
expect(Array.isArray(cycles)).toBe(true);
|
|
expect(dot).toContain('digraph');
|
|
expect(duration).toBeLessThan(1000); // Should complete within 1 second
|
|
});
|
|
|
|
it('should cache results for performance', () => {
|
|
const astAnalyzer = createASTAnalyzer();
|
|
const code = 'function test() { return 1; }';
|
|
|
|
// First analysis
|
|
const start1 = performance.now();
|
|
astAnalyzer.analyze(code, 'test.ts');
|
|
const duration1 = performance.now() - start1;
|
|
|
|
// Cached analysis
|
|
const start2 = performance.now();
|
|
astAnalyzer.analyze(code, 'test.ts');
|
|
const duration2 = performance.now() - start2;
|
|
|
|
// Cached should be faster (or at least not significantly slower)
|
|
expect(duration2).toBeLessThanOrEqual(duration1 + 5);
|
|
});
|
|
});
|