blob: 8d934d5eb5ef3cf164ebf54c5a5c0f21abb6ad44 [file]
import { newEnforcer, newModel, StringAdapter } from 'casbin';
import { RemoteCasbinEngine } from '../app/components/editor/core/CasbinEngine';
import { example } from '../app/components/editor/casbin-mode/example';
import { EngineType, ENGINES } from '@/app/config/engineConfig';
interface EngineResult {
engineType: EngineType;
allowed: boolean;
reason?: string[];
nodeResult: boolean;
}
describe('Casbin Engine Tests', () => {
describe('Cross-engine enforcement consistency', () => {
// Get all remote engines
const remoteEngines = Object.fromEntries(
Object.entries(ENGINES)
.filter(([_, config]) => config.isRemote)
.map(([id]) => [id, new RemoteCasbinEngine(id as Exclude<EngineType, 'node'>)]),
) as Record<Exclude<EngineType, 'node'>, RemoteCasbinEngine>;
// Test each engine for each test case
Object.entries(example).forEach(([key, testCase]) => {
Object.entries(remoteEngines).forEach(([engineType, engine]) => {
test(`should return consistent enforcement result for ${testCase.name} with ${engineType} engine`, async () => {
// Add delay for Python engine to avoid DLL conflicts
if (engineType === 'python') {
await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay
}
const nodeEnforcer = await newEnforcer(newModel(testCase.model), new StringAdapter(testCase.policy || ' '));
const requests = testCase.request.split('\n').filter(Boolean);
for (const request of requests) {
const requestParams = request.split(',').map((param) => {
const trimmed = param.trim();
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
try {
return JSON.parse(trimmed);
} catch {
return trimmed;
}
}
return trimmed;
});
const remoteRequest = requestParams
.map((param) => {
return typeof param === 'object' ? JSON.stringify(param) : param;
})
.join(',');
const nodeResult = await nodeEnforcer.enforce(...requestParams);
try {
const remoteResult = await engine.enforce({
model: testCase.model,
policy: testCase.policy || '',
request: remoteRequest,
});
if (remoteResult.error) {
throw new Error(`${engineType} engine error: ${remoteResult.error}`);
}
const logMessage = [
`\n=== Test Case: [${testCase.name}] (${engineType}) ===`,
`Request params: [${requestParams.join(', ')}]`,
`[${engineType.toUpperCase()}] Result:`,
` Allowed: [${remoteResult.allowed}]`,
` Reason: [${remoteResult.reason?.join(', ')}]`,
` Node Result: [${nodeResult}]`,
`=======================================\n`,
].join('\n');
console.log(logMessage);
expect(remoteResult.allowed).toBe(nodeResult);
} catch (engineError: any) {
const errorMessage = [
`\n=== Error in [${testCase.name}] ([${engineType}]) ===`,
`Error message: [${engineError.message}]`,
`Request: [${requestParams.join(', ')}]`,
`Model:\n${testCase.model}`,
`Policy: [${testCase.policy || '<empty>'}]\n`,
`=======================================\n`,
].join('\n');
console.error(errorMessage);
throw engineError;
}
}
}, engineType === 'python' ? 80000 : 40000); // Python: 80s, Others: 40s
});
});
});
});