122 lines
4.3 KiB
Python
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)
|