mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 19:29:13 +08:00
feat(ql3): page blocked cancellations
This commit is contained in:
@@ -118,6 +118,7 @@ test('defines the immutable PostgreSQL capability and Run core stream', async ()
|
||||
'pg-0065-approved-action-manual-recovery',
|
||||
'pg-0066-cancellation-dispatch',
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
],
|
||||
);
|
||||
for (const migration of postgresqlMainMigrationStream.migrations) {
|
||||
@@ -591,6 +592,11 @@ test('freezes every published PostgreSQL migration checksum', () => {
|
||||
checksum:
|
||||
'e78e24a06dc4c4dbdd859685f28b4bc837a8cfb279eb3512e0a57dc6d27eaaaa',
|
||||
},
|
||||
{
|
||||
id: 'pg-0068-cancellation-dispatch-project-keyset',
|
||||
checksum:
|
||||
'2fcac38386581189db63faacff325356f11c4529a8db9cef6be1a1ca706aaf10',
|
||||
},
|
||||
];
|
||||
assert.deepEqual(
|
||||
postgresqlMainMigrationStream.migrations.map(({ id, checksum }) => ({
|
||||
@@ -2373,3 +2379,45 @@ test('advances capability v66 with least-privilege cancellation diagnostics and
|
||||
assert.match(sql, /contract_version = 65/);
|
||||
assert.match(sql, /migration_id = 'pg-0066-cancellation-dispatch'/);
|
||||
});
|
||||
|
||||
test('advances capability v67 with a Project-scoped blocked keyset', async () => {
|
||||
const migration = migrationById(
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
const statements = [];
|
||||
await migration.up({
|
||||
async query(statement) {
|
||||
statements.push(statement);
|
||||
return { rows: [] };
|
||||
},
|
||||
});
|
||||
const sql = statements.join('\n');
|
||||
assert.match(
|
||||
sql,
|
||||
/ADD COLUMN project_id varchar\(128\)/,
|
||||
);
|
||||
assert.match(
|
||||
sql,
|
||||
/SET project_id = run\.project_id FROM "ql3"\."runs" AS run/,
|
||||
);
|
||||
assert.match(sql, /ALTER COLUMN project_id SET NOT NULL/);
|
||||
assert.match(
|
||||
sql,
|
||||
/CREATE UNIQUE INDEX ql3_runs_project_id_uidx ON "ql3"\."runs" \(project_id, id\)/,
|
||||
);
|
||||
assert.match(
|
||||
sql,
|
||||
/FOREIGN KEY \(project_id, run_id\) REFERENCES "ql3"\."runs" \(project_id, id\)/,
|
||||
);
|
||||
assert.match(
|
||||
sql,
|
||||
/CREATE INDEX ql3_run_cancellation_dispatch_project_blocked_idx[\s\S]+\(project_id, updated_at_ms, run_id\) WHERE status = 'blocked'/,
|
||||
);
|
||||
assert.match(sql, /contract_version = 67/);
|
||||
assert.match(sql, /"run_cancellation_dispatch_blocked_list":1/);
|
||||
assert.match(sql, /contract_version = 66/);
|
||||
assert.match(
|
||||
sql,
|
||||
/migration_id = 'pg-0067-cancellation-dispatch-management'/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -835,7 +835,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
|
||||
serverMajor: 16,
|
||||
currentUser: 'ql3_runtime',
|
||||
contractName: 'control-core',
|
||||
contractVersion: 66,
|
||||
contractVersion: 67,
|
||||
migrationIds: [
|
||||
'pg-0001-schema-capability',
|
||||
'pg-0002-run-core',
|
||||
@@ -904,6 +904,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
|
||||
'pg-0065-approved-action-manual-recovery',
|
||||
'pg-0066-cancellation-dispatch',
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -934,10 +935,10 @@ test('accepts the exact schema and isolated least-privilege admin role', async (
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_admin');
|
||||
assert.equal(report.contractVersion, 66);
|
||||
assert.equal(report.contractVersion, 67);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -950,10 +951,10 @@ test('accepts the isolated least-privilege automation manager role', async () =>
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_automation_manager');
|
||||
assert.equal(report.contractVersion, 66);
|
||||
assert.equal(report.contractVersion, 67);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
|
||||
const widened = automationManagerPrivileges();
|
||||
@@ -982,10 +983,10 @@ test('accepts the isolated least-privilege human Approval manager role', async (
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_approval_manager');
|
||||
assert.equal(report.contractVersion, 66);
|
||||
assert.equal(report.contractVersion, 67);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
|
||||
const widened = approvalManagerPrivileges();
|
||||
@@ -1016,10 +1017,10 @@ test('accepts the isolated least-privilege Run manager role', async () => {
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_run_manager');
|
||||
assert.equal(report.contractVersion, 66);
|
||||
assert.equal(report.contractVersion, 67);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
|
||||
const widened = runManagerPrivileges();
|
||||
@@ -1180,10 +1181,10 @@ test('accepts the exact schema and isolated Worker ingress role', async () => {
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_worker_ingress');
|
||||
assert.equal(report.contractVersion, 66);
|
||||
assert.equal(report.contractVersion, 67);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0067-cancellation-dispatch-management',
|
||||
'pg-0068-cancellation-dispatch-project-keyset',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+81
@@ -47,6 +47,16 @@ function summaryCommand(overrides = {}) {
|
||||
return { ...authority, ...overrides };
|
||||
}
|
||||
|
||||
function blockedListCommand(after) {
|
||||
return {
|
||||
...summaryCommand({
|
||||
requestId: 'request-blocked-1',
|
||||
auditEventId: '019f9600-0000-4000-8000-000000000021',
|
||||
}),
|
||||
...(after === undefined ? {} : { after }),
|
||||
};
|
||||
}
|
||||
|
||||
function runRow() {
|
||||
return {
|
||||
projectId: 'project-1',
|
||||
@@ -133,6 +143,13 @@ function fixture(options = {}) {
|
||||
rowCount: 1,
|
||||
};
|
||||
}
|
||||
if (
|
||||
text.startsWith(
|
||||
'SELECT run_id AS "runId", updated_at_ms AS "blockedAtMs"',
|
||||
)
|
||||
) {
|
||||
return { rows: options.blockedRows ?? [], rowCount: 0 };
|
||||
}
|
||||
if (
|
||||
text.startsWith('SELECT attempt_id AS "attemptId"') &&
|
||||
!text.includes('dispatchStatus') &&
|
||||
@@ -296,6 +313,70 @@ test('derives clear and converging assessments from fixed status counts', async
|
||||
assert.equal(result.operatorAction, 'wait');
|
||||
});
|
||||
|
||||
test('lists one fixed oldest-first blocked page with a snapshot cursor', async () => {
|
||||
const blockedRows = Array.from({ length: 17 }, (_, index) => ({
|
||||
runId: `run-${String(index + 1).padStart(2, '0')}`,
|
||||
blockedAtMs: String(NOW - 100 + index),
|
||||
}));
|
||||
const { calls, repository } = fixture({ blockedRows });
|
||||
const result = await repository.listBlocked(blockedListCommand());
|
||||
assert.equal(result.projectId, 'project-1');
|
||||
assert.equal(result.snapshotAtMs, NOW);
|
||||
assert.equal(result.observedAtMs, NOW);
|
||||
assert.equal(result.items.length, 16);
|
||||
assert.equal(result.items[0].runId, 'run-01');
|
||||
assert.equal(result.items[15].runId, 'run-16');
|
||||
assert.equal(result.truncated, true);
|
||||
assert.deepEqual(result.nextCursor, {
|
||||
snapshotAtMs: NOW,
|
||||
blockedAtMs: NOW - 85,
|
||||
runId: 'run-16',
|
||||
});
|
||||
const read = calls.find(({ sql }) =>
|
||||
sql.startsWith(
|
||||
'SELECT run_id AS "runId", updated_at_ms AS "blockedAtMs"',
|
||||
),
|
||||
);
|
||||
assert.deepEqual(read.params, ['project-1', NOW, null, '', 17]);
|
||||
assert.match(
|
||||
read.sql,
|
||||
/project_id = \$1 AND status = 'blocked'[\s\S]+ORDER BY updated_at_ms ASC, run_id ASC/,
|
||||
);
|
||||
const audit = calls.find(
|
||||
({ sql, params }) =>
|
||||
sql.startsWith('INSERT INTO "ql3"."security_audit_events"') &&
|
||||
params[2] === 'run.cancellation.blocked.list',
|
||||
);
|
||||
assert.equal(audit.params[0], blockedListCommand().auditEventId);
|
||||
});
|
||||
|
||||
test('continues only inside the original blocked snapshot', async () => {
|
||||
const after = {
|
||||
snapshotAtMs: NOW - 50,
|
||||
blockedAtMs: NOW - 80,
|
||||
runId: 'run-03',
|
||||
};
|
||||
const { calls, repository } = fixture({
|
||||
blockedRows: [{ runId: 'run-04', blockedAtMs: String(NOW - 79) }],
|
||||
});
|
||||
const result = await repository.listBlocked(blockedListCommand(after));
|
||||
assert.equal(result.snapshotAtMs, NOW - 50);
|
||||
assert.equal(result.truncated, false);
|
||||
assert.equal(Object.hasOwn(result, 'nextCursor'), false);
|
||||
const read = calls.find(({ sql }) =>
|
||||
sql.startsWith(
|
||||
'SELECT run_id AS "runId", updated_at_ms AS "blockedAtMs"',
|
||||
),
|
||||
);
|
||||
assert.deepEqual(read.params, [
|
||||
'project-1',
|
||||
NOW - 50,
|
||||
NOW - 80,
|
||||
'run-03',
|
||||
17,
|
||||
]);
|
||||
});
|
||||
|
||||
test('rearms an exact blocked dispatch with one event and allowed audit', async () => {
|
||||
const { calls, repository } = fixture();
|
||||
const result = await repository.rearm(rearmCommand());
|
||||
|
||||
Reference in New Issue
Block a user