mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-29 10:06:41 +00:00
Merge pull request #380 from f3rs3n/ci/scheduler-multilingual-coverage
test: exercise every shipped scheduler locale and cover its CI inputs
This commit is contained in:
@@ -35,7 +35,8 @@ def consumers():
|
||||
def fixture(directory, backend='pbs', consumer='attached', rows='', second=None,
|
||||
locale='en', catalog=None, real_dialog=None):
|
||||
directory = Path(directory)
|
||||
(directory / 'xx.json').write_text(json.dumps(catalog or {}))
|
||||
if catalog is not None:
|
||||
(directory / f'{locale}.json').write_text(json.dumps(catalog), encoding='utf-8')
|
||||
(directory / 'rows').write_text(rows)
|
||||
(directory / 'second').write_text(rows if second is None else second)
|
||||
bindir = directory / 'bin'
|
||||
@@ -51,7 +52,7 @@ FIXTURE={shlex.quote(str(directory))}
|
||||
BACKEND={backend}
|
||||
HB_UI_MENU_H=20 HB_UI_MENU_W=84 HB_UI_MENU_LIST=10
|
||||
command_not_found_handle() {{ printf 'FORBIDDEN:%s\\n' "$*" >> "$FIXTURE/errors"; return 99; }}
|
||||
jq() {{ [[ "$#" == 6 && "$1" == -r && "$2" == --arg && "$3" == text && "$5" == '.[$text] // empty' && "$6" == "$FIXTURE/xx.json" ]] || {{ printf 'bad jq' >> "$FIXTURE/errors"; return 99; }}; command jq "$@"; }}
|
||||
jq() {{ [[ "$#" == 6 && "$1" == -r && "$2" == --arg && "$3" == text && "$5" == '.[$text] // empty' && "$6" == "$FIXTURE/$LANGUAGE.json" ]] || {{ printf 'bad jq' >> "$FIXTURE/errors"; return 99; }}; command jq "$@"; }}
|
||||
head() {{ [[ "$*" == '-1' ]] || return 99; local first; IFS= read -r first; printf '%s\\n' "$first"; while IFS= read -r first; do :; done; }}
|
||||
hb_pve_list_vzdump_jobs() {{
|
||||
local file="$FIXTURE/rows" line
|
||||
@@ -107,20 +108,40 @@ class SchedulerMessages(unittest.TestCase):
|
||||
self.assertEqual(result['status'], '1')
|
||||
|
||||
def test_lookup_cache_modes_at_both_consumers(self):
|
||||
shipped = json.loads((ROOT / 'lang/it.json').read_text())
|
||||
# Unconditional synthetic coverage, independent of cache completeness.
|
||||
for backend, message in MESSAGES.items():
|
||||
for consumer in ('attached', 'new'):
|
||||
for locale, catalog, expected in (
|
||||
('en', {message: 'ignored'}, message),
|
||||
('missing', {}, message),
|
||||
('xx', {'unrelated': 'unrelated'}, message),
|
||||
('xx', shipped, shipped.get(message, message)),
|
||||
('xx', {message: 'SYNTHETIC reordered backend: ' + backend},
|
||||
'SYNTHETIC reordered backend: ' + backend),
|
||||
for mode, locale, catalog, expected, hint in (
|
||||
('english', 'en', {message: 'ignored', HINT: 'ignored'}, message, HINT),
|
||||
('missing-file', 'missing', None, message, HINT),
|
||||
('missing-key', 'xx', {'unrelated': 'unrelated'}, message, HINT),
|
||||
('translated', 'xx', {message: 'SYNTHETIC reordered backend: ' + backend,
|
||||
HINT: 'SYNTHETIC hint'},
|
||||
'SYNTHETIC reordered backend: ' + backend, 'SYNTHETIC hint'),
|
||||
):
|
||||
with self.subTest(backend=backend, consumer=consumer, locale=locale, expected=expected):
|
||||
with self.subTest(backend=backend, consumer=consumer, mode=mode):
|
||||
result = run_case(backend=backend, consumer=consumer, locale=locale, catalog=catalog)
|
||||
suffix = '\n\n' + catalog.get(HINT, HINT) if consumer == 'new' else ''
|
||||
suffix = '\n\n' + hint if consumer == 'new' else ''
|
||||
self.assertEqual(result['message'], expected + suffix)
|
||||
self.assertEqual(result['status'], '1')
|
||||
|
||||
def test_all_shipped_caches_at_both_consumers(self):
|
||||
catalogs = sorted((ROOT / 'lang').glob('*.json'))
|
||||
self.assertTrue(catalogs, 'No shipped locale catalogs discovered')
|
||||
for path in catalogs:
|
||||
catalog = json.loads(path.read_text(encoding='utf-8'))
|
||||
self.assertIsInstance(catalog, dict, path.name)
|
||||
for backend, message in MESSAGES.items():
|
||||
for consumer in ('attached', 'new'):
|
||||
with self.subTest(locale=path.stem, backend=backend, consumer=consumer):
|
||||
# Exercise the real translate function with the actual locale
|
||||
# filename, not just a comparison of JSON values. Missing or
|
||||
# empty translations are valid: runtime falls back to English.
|
||||
result = run_case(backend=backend, consumer=consumer,
|
||||
locale=path.stem, catalog=catalog)
|
||||
expected = message if path.stem == 'en' else catalog.get(message) or message
|
||||
hint = HINT if path.stem == 'en' else catalog.get(HINT) or HINT
|
||||
suffix = '\n\n' + hint if consumer == 'new' else ''
|
||||
self.assertEqual(result['message'], expected + suffix)
|
||||
self.assertEqual(result['status'], '1')
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ on:
|
||||
- 'AppImage/lib/i18n/**'
|
||||
- 'AppImage/components/terminal-panel.tsx'
|
||||
- 'CONTRIBUTING.md'
|
||||
# Scheduler consumers and the offline extractor's .sh/.func inputs.
|
||||
- 'scripts/**/*.sh'
|
||||
- 'scripts/**/*.func'
|
||||
- 'lang/*.json'
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
@@ -20,6 +24,10 @@ on:
|
||||
- 'AppImage/lib/i18n/**'
|
||||
- 'AppImage/components/terminal-panel.tsx'
|
||||
- 'CONTRIBUTING.md'
|
||||
# Scheduler consumers and the offline extractor's .sh/.func inputs.
|
||||
- 'scripts/**/*.sh'
|
||||
- 'scripts/**/*.func'
|
||||
- 'lang/*.json'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -39,6 +47,10 @@ jobs:
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22.14.0'
|
||||
- name: Check scheduler test dependencies
|
||||
run: |
|
||||
test -x /bin/bash
|
||||
test -x /usr/bin/jq
|
||||
- name: Run complete offline script test suite
|
||||
env:
|
||||
PYTHONDONTWRITEBYTECODE: '1'
|
||||
|
||||
+13
-1
@@ -826,7 +826,8 @@ From the repository root, run the complete script suite:
|
||||
python3 -m unittest discover -s .github/scripts/tests -v
|
||||
```
|
||||
|
||||
Prerequisites: Python 3.11+ (standard library only) and Node **22.14+**
|
||||
Prerequisites: Python 3.11+ (Python standard library only), Node **22.14+**,
|
||||
`/bin/bash`, and `/usr/bin/jq` for the isolated scheduler fixtures.
|
||||
(Node 22 LTS is the CI baseline). Node 20 can still build the Monitor, but
|
||||
cannot run this suite's native TypeScript consumer test. The test passes
|
||||
`--experimental-strip-types` explicitly and executes the actual pure lookup
|
||||
@@ -835,6 +836,17 @@ It does not launch React or require `npm install`, `pip install`, a Proxmox host
|
||||
API keys, or a translation provider. Generator tests use isolated temporary
|
||||
catalogs and fake/forbidden providers; repository catalogs are not regenerated.
|
||||
|
||||
Scheduler fixtures discover every shipped `lang/*.json` cache and run the actual
|
||||
`translate` lookup at both empty-job consumers for PBS and local archive backends.
|
||||
They accept English fallback for missing/empty entries; complete translations are
|
||||
not required. Unconditional synthetic cases cover English bypass, missing files,
|
||||
missing keys and translated messages/hints. Only bounded shell functions are
|
||||
extracted: no administrative script is sourced or run in full. These scheduler
|
||||
messages have no placeholders; named-token preservation is tested separately by
|
||||
the existing cache-generator tests, not by scheduler/count-message assertions.
|
||||
The workflow watches all `lang/*.json` catalogs plus `.sh` and `.func` inputs
|
||||
under `scripts/`, and checks the Bash/jq prerequisites before running the suite.
|
||||
|
||||
If Node is not on `PATH`, select a local executable without a global install:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user