fix: synchronize runtime locales and harden online updates

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.
This commit is contained in:
whyour
2026-10-17 07:07:09 +08:00
parent 8305825ffd
commit ef348b445b
72 changed files with 1733 additions and 553 deletions
+109
View File
@@ -0,0 +1,109 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const load = require('../helpers/load-security-module.cjs');
const yaml = require('js-yaml');
function service(request) {
const Service = load('back/services/system.ts', {
undici: { request },
'../config': {
versionFile: 'version.yaml',
lastVersionFile: 'https://version.example/version.yaml',
},
'../config/const': {},
'../config/util': {
parseVersion: async () => ({ version: '2.23.0' }),
parseContentVersion: yaml.load,
},
'../data/dependence': {},
'../data/notify': {},
'../data/system': {},
'../shared/pLimit': {},
'../schedule/client': {},
'../shared/i18n': { t: (key) => key },
'./notify': class {},
'./schedule': class {},
'./sock': class {},
}).default;
return new Service({}, {}, {});
}
for (const [name, request] of [
[
'unreachable server',
async () => {
throw new Error('network down');
},
],
[
'HTTP error with a version-like body',
async () => ({
statusCode: 503,
body: { text: async () => 'version: 2.23.0' },
}),
],
[
'HTML response',
async () => ({
statusCode: 200,
body: { text: async () => '<html>gateway error</html>' },
}),
],
[
'invalid version',
async () => ({
statusCode: 200,
body: { text: async () => 'version: latest' },
}),
],
[
'unreadable body',
async () => ({
statusCode: 200,
body: {
text: async () => {
throw new Error('reset');
},
},
}),
],
])
test(`update check reports failure for ${name}, without claiming the latest version`, async () => {
assert.deepEqual(await service(request).checkUpdate(), {
code: 400,
message: '检查更新失败,请检查网络后重试',
});
});
for (const [version, newer] of [
['2.23.0', false],
['2.23.1', true],
['2.22.0', false],
['3.0.0', true],
])
test(`valid update response ${version}`, async () => {
const result = await service(async (url, options) => {
assert.ok(options.signal instanceof AbortSignal);
assert.equal(options.signal.aborted, false);
return {
statusCode: 200,
body: {
text: async () => `version: ${version}\nchangeLog: release notes`,
},
};
}).checkUpdate();
assert.equal(result.code, 200);
assert.equal(result.data.hasNewVersion, newer);
assert.equal(result.data.lastVersion, version);
assert.equal(result.data.lastLog, 'release notes');
});
test('a stalled version request times out instead of hanging the update check', async (t) => {
t.mock.timers.enable({ apis: ['setTimeout'] });
const checking = service(async (url, { signal }) => {
return new Promise((resolve, reject) =>
signal.addEventListener('abort', () => reject(new Error('aborted')), {
once: true,
}),
);
}).checkUpdate();
await Promise.resolve();
t.mock.timers.tick(15000);
assert.equal((await checking).code, 400);
});