mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-09 23:16:41 +00:00
105 lines
4.7 KiB
Python
105 lines
4.7 KiB
Python
"""Every multi-container application offers extra paths in an advanced installation."""
|
|||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import unittest
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
ROOT = Path(__file__).resolve().parents[1]
|
||
|
|
sys.path.insert(0, str(ROOT / "src"))
|
||
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
|
|
|
||
|
|
from proxmenux_oci.catalog import Catalog
|
||
|
|
from proxmenux_oci.cli import _deployment_summary_text
|
||
|
|
from proxmenux_oci.installer import ADVANCED_MODE, DEFAULT_MODE, build_deployment
|
||
|
|
from test_advanced_flow_order import RecordingUI, addresses, storages
|
||
|
|
|
||
|
|
EXTRA = "Add an extra custom path"
|
||
|
|
SPECIAL = ("nextcloud-stack", "paperless-ngx", "tandoor", "immich")
|
||
|
|
|
||
|
|
|
||
|
|
class ExtraPathUI(RecordingUI):
|
||
|
|
"""Adds one container volume the first time the extra path is offered."""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
super().__init__({"Path inside the container (e.g. /media-extra)": "/media-extra",
|
||
|
|
"Volume size in GB": "20"})
|
||
|
|
self.offered = 0
|
||
|
|
|
||
|
|
def confirm(self, text, default=False):
|
||
|
|
if text == EXTRA:
|
||
|
|
self.asked.append(text)
|
||
|
|
self.offered += 1
|
||
|
|
return self.offered == 1
|
||
|
|
return super().confirm(text, default)
|
||
|
|
|
||
|
|
|
||
|
|
@patch("proxmenux_oci.i18n.language", return_value="en")
|
||
|
|
@patch("proxmenux_oci.installer.host.storages", side_effect=storages)
|
||
|
|
@patch("proxmenux_oci.installer.host.bridges", return_value=[{"iface": "vmbr0", "cidr": "192.0.2.10/24"}])
|
||
|
|
@patch("proxmenux_oci.installer.host.timezone", return_value="Europe/Madrid")
|
||
|
|
@patch("proxmenux_oci.installer.access.ask_addresses", side_effect=addresses)
|
||
|
|
class StackExtraPathTests(unittest.TestCase):
|
||
|
|
catalog = Catalog(ROOT)
|
||
|
|
|
||
|
|
def test_the_advanced_installation_offers_an_extra_path_before_the_network(self, *_):
|
||
|
|
for app in SPECIAL:
|
||
|
|
ui = ExtraPathUI()
|
||
|
|
template = self.catalog.compose(app)
|
||
|
|
plan = build_deployment(template, ui, ADVANCED_MODE)
|
||
|
|
self.assertEqual(ui.asked.count(EXTRA), 2, app)
|
||
|
|
bridge = next(text for text in ui.asked if text.startswith("Access bridge"))
|
||
|
|
self.assertLess(ui.asked.index(EXTRA), ui.asked.index(bridge), app)
|
||
|
|
self.assertEqual([(m["type"], m["container_path"], m["size_gb"]) for m in plan["extra_mounts"]],
|
||
|
|
[("managed-volume", "/media-extra", 20)], app)
|
||
|
|
self.assertIn("/media-extra", _deployment_summary_text(template, plan), app)
|
||
|
|
|
||
|
|
def test_an_extra_path_cannot_hide_the_data_of_the_application(self, *_):
|
||
|
|
ui = ExtraPathUI()
|
||
|
|
ui.answers["Path inside the container (e.g. /media-extra)"] = "/var/www/html/data"
|
||
|
|
with self.assertRaises(ValueError):
|
||
|
|
build_deployment(self.catalog.compose("nextcloud-stack"), ui, ADVANCED_MODE)
|
||
|
|
|
||
|
|
def test_the_advanced_installation_offers_usb_devices_for_the_application(self, *_):
|
||
|
|
device = "Add another GPU or USB device manually?"
|
||
|
|
usb = [{"path": "/dev/ttyACM1", "name": "Z-Stick", "kind": "Communications"}]
|
||
|
|
for app in SPECIAL:
|
||
|
|
ui = RecordingUI()
|
||
|
|
offered = []
|
||
|
|
|
||
|
|
def confirm(text, default=False, ui=ui, offered=offered):
|
||
|
|
ui.asked.append(text)
|
||
|
|
if text == device:
|
||
|
|
offered.append(text)
|
||
|
|
return len(offered) == 1
|
||
|
|
return default
|
||
|
|
|
||
|
|
def choose(text, options, default=None, ui=ui):
|
||
|
|
ui.asked.append(text)
|
||
|
|
tags = [tag for tag, _label in options]
|
||
|
|
if text == "Device to attach":
|
||
|
|
self.assertNotIn("nvidia", tags, app)
|
||
|
|
return "usb"
|
||
|
|
return "/dev/ttyACM1" if "/dev/ttyACM1" in tags else default
|
||
|
|
|
||
|
|
ui.confirm, ui.choose = confirm, choose
|
||
|
|
template = self.catalog.compose(app)
|
||
|
|
with patch("proxmenux_oci.extra_devices.host.usb_devices", return_value=usb):
|
||
|
|
plan = build_deployment(template, ui, ADVANCED_MODE)
|
||
|
|
self.assertEqual([(d["kind"], d["host_path"], d["gid_strategy"]) for d in plan["extra_devices"]],
|
||
|
|
[("character-device", "/dev/ttyACM1", "host-device-gid")], app)
|
||
|
|
self.assertIn("/dev/ttyACM1", _deployment_summary_text(template, plan), app)
|
||
|
|
|
||
|
|
def test_the_default_installation_does_not_ask_it(self, *_):
|
||
|
|
for app in SPECIAL:
|
||
|
|
ui = RecordingUI()
|
||
|
|
plan = build_deployment(self.catalog.compose(app), ui, DEFAULT_MODE)
|
||
|
|
self.assertNotIn(EXTRA, ui.asked, app)
|
||
|
|
self.assertEqual(plan["extra_mounts"], [], app)
|
||
|
|
self.assertEqual(plan["extra_devices"], [], app)
|
||
|
|
self.assertNotIn("Add another GPU or USB device manually?", ui.asked, app)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|