Skip to content

Commit 59b813f

Browse files
committed
test(metrics): add coverage for metrics timing decorator
Closes #978 Signed-off-by: Marcel Nadzam <mnadzam@redhat.com> Co-Authored-By: Cursor
1 parent aec9c9c commit 59b813f

1 file changed

Lines changed: 144 additions & 0 deletions

File tree

tests/test_metrics.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
5+
import pytest
6+
from packaging.requirements import Requirement
7+
from packaging.version import Version
8+
9+
from fromager import context, metrics
10+
11+
12+
@metrics.timeit(description="test description")
13+
def _test_func(
14+
*,
15+
ctx: context.WorkContext,
16+
req: Requirement | None = None,
17+
version: str | None = None,
18+
) -> str:
19+
return "ok"
20+
21+
22+
@metrics.timeit(description="test description")
23+
def _test_returns_version(
24+
*,
25+
ctx: context.WorkContext,
26+
req: Requirement | None = None,
27+
) -> tuple[str, Version]:
28+
return ("http://example.com", Version("1.2.3"))
29+
30+
31+
@metrics.timeit(description="test description")
32+
def _test_raises(
33+
*,
34+
ctx: context.WorkContext,
35+
req: Requirement | None = None,
36+
) -> None:
37+
raise RuntimeError("test error")
38+
39+
40+
def test_timeit_stores_timing(tmp_context: context.WorkContext) -> None:
41+
req = Requirement("numpy>=1.0")
42+
43+
_test_func(ctx=tmp_context, req=req, version="1.26.0")
44+
45+
key = "numpy==1.26.0"
46+
assert key in tmp_context.time_store
47+
assert tmp_context.time_store[key]["_test_func"] > 0
48+
49+
50+
def test_timeit_stores_description(tmp_context: context.WorkContext) -> None:
51+
_test_func(ctx=tmp_context)
52+
53+
assert tmp_context.time_description_store["_test_func"] == "test description"
54+
55+
56+
def test_timeit_no_storage_without_req(tmp_context: context.WorkContext) -> None:
57+
_test_func(ctx=tmp_context, req=None, version="1.0")
58+
59+
assert len(tmp_context.time_store) == 0
60+
61+
62+
def test_timeit_no_storage_without_version(tmp_context: context.WorkContext) -> None:
63+
req = Requirement("numpy>=1.0")
64+
65+
_test_func(ctx=tmp_context, req=req)
66+
67+
assert len(tmp_context.time_store) == 0
68+
69+
70+
def test_timeit_returns_original_result(tmp_context: context.WorkContext) -> None:
71+
result = _test_func(ctx=tmp_context)
72+
73+
assert result == "ok"
74+
75+
76+
def test_timeit_extracts_version_from_return(
77+
tmp_context: context.WorkContext,
78+
) -> None:
79+
req = Requirement("mypkg")
80+
81+
_test_returns_version(ctx=tmp_context, req=req)
82+
83+
assert "mypkg==1.2.3" in tmp_context.time_store
84+
85+
86+
def test_timeit_propagates_exception(tmp_context: context.WorkContext) -> None:
87+
with pytest.raises(RuntimeError, match="test error"):
88+
_test_raises(ctx=tmp_context)
89+
90+
91+
def test_timeit_no_storage_on_exception(tmp_context: context.WorkContext) -> None:
92+
req = Requirement("numpy>=1.0")
93+
94+
with pytest.raises(RuntimeError):
95+
_test_raises(ctx=tmp_context, req=req)
96+
97+
assert len(tmp_context.time_store) == 0
98+
99+
100+
def test_summarize_logs_timing(
101+
tmp_context: context.WorkContext,
102+
caplog: pytest.LogCaptureFixture,
103+
) -> None:
104+
req = Requirement("numpy>=1.0")
105+
_test_func(ctx=tmp_context, req=req, version="1.26.0")
106+
107+
with caplog.at_level(logging.INFO, logger="fromager.metrics"):
108+
metrics.summarize(tmp_context, "Building")
109+
110+
records = [r for r in caplog.records if r.name == "fromager.metrics"]
111+
assert len(records) == 1
112+
msg = records[0].message
113+
assert "Building" in msg
114+
assert "numpy==1.26.0" in msg
115+
assert "test description" in msg
116+
117+
118+
def test_summarize_empty(
119+
tmp_context: context.WorkContext,
120+
caplog: pytest.LogCaptureFixture,
121+
) -> None:
122+
with caplog.at_level(logging.INFO, logger="fromager.metrics"):
123+
metrics.summarize(tmp_context, "Building")
124+
125+
assert len(caplog.records) == 0
126+
127+
128+
def test_extract_version_from_tuple() -> None:
129+
ret = ("http://example.com", Version("2.0.0"))
130+
assert metrics._extract_version_from_return(ret) == Version("2.0.0")
131+
132+
133+
def test_extract_version_bare() -> None:
134+
ret = Version("3.0.0")
135+
assert metrics._extract_version_from_return(ret) == Version("3.0.0")
136+
137+
138+
def test_extract_version_no_version_in_iterable() -> None:
139+
ret = ("http://example.com", "not-a-version")
140+
assert metrics._extract_version_from_return(ret) is None
141+
142+
143+
def test_extract_version_non_iterable() -> None:
144+
assert metrics._extract_version_from_return(42) is None

0 commit comments

Comments
 (0)