Files
memind/services/orchestrator/executor-job-store.test.mjs
john 6df82818c5 feat(orchestrator): harden zero-impact shadow rollout
Gate and bound Portal shadow observations while preserving Native execution. Add fail-closed service boundaries, terminal retention controls, Canary readiness telemetry, ops visibility, and isolated regression coverage.
2026-07-25 07:28:37 +08:00

306 lines
9.6 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
createExecutorJobPersistence,
createPostgresExecutorJobStore,
executorJobStoreInternals,
} from './executor-job-store.mjs';
function record(overrides = {}) {
return {
version: 'executor-job-state-v1',
jobId: 'job-1',
idempotencyKey: 'idem-1',
requestFingerprint: 'a'.repeat(64),
status: 'blocked',
createdAt: 1000,
updatedAt: 1000,
...overrides,
};
}
function transactionalPool(query) {
return {
query,
async connect() {
return {
query,
release() {},
};
},
};
}
test('PostgreSQL Executor Job Store creates an isolated schema and job table', async () => {
const queries = [];
const store = createPostgresExecutorJobStore({
schema: 'memind_orchestrator_test',
pool: {
async query(sql, params = []) {
queries.push({ sql, params });
return { rows: [] };
},
},
});
await store.ensureSchema();
assert.equal(store.kind, 'postgres');
assert.equal(store.durable, true);
assert.match(queries[0].sql, /CREATE SCHEMA IF NOT EXISTS "memind_orchestrator_test"/);
assert.match(queries[1].sql, /"memind_orchestrator_test"\."executor_jobs"/);
assert.match(queries[1].sql, /idempotency_key VARCHAR\(200\) NOT NULL UNIQUE/);
assert.match(queries[2].sql, /executor_jobs_updated_at_idx/);
assert.match(queries[3].sql, /"memind_orchestrator_test"\."executor_job_events"/);
assert.match(queries[3].sql, /UNIQUE \(job_id, sequence\)/);
assert.match(queries[5].sql, /executor_job_snapshot_imported/);
assert.match(queries[6].sql, /executor_workers/);
assert.match(queries[7].sql, /executor_workers_last_seen_idx/);
});
test('PostgreSQL Executor Job Store atomically creates and reloads idempotent state', async () => {
const stored = record();
const blockedEvent = {
version: 'executor-job-event-v1',
eventId: 'event-1',
jobId: 'job-1',
sequence: 1,
type: 'executor_job_blocked',
timestamp: 1000,
data: { status: 'blocked' },
};
const calls = [];
const store = createPostgresExecutorJobStore({
pool: transactionalPool(async (sql, params = []) => {
calls.push({ sql, params });
if (sql.includes('INSERT INTO') && sql.includes('executor_jobs')) {
return { rows: [{ state_json: stored }] };
}
if (sql.includes('INSERT INTO') && sql.includes('executor_job_events')) {
return { rows: [] };
}
if (sql.includes('SELECT job_id') && sql.includes('FOR UPDATE')) {
return { rows: [{ job_id: 'job-1' }] };
}
if (sql.includes('UPDATE')) {
return { rows: [{ state_json: { ...stored, status: 'cancelled' } }] };
}
if (sql.includes('MAX(sequence)')) {
return { rows: [{ next_sequence: 2 }] };
}
if (sql.includes('SELECT event_json')) {
return { rows: [{ event_json: blockedEvent }] };
}
if (sql.includes('WHERE job_id =')) {
return { rows: [{ state_json: JSON.stringify(stored) }] };
}
if (sql.includes('WHERE idempotency_key =')) {
return { rows: [{ state_json: stored }] };
}
return { rows: [] };
}),
});
const created = await store.createIfAbsent(stored, { initialEvent: blockedEvent });
assert.equal(created.created, true);
assert.deepEqual(created.record, stored);
assert.deepEqual(await store.getById('job-1'), stored);
assert.deepEqual(await store.getByIdempotencyKey('idem-1'), stored);
assert.equal(
(await store.update(
{ ...stored, status: 'cancelled' },
{ event: { ...blockedEvent, eventId: 'event-2', type: 'executor_job_cancelled' } },
)).status,
'cancelled',
);
assert.deepEqual(await store.listEvents('job-1'), [blockedEvent]);
const jobInsert = calls.find((call) => (
call.sql.includes('INSERT INTO') && call.sql.includes('executor_jobs')
));
assert.equal(JSON.parse(jobInsert.params[3]).jobId, 'job-1');
assert.equal(calls.filter((call) => call.sql.trim() === 'BEGIN').length, 2);
assert.equal(calls.filter((call) => call.sql.trim() === 'COMMIT').length, 2);
});
test('PostgreSQL Executor Job Store returns the existing idempotent record after conflict', async () => {
const stored = record();
const store = createPostgresExecutorJobStore({
pool: transactionalPool(async (sql) => {
if (sql.includes('INSERT INTO')) return { rows: [] };
if (sql.includes('WHERE idempotency_key =')) {
return { rows: [{ state_json: stored }] };
}
return { rows: [] };
}),
});
assert.deepEqual(
await store.createIfAbsent(stored),
{ created: false, record: stored },
);
});
test('PostgreSQL Executor Job Store deletes a job and cascades its events', async () => {
const calls = [];
const store = createPostgresExecutorJobStore({
pool: {
async query(sql, params) {
calls.push({ sql, params });
return sql.includes('DELETE FROM')
? { rows: [{ job_id: 'job-1' }] }
: { rows: [] };
},
},
});
assert.equal(await store.deleteById('job-1'), true);
assert.match(calls[0].sql, /DELETE FROM .*executor_jobs/);
assert.deepEqual(calls[0].params, ['job-1']);
});
test('PostgreSQL Executor Job Store lists bounded terminal retention candidates', async () => {
const calls = [];
const store = createPostgresExecutorJobStore({
pool: {
async query(sql, params) {
calls.push({ sql, params });
return {
rows: [{
job_id: 'job-1',
workflow_run_id: 'run-1',
completed_at: '1000',
}],
};
},
},
});
assert.deepEqual(
await store.listTerminalBefore({ before: 2000, limit: 10 }),
[{ jobId: 'job-1', workflowRunId: 'run-1', completedAt: 1000 }],
);
assert.match(calls[0].sql, /workflowRunId/);
assert.deepEqual(calls[0].params, [
['succeeded', 'failed', 'cancelled', 'timed_out', 'blocked'],
2000,
10,
]);
});
test('PostgreSQL Executor Job Store rolls back job creation when its initial event fails', async () => {
const calls = [];
const eventError = new Error('event insert unavailable');
const store = createPostgresExecutorJobStore({
pool: transactionalPool(async (sql) => {
calls.push(sql.trim());
if (sql.includes('INSERT INTO') && sql.includes('executor_jobs')) {
return { rows: [{ state_json: record() }] };
}
if (sql.includes('INSERT INTO') && sql.includes('executor_job_events')) {
throw eventError;
}
return { rows: [] };
}),
});
await assert.rejects(
store.createIfAbsent(record(), {
initialEvent: {
eventId: 'event-failing',
jobId: 'job-1',
timestamp: 1000,
},
}),
eventError,
);
assert.ok(calls.includes('BEGIN'));
assert.ok(calls.includes('ROLLBACK'));
assert.ok(!calls.includes('COMMIT'));
});
test('Executor Job persistence supports explicit non-durable memory mode', async () => {
const persistence = await createExecutorJobPersistence({ mode: 'memory' });
assert.equal(persistence.kind, 'memory');
assert.equal(persistence.durable, false);
assert.equal(persistence.store.durable, false);
assert.equal(persistence.store.kind, 'memory');
assert.equal(await persistence.probe(), true);
await persistence.close();
});
test('Executor Job persistence initializes and closes its PostgreSQL pool', async () => {
const queries = [];
let closed = false;
const pool = {
async query(sql) {
queries.push(sql);
return { rows: [] };
},
async end() {
closed = true;
},
};
const persistence = await createExecutorJobPersistence({
mode: 'postgres',
connectionString: 'postgresql://orchestrator:test@postgres/orchestrator',
schema: 'memind_orchestrator',
poolFactory(config) {
assert.equal(
config.connectionString,
'postgresql://orchestrator:test@postgres/orchestrator',
);
return pool;
},
});
assert.equal(persistence.kind, 'postgres');
assert.equal(persistence.durable, true);
assert.equal(persistence.store.kind, 'postgres');
assert.equal(await persistence.probe(), true);
assert.match(queries.at(-1), /SELECT 1 AS ok/);
await persistence.close();
assert.equal(closed, true);
});
test('Executor Job persistence rejects missing PostgreSQL config and unsafe schema names', async () => {
let poolCreated = false;
await assert.rejects(
createExecutorJobPersistence({ mode: 'postgres', connectionString: '' }),
(error) => error.code === 'ORCHESTRATOR_DATABASE_URL_REQUIRED',
);
await assert.rejects(
createExecutorJobPersistence({
mode: 'postgres',
connectionString: 'postgresql://orchestrator:test@postgres/orchestrator',
schema: 'public; drop schema public',
poolFactory() {
poolCreated = true;
return null;
},
}),
/Invalid Executor Gateway PostgreSQL schema/,
);
assert.equal(poolCreated, false);
assert.throws(
() => executorJobStoreInternals.normalizeSchema('public; drop schema public'),
/Invalid Executor Gateway PostgreSQL schema/,
);
});
test('Executor Job persistence closes its pool when schema initialization fails', async () => {
let closed = false;
const initializationError = new Error('schema unavailable');
await assert.rejects(
createExecutorJobPersistence({
mode: 'postgres',
connectionString: 'postgresql://orchestrator:test@postgres/orchestrator',
poolFactory() {
return {
async query() {
throw initializationError;
},
async end() {
closed = true;
},
};
},
}),
initializationError,
);
assert.equal(closed, true);
});