Skip to content

Commit 38db6c4

Browse files
committed
fix: trigger error and termination from resource validation failure
Signed-off-by: tkqdldk <samia.20.bouchaal@gmail.com>
1 parent dc0cf10 commit 38db6c4

2 files changed

Lines changed: 70 additions & 49 deletions

File tree

oss_crs/src/crs_compose.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import os
66
import hashlib
77
from pathlib import Path
8-
from typing import Callable, Optional
8+
from typing import Optional
99
from .config.crs_compose import CRSComposeConfig, CRSComposeEnv, RunEnv
1010
from .env_policy import OSS_FUZZ_TARGET_ENV, build_target_builder_env
1111
from .llm import LLM
@@ -22,6 +22,7 @@
2222
rm_with_docker,
2323
get_host_memory,
2424
log_success,
25+
log_error,
2526
log_warning,
2627
log_dim,
2728
)
@@ -650,6 +651,9 @@ def build_target(
650651
if target_base_image is None:
651652
return False
652653

654+
if not self._validate_machine_resources():
655+
return False
656+
653657
# Resolve target source path: user-provided repo or extracted WORKDIR
654658
if target._has_repo:
655659
resolved_source_path = target.repo_path.resolve()
@@ -661,12 +665,7 @@ def build_target(
661665
return False
662666
resolved_source_path = source_dir
663667

664-
tasks: list[tuple[str, Callable[[MultiTaskProgress], TaskResult]]] = [
665-
(
666-
"Validate machine resources",
667-
lambda _: self._validate_machine_resources(),
668-
),
669-
]
668+
tasks = []
670669

671670
if bug_candidate is not None and bug_candidate_dir is not None:
672671
print(
@@ -931,7 +930,7 @@ def _validate_required_inputs(
931930
return TaskResult(success=False, error="\n".join(errors))
932931
return TaskResult(success=True)
933932

934-
def _validate_machine_resources(self) -> TaskResult:
933+
def _validate_machine_resources(self) -> bool:
935934
"""Validate that machine resources and resource config do not conflict."""
936935
# Get machine CPU count and memory (in Bytes)
937936
machine_cpu_count = os.cpu_count()
@@ -941,7 +940,7 @@ def _validate_machine_resources(self) -> TaskResult:
941940
log_warning(
942941
"Could not determine machine resources. Skipping resource check."
943942
)
944-
return TaskResult(success=True)
943+
return True
945944

946945
# Collect entries for shared infra and all crs
947946
entries = [("oss_crs_infra", self.config.oss_crs_infra)]
@@ -969,12 +968,13 @@ def _validate_machine_resources(self) -> TaskResult:
969968
memory_check = total_memory_required <= machine_memory
970969

971970
if not cpu_check or not memory_check:
972-
log_warning(
971+
log_error(
973972
f"Machine does not have adequate resources. "
974973
f"Only {machine_cpu_count} CPUs and {machine_memory // (1024**3)}G memory available. "
975974
f"Please edit the compose file. "
976975
)
977-
return TaskResult(success=True)
976+
return False
977+
return True
978978

979979
def __validate_before_run(
980980
self,
@@ -999,10 +999,6 @@ def __validate_before_run(
999999
bug_candidate_dir=bug_candidate_dir,
10001000
),
10011001
),
1002-
(
1003-
"Validate machine resources",
1004-
lambda _: self._validate_machine_resources(),
1005-
),
10061002
]
10071003

10081004
if self.llm.exists():

oss_crs/tests/unit/test_validate_machine_resources.py

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,72 +43,84 @@ def _make_compose(
4343
def patched_resources(monkeypatch):
4444
"""Patch machine resource detection with standard mock values.
4545
46-
Returns a list that captures all log_warning calls.
46+
Returns a tuple of (warnings, errors) lists.
4747
"""
4848
warnings = []
49+
errors = []
4950
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: MOCK_CPU_COUNT)
5051
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: MOCK_MEMORY)
5152
monkeypatch.setattr(
5253
"oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg)
5354
)
54-
return warnings
55+
monkeypatch.setattr(
56+
"oss_crs.src.crs_compose.log_error", lambda msg: errors.append(msg)
57+
)
58+
return warnings, errors
5559

5660

5761
## CPU and memory checks
5862

5963

6064
def test_cpu_within_bounds_no_warning(patched_resources):
65+
warnings, errors = patched_resources
6166
compose = _make_compose(f"0-{MOCK_CPU_COUNT - 2}")
62-
compose._validate_machine_resources()
63-
assert len(patched_resources) == 0
67+
assert compose._validate_machine_resources() is True
68+
assert len(errors) == 0
6469

6570

6671
def test_cpu_at_max_valid_id_no_warning(patched_resources):
72+
warnings, errors = patched_resources
6773
compose = _make_compose(f"0-{MOCK_CPU_COUNT - 1}")
68-
compose._validate_machine_resources()
69-
assert len(patched_resources) == 0
74+
assert compose._validate_machine_resources() is True
75+
assert len(errors) == 0
7076

7177

72-
def test_cpu_equals_machine_count_warns(patched_resources):
78+
def test_cpu_equals_machine_count_errors(patched_resources):
79+
warnings, errors = patched_resources
7380
compose = _make_compose(f"0-{MOCK_CPU_COUNT}")
74-
compose._validate_machine_resources()
75-
assert len(patched_resources) == 1
76-
assert "does not have adequate resources" in patched_resources[0]
81+
assert compose._validate_machine_resources() is False
82+
assert len(errors) == 1
83+
assert "does not have adequate resources" in errors[0]
7784

7885

79-
def test_cpu_exceeds_machine_count_warns(patched_resources):
86+
def test_cpu_exceeds_machine_count_errors(patched_resources):
87+
warnings, errors = patched_resources
8088
compose = _make_compose(f"0-{MOCK_CPU_COUNT + 1}")
81-
compose._validate_machine_resources()
82-
assert len(patched_resources) == 1
83-
assert "does not have adequate resources" in patched_resources[0]
89+
assert compose._validate_machine_resources() is False
90+
assert len(errors) == 1
91+
assert "does not have adequate resources" in errors[0]
8492

8593

8694
def test_memory_at_exact_limit_no_warning(patched_resources):
95+
warnings, errors = patched_resources
8796
exact_memory = f"{MOCK_MEMORY // (1024**3)}G"
8897
compose = _make_compose("0-3", exact_memory)
89-
compose._validate_machine_resources()
90-
assert len(patched_resources) == 0
98+
assert compose._validate_machine_resources() is True
99+
assert len(errors) == 0
91100

92101

93-
def test_memory_over_limit_warns(patched_resources):
102+
def test_memory_over_limit_errors(patched_resources):
103+
warnings, errors = patched_resources
94104
over_memory = f"{(MOCK_MEMORY // (1024**3)) + 1}G"
95105
compose = _make_compose("0-3", over_memory)
96-
compose._validate_machine_resources()
97-
assert len(patched_resources) == 1
98-
assert "does not have adequate resources" in patched_resources[0]
106+
assert compose._validate_machine_resources() is False
107+
assert len(errors) == 1
108+
assert "does not have adequate resources" in errors[0]
99109

100110

101-
def test_crs_entry_exceeds_cpu_count_warns(patched_resources):
111+
def test_crs_entry_exceeds_cpu_count_errors(patched_resources):
112+
warnings, errors = patched_resources
102113
compose = _make_compose(
103114
"0-3",
104115
crs_entries={"crs-a": _FakeResource(f"0-{MOCK_CPU_COUNT}", "4G")},
105116
)
106-
compose._validate_machine_resources()
107-
assert len(patched_resources) == 1
108-
assert "does not have adequate resources" in patched_resources[0]
117+
assert compose._validate_machine_resources() is False
118+
assert len(errors) == 1
119+
assert "does not have adequate resources" in errors[0]
109120

110121

111-
def test_combined_memory_across_entries_warns(patched_resources):
122+
def test_combined_memory_across_entries_errors(patched_resources):
123+
warnings, errors = patched_resources
112124
half_memory = f"{MOCK_MEMORY // (1024**3) // 2 + 1}G"
113125
compose = _make_compose(
114126
"0-3",
@@ -117,58 +129,71 @@ def test_combined_memory_across_entries_warns(patched_resources):
117129
"crs-a": _FakeResource("0-3", half_memory),
118130
},
119131
)
120-
compose._validate_machine_resources()
121-
assert len(patched_resources) == 1
122-
assert "does not have adequate resources" in patched_resources[0]
132+
assert compose._validate_machine_resources() is False
133+
assert len(errors) == 1
134+
assert "does not have adequate resources" in errors[0]
123135

124136

125137
def test_both_adequate_no_warning(patched_resources):
138+
warnings, errors = patched_resources
126139
compose = _make_compose("0-3", "4G")
127-
compose._validate_machine_resources()
128-
assert len(patched_resources) == 0
140+
assert compose._validate_machine_resources() is True
141+
assert len(errors) == 0
129142

130143

131144
## undetectable machine resources checks
132145

133146

134147
def test_undetectable_cpu_skips_check(monkeypatch):
135148
warnings = []
149+
errors = []
136150
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: None)
137151
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: MOCK_MEMORY)
138152
monkeypatch.setattr(
139153
"oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg)
140154
)
155+
monkeypatch.setattr(
156+
"oss_crs.src.crs_compose.log_error", lambda msg: errors.append(msg)
157+
)
141158

