testsAndMisc/linux_configuration/tests/test_usage_report_merge.py
Krzysztof kuhy Rudnicki b6a82093f2 usage_report: split test_usage_report_since.py 480 -> 186 + 145 + 178
Split three ways on the file's own section banners, which already grouped the
tests by concern:

  test_usage_report_merge.py (145)  aggregate and window merging, PID carry-over
  test_usage_report_since.py (186)  pmon filtering, atop bounds, state, planning
  test_usage_report_modes.py (178)  start resolution, dispatch, PRC HZ, native

6 + 13 + 11 = 30, the pre-split count -- the check that matters, since a file
that failed to import would collect nothing and still report success. Also
verified a negated assertion still fails, so none of the three is vacuous.

Only the test file is split. The usage_report SOURCE files stay over cap on
purpose: measured coverage is 21% for _usage_report_render.py, 39% for
_usage_report_parsing.py and 47% for usage_report.py, so a split there would
move code no test runs and pass either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-17 10:40:06 +02:00

147 lines
4.2 KiB
Python

"""Tests for merging usage_report daily aggregates: process and GPU aggregate
merging, window merging, and PID-count carry-over across days.
"""
from __future__ import annotations
import _usage_report_parsing as parsing
from _usage_report_types import GpuAgg, ProcAgg, _Window
# --------------------------------------------------------------------------- #
# PID-count carry-over (types)
# --------------------------------------------------------------------------- #
def test_proc_pid_count_combines_set_and_extra() -> None:
"""`pid_count` adds the live set length and merged-in extras."""
agg = ProcAgg("x", pid_set={1, 2, 3}, extra_pids=2)
assert agg.pid_count == 5
def test_gpu_pid_count_combines_set_and_extra() -> None:
"""GpuAgg exposes the same combined PID count."""
agg = GpuAgg("x", pid_set={9}, extra_pids=4)
assert agg.pid_count == 5
# --------------------------------------------------------------------------- #
# Aggregate merging (parsing)
# --------------------------------------------------------------------------- #
def test_merge_proc_aggs_sums_and_takes_peak() -> None:
"""CPU/RSS sums accumulate, peak RSS is the max, PID counts add."""
dst: dict[str, ProcAgg] = {}
parsing.merge_proc_aggs(
dst,
{
"a": ProcAgg(
"a",
cpu_ticks=100,
peak_rss_kb=200,
rss_kb_sum=50,
rss_samples=2,
pid_set={1, 2},
)
},
)
parsing.merge_proc_aggs(
dst,
{
"a": ProcAgg(
"a",
cpu_ticks=10,
peak_rss_kb=500,
rss_kb_sum=5,
rss_samples=1,
pid_set={3},
)
},
)
entry = dst["a"]
assert entry.cpu_ticks == 110
assert entry.peak_rss_kb == 500
assert entry.rss_kb_sum == 55
assert entry.rss_samples == 3
assert entry.pid_count == 3
def test_merge_gpu_aggs_sums_and_takes_peak() -> None:
"""GPU sample sums accumulate and peaks take the max across days."""
dst: dict[str, GpuAgg] = {}
parsing.merge_gpu_aggs(
dst,
{
"g": GpuAgg(
"g",
sm_pct_sum=30.0,
mem_pct_sum=10.0,
samples=3,
peak_sm_pct=40.0,
peak_mem_pct=20.0,
pid_set={1},
)
},
)
parsing.merge_gpu_aggs(
dst,
{
"g": GpuAgg(
"g",
sm_pct_sum=5.0,
mem_pct_sum=2.0,
samples=1,
peak_sm_pct=80.0,
peak_mem_pct=15.0,
pid_set={2, 3},
)
},
)
entry = dst["g"]
assert entry.sm_pct_sum == 35.0
assert entry.samples == 4
assert entry.peak_sm_pct == 80.0
assert entry.peak_mem_pct == 20.0
assert entry.pid_count == 3
# --------------------------------------------------------------------------- #
# Window merging (parsing)
# --------------------------------------------------------------------------- #
def test_merge_windows_empty_returns_default() -> None:
"""Merging no real windows yields the empty default window."""
assert parsing.merge_windows([]).distinct_samples == 0
assert parsing.merge_windows([_Window()]).distinct_samples == 0
def test_merge_windows_spans_and_sums() -> None:
"""Span uses min start / max end; samples and seconds sum; interval is modal."""
w_empty = _Window() # distinct_samples == 0, must be ignored
w1 = _Window(
start="s1",
end="e1",
distinct_samples=5,
interval_s=600,
seconds=100,
start_epoch=1000,
end_epoch=2000,
)
w2 = _Window(
start="s2",
end="e2",
distinct_samples=3,
interval_s=600,
seconds=50,
start_epoch=500,
end_epoch=3000,
)
merged = parsing.merge_windows([w_empty, w1, w2])
assert merged.start == "s2" # earliest start_epoch (500)
assert merged.end == "e2" # latest end_epoch (3000)
assert merged.distinct_samples == 8
assert merged.seconds == 150
assert merged.interval_s == 600