mirror of
https://github.com/whyour/qinglong.git
synced 2026-10-16 22:35:32 +08:00
fix: handle mobile INI editing and silence timeout cleanup
Map INI to the CodeMirror properties language and fall back to plain text for unsupported modes. Reap the timeout watchdog immediately under stderr redirection to prevent Bash job notifications during cleanup. Refs #3095, #3096
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { spawnSync } = require('node:child_process');
|
||||
const test = require('node:test');
|
||||
|
||||
const source = fs.readFileSync(
|
||||
path.resolve(__dirname, '../../shell/task-timeout.sh'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
test('timed task cleanup preserves output and exit codes without Bash job notifications', () => {
|
||||
const result = spawnSync(
|
||||
process.env.QL_TEST_BASH || '/bin/bash',
|
||||
[
|
||||
'-c',
|
||||
source +
|
||||
`
|
||||
command_timeout_time=1h
|
||||
for code in 0 7 0 7 0 7 0 7 0 7; do
|
||||
# Keep a descendant alive after the task leader exits so cleanup must
|
||||
# terminate the worker group as well as the sleeping watchdog.
|
||||
run_task_command bash -c 'sleep 10 & echo TASK_OUTPUT; echo TASK_ERROR >&2; exit "$1"' task "$code"
|
||||
actual=$?
|
||||
[[ $actual == "$code" ]] || exit 99
|
||||
done
|
||||
`,
|
||||
],
|
||||
{ encoding: 'utf8', timeout: 15000 },
|
||||
);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(result.stdout, 'TASK_OUTPUT\n'.repeat(10));
|
||||
assert.equal(result.stderr, 'TASK_ERROR\n'.repeat(10));
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const path = require('node:path');
|
||||
const { createRequire } = require('node:module');
|
||||
const test = require('node:test');
|
||||
const { EditorState } = require('@codemirror/state');
|
||||
const load = require('../helpers/load-security-module.cjs');
|
||||
const { getCodeMirrorExtensions } = load(
|
||||
path.resolve(__dirname, '../../src/utils/codemirror/language.ts'),
|
||||
);
|
||||
const { LANG_MAP } = load(path.resolve(__dirname, '../../src/utils/const.ts'));
|
||||
const languageRequire = createRequire(
|
||||
require.resolve('@uiw/codemirror-extensions-langs'),
|
||||
);
|
||||
const { syntaxTree } = languageRequire('@codemirror/language');
|
||||
|
||||
test('INI documents load and remain editable with CodeMirror syntax support', () => {
|
||||
const doc = '; comment\n[section]\nkey=value\n';
|
||||
const state = EditorState.create({
|
||||
doc,
|
||||
extensions: getCodeMirrorExtensions(LANG_MAP['.ini']),
|
||||
});
|
||||
assert.ok(syntaxTree(state).length > 0);
|
||||
assert.ok(syntaxTree(state).topNode.firstChild, 'INI tokens were parsed');
|
||||
const updated = state.update({
|
||||
changes: {
|
||||
from: doc.indexOf('value'),
|
||||
to: doc.indexOf('value') + 5,
|
||||
insert: 'edited',
|
||||
},
|
||||
}).state;
|
||||
assert.equal(updated.doc.toString(), '; comment\n[section]\nkey=edited\n');
|
||||
});
|
||||
|
||||
test('every configured script language supplies a valid CodeMirror extension', () => {
|
||||
for (const mode of new Set(Object.values(LANG_MAP))) {
|
||||
const extensions = getCodeMirrorExtensions(mode);
|
||||
assert.equal(extensions.length, 1, mode);
|
||||
assert.doesNotThrow(
|
||||
() => EditorState.create({ doc: 'sample', extensions }),
|
||||
mode,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('unknown or empty languages fall back to editable plain text', () => {
|
||||
for (const mode of ['', undefined, 'unknown', 'constructor', 'toString']) {
|
||||
const extensions = getCodeMirrorExtensions(mode);
|
||||
assert.deepEqual(extensions, []);
|
||||
const state = EditorState.create({ doc: 'text', extensions });
|
||||
assert.equal(
|
||||
state
|
||||
.update({ changes: { from: 4, insert: ' edited' } })
|
||||
.state.doc.toString(),
|
||||
'text edited',
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user