← Files Web App QA & Release CopilotARCHIVED FILE
tests/test_release_evidence.py
3.49 KB · Nov 14, 2026 · 00:40 UTC
import unittest
from scripts.check_release_evidence import evaluate
def sample():
return {"release_id":"abc123","gates":[{"id":"critical-flow","required":True,"status":"pass","evidence":"ci://run/123"}],"blockers":[],"limitations":[]}
class EvidenceTests(unittest.TestCase):
def test_ready_with_passed_required_evidence(self):
self.assertEqual(evaluate(sample())["verdict"],"Ready")
def test_missing_required_gate(self):
x=sample();x['gates']=[];self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_unknown_required_gate(self):
x=sample();x['gates'][0]['status']='unknown';self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_failed_required_gate(self):
x=sample();x['gates'][0]['status']='fail';self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_required_na_not_pass(self):
x=sample();x['gates'][0].update(status='na',reason='not supported');self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_pass_without_evidence(self):
x=sample();x['gates'][0]['evidence']='';self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_optional_failed_gate_is_not_necessarily_blocking(self):
x=sample();x['gates'].append({'id':'optional-lint','required':False,'status':'fail'});self.assertEqual(evaluate(x)['verdict'],'Ready')
def test_optional_na_needs_reason(self):
x=sample();x['gates'].append({'id':'seo','required':False,'status':'na'});self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_optional_na_with_reason(self):
x=sample();x['gates'].append({'id':'seo','required':False,'status':'na','reason':'internal tool'});self.assertEqual(evaluate(x)['verdict'],'Ready')
def test_duplicate_gate_id(self):
x=sample();x['gates'].append(dict(x['gates'][0]));self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_open_p1_blocks(self):
x=sample();x['blockers']=[{'id':'auth-1','severity':'P1','resolved':False}];self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_resolved_p1(self):
x=sample();x['blockers']=[{'id':'auth-1','severity':'P1','resolved':True}];self.assertEqual(evaluate(x)['verdict'],'Ready')
def test_p2_does_not_auto_block(self):
x=sample();x['blockers']=[{'id':'ui-1','severity':'P2','resolved':False}];self.assertEqual(evaluate(x)['verdict'],'Ready')
def test_accepted_limitation(self):
x=sample();x['limitations']=[{'id':'ui-1','accepted':True,'owner':'team','follow_up':'next release'}];self.assertEqual(evaluate(x)['verdict'],'Ready with known limitations')
def test_unaccepted_limitation(self):
x=sample();x['limitations']=[{'id':'ui-1','accepted':False,'owner':'team','follow_up':'next release'}];self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_approval_required(self):
x=sample();x['requires_deployment_approval']=True;self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_approval_provided(self):
x=sample();x['requires_deployment_approval']=True;x['deployment_approval']='granted';self.assertEqual(evaluate(x)['verdict'],'Ready')
def test_empty_release(self):
x=sample();x['release_id']='';self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_bad_status(self):
x=sample();x['gates'][0]['status']='ok';self.assertEqual(evaluate(x)['verdict'],'Not ready')
def test_nonstr_gate(self):
x=sample();x['gates'][0]['id']=None;self.assertEqual(evaluate(x)['verdict'],'Not ready')
if __name__=='__main__':unittest.main()
SHA-256: 5ec926b28d493d534fcc6b487f0e8f2e36743e34373de9ba746c6a83556b4c9f