Add unit tests
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user