Files
qinglong/packages/ql3-cluster-admin/test/runManagementTransport.test.cjs

547 lines
15 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterRunManagementTransportAuthenticationError,
ClusterRunManagementTransportRequestError,
createClusterRunManagementTransport,
normalizeClusterRunManagementCommand,
} = require('@qinglong/cluster-admin/run-management-transport');
const NOW = 1_000_000;
function principal(overrides = {}) {
return {
subject: { type: 'user', id: 'operator-1' },
authenticationId: 'oidc:run-management-1',
authenticatedAtMs: 999_000,
expiresAtMs: 1_100_000,
assurance: 'multi_factor',
...overrides,
};
}
function command(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.retry',
request: {
projectId: 'project-1',
sourceRunId: 'source-run-1',
requestId: 'request-1',
auditEventId: '019f9300-0000-4000-8000-000000000001',
failureAuditEventId: '019f9300-0000-4000-8000-000000000002',
body: {
schema: 'qinglong/run-manual-retry@v1',
mutationId: '019f9300-0000-4000-8000-000000000003',
expectedRunVersion: 7,
expectedRunStatus: 'failed',
},
...overrides,
},
};
}
function retryResult() {
return {
status: 'accepted',
projectId: 'project-1',
sourceRunId: 'source-run-1',
sourceRunStatus: 'failed',
sourceRunVersion: 7,
runId: '019f9300-0000-4000-8000-000000000010',
retryOfRunId: 'source-run-1',
taskId: 'task-1',
taskRevision: `qltd:v1:1:${'a'.repeat(64)}`,
attemptId: '019f9300-0000-4000-8000-000000000011',
runStatus: 'queued',
runVersion: 2,
eventSequence: 2,
executorType: 'remote_worker',
executionRevisionDigest: 'b'.repeat(64),
createdAtMs: NOW,
};
}
function stopCommand(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.stop',
request: {
projectId: 'project-1',
runId: 'run-1',
requestId: 'request-stop-1',
auditEventId: '019f9300-0000-4000-8000-000000000021',
failureAuditEventId: '019f9300-0000-4000-8000-000000000022',
body: {
schema: 'qinglong/run-cancellation@v1',
mutationId: '019f9300-0000-4000-8000-000000000023',
},
...overrides,
},
};
}
function stopResult() {
return {
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
cancelRequestedAtMs: NOW,
cancelReason: 'user',
};
}
function diagnosticResult() {
return {
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 6,
eventSequence: 8,
cancelRequestedAtMs: NOW - 1_000,
cancelReason: 'user',
operatorAction: 'rearm',
dispatch: {
attemptId: 'attempt-1',
status: 'blocked',
version: 3,
dispatchCount: 1,
lastResult: 'identity_mismatch',
createdAtMs: NOW - 900,
updatedAtMs: NOW - 800,
},
};
}
function summaryResult() {
return {
projectId: 'project-1',
observedAtMs: NOW,
assessment: 'attention_required',
operatorAction: 'inspect',
dispatches: {
total: 5,
pending: 1,
leased: 1,
retryWait: 1,
dispatched: 1,
blocked: 1,
},
signals: { due: 1, expiredLease: 1 },
blockingResults: {
identityMismatch: 1,
pidMismatch: 0,
unsupported: 0,
invalid: 0,
},
oldestBlockedAtMs: NOW - 800,
};
}
function blockedListResult() {
return {
projectId: 'project-1',
snapshotAtMs: NOW,
observedAtMs: NOW,
items: [{ runId: 'run-1', blockedAtMs: NOW - 800 }],
truncated: false,
};
}
function rearmResult() {
return {
status: 'rearmed',
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
previousDispatchVersion: 3,
dispatchVersion: 4,
previousResult: 'identity_mismatch',
retryDelayMs: 5_000,
nextAttemptAtMs: NOW + 5_000,
runVersion: 7,
eventSequence: 9,
};
}
function inspectCommand(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.cancellation.inspect',
request: {
projectId: 'project-1',
runId: 'run-1',
requestId: 'request-inspect-1',
auditEventId: '019f9300-0000-4000-8000-000000000031',
failureAuditEventId: '019f9300-0000-4000-8000-000000000032',
body: {
schema: 'qinglong/run-cancellation-dispatch-inspect@v1',
},
...overrides,
},
};
}
function summaryCommand(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.cancellation.summary',
request: {
projectId: 'project-1',
requestId: 'request-summary-1',
auditEventId: '019f9300-0000-4000-8000-000000000051',
failureAuditEventId: '019f9300-0000-4000-8000-000000000052',
body: {
schema: 'qinglong/run-cancellation-dispatch-summary-request@v1',
},
...overrides,
},
};
}
function blockedListCommand(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.cancellation.blocked.list',
request: {
projectId: 'project-1',
requestId: 'request-blocked-1',
auditEventId: '019f9300-0000-4000-8000-000000000061',
failureAuditEventId: '019f9300-0000-4000-8000-000000000062',
body: {
schema: 'qinglong/run-cancellation-dispatch-blocked-list-request@v1',
after: null,
},
...overrides,
},
};
}
function rearmCommand(overrides = {}) {
return {
schemaVersion: 1,
operation: 'run.cancellation.rearm',
request: {
projectId: 'project-1',
runId: 'run-1',
requestId: 'request-rearm-1',
auditEventId: '019f9300-0000-4000-8000-000000000041',
failureAuditEventId: '019f9300-0000-4000-8000-000000000042',
body: {
schema: 'qinglong/run-cancellation-dispatch-rearm-request@v1',
mutationId: '019f9300-0000-4000-8000-000000000043',
expectedDispatchVersion: 3,
expectedLastResult: 'identity_mismatch',
retryDelayMs: 5_000,
},
...overrides,
},
};
}
test('routes one exact strong User retry and emits the shared response', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry(request) {
calls.push(request);
return retryResult();
},
async stop() {
return stopResult();
},
async summarizeCancellation() {
return summaryResult();
},
async listBlockedCancellations() {
return blockedListResult();
},
async inspectCancellation() {
return diagnosticResult();
},
async rearmCancellation() {
return rearmResult();
},
},
});
const result = await transport.execute(command(), {
authenticate: async () => principal(),
});
assert.equal(calls.length, 1);
assert.equal(calls[0].mutationId, command().request.body.mutationId);
assert.equal(calls[0].principal.assurance, 'multi_factor');
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.retry',
retry: {
schema: 'qinglong/run-manual-retry@v1',
...retryResult(),
},
});
});
test('routes one exact strong User stop and emits the shared response', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() {
return retryResult();
},
async stop(request) {
calls.push(request);
return stopResult();
},
async summarizeCancellation() {
return summaryResult();
},
async listBlockedCancellations() {
return blockedListResult();
},
async inspectCancellation() {
return diagnosticResult();
},
async rearmCancellation() {
return rearmResult();
},
},
});
const result = await transport.execute(stopCommand(), {
authenticate: async () => principal({ assurance: 'hardware' }),
});
assert.equal(calls.length, 1);
assert.equal(calls[0].runId, 'run-1');
assert.equal(calls[0].mutationId, stopCommand().request.body.mutationId);
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.stop',
stop: {
schema: 'qinglong/run-cancellation@v1',
...stopResult(),
},
});
});
test('rejects weak or non-User identity before service authority', async () => {
let called = false;
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() {
called = true;
return retryResult();
},
async stop() {
return stopResult();
},
async summarizeCancellation() {
return summaryResult();
},
async listBlockedCancellations() {
return blockedListResult();
},
async inspectCancellation() {
return diagnosticResult();
},
async rearmCancellation() {
return rearmResult();
},
},
});
await assert.rejects(
transport.execute(command(), {
authenticate: async () => principal({ assurance: 'single_factor' }),
}),
ClusterRunManagementTransportAuthenticationError,
);
await assert.rejects(
transport.execute(command(), {
authenticate: async () =>
principal({ subject: { type: 'agent', id: 'agent-1' } }),
}),
ClusterRunManagementTransportAuthenticationError,
);
assert.equal(called, false);
});
test('routes bounded cancellation inspection without lease capability data', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() { return retryResult(); },
async stop() { return stopResult(); },
async summarizeCancellation() { return summaryResult(); },
async listBlockedCancellations() { return blockedListResult(); },
async inspectCancellation(request) {
calls.push(request);
return diagnosticResult();
},
async rearmCancellation() { return rearmResult(); },
},
});
const result = await transport.execute(inspectCommand(), {
authenticate: async () => principal(),
});
assert.equal(calls[0].runId, 'run-1');
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.cancellation.inspect',
diagnostic: {
schema: 'qinglong/run-cancellation-dispatch-diagnostic@v1',
...diagnosticResult(),
},
});
assert.equal(JSON.stringify(result).includes('leaseOwner'), false);
assert.equal(JSON.stringify(result).includes('leaseToken'), false);
});
test('routes one Project-scoped cancellation summary without Run identity', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() { return retryResult(); },
async stop() { return stopResult(); },
async summarizeCancellation(request) {
calls.push(request);
return summaryResult();
},
async listBlockedCancellations() { return blockedListResult(); },
async inspectCancellation() { return diagnosticResult(); },
async rearmCancellation() { return rearmResult(); },
},
});
const result = await transport.execute(summaryCommand(), {
authenticate: async () => principal(),
});
assert.equal(calls.length, 1);
assert.equal(calls[0].projectId, 'project-1');
assert.equal(Object.hasOwn(calls[0], 'runId'), false);
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.cancellation.summary',
summary: {
schema: 'qinglong/run-cancellation-dispatch-summary@v1',
...summaryResult(),
},
});
assert.equal(JSON.stringify(result).includes('attemptId'), false);
assert.equal(JSON.stringify(result).includes('leaseOwner'), false);
});
test('routes one fixed Project blocked page without dispatch internals', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() { return retryResult(); },
async stop() { return stopResult(); },
async summarizeCancellation() { return summaryResult(); },
async listBlockedCancellations(request) {
calls.push(request);
return blockedListResult();
},
async inspectCancellation() { return diagnosticResult(); },
async rearmCancellation() { return rearmResult(); },
},
});
const result = await transport.execute(blockedListCommand(), {
authenticate: async () => principal(),
});
assert.equal(calls.length, 1);
assert.equal(calls[0].projectId, 'project-1');
assert.equal(Object.hasOwn(calls[0], 'after'), false);
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.cancellation.blocked.list',
page: {
schema: 'qinglong/run-cancellation-dispatch-blocked-page@v1',
...blockedListResult(),
},
});
for (const forbidden of [
'attemptId',
'dispatchVersion',
'lastResult',
'leaseOwner',
'leaseToken',
]) {
assert.equal(JSON.stringify(result).includes(forbidden), false);
}
});
test('routes an exact blocked cancellation rearm receipt', async () => {
const calls = [];
const transport = createClusterRunManagementTransport({
now: () => NOW,
service: {
async retry() { return retryResult(); },
async stop() { return stopResult(); },
async summarizeCancellation() { return summaryResult(); },
async listBlockedCancellations() { return blockedListResult(); },
async inspectCancellation() { return diagnosticResult(); },
async rearmCancellation(request) {
calls.push(request);
return rearmResult();
},
},
});
const result = await transport.execute(rearmCommand(), {
authenticate: async () => principal({ assurance: 'hardware' }),
});
assert.equal(calls[0].expectedDispatchVersion, 3);
assert.equal(calls[0].expectedLastResult, 'identity_mismatch');
assert.deepEqual(result, {
schemaVersion: 1,
operation: 'run.cancellation.rearm',
rearm: {
schema: 'qinglong/run-cancellation-dispatch-rearm-receipt@v1',
...rearmResult(),
},
});
});
test('rejects widened commands and ambiguous audit identity', () => {
assert.throws(
() =>
normalizeClusterRunManagementCommand({
...command(),
principal: principal(),
}),
ClusterRunManagementTransportRequestError,
);
assert.throws(
() =>
normalizeClusterRunManagementCommand(
command({ failureAuditEventId: command().request.auditEventId }),
),
ClusterRunManagementTransportRequestError,
);
assert.throws(
() =>
normalizeClusterRunManagementCommand(
command({
body: { ...command().request.body, expectedRunStatus: 'lost' },
}),
),
ClusterRunManagementTransportRequestError,
);
assert.throws(
() =>
normalizeClusterRunManagementCommand(
stopCommand({
body: { ...stopCommand().request.body, mutationId: 'weak' },
}),
),
ClusterRunManagementTransportRequestError,
);
});