Skip to content

Commit c55125d

Browse files
committed
feat(bug-finding): add dynamic testing for machine resources check
Signed-off-by: tkqdldk <samia.20.bouchaal@gmail.com>
1 parent a6ed2a9 commit c55125d

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
"""Unit tests for _validate_machine_resources step in CRSCompose."""
2+
3+
from typing import cast
4+
5+
import pytest
6+
7+
from oss_crs.src.config.crs_compose import CRSComposeConfig
8+
from oss_crs.src.crs_compose import CRSCompose
9+
10+
MOCK_CPU_COUNT = 12
11+
MOCK_MEMORY = 32 * (1024**3)
12+
13+
14+
class _FakeResource:
15+
def __init__(self, cpuset: str, memory: str):
16+
self.cpuset = cpuset
17+
self.memory = memory
18+
19+
20+
class _FakeComposeConfig:
21+
def __init__(self, infra: _FakeResource, crs_entries: dict):
22+
self.oss_crs_infra = infra
23+
self.crs_entries = crs_entries
24+
25+
26+
def _make_compose(
27+
infra_cpuset: str,
28+
infra_memory: str = "4G",
29+
crs_entries: dict | None = None,
30+
) -> CRSCompose:
31+
compose = object.__new__(CRSCompose)
32+
compose.config = cast(
33+
CRSComposeConfig,
34+
_FakeComposeConfig(
35+
_FakeResource(infra_cpuset, infra_memory),
36+
crs_entries or {},
37+
),
38+
)
39+
return compose
40+
41+
42+
@pytest.fixture
43+
def patched_resources(monkeypatch):
44+
"""Patch machine resource detection with standard mock values.
45+
46+
Returns a list that captures all log_warning calls.
47+
"""
48+
warnings = []
49+
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: MOCK_CPU_COUNT)
50+
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: MOCK_MEMORY)
51+
monkeypatch.setattr("oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg))
52+
return warnings
53+
54+
55+
## CPU and memory checks
56+
57+
58+
def test_cpu_within_bounds_no_warning(patched_resources):
59+
compose = _make_compose(f"0-{MOCK_CPU_COUNT - 2}")
60+
compose._validate_machine_resources()
61+
assert len(patched_resources) == 0
62+
63+
64+
def test_cpu_at_max_valid_id_no_warning(patched_resources):
65+
compose = _make_compose(f"0-{MOCK_CPU_COUNT - 1}")
66+
compose._validate_machine_resources()
67+
assert len(patched_resources) == 0
68+
69+
70+
def test_cpu_equals_machine_count_warns(patched_resources):
71+
compose = _make_compose(f"0-{MOCK_CPU_COUNT}")
72+
compose._validate_machine_resources()
73+
assert len(patched_resources) == 1
74+
assert "does not have adequate resources" in patched_resources[0]
75+
76+
77+
def test_cpu_exceeds_machine_count_warns(patched_resources):
78+
compose = _make_compose(f"0-{MOCK_CPU_COUNT + 1}")
79+
compose._validate_machine_resources()
80+
assert len(patched_resources) == 1
81+
assert "does not have adequate resources" in patched_resources[0]
82+
83+
84+
def test_memory_at_exact_limit_no_warning(patched_resources):
85+
exact_memory = f"{MOCK_MEMORY // (1024**3)}G"
86+
compose = _make_compose("0-3", exact_memory)
87+
compose._validate_machine_resources()
88+
assert len(patched_resources) == 0
89+
90+
91+
def test_memory_over_limit_warns(patched_resources):
92+
over_memory = f"{(MOCK_MEMORY // (1024**3)) + 1}G"
93+
compose = _make_compose("0-3", over_memory)
94+
compose._validate_machine_resources()
95+
assert len(patched_resources) == 1
96+
assert "does not have adequate resources" in patched_resources[0]
97+
98+
99+
100+
def test_crs_entry_exceeds_cpu_count_warns(patched_resources):
101+
compose = _make_compose(
102+
"0-3",
103+
crs_entries={"crs-a": _FakeResource(f"0-{MOCK_CPU_COUNT}", "4G")},
104+
)
105+
compose._validate_machine_resources()
106+
assert len(patched_resources) == 1
107+
assert "does not have adequate resources" in patched_resources[0]
108+
109+
110+
def test_combined_memory_across_entries_warns(patched_resources):
111+
half_memory = f"{MOCK_MEMORY // (1024**3) // 2 + 1}G"
112+
compose = _make_compose(
113+
"0-3",
114+
infra_memory=half_memory,
115+
crs_entries={
116+
"crs-a": _FakeResource("0-3", half_memory),
117+
},
118+
)
119+
compose._validate_machine_resources()
120+
assert len(patched_resources) == 1
121+
assert "does not have adequate resources" in patched_resources[0]
122+
123+
124+
def test_both_adequate_no_warning(patched_resources):
125+
compose = _make_compose("0-3", "4G")
126+
compose._validate_machine_resources()
127+
assert len(patched_resources) == 0
128+
129+
130+
## undetectable machine resources checks
131+
132+
133+
def test_undetectable_cpu_skips_check(monkeypatch):
134+
warnings = []
135+
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: None)
136+
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: MOCK_MEMORY)
137+
monkeypatch.setattr("oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg))
138+
139+
compose = _make_compose("0-3")
140+
compose._validate_machine_resources()
141+
assert len(warnings) == 1
142+
assert "Could not determine machine resources" in warnings[0]
143+
144+
145+
def test_undetectable_memory_skips_check(monkeypatch):
146+
warnings = []
147+
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: MOCK_CPU_COUNT)
148+
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: None)
149+
monkeypatch.setattr("oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg))
150+
151+
compose = _make_compose("0-3")
152+
compose._validate_machine_resources()
153+
assert len(warnings) == 1
154+
assert "Could not determine machine resources" in warnings[0]
155+
156+
157+
# parsing error checks
158+
159+
160+
def test_invalid_cpuset_warns(patched_resources):
161+
compose = _make_compose("not-a-cpuset", "4G")
162+
compose._validate_machine_resources()
163+
assert any("Failed to validate cpuset" in w for w in patched_resources)
164+
165+
166+
def test_invalid_memory_string_warns(patched_resources):
167+
compose = _make_compose("0-3", "notmemory")
168+
compose._validate_machine_resources()
169+
assert any("Failed to parse memory" in w for w in patched_resources)

0 commit comments

Comments
 (0)