Files
2026-05-02 23:12:29 +02:00

178 lines
6.4 KiB
Python

import argparse
import sys
from unittest.mock import patch, MagicMock
import pytest
from bmspy import parse_args, main
from bmspy.classes import UPS
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_ups_data():
return {"testups": UPS.from_dict({
"bms_voltage": {"help": "V", "raw_value": 52.0, "value": "52.00", "units": "V"},
"bms_date": {"help": "Date", "info": "2023-01-15"},
})}
class TestParseArgs:
def _parse(self, args: list[str]):
with patch("sys.argv", ["bmspy"] + args):
return parse_args()
def test_socket_default(self):
assert self._parse([]).socket == "/run/bmspy/bms"
def test_socket_long(self):
assert self._parse(["--socket", "/tmp/test.sock"]).socket == "/tmp/test.sock"
def test_socket_short(self):
assert self._parse(["-s", "/tmp/test.sock"]).socket == "/tmp/test.sock"
def test_ups_default_is_none(self):
assert self._parse([]).ups is None
def test_ups_filter(self):
assert self._parse(["--ups", "myups"]).ups == "myups"
def test_json_default_false(self):
assert self._parse([]).report_json is False
def test_json_long(self):
assert self._parse(["--json"]).report_json is True
def test_json_short(self):
assert self._parse(["-j"]).report_json is True
def test_print_default_true(self):
assert self._parse([]).report_print is True
def test_prometheus_default_false(self):
assert self._parse([]).report_prometheus is False
def test_prometheus_flag(self):
assert self._parse(["--prometheus"]).report_prometheus is True
def test_influxdb_default_false(self):
assert self._parse([]).report_influxdb is False
def test_influxdb_long(self):
assert self._parse(["--influxdb"]).report_influxdb is True
def test_influxdb_short(self):
assert self._parse(["-i"]).report_influxdb is True
def test_bucket_default(self):
assert self._parse([]).influx_bucket == "ups"
def test_bucket_long(self):
assert self._parse(["--bucket", "mybucket"]).influx_bucket == "mybucket"
def test_bucket_short(self):
assert self._parse(["-b", "mybucket"]).influx_bucket == "mybucket"
def test_url_default_false(self):
assert self._parse([]).influx_url is False
def test_url_long(self):
assert self._parse(["--url", "http://influx.example.com"]).influx_url == "http://influx.example.com"
def test_org_long(self):
assert self._parse(["--org", "myorg"]).influx_org == "myorg"
def test_token_long(self):
assert self._parse(["--token", "mytoken"]).influx_token == "mytoken"
def test_verbose_default_zero(self):
assert self._parse([]).verbose == 0
def test_verbose_once(self):
assert self._parse(["-v"]).verbose == 1
def test_verbose_multiple(self):
assert self._parse(["-v", "-v", "-v"]).verbose == 3
def test_verbose_long(self):
assert self._parse(["--verbose"]).verbose == 1
# ---------------------------------------------------------------------------
# main()
# ---------------------------------------------------------------------------
class TestMain:
def _run_main(self, args: list[str]):
with patch("sys.argv", ["bmspy"] + args):
main()
def test_print_mode_default(self, capsys):
ups_data = _make_ups_data()
with patch("sys.argv", ["bmspy"]), \
patch("bmspy.client.handle_registration"), \
patch("bmspy.client.read_data", return_value=ups_data):
main()
captured = capsys.readouterr()
assert "testups" in captured.out
def test_json_mode(self, capsys):
ups_data = _make_ups_data()
with patch("sys.argv", ["bmspy", "--json"]), \
patch("bmspy.client.handle_registration"), \
patch("bmspy.client.read_data", return_value=ups_data):
main()
captured = capsys.readouterr()
# JSON output should contain field names
assert "bms_voltage" in captured.out
def test_keyboard_interrupt_is_caught(self, capsys):
with patch("sys.argv", ["bmspy"]), \
patch("bmspy.client.handle_registration"), \
patch("bmspy.client.read_data", side_effect=KeyboardInterrupt("stopped")):
main() # should not raise
def test_prometheus_flag_calls_export(self):
import bmspy.prometheus as prom_mod
mock_export = MagicMock()
with patch("sys.argv", ["bmspy", "--prometheus"]), \
patch.object(prom_mod, "prometheus_export", mock_export):
main()
mock_export.assert_called_once()
def test_textfile_flag_calls_prometheus_export(self, tmp_path):
import bmspy.prometheus as prom_mod
filename = str(tmp_path / "metrics.prom")
mock_export = MagicMock()
with patch("sys.argv", ["bmspy", "--file", filename]), \
patch.object(prom_mod, "prometheus_export", mock_export):
main()
mock_export.assert_called_once()
call_kwargs = mock_export.call_args[1]
assert call_kwargs.get("daemonize") is False
assert call_kwargs.get("filename") == filename
def test_influxdb_flag_calls_export(self):
pytest.importorskip("influxdb_client_3", reason="influxdb3-python not installed")
import bmspy.influxdb as influx_mod
mock_export = MagicMock()
with patch("sys.argv", ["bmspy", "--influxdb", "--url", "http://influx", "--org", "org", "--token", "tok"]), \
patch.object(influx_mod, "influxdb_export", mock_export):
main()
mock_export.assert_called_once()
def test_influxdb_partial_args_exits(self, capsys):
"""Providing only one of --url/--org/--token raises ArgumentTypeError (caught by KeyboardInterrupt handler)."""
with patch("sys.argv", ["bmspy", "--influxdb", "--url", "http://influx"]):
with pytest.raises(argparse.ArgumentTypeError):
main()
def test_influxdb_partial_raises_argument_error(self):
"""Two of three influx args causes ArgumentTypeError."""
import argparse as _ap
with patch("sys.argv", ["bmspy", "--influxdb", "--url", "http://influx", "--org", "org"]):
with pytest.raises(_ap.ArgumentTypeError):
main()