Files
rune/tests/test_testing_mode_delegation.py
T

122 lines
4.3 KiB
Python

"""test_testing_mode_delegation.py — literal-100% residue tests.
The facade must behave identically with the Rust core LIVE
(RUNE_TM_CORE unset, libtesting_mode.so built) and with the PYTHON
ORACLE pinned (RUNE_TM_CORE=python). Covers the probe slice (_now /
_tm_core) plus a session-state-machine smoke pass through both modes.
"""
import copy
import json
import sys
import time
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from rune import tm_loader # noqa: E402
from rune import testing_mode as tm # noqa: E402
needs_live = pytest.mark.skipif(
not tm_loader.available(), reason="Rust testing_mode core not built"
)
def run_both_modes(call):
results = []
for pin in (True, False):
if pin:
monkey = pytest.MonkeyPatch()
monkey.setenv("RUNE_TM_CORE", "python")
else:
monkey = pytest.MonkeyPatch()
monkey.delenv("RUNE_TM_CORE", raising=False)
try:
results.append(call())
finally:
monkey.undo()
assert json.dumps(results[0], sort_keys=True, default=str) == json.dumps(
results[1], sort_keys=True, default=str
), f"modes diverged:\n{json.dumps(results[0], sort_keys=True, default=str)}\n{json.dumps(results[1], sort_keys=True, default=str)}"
return results[0]
class TestProbeDualMode:
def test_now_matches_strftime(self):
def call():
import time as _t
epochs = [0, -1, 1, 1791806400, 4102444800, int(_t.time())]
return {
str(e): _t.strftime("%Y-%m-%dT%H:%M:%SZ", _t.gmtime(e))
for e in epochs
}
# the FFI stamp for each epoch must equal the oracle's strftime
stamps = call()
for e, want in stamps.items():
assert tm_loader.now(int(e)) == want, f"epoch {e}"
def test_tm_core_pin_semantics(self, monkeypatch):
# the pin is read at call time: pin → no core; unpin → core iff
# the .so is built (the kernel probe mirror is pinned in the
# Rust battery; here the facade probe is exercised)
monkeypatch.setenv("RUNE_TM_CORE", "python")
assert tm._tm_core() is None, "python pin disables the core"
monkeypatch.delenv("RUNE_TM_CORE", raising=False)
assert (tm._tm_core() is not None) == tm_loader.available()
@needs_live
class TestSessionDualMode:
def test_default_next_record_pause_resume_blocker(self, tmp_path, monkeypatch):
import time as _t
frozen = 1791806400
monkeypatch.setattr(tm, "time", type("T", (), {
"strftime": staticmethod(lambda fmt, t: _t.strftime(fmt, t)),
"gmtime": staticmethod(lambda: _t.gmtime(frozen)),
"time": staticmethod(lambda: frozen),
}))
calls = {"n": 0}
def call():
calls["n"] += 1
base = tmp_path / f"mode{calls['n']}"
base.mkdir()
s = tm.TestingSession(base, project="p", scope_component="c")
class FakeBeh:
def outstanding(self, *, component=None, project=None):
return [{"behaviour_id": "b:1"}, {"behaviour_id": "b:2"}]
def record_real_world(self, behaviour_id, **kw):
return {"behaviour_id": behaviour_id, "state": "USER_CONFIRMED"}
beh = FakeBeh()
first = s.next_item(beh)
s.record(beh, "b:1", passed=True)
s.pause()
paused_item = s.next_item(beh)
s.resume()
s.note_blocker("b:2", "x" * 300)
obs = tm.record_observation(base, observed="o", expected="e",
behaviour_id="b:1")
closed = tm.close_observation(base, obs["observation_id"],
behaviour_retest_passed=True,
user_confirmed=True)
title, body = tm._py_project("b:1", obs)
rows = tm._py_aggregate_rows([{"project_id": "p", "summary": None}])
return {
"state": s.state,
"first": first,
"paused_item": paused_item,
"obs": obs,
"closed": closed,
"title": title,
"rows": rows,
}
run_both_modes(call)