Files
ProxMenux/oci/tests/test_catalog_web_links.py

121 lines
6.3 KiB
Python

"""Catalog links agree with the configured service and preserve suite choices."""
import copy
import json
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(ROOT / "remote"))
sys.path.insert(0, str(Path(__file__).resolve().parent))
from proxmenux_oci.catalog import Catalog
from proxmenux_oci.installer import DEFAULT_MODE, build_deployment
from proxmenux_oci.stack import StackError
from test_advanced_flow_order import RecordingUI, addresses, storages
import oci_description
import oci_instance_transaction as transaction
class CatalogWebLinks(unittest.TestCase):
catalog = Catalog(ROOT)
def test_jdownloader_launch_matches_its_secure_web_service(self):
template = self.catalog.compose("jdownloader")
environment = {entry["name"]: entry.get("example")
for entry in template["container_contract"]["environment"]}
self.assertEqual(environment["SECURE_CONNECTION"], "1")
launch = template["catalog_ui"]["launch"]
self.assertEqual(launch, {"scheme": "https", "port": 5800, "path": "/"})
endpoint = template["first_run"]["endpoints"][0]
self.assertEqual({key: endpoint[key] for key in launch}, launch)
self.assertIn('href="https://192.0.2.10:5800/"',
oci_description.render(template, "", "test-installation", "192.0.2.10"))
def test_shipped_templates_keep_the_curated_link_contract(self):
for app in ("jdownloader", "suite-arr"):
with self.subTest(app=app):
curated = json.loads((ROOT / "catalog/curated" / (app + ".json")).read_text())
generated = json.loads((ROOT / "catalog/apps" / (app + ".json")).read_text())
self.assertEqual(curated["catalog_ui"]["launch"], generated["catalog_ui"]["launch"])
self.assertEqual(curated["first_run"], generated["first_run"])
def test_suite_parent_names_the_documented_prowlarr_web_endpoint(self):
template = self.catalog.compose("suite-arr")
endpoints = template["first_run"]["endpoints"]
self.assertEqual(len(endpoints), 1)
endpoint = endpoints[0]
self.assertEqual((endpoint["scheme"], endpoint["port"], endpoint["path"]),
("http", 9696, "/"))
self.assertEqual(endpoint["label"], "Web UI")
self.assertNotEqual(endpoint["source"], transaction.GUESSED_ENDPOINT)
check = transaction.effective_healthcheck(template)
self.assertEqual((check["scheme"], check["port"]), ("http", 9696))
self.assertNotIn("accept_non_http", check)
def test_ollama_links_to_its_api_instead_of_claiming_a_web_ui(self):
template = self.catalog.compose("ollama")
launch = template["catalog_ui"]["launch"]
self.assertEqual(launch, {"scheme": "http", "port": 11434, "path": "/api/version"})
endpoint = template["first_run"]["endpoints"][0]
self.assertEqual(endpoint["label"], "Ollama API (no Web UI)")
self.assertEqual({key: endpoint[key] for key in launch}, launch)
self.assertEqual(endpoint["source"], "ollama-http-api")
self.assertNotIn("Web interface", template["catalog_ui"]["description"]["en_US"])
self.assertIn("does not include an interactive Web UI",
template["catalog_ui"]["description"]["en_US"])
check = transaction.effective_healthcheck(template)
self.assertEqual((check["scheme"], check["port"], check["path"]),
("http", 11434, "/api/version"))
notes = oci_description.render(template, "", "ollama", "192.0.2.10")
self.assertIn('href="http://192.0.2.10:11434/api/version"', notes)
self.assertIn("Ollama API (no Web UI)", notes)
@patch("proxmenux_oci.installer.host.gpus", return_value={"intel": [], "amd": [], "nvidia": False})
@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.1/24"}])
@patch("proxmenux_oci.installer.host.timezone", return_value="Etc/UTC")
@patch("proxmenux_oci.installer.access.ask_ipv4", return_value=("dhcp", None))
@patch("proxmenux_oci.installer.access.ask_addresses", side_effect=addresses)
def test_suite_members_keep_their_own_links_with_or_without_prowlarr(self, *_):
template = self.catalog.compose("suite-arr")
before = copy.deepcopy(template)
with patch("subprocess.run") as command:
for selected in (["prowlarr", "sonarr"], ["sonarr"]):
ui = RecordingUI({"Arr suite: applications to install": selected,
"Media server": "none"})
plan = build_deployment(copy.deepcopy(template), ui, DEFAULT_MODE)
self.assertEqual([member["name"] for member in plan["services"]], selected)
for member in plan["services"]:
port = 9696 if member["name"] == "prowlarr" else 8989
endpoint = member["template"]["first_run"]["endpoints"][0]
self.assertEqual(endpoint["port"], port)
self.assertEqual(member["healthcheck"]["endpoint"]["port"], port)
notes = oci_description.render(member["template"], "", "test-installation", "192.0.2.10")
self.assertIn(f':{port}/"', notes)
if port != 9696:
self.assertNotIn(':9696/"', notes)
command.assert_not_called()
self.assertEqual(template, before)
def test_empty_suite_selection_has_no_host_or_runtime_effect(self):
template = self.catalog.compose("suite-arr")
before = copy.deepcopy(template)
ui = RecordingUI({"Arr suite: applications to install": [], "Media server": "none"})
with patch("proxmenux_oci.i18n.language", return_value="en"), \
patch("proxmenux_oci.installer.host.storages") as host, \
patch("subprocess.run") as command:
with self.assertRaises(StackError):
build_deployment(template, ui, DEFAULT_MODE)
host.assert_not_called()
command.assert_not_called()
self.assertEqual(template, before)
if __name__ == "__main__":
unittest.main()