Generalize OCI device setup and remove unused catalog hashes

This commit is contained in:
MacRimi
2026-09-26 01:22:37 +02:00
parent 88acceb8ef
commit f7266e7b44
26 changed files with 689 additions and 487 deletions
+104
View File
@@ -0,0 +1,104 @@
"""Shared wizard navigation and device choices do not depend on app overlays."""
from pathlib import Path
import sys
import unittest
from unittest.mock import patch
from subprocess import CompletedProcess
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'src'))
from proxmenux_oci.extra_devices import (ask_extra_devices, ask_stack_extra_devices,
device_permissions)
from proxmenux_oci.ui import BackRequested, BacktrackUI, DialogUI, RestartWizard
class SequenceUI:
def __init__(self, answers):
self.answers = iter(answers)
self.back_enabled = False
def ask(self, *_args, **_kwargs):
result = next(self.answers)
if result == 'back':
raise BackRequested()
return result
def confirm(self, *_args, **_kwargs):
return next(self.answers)
def choose(self, *_args, **_kwargs):
return next(self.answers)
def checklist(self, *_args, **_kwargs):
return next(self.answers)
def info(self, _text):
pass
class WizardTests(unittest.TestCase):
def test_back_returns_to_previous_answer_without_reasking_first(self):
base = SequenceUI(['first', 'second', 'back', 'corrected', 'third'])
wizard = BacktrackUI(base)
try:
self.assertEqual(wizard.ask('first'), 'first')
self.assertEqual(wizard.ask('second'), 'second')
with self.assertRaises(RestartWizard):
wizard.ask('third')
wizard.restart()
self.assertEqual(wizard.ask('first'), 'first')
self.assertEqual(wizard.ask('second'), 'corrected')
self.assertEqual(wizard.ask('third'), 'third')
finally:
wizard.close()
self.assertFalse(base.back_enabled)
def test_back_from_review_reopens_last_question(self):
class ReviewUI(SequenceUI):
def review(self, *_args, **_kwargs):
raise BackRequested()
wizard = BacktrackUI(ReviewUI(['value', 'replacement']))
try:
self.assertEqual(wizard.ask('value'), 'value')
with self.assertRaises(RestartWizard):
wizard.review('summary')
wizard.restart()
self.assertEqual(wizard.ask('value'), 'replacement')
finally:
wizard.close()
def test_manual_usb_is_available_without_profile(self):
ui = SequenceUI([True, 'usb', '/dev/ttyACM0', False])
devices = ask_extra_devices(ui, [], True)
self.assertEqual(devices[0]['host_path'], '/dev/ttyACM0')
self.assertEqual(devices[0]['container_path'], '/dev/ttyACM0')
def test_linuxserver_device_permissions_are_generic(self):
permissions = device_permissions('lscr.io/linuxserver/chromium:latest',
[{'kind': 'character-device'}])
self.assertEqual(permissions['strategy'], 'linuxserver-native-init')
def test_stack_device_goes_only_to_selected_member(self):
ui = SequenceUI([True, 'usb', '/dev/ttyACM0', False, ['server']])
services = [
{'name': name, 'main': name == 'server',
'template': {'container_contract': {'image': {'reference': 'example/app:latest'}}},
'deployment': {'devices': [], 'security': {'unprivileged': True}}}
for name in ('database', 'server')
]
ask_stack_extra_devices(ui, services)
self.assertEqual(services[0]['deployment']['devices'], [])
self.assertEqual(services[1]['deployment']['devices'][0]['host_path'], '/dev/ttyACM0')
def test_dialog_back_button_is_only_on_wizard_inputs(self):
ui = DialogUI(back_enabled=True)
with patch('proxmenux_oci.ui.subprocess.run', return_value=CompletedProcess([], 3, '', '')) as run:
with self.assertRaises(BackRequested):
ui._run(['--inputbox', 'Name', '10', '50', ''])
self.assertIn('--extra-button', run.call_args.args[0])
if __name__ == '__main__':
unittest.main()