-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_read_ci_verdict.py
More file actions
159 lines (123 loc) · 4.64 KB
/
Copy pathtest_read_ci_verdict.py
File metadata and controls
159 lines (123 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python3
# FLOOR
"""Red floor for read_ci_verdict -- the deterministic core.
Proves the decision logic and the policy loader offline (no network, no auth):
mutating decide or load_policy turns one of these red. Runs standalone
(exit 0/1) and under pytest.
"""
from __future__ import annotations
import json
import sys
import tempfile
from pathlib import Path
from read_ci_verdict import Policy, PolicyError, decide, load_policy
DECISIONAL = ("quality", "tests", "security")
GREEN = [
{"name": "quality", "conclusion": "SUCCESS"},
{"name": "tests", "conclusion": "SUCCESS"},
{"name": "security", "conclusion": "SUCCESS"},
]
def test_all_green_passes():
v = decide(GREEN, DECISIONAL)
assert v.ok is True
assert all(r.ok for r in v.results)
def test_one_gate_failure_fails():
rollup = [
{"name": "quality", "conclusion": "SUCCESS"},
{"name": "tests", "conclusion": "FAILURE"},
{"name": "security", "conclusion": "SUCCESS"},
]
v = decide(rollup, DECISIONAL)
assert v.ok is False
assert [r.name for r in v.results if not r.ok] == ["tests"]
def test_missing_decisional_fails_not_silent_pass():
rollup = [
{"name": "quality", "conclusion": "SUCCESS"},
{"name": "security", "conclusion": "SUCCESS"},
] # 'tests' absent entirely
v = decide(rollup, DECISIONAL)
assert v.ok is False
assert [r.name for r in v.results if not r.present] == ["tests"]
def test_non_decisional_red_is_ignored():
# The rule: a red non-decisional check (CodeQL) does not block.
rollup = GREEN + [{"name": "Analyze (python)", "conclusion": "FAILURE"}]
v = decide(rollup, DECISIONAL)
assert v.ok is True
def test_pending_decisional_is_not_pass():
rollup = [
{"name": "quality", "conclusion": "SUCCESS"},
{"name": "tests", "conclusion": None}, # in progress, not yet concluded
{"name": "security", "conclusion": "SUCCESS"},
]
v = decide(rollup, DECISIONAL)
assert v.ok is False
def _write(tmp: str, name: str, text: str) -> Path:
path = Path(tmp) / name
path.write_text(text, encoding="utf-8")
return path
_GOOD = {
"required": ["quality", "tests", "security", "Analyze (python)"],
"decisional": ["quality", "tests", "security"],
}
def test_load_policy_reads_conforming_object():
with tempfile.TemporaryDirectory() as tmp:
path = _write(tmp, "required-checks.json", json.dumps(_GOOD))
policy = load_policy(path)
assert policy == Policy(
required=("quality", "tests", "security", "Analyze (python)"),
decisional=("quality", "tests", "security"),
)
def test_load_policy_absent_raises():
missing = Path(tempfile.gettempdir()) / "no-such-required-checks-file-xyz.json"
try:
load_policy(missing)
except PolicyError:
return
raise AssertionError("absent file must raise")
def test_load_policy_malformed_raises():
with tempfile.TemporaryDirectory() as tmp:
path = _write(tmp, "bad.json", "not json {")
try:
load_policy(path)
except PolicyError:
return
raise AssertionError("malformed JSON must raise")
def test_load_policy_bare_array_raises():
# The earlier mistake: a bare array is not the object shape -- must fail loud.
with tempfile.TemporaryDirectory() as tmp:
path = _write(tmp, "arr.json", json.dumps(["quality", "tests", "security"]))
try:
load_policy(path)
except PolicyError:
return
raise AssertionError("bare array must raise")
def test_load_policy_missing_decisional_raises():
with tempfile.TemporaryDirectory() as tmp:
path = _write(tmp, "nodec.json", json.dumps({"required": ["quality"]}))
try:
load_policy(path)
except PolicyError:
return
raise AssertionError("missing decisional must raise")
def test_load_policy_empty_decisional_raises():
with tempfile.TemporaryDirectory() as tmp:
path = _write(tmp, "empty.json", json.dumps({"required": ["quality"], "decisional": []}))
try:
load_policy(path)
except PolicyError:
return
raise AssertionError("empty decisional must raise")
def _run() -> int:
fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
failed = 0
for fn in fns:
try:
fn()
print(f"PASS {fn.__name__}")
except AssertionError as exc:
failed += 1
print(f"FAIL {fn.__name__}: {exc}")
print(f"\n{len(fns) - failed}/{len(fns)} green")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(_run())