Revert "feat(lvl5): P1 — 5-rung ladder (L5=abra recipe lint) + de-capped level semantics"
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit e219a7891d.
This commit is contained in:
@ -1,8 +1,7 @@
|
||||
"""Unit tests for results assembly (harness.results) — phase lvl5 semantics.
|
||||
"""Unit tests for Phase-3 results assembly (harness.results), plan-phase3-results-ux.md §4.2 / R1/R3.
|
||||
|
||||
Covers JUnit parsing, stage roll-up, the tier→rung derivation (the SINGLE place every N/A source
|
||||
is classified intentional-skip vs unverified — the table in DECISIONS.md phase lvl5), the L5 lint
|
||||
rung wiring, and full results.json assembly. Pure / tmp-file only. Run cold:
|
||||
Covers JUnit parsing, stage roll-up, the tier→rung derivation (the documented mapping the level
|
||||
depends on), and full results.json assembly incl. the U0 gate cases. Pure / tmp-file only. Run cold:
|
||||
cc-ci-run -m pytest tests/unit/test_results.py -q
|
||||
"""
|
||||
|
||||
@ -28,8 +27,6 @@ JUNIT_MIXED = """<?xml version="1.0"?>
|
||||
<testcase classname="tests.y" name="test_skipped" time="0"><skipped message="no deps"/></testcase>
|
||||
</testsuite></testsuites>"""
|
||||
|
||||
LINT_PASS = {"status": "pass", "detail": "", "rules_failed": []}
|
||||
|
||||
|
||||
def _write(tmp_path, name, content):
|
||||
p = tmp_path / name
|
||||
@ -93,7 +90,7 @@ def test_collect_stages_synthesizes_when_no_junit():
|
||||
assert len(stages[0]["tests"]) == 1
|
||||
|
||||
|
||||
# ---- derive_rungs: the documented N/A-classification mapping (DECISIONS.md phase lvl5) ----
|
||||
# ---- derive_rungs: the documented mapping ----
|
||||
|
||||
|
||||
def _results(**kw):
|
||||
@ -108,113 +105,34 @@ def _results(**kw):
|
||||
return base
|
||||
|
||||
|
||||
def test_derive_rungs_full_climb_five_rungs():
|
||||
rungs = R.derive_rungs(
|
||||
_results(), backup_capable=True, has_upgrade_target=True, lint_status="pass"
|
||||
)
|
||||
# the five essential rungs — integration/recipe-local are optional, not produced here.
|
||||
def test_derive_rungs_full_climb_four_essential():
|
||||
rungs = R.derive_rungs(_results(), backup_capable=True, has_custom=True)
|
||||
# only the four essential rungs — integration/recipe-local are optional, not produced here.
|
||||
assert rungs == {
|
||||
"install": "pass",
|
||||
"upgrade": "pass",
|
||||
"backup_restore": "pass",
|
||||
"functional": "pass",
|
||||
"lint": "pass",
|
||||
}
|
||||
|
||||
|
||||
def test_derive_rungs_structural_skips_are_intentional():
|
||||
# single published version (tier skipped, no upgrade target) + not backup-capable →
|
||||
# both rungs are INTENTIONAL skips, not unverified.
|
||||
def test_derive_rungs_stateless_backup_and_functional_na():
|
||||
rungs = R.derive_rungs(
|
||||
_results(upgrade="skip", backup="skip", restore="skip"),
|
||||
_results(backup="skip", restore="skip", custom="skip"),
|
||||
backup_capable=False,
|
||||
has_upgrade_target=False,
|
||||
lint_status="pass",
|
||||
has_custom=False,
|
||||
)
|
||||
assert rungs["upgrade"] == "skip"
|
||||
assert rungs["backup_restore"] == "skip"
|
||||
assert rungs["backup_restore"] == "na"
|
||||
assert rungs["functional"] == "na"
|
||||
assert "integration" not in rungs and "recipe_local" not in rungs
|
||||
|
||||
|
||||
def test_derive_rungs_upgrade_skip_with_target_is_unverified():
|
||||
# the tier skipped although an upgrade target exists (e.g. install failed → downstream
|
||||
# skipped): NOT structural → unver.
|
||||
rungs = R.derive_rungs(
|
||||
_results(install="fail", upgrade="skip", backup="skip", restore="skip", custom="skip"),
|
||||
backup_capable=True,
|
||||
has_upgrade_target=True,
|
||||
lint_status="pass",
|
||||
)
|
||||
assert rungs["install"] == "fail"
|
||||
assert rungs["upgrade"] == "unver"
|
||||
assert rungs["backup_restore"] == "unver"
|
||||
assert rungs["functional"] == "unver"
|
||||
|
||||
|
||||
def test_derive_rungs_missing_tier_is_unverified():
|
||||
# a tier excluded from the run entirely (dev CCCI_STAGES escape) → no result key → unver,
|
||||
# never an intentional skip (the recipe didn't declare anything).
|
||||
res = {"install": "pass"}
|
||||
rungs = R.derive_rungs(res, backup_capable=True, has_upgrade_target=True, lint_status="pass")
|
||||
assert rungs["upgrade"] == "unver"
|
||||
assert rungs["backup_restore"] == "unver"
|
||||
assert rungs["functional"] == "unver"
|
||||
|
||||
|
||||
def test_derive_rungs_expected_na_declares_intentional():
|
||||
# EXPECTED_NA turns a non-run rung into an intentional skip (declared source).
|
||||
rungs = R.derive_rungs(
|
||||
_results(custom="skip"),
|
||||
backup_capable=True,
|
||||
has_upgrade_target=True,
|
||||
expected_na={"functional": "no functional surface"},
|
||||
lint_status="pass",
|
||||
)
|
||||
assert rungs["functional"] == "skip"
|
||||
|
||||
|
||||
def test_derive_rungs_no_custom_tests_defaults_unverified():
|
||||
# absent functional coverage with NO declaration is a gap → unver (conservative default).
|
||||
rungs = R.derive_rungs(
|
||||
_results(custom="skip"), backup_capable=True, has_upgrade_target=True, lint_status="pass"
|
||||
)
|
||||
assert rungs["functional"] == "unver"
|
||||
|
||||
|
||||
def test_derive_rungs_expected_na_never_overrides_a_real_result():
|
||||
# a declaration cannot soften an exercised rung: fail stays fail.
|
||||
rungs = R.derive_rungs(
|
||||
_results(custom="fail"),
|
||||
backup_capable=True,
|
||||
has_upgrade_target=True,
|
||||
expected_na={"functional": "declared"},
|
||||
lint_status="pass",
|
||||
)
|
||||
assert rungs["functional"] == "fail"
|
||||
|
||||
|
||||
def test_derive_rungs_lint_never_skips():
|
||||
# lint has NO intentional-skip escape hatch: pass/fail from the executor, anything else
|
||||
# (None, "unver", junk) → unver — even if a recipe tries to declare it away.
|
||||
for status, want in (("pass", "pass"), ("fail", "fail"), ("unver", "unver"), (None, "unver")):
|
||||
rungs = R.derive_rungs(
|
||||
_results(),
|
||||
backup_capable=True,
|
||||
has_upgrade_target=True,
|
||||
expected_na={"lint": "nope"},
|
||||
lint_status=status,
|
||||
)
|
||||
assert rungs["lint"] == want, status
|
||||
|
||||
|
||||
def test_derive_rungs_functional_fail():
|
||||
rungs = R.derive_rungs(
|
||||
_results(custom="fail"), backup_capable=True, has_upgrade_target=True, lint_status="pass"
|
||||
)
|
||||
rungs = R.derive_rungs(_results(custom="fail"), backup_capable=True, has_custom=True)
|
||||
assert rungs["functional"] == "fail"
|
||||
|
||||
|
||||
# ---- build_results: end-to-end incl level + lint + flags ----
|
||||
# ---- build_results: end-to-end incl level + flags ----
|
||||
|
||||
|
||||
def test_build_results_level_and_flags(tmp_path):
|
||||
@ -245,75 +163,17 @@ def test_build_results_level_and_flags(tmp_path):
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=1234.0,
|
||||
lint=LINT_PASS,
|
||||
)
|
||||
# all five essential rungs pass → full climb to L5; no cap concept anywhere.
|
||||
assert data["schema"] == 2
|
||||
assert data["level"] == 5
|
||||
assert "level_cap_reason" not in data and "level_cap_rung" not in data
|
||||
# all four essential rungs pass → full climb to L4 (the top), no cap
|
||||
assert data["level"] == 4
|
||||
assert data["level_cap_reason"] == ""
|
||||
assert data["recipe"] == "hedgedoc"
|
||||
assert data["ref"] == "deadbeefcafe"
|
||||
assert data["flags"] == {"clean_teardown": True, "no_secret_leak": True}
|
||||
# lint appears as a synthetic stage so the card's table carries all five rungs.
|
||||
assert [s["name"] for s in data["stages"]] == ["install", "custom", "lint"]
|
||||
assert data["lint"] == {"status": "pass", "detail": "", "rules_failed": []}
|
||||
assert [s["name"] for s in data["stages"]] == ["install", "custom"]
|
||||
|
||||
|
||||
def test_build_results_lint_fail_blocks_at_4(tmp_path):
|
||||
recs = [
|
||||
{
|
||||
"tier": "install",
|
||||
"source": "generic",
|
||||
"file": "g/test_install.py",
|
||||
"rc": 0,
|
||||
"junit": _write(tmp_path, "i.xml", JUNIT_PASS),
|
||||
}
|
||||
]
|
||||
data = R.build_results(
|
||||
recipe="x",
|
||||
version=None,
|
||||
pr="0",
|
||||
ref=None,
|
||||
records=recs,
|
||||
results=_results(),
|
||||
backup_capable=True,
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=0.0,
|
||||
lint={
|
||||
"status": "fail",
|
||||
"detail": "error rule(s) unsatisfied: R014",
|
||||
"rules_failed": ["R014"],
|
||||
},
|
||||
)
|
||||
assert data["level"] == 4
|
||||
assert data["rungs"]["lint"] == "fail"
|
||||
assert data["lint"]["rules_failed"] == ["R014"]
|
||||
lint_stage = [s for s in data["stages"] if s["name"] == "lint"][0]
|
||||
assert lint_stage["status"] == "fail"
|
||||
assert "R014" in lint_stage["tests"][0]["message"]
|
||||
|
||||
|
||||
def test_build_results_no_lint_given_is_unverified_never_pass(tmp_path):
|
||||
# an old/lint-less caller must NEVER get a free L5: the rung derives as unver → level 4 max.
|
||||
data = R.build_results(
|
||||
recipe="x",
|
||||
version=None,
|
||||
pr="0",
|
||||
ref=None,
|
||||
records=[],
|
||||
results=_results(),
|
||||
backup_capable=True,
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=0.0,
|
||||
)
|
||||
assert data["rungs"]["lint"] == "unver"
|
||||
assert data["level"] == 4
|
||||
assert "lint" in data["skips"]["unintentional"]
|
||||
|
||||
|
||||
def test_build_results_level1_on_upgrade_fail(tmp_path):
|
||||
def test_build_results_capped_at_L1_on_upgrade_fail(tmp_path):
|
||||
recs = [
|
||||
{
|
||||
"tier": "install",
|
||||
@ -334,13 +194,12 @@ def test_build_results_level1_on_upgrade_fail(tmp_path):
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=0.0,
|
||||
lint=LINT_PASS,
|
||||
)
|
||||
assert data["level"] == 1
|
||||
assert data["rungs"]["upgrade"] == "fail"
|
||||
assert "L2" in data["level_cap_reason"]
|
||||
|
||||
|
||||
# ---- skips: intentional (declared/structural, with reason) vs unintentional (= unver) ----
|
||||
# ---- skips: intentional (declared) vs unintentional (everything else skipped) ----
|
||||
|
||||
|
||||
def _rungs(**kw):
|
||||
@ -349,26 +208,24 @@ def _rungs(**kw):
|
||||
"upgrade": "pass",
|
||||
"backup_restore": "pass",
|
||||
"functional": "pass",
|
||||
"lint": "pass",
|
||||
}
|
||||
base.update(kw)
|
||||
return base
|
||||
|
||||
|
||||
def test_skips_declared_reason_and_unverified_split():
|
||||
rungs = _rungs(backup_restore="skip", functional="unver")
|
||||
def test_skips_intentional_vs_unintentional():
|
||||
rungs = _rungs(backup_restore="na", functional="na")
|
||||
sk = R.skips(rungs, {"backup_restore": "stateless static server"})
|
||||
# backup_restore is declared (intentional, with reason); functional skipped but not declared.
|
||||
assert sk["intentional"] == {"backup_restore": "stateless static server"}
|
||||
assert sk["unintentional"] == ["functional"]
|
||||
|
||||
|
||||
def test_skips_structural_reason_when_undeclared():
|
||||
# a structural skip (derive_rungs) carries its structural reason even without EXPECTED_NA.
|
||||
rungs = _rungs(upgrade="skip", backup_restore="skip")
|
||||
def test_skips_none_declared_all_unintentional():
|
||||
rungs = _rungs(backup_restore="na")
|
||||
sk = R.skips(rungs, None)
|
||||
assert "only one published version" in sk["intentional"]["upgrade"]
|
||||
assert "not backup-capable" in sk["intentional"]["backup_restore"]
|
||||
assert sk["unintentional"] == []
|
||||
assert sk["intentional"] == {}
|
||||
assert sk["unintentional"] == ["backup_restore"]
|
||||
|
||||
|
||||
def test_skips_declaration_only_counts_when_actually_skipped():
|
||||
@ -379,9 +236,9 @@ def test_skips_declaration_only_counts_when_actually_skipped():
|
||||
assert "backup_restore" not in sk["unintentional"]
|
||||
|
||||
|
||||
def test_build_results_stateless_recipe_climbs(tmp_path):
|
||||
# custom-html-tiny shape: no backup surface (declared), single published version, passing
|
||||
# functional — formerly capped at L2 by the N/A; now climbs to L5 (the de-cap, mission §2).
|
||||
def test_build_results_threads_expected_na(tmp_path):
|
||||
# Mirrors custom-html-tiny post-change: install + a passing functional (custom) test, but no
|
||||
# backup surface (backup_restore declared intentionally skipped).
|
||||
recs = [
|
||||
{
|
||||
"tier": "install",
|
||||
@ -404,47 +261,23 @@ def test_build_results_stateless_recipe_climbs(tmp_path):
|
||||
pr="0",
|
||||
ref=None,
|
||||
records=recs,
|
||||
results=_results(upgrade="skip", backup="skip", restore="skip"),
|
||||
backup_capable=False, # no backupbot label → structural intentional skip
|
||||
has_upgrade_target=False, # single published version → structural intentional skip
|
||||
results=_results(backup="skip", restore="skip"), # custom=pass (default) → functional pass
|
||||
backup_capable=False, # no backupbot label → backup_restore skipped (N/A)
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=0.0,
|
||||
lint=LINT_PASS,
|
||||
expected_na={"backup_restore": "stateless static file server"},
|
||||
)
|
||||
assert data["level"] == 5 # skips are climbed past; nothing was inflated to get here
|
||||
assert data["rungs"] == {
|
||||
"install": "pass",
|
||||
"upgrade": "skip",
|
||||
"backup_restore": "skip",
|
||||
"functional": "pass",
|
||||
"lint": "pass",
|
||||
}
|
||||
assert data["skips"]["intentional"]["backup_restore"] == "stateless static file server"
|
||||
assert "only one published version" in data["skips"]["intentional"]["upgrade"]
|
||||
assert data["skips"]["unintentional"] == []
|
||||
|
||||
|
||||
def test_build_results_unverified_backup_blocks(tmp_path):
|
||||
# synthesized tier abort: backup-capable but the tiers never produced a result → unver → the
|
||||
# level stays below the unverified rung (mission worked example #3).
|
||||
data = R.build_results(
|
||||
recipe="x",
|
||||
version=None,
|
||||
pr="0",
|
||||
ref=None,
|
||||
records=[],
|
||||
results=_results(backup="skip", restore="skip"),
|
||||
backup_capable=True,
|
||||
clean_teardown=True,
|
||||
no_secret_leak=True,
|
||||
finished_ts=0.0,
|
||||
lint=LINT_PASS,
|
||||
)
|
||||
assert data["rungs"]["backup_restore"] == "unver"
|
||||
# backup_restore skip still caps at L2 (never inflates) — even though functional passes above it,
|
||||
# the skip caps the climb — but it's the declared (intentional) rung that capped.
|
||||
assert data["level"] == 2
|
||||
assert data["skips"]["unintentional"] == ["backup_restore"]
|
||||
assert "L3" in data["level_cap_reason"]
|
||||
assert data["level_cap_rung"] == "backup_restore"
|
||||
assert data["rungs"]["functional"] == "pass"
|
||||
assert data["skips"]["intentional"]["backup_restore"] == "stateless static file server"
|
||||
assert (
|
||||
data["skips"]["unintentional"] == []
|
||||
) # backup_restore declared; functional passed → clean
|
||||
|
||||
|
||||
def test_build_results_threads_customization(tmp_path):
|
||||
@ -477,7 +310,6 @@ def test_build_results_threads_customization(tmp_path):
|
||||
"clean_teardown": True,
|
||||
"no_secret_leak": True,
|
||||
"finished_ts": 0.0,
|
||||
"lint": LINT_PASS,
|
||||
}
|
||||
assert R.build_results(**kwargs, customization=cust)["customization"] == cust
|
||||
assert R.build_results(**kwargs)["customization"] is None
|
||||
|
||||
Reference in New Issue
Block a user