Files
core/tests/rules/chain-rule/performance.test.js
T

161 lines
5.7 KiB
JavaScript
Raw Normal View History

import { test, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { setupChainRuleTestGraph } from './helpers.js';
describe('ChainRule Comprehensive Tests', () => {
describe('Fast Path and Performance Optimization', () => {
it('supports early exit with minAllowPossibility threshold', () => {
const arbiter = setupChainRuleTestGraph();
arbiter.setRelationConfig('quick_access_check', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'manages', direction: 'out' }
]
});
// Test with fast path enabled and low threshold
const result = arbiter.check('user:alice', 'quick_access_check', 'project:web-app', {
fastPath: true,
minAllowPossibility: 0.5 // Exit early if possibility >= 0.5
});
assert.equal(result.possibility, 1);
assert.equal(result.reason, 'allow_threshold_met');
});
it('supports early exit with maxDenyPossibility threshold', () => {
const arbiter = setupChainRuleTestGraph();
arbiter.setRelationConfig('deny_check', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'manages', direction: 'out' }
]
});
// Test denial with fast path
const result = arbiter.check('user:alice', 'deny_check', 'project:mobile-app', {
fastPath: true,
maxDenyPossibility: 0.8 // Exit early if denial >= 0.8
});
assert.equal(result.possibility, 0);
assert.equal(result.reason, 'no_chain_path_found');
});
});
describe('Comparison with Other Rules', () => {
it('compares ChainRule vs ParentRule performance', () => {
const arbiter = setupChainRuleTestGraph();
// Set up equivalent rules using ChainRule and ParentRule
arbiter.setRelationConfig('chain_parent_check', {
type: 'chain',
steps: [
{ relation: 'manages', direction: 'in' }, // project ← group
{ relation: 'member_of', direction: 'in' } // group ← user
]
});
arbiter.setRelationConfig('traditional_parent_check', {
type: 'parent',
parentRelation: 'manages',
relation: 'member_of',
reverse: true
});
const startTime1 = Date.now();
const chainResult = arbiter.check('project:web-app', 'chain_parent_check', 'user:alice');
const chainTime = Date.now() - startTime1;
const startTime2 = Date.now();
const parentResult = arbiter.check('project:web-app', 'traditional_parent_check', 'user:alice');
const parentTime = Date.now() - startTime2;
if (process.env.TEST_DEBUG === '1') console.log('ChainRule result:', chainResult.possibility);
if (process.env.TEST_DEBUG === '1') console.log('ParentRule result:', parentResult.possibility);
// ChainRule should succeed (Alice is member of engineering, which manages web-app)
assert.equal(chainResult.possibility, 1);
// ParentRule might have different semantics - just verify it returns a valid result
assert.ok(typeof parentResult.possibility === 'number');
if (process.env.TEST_DEBUG === '1') console.log(`ChainRule time: ${chainTime}ms, ParentRule time: ${parentTime}ms`);
// ChainRule should be reasonably performant
assert.ok(chainTime < 100); // Should complete in reasonable time
});
it('compares ChainRule vs MultiHopRule for path finding', () => {
const arbiter = setupChainRuleTestGraph();
// ChainRule: specific path
arbiter.setRelationConfig('chain_access', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'belongs_to', direction: 'out' },
{ relation: 'has_access_level', direction: 'out' }
]
});
// MultiHopRule: flexible path finding
arbiter.setRelationConfig('multihop_access', {
type: 'multi_hop',
relation: 'member_of',
maxDepth: 3,
pathAggregation: 'max'
});
const chainResult = arbiter.check('user:alice', 'chain_access', 'access:level-5');
const multihopResult = arbiter.check('user:alice', 'multihop_access', 'access:level-5');
// ChainRule should give precise result for defined path
assert.equal(chainResult.possibility, 1);
// MultiHopRule might give different result based on path exploration
if (process.env.TEST_DEBUG === '1') console.log('Chain vs MultiHop results:', {
chain: chainResult.possibility,
multihop: multihopResult.possibility
});
});
it('demonstrates ChainRule semantic clarity vs other approaches', () => {
const arbiter = setupChainRuleTestGraph();
// ChainRule: explicit semantic path
arbiter.setRelationConfig('semantic_chain', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'manages', direction: 'out' },
{ relation: 'has_budget', direction: 'out' }
],
extractValues: true,
extractFrom: 2,
extractRelation: 'has_budget',
valueAggregation: 'sum'
});
const result = arbiter.check('user:alice', 'semantic_chain', 'budget:tech-2024');
// Should provide clear semantic meaning:
// "user's budget access through group project management"
assert.equal(result.possibility, 1);
// Values are internal only, not exposed in authorization results
assert.equal(result.value, undefined);
if (process.env.TEST_DEBUG === '1') console.log('Semantic chain result:', {
access: result.possibility,
meaning: 'user → group → project → budget'
});
});
});
});