142159
compose = _make_compose("0-3")
143-
compose._validate_machine_resources()
160+
assert compose._validate_machine_resources() is True
144161
assert len(warnings) == 1
145162
assert "Could not determine machine resources" in warnings[0]
163+
assert len(errors) == 0
146164

147165

148166
def test_undetectable_memory_skips_check(monkeypatch):
149167
warnings = []
168+
errors = []
150169
monkeypatch.setattr("oss_crs.src.crs_compose.os.cpu_count", lambda: MOCK_CPU_COUNT)
151170
monkeypatch.setattr("oss_crs.src.crs_compose.get_host_memory", lambda: None)
152171
monkeypatch.setattr(
153172
"oss_crs.src.crs_compose.log_warning", lambda msg: warnings.append(msg)
154173
)
174+
monkeypatch.setattr(
175+
"oss_crs.src.crs_compose.log_error", lambda msg: errors.append(msg)
176+
)
155177

156178
compose = _make_compose("0-3")
157-
compose._validate_machine_resources()
179+
assert compose._validate_machine_resources() is True
158180
assert len(warnings) == 1
159181
assert "Could not determine machine resources" in warnings[0]
182+
assert len(errors) == 0
160183

161184

162185
# parsing error checks
163186

164187

165188
def test_invalid_cpuset_warns(patched_resources):
189+
warnings, errors = patched_resources
166190
compose = _make_compose("not-a-cpuset", "4G")
167191
compose._validate_machine_resources()
168-
assert any("Failed to validate cpuset" in w for w in patched_resources)
192+
assert any("Failed to validate cpuset" in w for w in warnings)
169193

170194

171195
def test_invalid_memory_string_warns(patched_resources):
196+
warnings, errors = patched_resources
172197
compose = _make_compose("0-3", "notmemory")
173198
compose._validate_machine_resources()
174-
assert any("Failed to parse memory" in w for w in patched_resources)
199+
assert any("Failed to parse memory" in w for w in warnings)

0 commit comments

Comments
 (0)