initial commit: @arbiter/core authorization engine with js-rigor hardening
Zanzibar-style authorization graph engine (direct/chain/TTU/defeasible/ binary modes, condensed snapshots, value relations) with 39 rigor test campaigns. Includes fixes for snapshot binary writer/reader format mismatch (snapshot-of-snapshot corruption), possibility write-boundary validation, empty-graph snapshot serialization, relation lookup cache direction collision, config-redefinition cache invalidation, binary threshold semantics, defeasible compiled routing, and comparator reason whitelisting.
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
import { test, describe, before, after } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { Arbiter } from '../../src/index.js';
|
||||
import { BigGraphGenerator } from '../helpers/big-graph-generator.js';
|
||||
import { PerformanceMetrics } from '../helpers/performance-metrics.js';
|
||||
|
||||
describe.skip('Big Graph Optimized Performance Tests (Simplified)', () => {
|
||||
let generator;
|
||||
let metrics;
|
||||
|
||||
before(() => {
|
||||
generator = new BigGraphGenerator({ scale: 'small', seed: 12345 });
|
||||
metrics = new PerformanceMetrics();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// Cleanup
|
||||
generator = null;
|
||||
metrics = null;
|
||||
});
|
||||
|
||||
test('runs comprehensive performance test suite', async () => {
|
||||
if (process.env.TEST_DEBUG === '1') console.log('🚀 Starting Big Graph Optimized Performance Test Suite...');
|
||||
|
||||
// Test small scale performance
|
||||
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}`);
|
||||
|
||||
// Load into arbiter
|
||||
const arbiterStart = process.hrtime.bigint();
|
||||
const arbiter = generator.loadIntoArbiter(graphData);
|
||||
const arbiterEnd = process.hrtime.bigint();
|
||||
|
||||
const arbiterTime = Number(arbiterEnd - arbiterStart) / 1000000;
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Arbiter Time: ${arbiterTime.toFixed(2)}ms`);
|
||||
|
||||
// Test authorization performance
|
||||
const authStart = process.hrtime.bigint();
|
||||
let authTests = 0;
|
||||
let authSuccess = 0;
|
||||
|
||||
const testRelations = graphData.relations.slice(0, 10);
|
||||
for (const relation of testRelations) {
|
||||
try {
|
||||
const result = arbiter.check(relation.src, relation.relation, relation.dst);
|
||||
authTests++;
|
||||
if (result.possibility > 0) {
|
||||
authSuccess++;
|
||||
}
|
||||
} catch (error) {
|
||||
authTests++;
|
||||
}
|
||||
}
|
||||
|
||||
const authEnd = process.hrtime.bigint();
|
||||
const authTime = Number(authEnd - authStart) / 1000000;
|
||||
const authSuccessRate = authTests > 0 ? (authSuccess / authTests) * 100 : 0;
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Auth Time: ${authTime.toFixed(2)}ms`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Auth Success: ${authSuccess}/${authTests} (${authSuccessRate.toFixed(1)}%)`);
|
||||
|
||||
// Verify performance thresholds
|
||||
assert.ok(loadTime < 1000, `Load time ${loadTime}ms exceeds 1s limit`);
|
||||
assert.ok(memoryUsage < 128, `Memory usage ${memoryUsage}MB exceeds 128MB limit`);
|
||||
assert.ok(authSuccessRate >= 50, `Auth success rate ${authSuccessRate}% too low`);
|
||||
|
||||
// Record metrics
|
||||
metrics.record('graph_loading', {
|
||||
loadTime,
|
||||
memoryUsage,
|
||||
userCount: graphData.users.length,
|
||||
documentCount: graphData.documents.length,
|
||||
relationCount: graphData.relations.length
|
||||
});
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log('✅ Comprehensive performance test suite completed successfully');
|
||||
});
|
||||
|
||||
test('validates memory management', async () => {
|
||||
if (process.env.TEST_DEBUG === '1') console.log('🧠 Validating Memory Management...');
|
||||
|
||||
const generator = new BigGraphGenerator({ scale: 'small', seed: 12345 });
|
||||
const graphData = generator.generateGraph('enterprise');
|
||||
const arbiter = generator.loadIntoArbiter(graphData);
|
||||
|
||||
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
|
||||
|
||||
// Verify memory usage is reasonable
|
||||
assert.ok(memoryUsage < 128, `Memory usage ${memoryUsage}MB exceeds 128MB limit`);
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log('✅ Memory management validated successfully');
|
||||
});
|
||||
|
||||
test('validates scalability characteristics', async () => {
|
||||
if (process.env.TEST_DEBUG === '1') console.log('📈 Validating Scalability Characteristics...');
|
||||
|
||||
// Test small scale
|
||||
const smallGenerator = new BigGraphGenerator({ scale: 'small', seed: 12345 });
|
||||
const smallStart = process.hrtime.bigint();
|
||||
const smallData = smallGenerator.generateGraph('enterprise');
|
||||
const smallEnd = process.hrtime.bigint();
|
||||
const smallTime = Number(smallEnd - smallStart) / 1000000;
|
||||
|
||||
// Test medium scale
|
||||
const mediumGenerator = new BigGraphGenerator({ scale: 'medium', seed: 12345 });
|
||||
const mediumStart = process.hrtime.bigint();
|
||||
const mediumData = mediumGenerator.generateGraph('enterprise');
|
||||
const mediumEnd = process.hrtime.bigint();
|
||||
const mediumTime = Number(mediumEnd - mediumStart) / 1000000;
|
||||
|
||||
// Calculate scaling factor
|
||||
const scalingFactor = mediumTime / smallTime;
|
||||
const relationRatio = mediumData.relations.length / smallData.relations.length;
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Small scale: ${smallTime.toFixed(2)}ms (${smallData.relations.length} relations)`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Medium scale: ${mediumTime.toFixed(2)}ms (${mediumData.relations.length} relations)`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Scaling factor: ${scalingFactor.toFixed(2)}x`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Relation ratio: ${relationRatio.toFixed(2)}x`);
|
||||
|
||||
// Verify scaling is reasonable (should be roughly linear)
|
||||
assert.ok(scalingFactor < relationRatio * 2, `Scaling factor ${scalingFactor.toFixed(2)}x too high`);
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log('✅ Scalability characteristics validated');
|
||||
});
|
||||
|
||||
test('validates cache performance', async () => {
|
||||
if (process.env.TEST_DEBUG === '1') console.log('💾 Validating Cache Performance...');
|
||||
|
||||
const generator = new BigGraphGenerator({ scale: 'small', seed: 12345 });
|
||||
const graphData = generator.generateGraph('enterprise');
|
||||
const arbiter = generator.loadIntoArbiter(graphData);
|
||||
|
||||
// Test cache performance by running the same queries multiple times
|
||||
const testRelations = graphData.relations.slice(0, 5);
|
||||
|
||||
// First run (cold cache)
|
||||
const coldStart = process.hrtime.bigint();
|
||||
for (const relation of testRelations) {
|
||||
try {
|
||||
arbiter.check(relation.src, relation.relation, relation.dst);
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
const coldEnd = process.hrtime.bigint();
|
||||
const coldTime = Number(coldEnd - coldStart) / 1000000;
|
||||
|
||||
// Second run (warm cache)
|
||||
const warmStart = process.hrtime.bigint();
|
||||
for (const relation of testRelations) {
|
||||
try {
|
||||
arbiter.check(relation.src, relation.relation, relation.dst);
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
const warmEnd = process.hrtime.bigint();
|
||||
const warmTime = Number(warmEnd - warmStart) / 1000000;
|
||||
|
||||
const speedup = coldTime / warmTime;
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Cold cache time: ${coldTime.toFixed(2)}ms`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Warm cache time: ${warmTime.toFixed(2)}ms`);
|
||||
if (process.env.TEST_DEBUG === '1') console.log(` Cache speedup: ${speedup.toFixed(2)}x`);
|
||||
|
||||
// Verify cache provides some speedup
|
||||
assert.ok(speedup >= 1.0, `Cache speedup ${speedup.toFixed(2)}x below 1.0x threshold`);
|
||||
assert.ok(speedup < 10.0, `Cache speedup ${speedup.toFixed(2)}x above 10x threshold (unrealistic)`);
|
||||
|
||||
if (process.env.TEST_DEBUG === '1') console.log('✅ Cache performance validated');
|
||||
});
|
||||
|
||||
test('generates performance report', async () => {
|
||||
if (process.env.TEST_DEBUG === '1') console.log('📊 Generating Performance Report...');
|
||||
|
||||
// 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));
|
||||
if (process.env.TEST_DEBUG === '1') console.log('✅ Performance report generated successfully');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user