Initial
This commit is contained in:
71
server/test/governance.test.mjs
Normal file
71
server/test/governance.test.mjs
Normal file
@@ -0,0 +1,71 @@
|
||||
import { db, adminUserId, makeUser, load } from './setup.mjs';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
const {
|
||||
createChangeRequest, findApprovedRequest, findPendingRequest, decideChangeRequest, markRequestExecuted, listChangeRequests
|
||||
} = await load('../models/changeRequestModel.js');
|
||||
const { intuneReportingOverview, recordGraphAudit } = await load('../models/graphModel.js');
|
||||
const { createIntuneDeployment } = await load('../models/psadtModel.js');
|
||||
|
||||
const owner = adminUserId();
|
||||
const other = makeUser({ email: 'gov-other@test.local' });
|
||||
|
||||
const deployment = createIntuneDeployment({ name: 'Gov Test App', visibility: 'shared', status: 'ready' }, owner);
|
||||
|
||||
test('approval lifecycle: pending -> approved -> executed', () => {
|
||||
const request = createChangeRequest({ deploymentId: deployment.id, connectionId: null, action: 'publish', requestedBy: owner, requesterEmail: 'a@b.c' });
|
||||
assert.equal(request.status, 'pending');
|
||||
assert.equal(findPendingRequest(deployment.id, 'publish').id, request.id);
|
||||
assert.equal(findApprovedRequest(deployment.id, 'publish'), null);
|
||||
|
||||
const approved = decideChangeRequest(request.id, { status: 'approved', approverUserId: owner, approverEmail: 'admin@b.c' });
|
||||
assert.equal(approved.status, 'approved');
|
||||
assert.equal(findApprovedRequest(deployment.id, 'publish').id, request.id);
|
||||
|
||||
markRequestExecuted(request.id);
|
||||
assert.equal(findApprovedRequest(deployment.id, 'publish'), null, 'executed request is no longer approved');
|
||||
});
|
||||
|
||||
test('deciding an already-decided request returns null', () => {
|
||||
const request = createChangeRequest({ deploymentId: deployment.id, action: 'assign', requestedBy: owner });
|
||||
decideChangeRequest(request.id, { status: 'rejected', approverUserId: owner });
|
||||
assert.equal(decideChangeRequest(request.id, { status: 'approved', approverUserId: owner }), null);
|
||||
});
|
||||
|
||||
test('change requests are scoped to visible deployments for non-admins', () => {
|
||||
createChangeRequest({ deploymentId: deployment.id, action: 'relationships', requestedBy: owner });
|
||||
// deployment is shared, so a non-admin still sees its requests
|
||||
assert.ok(listChangeRequests(other, { isAdmin: false }).some((r) => r.deploymentId === deployment.id));
|
||||
});
|
||||
|
||||
test('reporting overview aggregates deployment status and install states', () => {
|
||||
const ts = new Date().toISOString();
|
||||
const insert = db.prepare(`
|
||||
INSERT INTO intune_deployment_statuses (id, deployment_id, graph_app_id, scope, install_state, error_code, created_at, updated_at)
|
||||
VALUES (?, ?, 'app-1', 'device', ?, ?, ?, ?)
|
||||
`);
|
||||
insert.run('ids_1', deployment.id, 'failed', '0x87D1041C', ts, ts);
|
||||
insert.run('ids_2', deployment.id, 'installed', '', ts, ts);
|
||||
insert.run('ids_3', deployment.id, 'failed', '0x87D1041C', ts, ts);
|
||||
|
||||
const overview = intuneReportingOverview(owner, false);
|
||||
const failed = overview.installStateCounts.find((row) => row.state === 'failed');
|
||||
assert.equal(failed.count, 2);
|
||||
assert.ok(overview.deploymentsByStatus.some((row) => row.status === 'ready'));
|
||||
assert.equal(overview.topErrors[0].code, '0x87D1041C');
|
||||
assert.equal(overview.topErrors[0].count, 2);
|
||||
});
|
||||
|
||||
test('reporting overview includes soak timers and a write-action trend', () => {
|
||||
const soaking = createIntuneDeployment({ name: 'Soak Report', visibility: 'shared', autoPromoteAfterHours: 24, autoPromoteRing: 'Broad' }, owner);
|
||||
db.prepare('UPDATE intune_deployments SET soak_started_at = ? WHERE id = ?')
|
||||
.run(new Date(Date.now() - 3_600_000).toISOString(), soaking.id);
|
||||
recordGraphAudit({ deploymentId: soaking.id, actorUserId: owner, action: 'win32app.publish', status: 'success', message: 'ok' });
|
||||
|
||||
const overview = intuneReportingOverview(owner, false);
|
||||
const timer = overview.soakTimers.find((row) => row.id === soaking.id);
|
||||
assert.ok(timer, 'soak timer present');
|
||||
assert.ok(timer.hoursRemaining > 22 && timer.hoursRemaining <= 24, `~23h remaining, got ${timer.hoursRemaining}`);
|
||||
assert.ok(overview.auditTrend.some((row) => row.status === 'success' && row.count >= 1));
|
||||
});
|
||||
Reference in New Issue
Block a user