Unify halt and fire cancellation by verified run identity with durable first-owner receipts and shared deadlines. Integrate the instance control with the current host, library and tester-socket paths. Focused nine-file evidence is 62 passing tests; broad suites, mutants and review remain pending.
54 lines
3.6 KiB
JavaScript
54 lines
3.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { world } from './world.mjs';
|
|
import { tasksAdapter } from '../src/adapter.mjs';
|
|
import { createProcessing } from '../../processing-control/src/coordinator.mjs';
|
|
import { transition } from '../../processing-control/src/state.mjs';
|
|
const actor = { business: 'demo', human: 'jason', halted: true };
|
|
test('halted tracker startup makes no fetch and a later clear permits its ordinary startup', async t => {
|
|
const w = await world(t), processing = createProcessing({ dataRoot: w.root });
|
|
let calls = 0;
|
|
const adapter = await tasksAdapter({ trackers: { demo: { baseUrl: 'http://vikunja.test', project: w.project } },
|
|
autostart: false, fetch: (...args) => { calls++; return w.fake.fetch(...args); }, log: () => {} })
|
|
({ broker: w.broker, credentials: w.credentials, businesses: w.businesses, processing });
|
|
t.after(async () => { await adapter.close(); await processing.close(); });
|
|
const halted = transition(w.root, actor);
|
|
await assert.rejects(adapter.start('demo'), e => e.code === 'processing-halted');
|
|
assert.equal(calls, 0);
|
|
transition(w.root, { ...actor, halted: false, generation: halted.generation });
|
|
await adapter.start('demo'); assert.ok(calls > 0); assert.equal(adapter.status()[0].state, 'ready');
|
|
transition(w.root, actor); calls = 0;
|
|
await assert.rejects(adapter.tick('demo'), e => e.code === 'processing-halted');
|
|
await assert.rejects(adapter.reconcile('demo'), e => e.code === 'processing-halted');
|
|
assert.equal(calls, 0);
|
|
});
|
|
test('halt aborts the tracker HTTP request already in progress', async t => {
|
|
const w = await world(t), processing = createProcessing({ dataRoot: w.root });
|
|
let ready, aborted = false;
|
|
const started = new Promise(resolve => { ready = resolve; });
|
|
const adapter = await tasksAdapter({ trackers: { demo: { baseUrl: 'http://vikunja.test', project: w.project } },
|
|
autostart: false, log: () => {}, fetch: (_url, init) => new Promise((_resolve, reject) => {
|
|
init.signal.addEventListener('abort', () => { aborted = true; reject(Error('fixture abort')); }, { once: true }); ready();
|
|
}) })({ broker: w.broker, credentials: w.credentials, businesses: w.businesses, processing });
|
|
t.after(async () => { await adapter.close(); await processing.close(); });
|
|
const run = adapter.start('demo'); await started; const began = Date.now(); transition(w.root, actor);
|
|
await run.catch(() => {}); assert.equal(aborted, true);
|
|
assert.ok(Date.now() - began < 2000, 'halt must abort before the ordinary 15-second HTTP deadline');
|
|
});
|
|
|
|
test('an initially halted background startup remains retryable after clear', async t => {
|
|
const w = await world(t), processing = createProcessing({ dataRoot: w.root }), ticks = [];
|
|
const halted = transition(w.root, actor); let calls = 0;
|
|
const adapter = await tasksAdapter({ trackers: { demo: { baseUrl: 'http://vikunja.test', project: w.project } },
|
|
log: () => {}, timers: { setInterval: fn => { ticks.push(fn); return { unref() {} }; }, clearInterval() {} },
|
|
fetch: (...args) => { calls++; return w.fake.fetch(...args); } })
|
|
({ broker: w.broker, credentials: w.credentials, businesses: w.businesses, processing });
|
|
t.after(async () => { await adapter.close(); await processing.close(); });
|
|
await adapter.ready; assert.equal(calls, 0); assert.equal(adapter.status()[0].refused, 'processing-halted');
|
|
transition(w.root, { ...actor, halted: false, generation: halted.generation });
|
|
ticks[0]();
|
|
for (let i = 0; i < 100 && adapter.status()[0].state !== 'ready'; i++)
|
|
await new Promise(resolve => setTimeout(resolve, 10));
|
|
assert.equal(adapter.status()[0].state, 'ready'); assert.ok(calls > 0);
|
|
});
|