Files
qinglong/test/back/stop-failure-feedback.test.cjs
T
da9c6a6bbb fix: skip new scheduled triggers while a single-instance task is active (#3101)
* fix: skip active single-instance scheduled executions

* fix: recover stale single-instance scheduled tasks

* test: remove obsolete single-instance replacement assertions

---------

Co-authored-by: Patrick Gu <username@users.noreply.github.com>
Co-authored-by: whyour <imwhyour@gmail.com>
2026-10-24 23:11:36 +08:00

90 lines
2.8 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const load = require('../helpers/load-security-module.cjs');
const logger = { info() {}, error() {} };
function subscriptionFixture(killTask) {
const updates = [];
const Service = load('back/services/subscription.ts', {
'../config': {},
'../data/cron': {},
'../config/const': {},
'../data/subscription': {
SubscriptionModel: {
findAll: async () => [
{ id: 1, pid: 101 },
{ id: 2, pid: 102 },
],
update: async (values, query) => updates.push({ values, query }),
},
SubscriptionStatus: { idle: 1 },
},
'../config/util': { killTask },
'../config/subscription': {},
'../shared/i18n': {},
'../shared/pLimit': {},
'../shared/logReader': {},
'../shared/logStreamManager': {},
'./schedule': {},
'./sock': {},
'./sshKey': {},
'./cron': {},
}).default;
return { service: new Service(logger, {}, {}, {}, {}), updates };
}
test('batch subscription stop preserves failed items and reports failure while stopping others', async () => {
const calls = [];
const denied = Error('EPERM');
const f = subscriptionFixture(async (pid, wait) => {
calls.push([pid, wait]);
if (pid === 101) throw denied;
});
await assert.rejects(f.service.stop([1, 2]), (e) => e === denied);
assert.deepEqual(calls, [
[101, true],
[102, true],
]);
assert.equal(f.updates.length, 1);
assert.equal(f.updates[0].query.where.id, 2);
assert.equal(f.updates[0].values.status, 1);
});
function scriptFixture(killTask, pid = 100) {
const Service = load('back/services/script.ts', {
'../config': { scriptPath: '/scripts' },
'../config/const': { TASK_COMMAND: 'task' },
'../config/util': { killTask, getPid: async () => pid },
'../shared/pLimit': { removeQueuedCron() {} },
'./sock': {},
'./cron': {},
'./schedule': {},
'../shared/fileAccess': {},
}).default;
return new Service(logger, {}, {}, {});
}
test('script stop propagates failure instead of returning success', async () => {
const denied = Error('EPERM');
const service = scriptFixture(async () => {
throw denied;
});
await assert.rejects(
service.stopScript('/scripts/test.js', 100),
(e) => e === denied,
);
});
test('script stop verifies exit and treats an absent queued process as already stopped', async () => {
const calls = [];
const service = scriptFixture(async (...args) => calls.push(args), undefined);
assert.equal((await service.stopScript('/scripts/test.js', 100)).code, 200);
assert.deepEqual(calls, [[100, true]]);
const absent = scriptFixture(async () => assert.fail('no PID to stop'), null);
assert.equal(
(await absent.stopScript('/scripts/test.js', undefined)).code,
200,
);
});