mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-08 14:36:38 +00:00
95 lines
4.2 KiB
Python
95 lines
4.2 KiB
Python
"""USB devices are offered by name, as the Monitor shows them, with the node an LXC receives."""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import Mock, patch
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
|
|
from proxmenux_oci import host
|
|
from proxmenux_oci.extra_devices import ask_extra_devices, choose_usb_device
|
|
|
|
LSUSB = """Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
|
|
Bus 003 Device 002: ID 0463:ffff MGE UPS Systems UPS
|
|
Bus 003 Device 003: ID 0658:0200 Sigma Designs, Inc. Aeotec Z-Stick Gen5 (ZW090) - UZB
|
|
Bus 003 Device 004: ID 1cf1:0030 Dresden Elektronik ZigBee gateway [ConBee II]
|
|
Bus 003 Device 005: ID 0781:5581 SanDisk Corp. Ultra
|
|
"""
|
|
|
|
|
|
class UsbDevicesTests(unittest.TestCase):
|
|
def setUp(self):
|
|
tmp = tempfile.TemporaryDirectory()
|
|
self.addCleanup(tmp.cleanup)
|
|
self.root = Path(tmp.name)
|
|
pci = self.root / "sys/devices/pci0000:00/usb3"
|
|
self.device(pci, "usb3", "1d6b", "09", 1)
|
|
self.device(pci, "3-3", "0463", "00", 2, product="Ellipse ECO", interface="03")
|
|
self.device(pci, "3-8", "0658", "02", 3, tty="ttyACM1")
|
|
self.device(pci, "3-9", "1cf1", "02", 4, product="ConBee II", tty="ttyACM0")
|
|
self.device(pci, "3-10", "0781", "00", 5, product="Ultra", interface="08")
|
|
|
|
def device(self, parent, name, vendor, device_class, number, product="", interface="", tty=""):
|
|
path = parent / name
|
|
path.mkdir(parents=True)
|
|
for key, value in {"idVendor": vendor, "idProduct": "0001", "bDeviceClass": device_class,
|
|
"busnum": "3", "devnum": str(number)}.items():
|
|
(path / key).write_text(value + "\n")
|
|
if product:
|
|
(path / "product").write_text(product + "\n")
|
|
if interface:
|
|
(path / f"{name}:1.0").mkdir()
|
|
(path / f"{name}:1.0" / "bInterfaceClass").write_text(interface + "\n")
|
|
link = self.root / "sys/bus/usb/devices" / name
|
|
link.parent.mkdir(parents=True, exist_ok=True)
|
|
os.symlink(path, link)
|
|
if tty:
|
|
port = path / f"{name}:1.0" / "tty" / tty
|
|
port.mkdir(parents=True)
|
|
(self.root / "sys/class/tty").mkdir(parents=True, exist_ok=True)
|
|
(self.root / "sys/class/tty" / tty).mkdir()
|
|
os.symlink(path / f"{name}:1.0", self.root / "sys/class/tty" / tty / "device")
|
|
|
|
def test_devices_are_named_as_the_monitor_names_them(self):
|
|
rows = host.usb_devices(self.root, LSUSB)
|
|
self.assertEqual(rows, [
|
|
{"path": "/dev/bus/usb/003/002", "name": "Ellipse ECO", "kind": "UPS"},
|
|
{"path": "/dev/ttyACM1", "name": "Sigma Designs, Inc. Aeotec Z-Stick Gen5 (ZW090) - UZB",
|
|
"kind": "Communications"},
|
|
{"path": "/dev/ttyACM0", "name": "ConBee II", "kind": "Communications"},
|
|
])
|
|
|
|
def test_the_menu_lists_the_devices_and_leaves_attached_ones_out(self):
|
|
ui = Mock()
|
|
ui.choose.return_value = "/dev/ttyACM1"
|
|
with patch.object(host, "usb_devices", return_value=host.usb_devices(self.root, LSUSB)):
|
|
self.assertEqual(choose_usb_device(ui, "USB", attached={"/dev/ttyACM0"}), "/dev/ttyACM1")
|
|
tags = [tag for tag, _label in ui.choose.call_args.args[1]]
|
|
self.assertEqual(tags, ["/dev/bus/usb/003/002", "/dev/ttyACM1", "manual"])
|
|
ui.ask.assert_not_called()
|
|
|
|
def test_without_devices_the_node_is_typed(self):
|
|
ui = Mock()
|
|
ui.ask.return_value = "/dev/ttyUSB0"
|
|
with patch.object(host, "usb_devices", return_value=[]):
|
|
self.assertEqual(choose_usb_device(ui, "USB"), "/dev/ttyUSB0")
|
|
ui.message.assert_called_once()
|
|
ui.choose.assert_not_called()
|
|
|
|
def test_extra_usb_device_comes_from_the_list(self):
|
|
ui = Mock()
|
|
ui.confirm.side_effect = [True, False]
|
|
ui.choose.side_effect = ["usb", "/dev/ttyACM0"]
|
|
with patch.object(host, "usb_devices", return_value=host.usb_devices(self.root, LSUSB)):
|
|
devices = ask_extra_devices(ui, [], True)
|
|
self.assertEqual([(d["host_path"], d["container_path"]) for d in devices],
|
|
[("/dev/ttyACM0", "/dev/ttyACM0")])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|