Skip to content

Commit 415ece4

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 415ece4

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

tests/test_metrics.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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+
version: str | None = None,
37+
) -> None:
38+
raise RuntimeError("test error")
39+
40+
41+
def test_timeit_stores_timing(tmp_context: context.WorkContext) -> None:
42+
req = Requirement("numpy>=1.0")
43+
44+
_test_func(ctx=tmp_context, req=req, version="1.26.0")
45+
46+
key = "numpy==1.26.0"
47+
assert key in tmp_context.time_store
48+
assert tmp_context.time_store[key]["_test_func"] > 0
49+
50+
51+
def test_timeit_stores_description(tmp_context: context.WorkContext) -> None:
52+
_test_func(ctx=tmp_context)
53+
54+
assert tmp_context.time_description_store["_test_func"] == "test description"
55+
56+
57+
def test_timeit_no_storage_without_req(tmp_context: context.WorkContext) -> None:
58+
_test_func(ctx=tmp_context, req=None, version="1.0")
59+
60+
assert len(tmp_context.time_store) == 0
61+
62+
63+
def test_timeit_no_storage_without_version(tmp_context: context.WorkContext) -> None:
64+
req = Requirement("numpy>=1.0")
65+
66+
_test_func(ctx=tmp_context, req=req)
67+
68+
assert len(tmp_context.time_store) == 0
69+
70+
71+
def test_timeit_returns_original_result(tmp_context: context.WorkContext) -> None:
72+
result = _test_func(ctx=tmp_context)
73+
74+
assert result == "ok"
75+
76+
77+
def test_timeit_extracts_version_from_return(
78+
tmp_context: context.WorkContext,
79+
) -> None:
80+
req = Requirement("mypkg")
81+
82+
_test_returns_version(ctx=tmp_context, req=req)
83+
84+
assert "mypkg==1.2.3" in tmp_context.time_store
85+
86+
87+
def test_timeit_propagates_exception(tmp_context: context.WorkContext) -> None:
88+
with pytest.raises(RuntimeError, match="test error"):
89+
_test_raises(ctx=tmp_context)
90+
91+
92+
def test_timeit_no_storage_on_exception(tmp_context: context.WorkContext) -> None:
93+
req = Requirement("numpy>=1.0")
94+
95+
with pytest.raises(RuntimeError):
96+
_test_raises(ctx=tmp_context, req=req, version="1.0")
97+
98+
assert len(tmp_context.time_store) == 0
99+
100+
101+
def test_summarize_logs_timing(
102+
tmp_context: context.WorkContext,
103+
caplog: pytest.LogCaptureFixture,
104+
) -> None:
105+
req = Requirement("numpy>=1.0")
106+
_test_func(ctx=tmp_context, req=req, version="1.26.0")
107+
108+
with caplog.at_level(logging.INFO, logger="fromager.metrics"):
109+
metrics.summarize(tmp_context, "Building")
110+
111+
records = [r for r in caplog.records if r.name == "fromager.metrics"]
112+
assert len(records) == 1
113+
msg = records[0].message
114+
assert "Building" in msg
115+
assert "numpy==1.26.0" in msg
116+
assert "test description" in msg
117+
118+
119+
def test_summarize_empty(
120+
tmp_context: context.WorkContext,
121+
caplog: pytest.LogCaptureFixture,
122+
) -> None:
123+
with caplog.at_level(logging.INFO, logger="fromager.metrics"):
124+
metrics.summarize(tmp_context, "Building")
125+
126+
assert len(caplog.records) == 0
127+
128+
129+
def test_extract_version_from_tuple() -> None:
130+
ret = ("http://example.com", Version("2.0.0"))
131+
assert metrics._extract_version_from_return(ret) == Version("2.0.0")
132+
133+
134+
def test_extract_version_bare() -> None:
135+
ret = Version("3.0.0")
136+
assert metrics._extract_version_from_return(ret) == Version("3.0.0")
137+
138+
139+
def test_extract_version_no_version_in_iterable() -> None:
140+
ret = ("http://example.com", "not-a-version")
141+
assert metrics._extract_version_from_return(ret) is None
142+
143+
144+
def test_extract_version_non_iterable() -> None:
145+
assert metrics._extract_version_from_return(42) is None
146+
147+
148+
def test_extract_version_none() -> None:
149+
assert metrics._extract_version_from_return(None) is None

0 commit comments

Comments
 (0)