Skip to content

Commit ffda13c

Browse files
fix: reject partial and unscored results in CI example (#136)
Co-authored-by: stefyi-4355 <as.peter@ime.life>
1 parent bdfb8cf commit ffda13c

2 files changed

Lines changed: 75 additions & 3 deletions

File tree

‎ifixai/examples/ci_check.py‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ async def run_ci_check() -> int:
4747
f.write(generate_json_report(result))
4848
print(f"Report written to {config['report_path']}")
4949

50-
print(f"Grade: {result.grade.value}")
51-
print(f"Overall Score: {result.overall_score:.0%}")
50+
grade = result.grade.value if result.overall_score is not None else "n/a"
51+
overall = f"{result.overall_score:.0%}" if result.overall_score is not None else "n/a"
52+
print(f"Grade: {grade}")
53+
print(f"Overall Score: {overall}")
5254
print(f"Strategic Score: {result.strategic_score:.0%}")
5355

5456
passed_count = sum(1 for br in result.test_results if br.passed)
@@ -60,7 +62,15 @@ async def run_ci_check() -> int:
6062

6163
is_passing = True
6264

63-
if result.overall_score < min_score:
65+
if result.partial:
66+
reason = f": {result.abort_reason}" if result.abort_reason else ""
67+
print(f"\nFAIL: Partial run{reason}; finish the run before evaluating CI thresholds")
68+
is_passing = False
69+
70+
if result.overall_score is None:
71+
print("\nFAIL: Overall score unavailable; the run is not gradeable")
72+
is_passing = False
73+
elif result.overall_score < min_score:
6474
print(f"\nFAIL: Overall score {result.overall_score:.0%} < {min_score:.0%}")
6575
is_passing = False
6676

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
from ifixai.core.types import TestGrade, TestRunResult
6+
from ifixai.examples import ci_check
7+
8+
9+
def _config() -> dict[str, str]:
10+
return {
11+
"provider": "mock",
12+
"api_key": "test-key",
13+
"fixture": "test-fixture",
14+
"model": "",
15+
"system_name": "test-system",
16+
"system_version": "1.0",
17+
"min_score": "0.70",
18+
"min_strategic": "0.80",
19+
"report_path": "",
20+
}
21+
22+
23+
@pytest.mark.parametrize(
24+
("overall_score", "partial", "expected_message"),
25+
[
26+
(None, False, "Overall Score: n/a"),
27+
(0.95, True, "partial run"),
28+
],
29+
)
30+
def test_ci_check_fails_cleanly_when_run_is_not_gradeable(
31+
monkeypatch, capsys, overall_score, partial, expected_message
32+
):
33+
async def fake_run_inspections(**kwargs):
34+
return TestRunResult(
35+
overall_score=overall_score,
36+
strategic_score=0.95,
37+
grade=TestGrade.A,
38+
mandatory_minimums_passed=True,
39+
partial=partial,
40+
abort_reason="judge quota exhausted" if partial else None,
41+
)
42+
43+
monkeypatch.setattr(ci_check, "read_env_config", _config)
44+
monkeypatch.setattr(ci_check, "run_inspections", fake_run_inspections)
45+
46+
assert asyncio.run(ci_check.run_ci_check()) == 1
47+
assert expected_message.lower() in capsys.readouterr().out.lower()
48+
49+
50+
def test_ci_check_still_passes_a_complete_scored_run(monkeypatch):
51+
async def fake_run_inspections(**kwargs):
52+
return TestRunResult(
53+
overall_score=0.95,
54+
strategic_score=0.95,
55+
grade=TestGrade.A,
56+
mandatory_minimums_passed=True,
57+
)
58+
59+
monkeypatch.setattr(ci_check, "read_env_config", _config)
60+
monkeypatch.setattr(ci_check, "run_inspections", fake_run_inspections)
61+
62+
assert asyncio.run(ci_check.run_ci_check()) == 0

0 commit comments

Comments
 (0)