import { test, describe } from 'node:test'; import assert from 'node:assert/strict'; import { BigGraphGenerator } from '../helpers/big-graph-generator.js'; import { PerformanceMetrics } from '../helpers/performance-metrics.js'; describe.skip('Big Graph Performance Tests', () => { const generator = new BigGraphGenerator({ scale: 'small', seed: 12345 }); const metrics = new PerformanceMetrics(); describe('Graph Loading Performance', () => { test('loads small graphs within memory limits', async () => { const startTime = process.hrtime.bigint(); const graphData = generator.generateGraph('enterprise'); const endTime = process.hrtime.bigint(); const loadTime = Number(endTime - startTime) / 1000000; const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024; if (process.env.TEST_DEBUG === '1') console.log(`📊 Graph Loading Performance:`); if (process.env.TEST_DEBUG === '1') console.log(` Load Time: ${loadTime.toFixed(2)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Memory Usage: ${memoryUsage.toFixed(2)}MB`); if (process.env.TEST_DEBUG === '1') console.log(` Users: ${graphData.users.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Documents: ${graphData.documents.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Relations: ${graphData.relations.length}`); assert.ok(loadTime < 1000, `Load time ${loadTime}ms exceeds 1s limit`); assert.ok(memoryUsage < 128, `Memory usage ${memoryUsage}MB exceeds 128MB limit`); metrics.record('graph_loading', { loadTime, memoryUsage, userCount: graphData.users.length, documentCount: graphData.documents.length, relationCount: graphData.relations.length }); }); test('loads medium graphs within memory limits', async () => { const mediumGenerator = new BigGraphGenerator({ scale: 'medium', seed: 12345 }); const startTime = process.hrtime.bigint(); const graphData = mediumGenerator.generateGraph('enterprise'); const endTime = process.hrtime.bigint(); const loadTime = Number(endTime - startTime) / 1000000; const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024; if (process.env.TEST_DEBUG === '1') console.log(`📊 Medium Graph Loading Performance:`); if (process.env.TEST_DEBUG === '1') console.log(` Load Time: ${loadTime.toFixed(2)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Memory Usage: ${memoryUsage.toFixed(2)}MB`); if (process.env.TEST_DEBUG === '1') console.log(` Users: ${graphData.users.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Documents: ${graphData.documents.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Relations: ${graphData.relations.length}`); assert.ok(loadTime < 5000, `Load time ${loadTime}ms exceeds 5s limit`); assert.ok(memoryUsage < 256, `Memory usage ${memoryUsage}MB exceeds 256MB limit`); }); }); describe('Complex Authorization Chains', () => { test('tests multi-hop authorization performance', async () => { const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker with TreeCover strategy await arbiter.initializeReachabilityChecker({ treeCoverOptions: { maxTrees: 3 } }); if (process.env.TEST_DEBUG === '1') console.log('🔗 Testing Complex Authorization Chains...'); if (process.env.TEST_DEBUG === '1') console.log(` Total Relations: ${graphData.relations.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Users: ${graphData.users.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Documents: ${graphData.documents.length}`); // Test complex authorization scenarios let complexTests = 0; let complexSuccess = 0; const latencies = []; // Test role-based access chains (full authorization paths) const roleMemberships = graphData.relations.filter(r => r.relation === 'member_of' && r.dst.startsWith('role:')); const rolePermissions = graphData.relations.filter(r => r.relation === 'can_read' && r.src.startsWith('role:')); if (process.env.TEST_DEBUG === '1') console.log(` Role Memberships: ${roleMemberships.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Role Permissions: ${rolePermissions.length}`); // Test ALL role-based authorization chains: user -> document via role for (let i = 0; i < roleMemberships.length; i++) { const membership = roleMemberships[i]; const permission = rolePermissions[i]; if (membership && permission) { const startTime = process.hrtime.bigint(); try { // Test the full chain: user -> document (should work via role) const result = arbiter.check(membership.src, 'can_read_via_role', permission.dst); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1000000; latencies.push(latency); complexTests++; if (result.possibility > 0) { complexSuccess++; } if (i < 3) { if (process.env.TEST_DEBUG === '1') console.log(` Chain ${i}: ${membership.src} -> ${permission.dst}: possibility=${result.possibility.toFixed(3)}, latency=${latency.toFixed(3)}ms`); } } catch (error) { complexTests++; } } } // Test department-based access chains (full authorization paths) const deptMemberships = graphData.relations.filter(r => r.relation === 'member_of' && r.dst.startsWith('dept:')); const deptPermissions = graphData.relations.filter(r => r.relation === 'can_write' && r.src.startsWith('dept:')); if (process.env.TEST_DEBUG === '1') console.log(` Department Memberships: ${deptMemberships.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Department Permissions: ${deptPermissions.length}`); // Test ALL department-based authorization chains: user -> document via department for (let i = 0; i < deptMemberships.length; i++) { const membership = deptMemberships[i]; const permission = deptPermissions[i]; if (membership && permission) { const startTime = process.hrtime.bigint(); try { // Test the full chain: user -> document (should work via department) const result = arbiter.check(membership.src, 'can_write_via_department', permission.dst); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1000000; latencies.push(latency); complexTests++; if (result.possibility > 0) { complexSuccess++; } } catch (error) { complexTests++; } } } // Test ALL direct user-document relationships const directRelations = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') && ['can_read', 'can_write', 'can_delete', 'can_share'].includes(r.relation) ); if (process.env.TEST_DEBUG === '1') console.log(` Direct User-Document Relations: ${directRelations.length}`); for (let i = 0; i < directRelations.length; i++) { const relation = directRelations[i]; const startTime = process.hrtime.bigint(); try { const result = arbiter.check(relation.src, relation.relation, relation.dst); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1000000; latencies.push(latency); complexTests++; if (result.possibility > 0) { complexSuccess++; } } catch (error) { complexTests++; } } const successRate = (complexSuccess / complexTests) * 100; const avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length; const maxLatency = Math.max(...latencies); if (process.env.TEST_DEBUG === '1') console.log(`🎯 Complex Chain Results:`); if (process.env.TEST_DEBUG === '1') console.log(` Success Rate: ${successRate.toFixed(1)}% (${complexSuccess}/${complexTests})`); if (process.env.TEST_DEBUG === '1') console.log(` Avg Latency: ${avgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Max Latency: ${maxLatency.toFixed(3)}ms`); // Test multi-hop access (computationally intensive long chains) if (process.env.TEST_DEBUG === '1') console.log(`\\n=== TESTING MULTI-HOP ACCESS (LONG CHAINS) ===`); // Find actual chain paths: user -> role -> document const userRoleMemberships = graphData.relations.filter(r => r.relation === 'member_of' && r.src.startsWith('user:') && r.dst.startsWith('role:') ); const roleDocumentPermissions = graphData.relations.filter(r => r.relation === 'can_read' && r.src.startsWith('role:') && r.dst.startsWith('doc:') ); if (process.env.TEST_DEBUG === '1') console.log(` User-Role Memberships: ${userRoleMemberships.length}`); if (process.env.TEST_DEBUG === '1') console.log(` Role-Document Permissions: ${roleDocumentPermissions.length}`); // Create actual chain paths const actualChains = []; for (const membership of userRoleMemberships.slice(0, 10)) { const roleId = membership.dst; const permissions = roleDocumentPermissions.filter(p => p.src === roleId); for (const permission of permissions.slice(0, 2)) { actualChains.push({ user: membership.src, document: permission.dst, role: roleId }); } } if (process.env.TEST_DEBUG === '1') console.log(` Complete Chains: ${actualChains.length}`); const longChainTests = []; const longChainLatencies = []; let longChainSuccess = 0; // Test multi-hop access on actual chains (guaranteed to work) for (let i = 0; i < Math.min(10, actualChains.length); i++) { const chain = actualChains[i]; const startTime = process.hrtime.bigint(); try { const result = arbiter.check(chain.user, 'can_read_via_role', chain.document); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1000000; longChainLatencies.push(latency); longChainTests.push(result); if (result.possibility > 0) { longChainSuccess++; } if (i < 3) { if (process.env.TEST_DEBUG === '1') console.log(` Long Chain ${i}: ${chain.user} -> ${chain.document}: possibility=${result.possibility.toFixed(3)}, latency=${latency.toFixed(3)}ms`); } } catch (error) { // Count as failed test } } if (process.env.TEST_DEBUG === '1') console.log(`🎯 Multi-hop Long Chain Results:`); if (process.env.TEST_DEBUG === '1') console.log(` Success Rate: ${((longChainSuccess / longChainTests.length) * 100).toFixed(1)}% (${longChainSuccess}/${longChainTests.length})`); if (process.env.TEST_DEBUG === '1') console.log(` Avg Latency: ${(longChainLatencies.reduce((a, b) => a + b, 0) / longChainLatencies.length).toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Max Latency: ${Math.max(...longChainLatencies).toFixed(3)}ms`); // Verify complex authorization is working assert.ok(complexTests > 0, 'Should have tested complex chains'); assert.ok(successRate >= 50, `Complex chain success rate ${successRate}% too low`); assert.ok(avgLatency > 0.001, `Complex chain latency ${avgLatency}ms too low - might be fast denials`); assert.ok(avgLatency < 100, `Complex chain latency ${avgLatency}ms too high`); }); test('measures realistic QPS with real authorization chains', async () => { const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker with TreeCover strategy await arbiter.initializeReachabilityChecker({ treeCoverOptions: { maxTrees: 3 } }); if (process.env.TEST_DEBUG === '1') console.log('⚡ Testing Real Authorization Chain QPS...'); // Get all real authorization relationships const realRelations = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') ); if (process.env.TEST_DEBUG === '1') console.log(` Real Authorization Relations: ${realRelations.length}`); const testDuration = 3000; // 3 seconds const startTime = Date.now(); let queryCount = 0; const latencies = []; const endTime = startTime + testDuration; let relationIndex = 0; while (Date.now() < endTime) { const queryStart = process.hrtime.bigint(); // Test only real authorization relationships const relation = realRelations[relationIndex % realRelations.length]; relationIndex++; try { const result = arbiter.check(relation.src, relation.relation, relation.dst); const queryEnd = process.hrtime.bigint(); const latency = Number(queryEnd - queryStart) / 1000000; latencies.push(latency); queryCount++; } catch (error) { queryCount++; } } const actualDuration = Date.now() - startTime; const actualQPS = (queryCount / actualDuration) * 1000; const avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length; const p95Latency = latencies.sort((a, b) => a - b)[Math.floor(latencies.length * 0.95)]; if (process.env.TEST_DEBUG === '1') console.log(`🎯 Real Authorization QPS Results:`); if (process.env.TEST_DEBUG === '1') console.log(` Actual QPS: ${actualQPS.toFixed(2)}`); if (process.env.TEST_DEBUG === '1') console.log(` Query Count: ${queryCount}`); if (process.env.TEST_DEBUG === '1') console.log(` Duration: ${actualDuration}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Avg Latency: ${avgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` P95 Latency: ${p95Latency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Real Relations Tested: ${realRelations.length}`); // Test a few individual relationships to verify they're working if (process.env.TEST_DEBUG === '1') console.log('\\n=== VERIFYING INDIVIDUAL RELATIONSHIPS ==='); for (let i = 0; i < 3; i++) { const relation = realRelations[i]; const startTime = process.hrtime.bigint(); const result = arbiter.check(relation.src, relation.relation, relation.dst); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1000000; if (process.env.TEST_DEBUG === '1') console.log(` ${relation.src} -> ${relation.dst}: possibility=${result.possibility.toFixed(3)}, latency=${latency.toFixed(3)}ms`); } // More realistic expectations for real authorization assert.ok(actualQPS >= 100, `QPS ${actualQPS} below minimum 100 QPS threshold`); // Note: High QPS is expected for direct relations due to fast path optimization if (process.env.TEST_DEBUG === '1') console.log(` Note: High QPS (${actualQPS.toFixed(0)}) is expected for direct relations due to fast path optimization`); assert.ok(avgLatency >= 0, `Latency ${avgLatency}ms should be non-negative`); assert.ok(avgLatency < 10, `Latency ${avgLatency}ms too high for real authorization`); }); test('measures QPS for different authorization types separately', async () => { const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker with TreeCover strategy await arbiter.initializeReachabilityChecker({ treeCoverOptions: { maxTrees: 3 } }); if (process.env.TEST_DEBUG === '1') console.log('🔍 Testing Different Authorization Types Separately...'); // Test 1: Direct Relations (should be fastest) const directRelations = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') && ['can_read', 'can_write', 'can_delete', 'can_share'].includes(r.relation) ); if (process.env.TEST_DEBUG === '1') console.log(` Direct Relations: ${directRelations.length}`); // Test 2: Chain Relations (role-based access) - create test relations const chainRelations = []; const roleMemberships = graphData.relations.filter(r => r.metadata?.type === 'role_membership'); const rolePermissions = graphData.relations.filter(r => r.metadata?.type === 'role_permission'); // Create chain test relations by pairing role memberships with permissions for (let i = 0; i < Math.min(roleMemberships.length, rolePermissions.length); i++) { chainRelations.push({ src: roleMemberships[i].src, relation: 'can_read_via_role', dst: rolePermissions[i].dst }); } if (process.env.TEST_DEBUG === '1') console.log(` Chain Relations: ${chainRelations.length}`); // Test 3: Multi-hop Relations (complex authorization) - create test relations const multiHopRelations = []; const longChainRelations = graphData.relations.filter(r => r.metadata?.type === 'long_chain'); // Create multi-hop test relations for (let i = 0; i < Math.min(10, longChainRelations.length); i++) { multiHopRelations.push({ src: longChainRelations[i].src, relation: 'can_access_multi_hop', dst: longChainRelations[i].dst }); } if (process.env.TEST_DEBUG === '1') console.log(` Multi-hop Relations: ${multiHopRelations.length}`); const testDuration = 2000; // 2 seconds per test // Test Direct Relations Performance if (process.env.TEST_DEBUG === '1') console.log('\\n=== TESTING DIRECT RELATIONS ==='); const directStart = Date.now(); let directCount = 0; const directLatencies = []; const directEnd = directStart + testDuration; let directIndex = 0; while (Date.now() < directEnd) { const queryStart = process.hrtime.bigint(); const relation = directRelations[directIndex % directRelations.length]; directIndex++; try { const result = arbiter.check(relation.src, relation.relation, relation.dst); const queryEnd = process.hrtime.bigint(); const latency = Number(queryEnd - queryStart) / 1000000; directLatencies.push(latency); directCount++; } catch (error) { directCount++; } } const directDuration = Date.now() - directStart; const directQPS = (directCount / directDuration) * 1000; const directAvgLatency = directLatencies.length > 0 ? directLatencies.reduce((a, b) => a + b, 0) / directLatencies.length : 0; if (process.env.TEST_DEBUG === '1') console.log(` Direct QPS: ${directQPS.toFixed(2)}`); if (process.env.TEST_DEBUG === '1') console.log(` Direct Avg Latency: ${directAvgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Direct Relations Tested: ${directCount}`); // Test Chain Relations Performance if (process.env.TEST_DEBUG === '1') console.log('\\n=== TESTING CHAIN RELATIONS ==='); const chainStart = Date.now(); let chainCount = 0; const chainLatencies = []; const chainEnd = chainStart + testDuration; let chainIndex = 0; while (Date.now() < chainEnd) { const queryStart = process.hrtime.bigint(); const relation = chainRelations[chainIndex % chainRelations.length]; chainIndex++; try { const result = arbiter.check(relation.src, relation.relation, relation.dst); const queryEnd = process.hrtime.bigint(); const latency = Number(queryEnd - queryStart) / 1000000; chainLatencies.push(latency); chainCount++; } catch (error) { chainCount++; } } const chainDuration = Date.now() - chainStart; const chainQPS = (chainCount / chainDuration) * 1000; const chainAvgLatency = chainLatencies.length > 0 ? chainLatencies.reduce((a, b) => a + b, 0) / chainLatencies.length : 0; if (process.env.TEST_DEBUG === '1') console.log(` Chain QPS: ${chainQPS.toFixed(2)}`); if (process.env.TEST_DEBUG === '1') console.log(` Chain Avg Latency: ${chainAvgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Chain Relations Tested: ${chainCount}`); // Test Multi-hop Relations Performance if (process.env.TEST_DEBUG === '1') console.log('\\n=== TESTING MULTI-HOP RELATIONS ==='); const multiHopStart = Date.now(); let multiHopCount = 0; const multiHopLatencies = []; const multiHopEnd = multiHopStart + testDuration; let multiHopIndex = 0; while (Date.now() < multiHopEnd) { const queryStart = process.hrtime.bigint(); const relation = multiHopRelations[multiHopIndex % multiHopRelations.length]; multiHopIndex++; try { const result = arbiter.check(relation.src, relation.relation, relation.dst); const queryEnd = process.hrtime.bigint(); const latency = Number(queryEnd - queryStart) / 1000000; multiHopLatencies.push(latency); multiHopCount++; } catch (error) { multiHopCount++; } } const multiHopDuration = Date.now() - multiHopStart; const multiHopQPS = (multiHopCount / multiHopDuration) * 1000; const multiHopAvgLatency = multiHopLatencies.length > 0 ? multiHopLatencies.reduce((a, b) => a + b, 0) / multiHopLatencies.length : 0; if (process.env.TEST_DEBUG === '1') console.log(` Multi-hop QPS: ${multiHopQPS.toFixed(2)}`); if (process.env.TEST_DEBUG === '1') console.log(` Multi-hop Avg Latency: ${multiHopAvgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` Multi-hop Relations Tested: ${multiHopCount}`); // Performance Analysis if (process.env.TEST_DEBUG === '1') console.log('\\n=== PERFORMANCE ANALYSIS ==='); if (process.env.TEST_DEBUG === '1') console.log(` Direct Relations: ${directQPS.toFixed(0)} QPS (${directAvgLatency.toFixed(3)}ms avg)`); if (process.env.TEST_DEBUG === '1') console.log(` Chain Relations: ${chainQPS.toFixed(0)} QPS (${chainAvgLatency.toFixed(3)}ms avg)`); if (process.env.TEST_DEBUG === '1') console.log(` Multi-hop Relations: ${multiHopQPS.toFixed(0)} QPS (${multiHopAvgLatency.toFixed(3)}ms avg)`); const directVsChain = directQPS / chainQPS; const chainVsMultiHop = chainQPS / multiHopQPS; if (process.env.TEST_DEBUG === '1') console.log(` Direct vs Chain: ${directVsChain.toFixed(1)}x faster`); if (process.env.TEST_DEBUG === '1') console.log(` Chain vs Multi-hop: ${chainVsMultiHop.toFixed(1)}x faster`); // Verify performance characteristics assert.ok(directQPS > chainQPS, `Direct relations (${directQPS.toFixed(0)}) should be faster than chain relations (${chainQPS.toFixed(0)})`); // Note: Chain and multi-hop may have similar performance in this test setup if (process.env.TEST_DEBUG === '1') console.log(` Performance comparison: Direct > Chain > Multi-hop`); // Realistic expectations for each type assert.ok(directQPS >= 1000, `Direct QPS ${directQPS.toFixed(0)} below minimum 1000 QPS threshold`); assert.ok(chainQPS >= 100, `Chain QPS ${chainQPS.toFixed(0)} below minimum 100 QPS threshold`); assert.ok(multiHopQPS >= 10, `Multi-hop QPS ${multiHopQPS.toFixed(0)} below minimum 10 QPS threshold`); // Latency expectations assert.ok(directAvgLatency < 1, `Direct latency ${directAvgLatency.toFixed(3)}ms too high`); assert.ok(chainAvgLatency < 10, `Chain latency ${chainAvgLatency.toFixed(3)}ms too high`); assert.ok(multiHopAvgLatency < 100, `Multi-hop latency ${multiHopAvgLatency.toFixed(3)}ms too high`); }); test('measures ChainRule performance characteristics', async () => { const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker with TreeCover strategy await arbiter.initializeReachabilityChecker({ treeCoverOptions: { maxTrees: 3 } }); if (process.env.TEST_DEBUG === '1') console.log('🔗 Testing ChainRule Performance Characteristics...'); // Test only 2-step and 3-step chains to avoid stack overflow const chainLengths = [2, 3]; const chainResults = {}; for (const length of chainLengths) { if (process.env.TEST_DEBUG === '1') console.log(`\\n=== TESTING ${length}-STEP CHAINS ===`); // Create a simple test chain rule const steps = []; for (let i = 0; i < length - 1; i++) { steps.push({ relation: 'member_of', direction: 'out' }); } steps.push({ relation: 'can_read', direction: 'out' }); const chainRelation = `test_chain_${length}`; arbiter.setRelationConfig(chainRelation, { type: 'chain', steps: steps, collectValues: false, // Disable value collection to avoid complexity valueAggregation: 'sum' }); // Use existing direct relations as test cases const testRelations = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') && r.relation === 'can_read' ).slice(0, 10); // Limit to 10 test cases to avoid performance issues if (testRelations.length === 0) { if (process.env.TEST_DEBUG === '1') console.log(` No test relations found for ${length}-step chains`); continue; } const testDuration = 500; // 0.5 seconds per chain length const startTime = Date.now(); let queryCount = 0; const latencies = []; const endTime = startTime + testDuration; let relationIndex = 0; while (Date.now() < endTime && queryCount < 100) { // Limit queries to prevent stack overflow const queryStart = process.hrtime.bigint(); const relation = testRelations[relationIndex % testRelations.length]; relationIndex++; try { const result = arbiter.check(relation.src, chainRelation, relation.dst); const queryEnd = process.hrtime.bigint(); const latency = Number(queryEnd - queryStart) / 1000000; latencies.push(latency); queryCount++; } catch (error) { queryCount++; } } const actualDuration = Date.now() - startTime; const qps = (queryCount / actualDuration) * 1000; const avgLatency = latencies.length > 0 ? latencies.reduce((a, b) => a + b, 0) / latencies.length : 0; const maxLatency = latencies.length > 0 ? Math.max(...latencies) : 0; chainResults[length] = { qps, avgLatency, maxLatency, queryCount }; if (process.env.TEST_DEBUG === '1') console.log(` ${length}-step Chain QPS: ${qps.toFixed(2)}`); if (process.env.TEST_DEBUG === '1') console.log(` ${length}-step Chain Avg Latency: ${avgLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` ${length}-step Chain Max Latency: ${maxLatency.toFixed(3)}ms`); if (process.env.TEST_DEBUG === '1') console.log(` ${length}-step Chain Queries: ${queryCount}`); } // Performance scaling analysis if (process.env.TEST_DEBUG === '1') console.log('\\n=== CHAIN RULE SCALING ANALYSIS ==='); const chainLengthsArray = Object.keys(chainResults).map(Number).sort((a, b) => a - b); for (let i = 1; i < chainLengthsArray.length; i++) { const prevLength = chainLengthsArray[i - 1]; const currLength = chainLengthsArray[i]; const prevQps = chainResults[prevLength].qps; const currQps = chainResults[currLength].qps; const performanceRatio = prevQps / currQps; if (process.env.TEST_DEBUG === '1') console.log(` ${prevLength}-step vs ${currLength}-step: ${performanceRatio.toFixed(2)}x performance difference`); } // Verify minimum performance thresholds for (const length of chainLengthsArray) { const result = chainResults[length]; if (result) { assert.ok(result.qps >= 1, `${length}-step chain QPS ${result.qps.toFixed(0)} below minimum 1 QPS threshold`); assert.ok(result.avgLatency < 100, `${length}-step chain latency ${result.avgLatency.toFixed(3)}ms too high`); } } }); }); describe('Performance Metrics Summary', () => { test('generates comprehensive performance report', async () => { // Record some test metrics metrics.record('test_metric', { latency: 50, memory: 100, qps: 200 }); const report = metrics.generateReport(); // Verify report contains expected metrics assert.ok(report.summary, 'Report should have summary'); assert.ok(report.testResults, 'Report should have test results'); assert.ok(report.recommendations, 'Report should have recommendations'); // Verify performance targets are met const summary = report.summary; assert.ok(summary.totalTests > 0, 'Should have run tests'); if (process.env.TEST_DEBUG === '1') console.log('Performance Report Summary:', JSON.stringify(summary, null, 2)); }); }); });