From 4322ae517ba2a971f5474f9dc264b207d6f3378f Mon Sep 17 00:00:00 2001 From: martino <32328813+f3rs3n@users.noreply.github.com> Date: Tue, 22 Sep 2026 19:59:31 +0200 Subject: [PATCH] fix(storage): translate disk passthrough completion messages as a whole --- scripts/storage/disk-passthrough.sh | 8 +- scripts/storage/disk-passthrough_ct.sh | 8 +- tests/test_disk_passthrough_completion.py | 101 ++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 tests/test_disk_passthrough_completion.py diff --git a/scripts/storage/disk-passthrough.sh b/scripts/storage/disk-passthrough.sh index 0a303f43..f20270a4 100644 --- a/scripts/storage/disk-passthrough.sh +++ b/scripts/storage/disk-passthrough.sh @@ -443,7 +443,13 @@ done echo "" if [ "$DISKS_ADDED" -gt 0 ]; then - msg_ok "$(translate "Completed.") $DISKS_ADDED $(translate "disk(s) added to VM") $VMID." + COMPLETED_MESSAGE="$(translate "Completed. Disks added to VM {vmid}: {count}.")" + if [[ "$COMPLETED_MESSAGE" != *'{vmid}'* || "$COMPLETED_MESSAGE" != *'{count}'* ]]; then + COMPLETED_MESSAGE="Completed. Disks added to VM {vmid}: {count}." + fi + COMPLETED_MESSAGE="${COMPLETED_MESSAGE//\{vmid\}/$VMID}" + COMPLETED_MESSAGE="${COMPLETED_MESSAGE//\{count\}/$DISKS_ADDED}" + msg_ok "$COMPLETED_MESSAGE" else msg_warn "$(translate "No disks were added.")" fi diff --git a/scripts/storage/disk-passthrough_ct.sh b/scripts/storage/disk-passthrough_ct.sh index 1f4bafd5..c7aaa841 100644 --- a/scripts/storage/disk-passthrough_ct.sh +++ b/scripts/storage/disk-passthrough_ct.sh @@ -713,7 +713,13 @@ done echo "" if [ "$DISKS_ADDED" -gt 0 ]; then - msg_ok "$(translate "Completed.") $DISKS_ADDED $(translate "disk(s) added to CT") $CTID." + COMPLETED_MESSAGE="$(translate "Completed. Disks added to CT {ctid}: {count}.")" + if [[ "$COMPLETED_MESSAGE" != *'{ctid}'* || "$COMPLETED_MESSAGE" != *'{count}'* ]]; then + COMPLETED_MESSAGE="Completed. Disks added to CT {ctid}: {count}." + fi + COMPLETED_MESSAGE="${COMPLETED_MESSAGE//\{ctid\}/$CTID}" + COMPLETED_MESSAGE="${COMPLETED_MESSAGE//\{count\}/$DISKS_ADDED}" + msg_ok "$COMPLETED_MESSAGE" else msg_warn "$(translate "No disks were added.")" fi diff --git a/tests/test_disk_passthrough_completion.py b/tests/test_disk_passthrough_completion.py new file mode 100644 index 00000000..354942a5 --- /dev/null +++ b/tests/test_disk_passthrough_completion.py @@ -0,0 +1,101 @@ +"""Offline completion consumers only; never source VM/CT admin entrypoints. + +Run: python3 -m unittest discover -s tests -p test_disk_passthrough_completion.py -v +Bash and jq required. The existing harness exposes jq only on PATH. +""" +import importlib.util +import json +import unittest + +import test_tui_count_messages as harness +from test_tui_count_messages import ROOT, between + +VM = 'scripts/storage/disk-passthrough.sh' +CT = 'scripts/storage/disk-passthrough_ct.sh' + + +class DiskCompletion(unittest.TestCase): + def check_consumer(self, path, target): + seam = between(path, 'if [ "$DISKS_ADDED" -gt 0 ]; then', + 'msg_success "$(translate "Press Enter to return to menu...")"') + token = '{' + target.lower() + 'id}' + key = f'Completed. Disks added to {target} {token}: {{count}}.' + cases = [('en', None), ('missing', {}), + ('it', json.loads((ROOT / 'lang/it.json').read_text())), + ('reorder', {key: '{count} / destination ' + token + ' / done 100%.'}), + ('repeat', {key: token + ' {count} {count} ' + token + ' {unknown} $(literal) %s'})] + for bad in ('No values', key.replace(token, ''), key.replace('{count}', ''), + key.replace(token, token.upper()), key.replace('{count}', '{renamed}')): + cases.append(('bad', {key: bad})) + renderer = harness.CountMessages() + for count in (0, 1, 3): + for identifier in ('101', '987654'): + for language, catalog in cases: + with self.subTest(target=target, count=count, identifier=identifier, language=language): + result = renderer.render(seam, f'DISKS_ADDED={count}; {target}ID={identifier}', language, catalog) + if count == 0: + expected = 'WARN:' + ((catalog or {}).get('No disks were added.') or 'No disks were added.') + else: + template = key if language == 'bad' else ((catalog or {}).get(key) or key) + expected = 'OK:' + template.replace(token, identifier).replace('{count}', str(count)) + self.assertEqual(result, expected) + spec = importlib.util.spec_from_file_location('disk_cache', ROOT / '.github/scripts/build_translation_cache.py') + builder = importlib.util.module_from_spec(spec) + spec.loader.exec_module(builder) + self.assertIn(key, builder.extract_translate_texts(ROOT / 'scripts/storage')) + + def test_assignment_outcomes_and_counts(self): + # Execute bounded assignment consumers, with no disk discovery/formatting. + # Configuration success is counted even if CT accessibility fails. + for path, target, start in ((VM, 'VM', ' ASSIGN_PATH=$(get_preferred_disk_path "$DISK")'), + (CT, 'CT', ' PERSISTENT_PARTITION=$(get_preferred_disk_path "$PARTITION")')): + assignment = between(path, start, '\ndone\n') + summary = between(path, 'if [ "$DISKS_ADDED" -gt 0 ]; then', + 'msg_success "$(translate "Press Enter to return to menu...")"') + for statuses, expected in (([], 0), ([0], 1), ([0, 0, 0], 3), ([1], 0), ([0, 1, 0], 2)): + for filesystem in ('ext4', 'xfs'): + with self.subTest(target=target, statuses=statuses, filesystem=filesystem): + setup = '''DISKS_ADDED=0; VMID=101; CTID=101; INDEX=0; INTERFACE=scsi +DISK=fixture; PARTITION=fixture; MOUNT_POINT=/fixture/mount +ASSIGNED_TO=''; CT_RUNNING=true; _model=fixture; _size=1G; DISK_INFO=fixture +get_preferred_disk_path() { [[ "$1" == fixture ]] || exit 99; printf /fixture/disk; } +msg_info() { :; } +msg_error() { printf 'ERROR:%s\\n' "$1"; } +sleep() { [[ "$1" == 1 ]] || exit 99; } +qm() { + [[ "$*" == 'set 101 -scsi0 /fixture/disk' ]] || exit 99 + printf 'CALL:qm:%s\\n' "$*" >&3 + return "$status" +} +pct() { + if [[ "$1" == exec ]]; then + [[ "$*" == "exec 101 -- sh -c mountpoint -q '/fixture/mount' || [ -d '/fixture/mount' ]" ]] || exit 99 + printf 'CALL:verify\\n' >&3 + return 1 + fi + local expected='set 101 -mp0 /fixture/disk,mp=/fixture/mount,backup=0,ro=0' + [[ "$FORMAT_TYPE" == xfs ]] || expected+=',acl=1' + [[ "$*" == "$expected" ]] || exit 99 + printf 'CALL:pct:%s\\n' "$*" >&3 + return "$status" +} +exec 3>&1 +''' + setup += f'FORMAT_TYPE={filesystem}\n' + seam = 'for status in ' + ' '.join(map(str, statuses)) + '; do\n' + assignment + '\ndone\n' + summary + result = harness.CountMessages().render(seam, setup) + final = result.splitlines()[-1] + self.assertEqual(final, f'OK:Completed. Disks added to {target} 101: {expected}.' if expected else 'WARN:No disks were added.') + calls = [line for line in result.splitlines() if line.startswith('CALL:')] + self.assertEqual(len(calls), len(statuses) + (expected if target == 'CT' else 0)) + self.assertNotIn('Disk verified and accessible', result) + + def test_ct_complete_message(self): + self.check_consumer(CT, 'CT') + + def test_vm_complete_message(self): + self.check_consumer(VM, 'VM') + + +if __name__ == '__main__': + unittest.main()