Files
CASAN/packages/casan-control-panel/backend/test/kill-switch.test.ts
T
2026-07-08 19:07:35 +09:00

60 lines
2.1 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { ForbiddenException } from '@nestjs/common';
import { KillSwitchService } from '../src/kill-switch/kill-switch.service.js';
const viewer = { actor: 'viewer-1', role: 'viewer', project: 'default', tenant: 'default' };
const operator = { actor: 'operator-1', role: 'operator', project: 'default', tenant: 'default' };
const admin = { actor: 'admin-1', role: 'org-admin', project: 'default', tenant: 'default' };
function withTempKillSwitch(fn: () => void) {
const prev = process.env.CASAN_KILLSWITCH_DIR;
process.env.CASAN_KILLSWITCH_DIR = mkdtempSync(join(tmpdir(), 'cp-ks-'));
try {
fn();
} finally {
if (prev === undefined) delete process.env.CASAN_KILLSWITCH_DIR;
else process.env.CASAN_KILLSWITCH_DIR = prev;
}
}
test('kill-switch status is readable by viewer', () => {
withTempKillSwitch(() => {
const svc = new KillSwitchService();
const status = svc.status(viewer);
assert.equal(status.count, 0);
assert.deepEqual(status.engaged, []);
});
});
test('viewer cannot engage kill-switch', () => {
withTempKillSwitch(() => {
const svc = new KillSwitchService();
assert.throws(
() => svc.engage({ scope: 'project', id: 'p1', reason: 'viewer should fail' }, viewer),
ForbiddenException,
);
});
});
test('operator can engage and org-admin can clear kill-switch', () => {
withTempKillSwitch(() => {
const svc = new KillSwitchService();
const engaged = svc.engage({ scope: 'project', id: 'p1', reason: 'incident drill' }, operator) as any;
assert.equal(engaged.status.count, 1);
assert.equal(engaged.status.engaged[0].scope, 'project');
assert.equal(engaged.status.engaged[0].actor, 'operator-1');
assert.throws(
() => svc.clear({ scope: 'project', id: 'p1', reason: 'viewer clear should fail' }, viewer),
ForbiddenException,
);
const cleared = svc.clear({ scope: 'project', id: 'p1', reason: 'resolved' }, admin) as any;
assert.equal(cleared.status.count, 0);
});
});