diff --git a/goodwe_controller/test_rehearse.py b/goodwe_controller/test_rehearse.py index 1367519..3b3c54d 100644 --- a/goodwe_controller/test_rehearse.py +++ b/goodwe_controller/test_rehearse.py @@ -128,13 +128,14 @@ check("⚠️ ...and a LEGACY-SHAPED KEY WHOSE LOSS WOULD BE SILENT: a LATCHED " # --------------------------------------------------------------------------- # print() -print("2. THE CLEAN CONTROLS: two transitions on which the shipped code is " +print("2. THE CLEAN CONTROLS: three transitions on which the shipped code is " "right and the harness must say nothing") # --------------------------------------------------------------------------- # # ⚠️ THIS PART IS WHAT MAKES PART 3 EVIDENCE. Six reds prove nothing about an # instrument that is red on its own fixtures. Each control below is a genuine # flat -> roster switch that the shipped migration handles correctly, and the -# required answer is EXIT 0. +# required answer is EXIT 0. CONTROL-C earned its place by failing: it found the +# harness reporting a defect on every fresh install. # # CONTROL-A a PRE-DEV-02 flat store, latch tripped, onto a roster whose # first entry IS `inverter-a`. This is the path SAFETY-44's @@ -182,6 +183,22 @@ for label, (state, after) in CONTROLS.items(): check(f"{label}: the shipped code, {state} -> {after}, exits 0 with no " f"findings", code == RR.EXIT_OK and "NO FINDINGS" in out) +# ⚠️ AND THE SOFTENING IS NOT A HOLE. The SAME key stranded with a NON-default +# value is still a finding - that is the whole of part 5 - so the two cases are +# separated by the VALUE and not by the key name. +_fresh_code, _fresh_out = run(HERE, "state-fresh.json", "roster.yaml") +check("a fresh install DOES strand `unit/inverter-a/sign_tripped` - the key is " + "written and nothing on the roster reads it - and the report SAYS SO", + _fresh_code == RR.EXIT_OK + and "unit/inverter-a/sign_tripped = False" in _fresh_out) +check("...and does NOT call it a finding, because the value is the default; " + "the same key at True is the finding part 5 turns on, so the two cases " + "are separated by the VALUE and not by the key name", + "STRANDED STORE KEY: unit/inverter-a/sign_tripped" not in _fresh_out + and "STRANDED STORE KEY: unit/inverter-a/sign_tripped = True" + in "\n".join(l.strip() for l in + run(HERE, "state-legacy.json", "roster.yaml")[1].splitlines())) + # ⚠️ AND THE INPUT FILE IS NEVER WRITTEN. The owner runs this against a copy of # a live state file; a tool that edited it would be a tool that had to be # trusted rather than one that cannot do harm. @@ -388,22 +405,6 @@ print("6. THE REVERSE DIRECTION: the retreat, and the return from it") # --------------------------------------------------------------------------- # code_r, out_r = run(HERE, "state-flat-070.json", "roster.yaml", "--reverse", "--round-trip") -# ⚠️ AND THE SOFTENING IS NOT A HOLE. The SAME key stranded with a NON-default -# value is still a finding - that is the whole of part 5 - so the two cases are -# separated by the VALUE and not by the key name. -_fresh_code, _fresh_out = run(HERE, "state-fresh.json", "roster.yaml") -check("a fresh install DOES strand `unit/inverter-a/sign_tripped` - the key is " - "written and nothing on the roster reads it - and the report SAYS SO", - _fresh_code == RR.EXIT_OK - and "unit/inverter-a/sign_tripped = False" in _fresh_out) -check("...and does NOT call it a finding, because the value is the default; " - "the same key at True is the finding part 5 turns on, so the two cases " - "are separated by the VALUE and not by the key name", - "STRANDED STORE KEY: unit/inverter-a/sign_tripped" not in _fresh_out - and "STRANDED STORE KEY: unit/inverter-a/sign_tripped = True" - in "\n".join(l.strip() for l in - run(HERE, "state-legacy.json", "roster.yaml")[1].splitlines())) - _orphaned = set(re.findall(r"ORPHANED ENTITY: (sensor\.\S+)", out_r)) print(f" the retreat orphans: {sorted(_orphaned)}") check("the RETREAT is rehearsed at all, and it reports the entities it "