bc1d56d1a4
P0.6: gcov infrastructure P1: extract_structure output expansion (11 new feature fields) P2: Confusion group rule engine (8 pairs + contradiction + backtrack) P3: 4-factor confidence calculation + quality gate update P4: 33+2 COBOL program type test samples (22 files, 7 categories) P5: parametrized/ test data generation engine P6: japanese_data.py lookup tables P7-10: Type-specific test suites (~159 parametrized tests) P11: Full classification pipeline (classify_program) + orchestrator integration P12: Documentation (module-interfaces, test-plan v3.0, coverage-matrix) Architecture decisions: - classification_pipeline/ merged to hina/pipeline/ - parametrized/ as independent module - japanese_data.py as root-level file - hina/__all__ only exports classify_program() Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
3.3 KiB
Python
116 lines
3.3 KiB
Python
"""RH-01~07: Retry Handler — 分层重试 + heal/simple 分离"""
|
|
|
|
import sys, os
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
|
from hina.retry import RetryHandler, HEALING_FIXES
|
|
from data.diff_result import VerificationRun
|
|
|
|
|
|
def _vr(status="PASS", build_log=""):
|
|
vr = VerificationRun(status=status, program="TEST")
|
|
if build_log:
|
|
vr.debug = {"cobol_build": {"log": build_log}}
|
|
return vr
|
|
|
|
|
|
def test_immediate_pass():
|
|
"""RH-01: 1次 PASS → heal=0, simple=0"""
|
|
h = RetryHandler()
|
|
vr = h.run(lambda: _vr("PASS"))
|
|
assert vr.status == "PASS"
|
|
assert vr.heal_retry == 0
|
|
assert vr.simple_retry == 0
|
|
|
|
|
|
def test_heal_recovery():
|
|
"""RH-02: BLOCKED(not found) → heal修复→PASS"""
|
|
calls = [0]
|
|
def fn():
|
|
calls[0] += 1
|
|
if calls[0] == 1:
|
|
return _vr("BLOCKED", build_log="file not found: libcob.so")
|
|
return _vr("PASS")
|
|
h = RetryHandler()
|
|
vr = h.run(fn)
|
|
assert vr.status == "PASS"
|
|
assert vr.heal_retry >= 1
|
|
assert vr.simple_retry == 0
|
|
|
|
|
|
def test_simple_retry():
|
|
"""RH-03: BLOCKED→重试→PASS (无 heal 匹配)"""
|
|
calls = [0]
|
|
def fn():
|
|
calls[0] += 1
|
|
if calls[0] == 1:
|
|
return _vr("BLOCKED", build_log="some random error")
|
|
return _vr("PASS")
|
|
h = RetryHandler()
|
|
vr = h.run(fn)
|
|
assert vr.status == "PASS"
|
|
assert vr.simple_retry >= 1
|
|
|
|
|
|
def test_max_retries_exceeded():
|
|
"""RH-04: 全部失败 → FATAL"""
|
|
h = RetryHandler(max_heal=1, max_simple=1)
|
|
vr = h.run(lambda: _vr("BLOCKED"))
|
|
assert vr.status == "FATAL"
|
|
assert vr.exit_code == 4
|
|
|
|
|
|
def test_quality_warn_no_retry():
|
|
"""RH-05: QUALITY_WARN → 立即返回 不重试"""
|
|
h = RetryHandler()
|
|
vr = h.run(lambda: _vr("QUALITY_WARN"))
|
|
assert vr.status == "QUALITY_WARN"
|
|
assert vr.heal_retry == 0
|
|
assert vr.simple_retry == 0
|
|
|
|
|
|
def test_heal_fails_then_simple():
|
|
"""RH-06: heal 尝试但仍然 BLOCKED → 回退 simple"""
|
|
calls = [0]
|
|
def fn():
|
|
calls[0] += 1
|
|
return _vr("BLOCKED", build_log="file not found: libcob.so")
|
|
h = RetryHandler(max_heal=2, max_simple=2)
|
|
vr = h.run(fn)
|
|
assert vr.status == "FATAL"
|
|
# 应已消耗所有 heal+simple
|
|
assert vr.heal_retry + vr.simple_retry >= 1
|
|
|
|
|
|
def test_concurrent_count_separation():
|
|
"""RH-07: heal 和 simple 计数互不影响"""
|
|
h = RetryHandler(max_heal=2, max_simple=2)
|
|
calls = [0, False] # [count, callable flag]
|
|
def fn():
|
|
calls[0] += 1
|
|
if calls[0] == 1:
|
|
return _vr("BLOCKED", build_log="file not found: libcob.so")
|
|
return _vr("PASS")
|
|
h._try_set_env = lambda k, v: None # no-op fix
|
|
# Mock fix to succeed on first heal
|
|
original_fix = HEALING_FIXES["compile_error"]["fix"]
|
|
HEALING_FIXES["compile_error"]["fix"] = lambda: None
|
|
try:
|
|
vr = h.run(fn)
|
|
assert vr.heal_retry >= 0
|
|
assert vr.simple_retry >= 0
|
|
# heal 和 simple 的计数不会混淆
|
|
finally:
|
|
HEALING_FIXES["compile_error"]["fix"] = original_fix
|
|
|
|
|
|
def test_history_records():
|
|
"""所有 VR 被记录到 history"""
|
|
h = RetryHandler(max_heal=0, max_simple=2)
|
|
results = []
|
|
def fn():
|
|
vr = _vr("BLOCKED") if len(results) < 2 else _vr("PASS")
|
|
results.append(vr)
|
|
return vr
|
|
h.run(fn)
|
|
assert len(h.history) >= 2
|