60 lines
2.1 KiB
TypeScript
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);
|
|
});
|
|
});
|