"""Unit tests for the host agent's new metric collectors / parsers. Pure parsers and the rate helper are tested directly; the file-reading collectors are tested by monkeypatching agent._read_file with fixtures. """ import plugins.host_agent.agent as agent def test_parse_cpu_lines_aggregate_and_per_core(): text = ( "cpu 100 0 100 800 0 0 0\n" "cpu0 50 0 50 400 0\n" "cpu1 50 0 50 400 0\n" "intr 12345\n" ) parsed = agent._parse_cpu_lines(text) assert set(parsed) == {"cpu", "cpu0", "cpu1"} assert parsed["cpu"] == (1000, 800) # total, idle(=idle+iowait) def test_collect_cpu_returns_aggregate_and_cores(monkeypatch): snapshots = iter([ "cpu 100 0 100 800\ncpu0 50 0 50 400\ncpu1 50 0 50 400\n", "cpu 200 0 200 1200\ncpu0 100 0 100 600\ncpu1 100 0 100 600\n", ]) monkeypatch.setattr(agent, "_read_file", lambda p: next(snapshots)) monkeypatch.setattr(agent.time, "sleep", lambda s: None) agg, cores = agent.collect_cpu() assert isinstance(agg, float) assert len(cores) == 2 def test_parse_psi(): text = ( "some avg10=1.50 avg60=2.00 avg300=3.00 total=12345\n" "full avg10=0.50 avg60=0.10 avg300=0.00 total=678\n" ) r = agent._parse_psi(text) assert r["some_avg10"] == 1.5 assert r["some_avg60"] == 2.0 assert r["full_avg10"] == 0.5 def test_rates_basic_and_counter_reset(): cur = {"eth0": (2000, 1000), "sda": (5000, 0)} prev = {"eth0": (1000, 500), "sda": (10000, 0)} # sda counter went backwards out = agent._rates(cur, prev, dt=10.0) assert out["eth0"] == (100.0, 50.0) assert "sda" not in out # negative delta dropped assert agent._rates(cur, prev, dt=0.0) == {} # no elapsed time → no rates def test_rates_skips_names_missing_from_prev(): assert agent._rates({"new": (5, 5)}, {}, dt=1.0) == {} def test_collect_net_raw_skips_lo_and_veth(monkeypatch): fixture = ( "Inter-| Receive\n" " face |bytes\n" " lo: 100 1 0 0 0 0 0 0 200 2 0 0 0 0 0 0\n" " eth0: 1000 5 0 0 0 0 0 0 500 4 0 0 0 0 0 0\n" " veth9: 9 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0\n" ) monkeypatch.setattr(agent, "_read_file", lambda p: fixture) assert agent.collect_net_raw() == {"eth0": (1000, 500)} def test_collect_diskio_raw_whole_disks_only(monkeypatch): # fields: major minor name reads rd_merged sectors_read ms ... sectors_written ... fixture = ( " 8 0 sda 1 0 10 0 1 0 20 0 0 0 0\n" " 8 1 sda1 1 0 5 0 1 0 5 0 0 0 0\n" " 259 0 nvme0n1 1 0 100 0 1 0 200 0 0 0 0\n" " 7 0 loop0 1 0 1 0 1 0 1 0 0 0 0\n" ) monkeypatch.setattr(agent, "_read_file", lambda p: fixture) out = agent.collect_diskio_raw() assert out == {"sda": (10 * 512, 20 * 512), "nvme0n1": (100 * 512, 200 * 512)} def test_build_sample_first_call_has_no_rates_but_keeps_state(monkeypatch): monkeypatch.setattr(agent, "collect_cpu", lambda: (5.0, [5.0])) monkeypatch.setattr(agent, "collect_memory", lambda: {"total_bytes": 10, "available_bytes": 5}) monkeypatch.setattr(agent, "collect_load", lambda: {"1m": 0.0, "5m": 0.0, "15m": 0.0}) monkeypatch.setattr(agent, "collect_uptime", lambda: 1) monkeypatch.setattr(agent, "collect_storage", lambda m: []) monkeypatch.setattr(agent, "collect_temps", lambda: []) monkeypatch.setattr(agent, "collect_psi", lambda: {}) monkeypatch.setattr(agent, "collect_net_raw", lambda: {"eth0": (1000, 500)}) monkeypatch.setattr(agent, "collect_diskio_raw", lambda: {"sda": (10, 20)}) state: dict = {} s1 = agent.build_sample(["/"], state) assert s1["net"] == [] and s1["diskio"] == [] # no prior counters yet assert state["mono"] is not None assert state["net"] == {"eth0": (1000, 500)}