mirror of
https://github.com/whyour/qinglong.git
synced 2026-10-17 07:20:51 +08:00
Translate UI, scheduler, validation, preload and maintenance messages dynamically, and propagate locale changes between workers. Harden update checks, downloads and terminal states, verify Debian pnpm, and ignore generated test artifacts.
89 lines
3.6 KiB
JavaScript
89 lines
3.6 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const fs = require('node:fs/promises');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { execFile } = require('node:child_process');
|
|
const { promisify } = require('node:util');
|
|
|
|
test('language changes reach live HTTP/scheduler workers and replacement workers restore the saved language', async () => {
|
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'ql-language-cluster-'));
|
|
const root = path.resolve(__dirname, '../..');
|
|
try {
|
|
const state = path.join(dir, 'language.json');
|
|
await fs.writeFile(state, '"en"');
|
|
const fixture = path.join(dir, 'cluster.cjs');
|
|
await fs.writeFile(
|
|
fixture,
|
|
`
|
|
require(${JSON.stringify(require.resolve('ts-node/register/transpile-only'))});
|
|
const cluster = require('node:cluster');
|
|
const fs = require('node:fs/promises');
|
|
const storePath = require.resolve(${JSON.stringify(
|
|
path.join(root, 'back/shared/store.ts'),
|
|
)});
|
|
require.cache[storePath] = { id: storePath, filename: storePath, loaded: true, exports: { shareStore: {
|
|
getLang: async () => JSON.parse(await fs.readFile(process.env.LANGUAGE_STATE, 'utf8')),
|
|
setLang: (lang) => fs.writeFile(process.env.LANGUAGE_STATE, JSON.stringify(lang)),
|
|
} } };
|
|
const { initializeLanguageSync } = require(${JSON.stringify(
|
|
path.join(root, 'back/shared/languageSync.ts'),
|
|
)});
|
|
const { setLang, t } = require(${JSON.stringify(
|
|
path.join(root, 'back/shared/i18n.ts'),
|
|
)});
|
|
(async () => {
|
|
await initializeLanguageSync();
|
|
if (cluster.isPrimary) {
|
|
const ready = new Map(), observed = new Set(); let phase = 'initial';
|
|
cluster.on('message', (worker, message) => {
|
|
if (message.kind === 'ready') {
|
|
ready.set(worker.id, message.value);
|
|
if (phase === 'initial' && ready.size === 2) {
|
|
if ([...ready.values()].some(value => value !== 'Update successful')) throw Error('Initial language was not restored');
|
|
phase = 'zh'; cluster.workers[1].send({ command: 'switch', lang: 'zh' });
|
|
} else if (phase === 'replacement' && ready.size === 3) {
|
|
if (message.value !== '更新成功') throw Error('Replacement lost saved language');
|
|
phase = 'en'; observed.clear(); cluster.workers[1].send({ command: 'switch', lang: 'en' });
|
|
}
|
|
}
|
|
if (message.kind === 'observed') {
|
|
if (message.value !== (phase === 'zh' ? '更新成功' : 'Update successful')) throw Error('Worker language did not change');
|
|
observed.add(worker.id);
|
|
if (phase === 'zh' && observed.size === 2) { phase = 'replacement'; cluster.fork(); }
|
|
else if (phase === 'en' && observed.size === 3) {
|
|
console.log(JSON.stringify({ initialWorkers: 2, updatedWorkers: 3, replacementRestored: true }));
|
|
for (const w of Object.values(cluster.workers)) w.kill();
|
|
}
|
|
}
|
|
});
|
|
cluster.fork(); cluster.fork();
|
|
} else {
|
|
process.on('message', async message => {
|
|
if (message.command === 'switch') await setLang(message.lang);
|
|
if (message.type === 'language-changed') process.send({ kind: 'observed', value: t('更新成功') });
|
|
});
|
|
process.send({ kind: 'ready', value: t('更新成功') });
|
|
}
|
|
})().catch(error => { console.error(error); process.exit(1); });
|
|
`,
|
|
);
|
|
const result = await promisify(execFile)(process.execPath, [fixture], {
|
|
cwd: root,
|
|
timeout: 15000,
|
|
env: {
|
|
...process.env,
|
|
TS_NODE_PROJECT: path.join(root, 'back/tsconfig.json'),
|
|
LANGUAGE_STATE: state,
|
|
},
|
|
});
|
|
assert.deepEqual(JSON.parse(result.stdout), {
|
|
initialWorkers: 2,
|
|
updatedWorkers: 3,
|
|
replacementRestored: true,
|
|
});
|
|
} finally {
|
|
await fs.rm(dir, { recursive: true, force: true });
|
|
}
|
|
});
|