mirror of
https://github.com/whyour/qinglong.git
synced 2026-10-18 18:33:06 +08:00
fix: preserve active system log files when clearing logs
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs/promises');
|
||||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
const load = require('../helpers/load-security-module.cjs');
|
||||
|
||||
async function fixture(t) {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ql-system-log-clear-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const SystemService = load('back/services/system.ts', {
|
||||
'../config': { systemLogPath: root },
|
||||
'../config/const': {},
|
||||
'../config/util': {
|
||||
readDirs: async () =>
|
||||
(await fs.readdir(root)).map((title) => ({ title })),
|
||||
rmPath: (file) => fs.rm(file),
|
||||
},
|
||||
'../data/dependence': {},
|
||||
'../data/notify': {},
|
||||
'../data/system': {},
|
||||
'../shared/pLimit': {},
|
||||
'../schedule/client': {},
|
||||
'../shared/i18n': { t: (x) => x },
|
||||
'./notify': class {},
|
||||
'./schedule': class {},
|
||||
'./sock': class {},
|
||||
}).default;
|
||||
return { root, service: new SystemService({}, {}, {}) };
|
||||
}
|
||||
|
||||
test('clearing system logs preserves append handles used by existing workers', async (t) => {
|
||||
const { root, service } = await fixture(t);
|
||||
const active = path.join(root, '2026-10-17.log');
|
||||
const rotated = path.join(root, '2026-10-16.log');
|
||||
await fs.writeFile(active, 'old active logs\n');
|
||||
await fs.writeFile(rotated, 'old rotated logs\n');
|
||||
await fs.writeFile(path.join(root, 'audit.json'), 'rotation metadata');
|
||||
const workers = await Promise.all([fs.open(active, 'a'), fs.open(active, 'a')]);
|
||||
t.after(async () => {
|
||||
await Promise.all(workers.map((worker) => worker.close()));
|
||||
});
|
||||
const inode = (await fs.stat(active)).ino;
|
||||
|
||||
for (let clear = 0; clear < 2; clear++) {
|
||||
await service.deleteSystemLog();
|
||||
assert.equal(await fs.readFile(active, 'utf8'), '');
|
||||
assert.equal(await fs.readFile(rotated, 'utf8'), '');
|
||||
assert.equal((await fs.stat(active)).ino, inode);
|
||||
await workers[0].write('new scheduler log\n');
|
||||
await workers[1].write('new queue log\n');
|
||||
assert.equal(
|
||||
await fs.readFile(active, 'utf8'),
|
||||
'new scheduler log\nnew queue log\n',
|
||||
);
|
||||
}
|
||||
assert.equal(
|
||||
await fs.readFile(path.join(root, 'audit.json'), 'utf8'),
|
||||
'rotation metadata',
|
||||
);
|
||||
});
|
||||
|
||||
test('clearing system logs refuses symlinks without truncating their target', async (t) => {
|
||||
const { root, service } = await fixture(t);
|
||||
const target = path.join(root, 'keep.txt');
|
||||
await fs.writeFile(target, 'keep this content');
|
||||
await fs.symlink(target, path.join(root, 'linked.log'));
|
||||
await assert.rejects(service.deleteSystemLog(), { code: 'ELOOP' });
|
||||
assert.equal(await fs.readFile(target, 'utf8'), 'keep this content');
|
||||
});
|
||||
Reference in New Issue
Block a user