FiWiControl/tests/test_inventory_config.py

187 lines
5.2 KiB
Python

# Copyright (c) 2026 Umber
#
# Licensed under the Apache License, Version 2.0; see LICENSE.
from __future__ import annotations
import textwrap
from io import StringIO
from pathlib import Path
import pytest
from fiwicontrol.lab.inventory_config import HostInventorySpec, load_inventory_ini, resolve_fabric_concentrator
from fiwicontrol.lab.inventory_verify import compare_host_inventory, dump_inventory_discovery_ini_sync
def test_resolve_fabric_concentrator_by_machine_name(tmp_path: Path) -> None:
p = tmp_path / "lab.ini"
p.write_text(
textwrap.dedent(
"""
[machine.a]
machine.name = bench-workstation
ipaddr = 10.0.0.1
sshtype = ssh
usb = local
acroname =
hvpm = HVPM:0
[machine.b]
machine.name = bench-pi
ipaddr = 10.0.0.2
sshtype = ssh
usb = remote
acroname =
hvpm = HVPM:0
"""
).strip(),
encoding="utf-8",
)
doc = load_inventory_ini(p)
sid, n = resolve_fabric_concentrator(doc.nodes, "bench-workstation")
assert sid == "a" and n.ipaddr == "10.0.0.1"
def test_load_default_lab_ini(tmp_path: Path) -> None:
src = Path(__file__).resolve().parents[1] / "configs" / "default.ini"
doc = load_inventory_ini(src)
assert doc.site_name == "UAX-24"
assert "raspberry_pi5" in doc.nodes
names = {h.name for h in doc.hosts}
assert names == {"fedora42", "raspberry_pi5"}
local = next(h for h in doc.hosts if h.name == "fedora42")
assert local.mode == "local"
assert local.expected_acronames == (("USBHub2x4", 4),)
assert local.hvpm_count == 0
pi = next(h for h in doc.hosts if h.name == "raspberry_pi5")
assert pi.mode == "relay"
assert pi.relay_node_id == "raspberry_pi5"
assert pi.ipaddr == "192.168.1.39"
assert pi.expected_acronames == (("USBHub3p", 8), ("USBHub3p", 8), ("USBHub2x4", 4))
assert pi.hvpm_count == 1
def test_compare_host_inventory_match() -> None:
spec = HostInventorySpec(
name="t",
mode="local",
relay_node_id=None,
ipaddr=None,
sshtype="ssh",
expected_acronames=(("USBHub2x4", 4), ("USBHub2x4", 4)),
hvpm_count=0,
)
payload = {
"acroname": [
{
"transport": "USB",
"serial_number": 1,
"module_address": 6,
"model_id": 17,
"model_name": "USBHub2x4",
"model_description": "",
"stem_class": "USBHub2x4",
"downstream_usb_ports": 4,
"hub_port_entities": 6,
},
{
"transport": "USB",
"serial_number": 2,
"module_address": 6,
"model_id": 17,
"model_name": "USBHub2x4",
"model_description": "",
"stem_class": "USBHub2x4",
"downstream_usb_ports": 4,
"hub_port_entities": 6,
},
],
"monsoon": [],
}
assert compare_host_inventory(spec, payload) == []
def test_compare_host_inventory_mismatch() -> None:
spec = HostInventorySpec(
name="t",
mode="local",
relay_node_id=None,
ipaddr=None,
sshtype="ssh",
expected_acronames=(("USBHub3p", 8),),
hvpm_count=1,
)
payload = {
"acroname": [
{
"transport": "USB",
"serial_number": 1,
"module_address": 6,
"model_id": 17,
"model_name": "USBHub2x4",
"model_description": "",
"stem_class": "USBHub2x4",
"downstream_usb_ports": 4,
"hub_port_entities": 6,
},
],
"monsoon": [],
}
errs = compare_host_inventory(spec, payload)
assert len(errs) == 2
def test_parse_hvpm_invalid(tmp_path: Path) -> None:
p = tmp_path / "x.ini"
p.write_text(
textwrap.dedent(
"""
[host.x]
mode = local
acroname =
hvpm = Monsoon:1
"""
).strip(),
encoding="utf-8",
)
with pytest.raises(ValueError, match="stem must be HVPM"):
load_inventory_ini(p)
def test_parse_acroname_invalid(tmp_path: Path) -> None:
p = tmp_path / "x.ini"
p.write_text(
textwrap.dedent(
"""
[host.x]
mode = local
acroname = BadEntry
hvpm = HVPM:0
"""
).strip(),
encoding="utf-8",
)
with pytest.raises(ValueError, match="Stem:ports"):
load_inventory_ini(p)
def test_dump_inventory_discovery_local_only(tmp_path: Path) -> None:
ini = tmp_path / "solo.ini"
ini.write_text(
textwrap.dedent(
"""
[host.solo]
mode = local
acroname =
hvpm = HVPM:0
"""
).strip(),
encoding="utf-8",
)
buf = StringIO()
dump_inventory_discovery_ini_sync(ini, file=buf)
text = buf.getvalue()
assert "=== solo (mode=local;" in text
assert '"acroname"' in text and '"monsoon"' in text