mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
const {
|
||||
TASK_START_SCHEMA,
|
||||
TaskStartFenceRejectedError,
|
||||
TaskStartNotFoundError,
|
||||
TaskStartUnavailableError,
|
||||
} = require('@qinglong/runtime-core/task-start');
|
||||
const {
|
||||
createLocalApiTaskStartRoute,
|
||||
} = require('../dist/task/taskStartRoute.js');
|
||||
|
||||
const IDS = [
|
||||
'019f7300-0000-7000-8000-000000000701',
|
||||
'019f7300-0000-7000-8000-000000000702',
|
||||
'019f7300-0000-7000-8000-000000000703',
|
||||
'019f7300-0000-7000-8000-000000000704',
|
||||
];
|
||||
const MUTATION_ID = '019f7300-0000-7000-8000-000000000700';
|
||||
const DIGEST = 'a'.repeat(64);
|
||||
const PRINCIPAL = Object.freeze({
|
||||
subject: Object.freeze({ type: 'user', id: 'user-1' }),
|
||||
authenticationId: 'credential-1',
|
||||
authenticatedAtMs: 1,
|
||||
expiresAtMs: 20,
|
||||
assurance: 'single_factor',
|
||||
});
|
||||
|
||||
function request(overrides = {}) {
|
||||
return {
|
||||
projectId: 'project-1',
|
||||
taskId: 'task-1',
|
||||
body: {
|
||||
schema: TASK_START_SCHEMA,
|
||||
mutationId: MUTATION_ID,
|
||||
expectedRevision: 3,
|
||||
expectedContentDigest: DIGEST,
|
||||
},
|
||||
principal: PRINCIPAL,
|
||||
policyFence: { projectVersion: 2, bindingVersion: 4 },
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function receipt(overrides = {}) {
|
||||
return {
|
||||
status: 'accepted',
|
||||
projectId: 'project-1',
|
||||
taskId: 'task-1',
|
||||
taskRevision: 3,
|
||||
taskContentDigest: DIGEST,
|
||||
runId: IDS[0],
|
||||
attemptId: IDS[1],
|
||||
runStatus: 'queued',
|
||||
runVersion: 2,
|
||||
eventSequence: 2,
|
||||
executorType: 'local_process',
|
||||
executionRevisionDigest: 'b'.repeat(64),
|
||||
createdAtMs: 10,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function route(repository) {
|
||||
let index = 0;
|
||||
return createLocalApiTaskStartRoute(repository, () => IDS[index++]);
|
||||
}
|
||||
|
||||
test('publishes one server-owned Task start command and exact receipt', async () => {
|
||||
let observed;
|
||||
const result = await route({
|
||||
async startTask(command) {
|
||||
observed = command;
|
||||
return receipt();
|
||||
},
|
||||
}).handle(request());
|
||||
assert.deepEqual(result, {
|
||||
statusCode: 202,
|
||||
body: { schema: TASK_START_SCHEMA, ...receipt() },
|
||||
});
|
||||
assert.deepEqual(observed, {
|
||||
projectId: 'project-1',
|
||||
taskId: 'task-1',
|
||||
mutationId: MUTATION_ID,
|
||||
expectedRevision: 3,
|
||||
expectedContentDigest: DIGEST,
|
||||
runId: IDS[0],
|
||||
attemptId: IDS[1],
|
||||
createdEventId: IDS[2],
|
||||
queuedEventId: IDS[3],
|
||||
subject: PRINCIPAL.subject,
|
||||
policyFence: { projectVersion: 2, bindingVersion: 4 },
|
||||
});
|
||||
});
|
||||
|
||||
test('rejects widened bodies and maps replay plus stable failures', async () => {
|
||||
let calls = 0;
|
||||
assert.equal((await route({
|
||||
async startTask() { calls += 1; return receipt(); },
|
||||
}).handle(request({ body: { ...request().body, command: '/bin/sh' } }))).statusCode, 400);
|
||||
assert.equal(calls, 0);
|
||||
|
||||
assert.equal((await route({
|
||||
async startTask() { return receipt({ status: 'existing' }); },
|
||||
}).handle(request())).statusCode, 200);
|
||||
|
||||
for (const [error, statusCode, code] of [
|
||||
[new TaskStartNotFoundError(), 404, 'task_not_found'],
|
||||
[new TaskStartFenceRejectedError('task_disabled'), 409, 'task_start_fence_rejected'],
|
||||
[new TaskStartUnavailableError(), 503, 'task_start_unavailable'],
|
||||
]) {
|
||||
const result = await route({ async startTask() { throw error; } }).handle(request());
|
||||
assert.equal(result.statusCode, statusCode);
|
||||
assert.equal(result.body.code, code);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user