mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 20:47:14 +01:00
_morning_session.py is now a thin binding of screen-locker's path and retry budget over gatelock.morning_session, shared with leetcode-guard and book-guard; the verdict tests live there once. Same behaviour, same string. Also bumps mypy 2.4.0 / pylint 4.1.1 / ruff 0.16.10 (newest stable gate) and the stale gatelock pins in install_systemd.sh and the pylint hook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FBbkN4ZB4aUPJPzR2prRan
76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
"""screen_locker._morning_session — binds screen-locker's file to gatelock's reader.
|
|
|
|
The verdict rules themselves (signed, today, not expired, the boot retry) are
|
|
tested once, in gatelock.morning_session.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
import json
|
|
from typing import TYPE_CHECKING
|
|
from unittest.mock import patch
|
|
|
|
from gatelock.log_integrity import compute_entry_hmac
|
|
import pytest
|
|
|
|
from screen_locker import _morning_session
|
|
from screen_locker._morning_session import (
|
|
MorningSkip,
|
|
has_workout_skip_today,
|
|
morning_skip_today,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterator
|
|
from pathlib import Path
|
|
|
|
NOW = datetime(2026, 9, 19, 9, 0).astimezone()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _signing_key(tmp_path: Path) -> Iterator[None]:
|
|
key = tmp_path / "hmac.key"
|
|
key.write_bytes(b"1" * 32)
|
|
with patch("gatelock.log_integrity.DEFAULT_HMAC_KEY_FILE", key):
|
|
yield
|
|
|
|
|
|
def _write(date: str, exempt_until: str) -> None:
|
|
"""Sign an entry into the file the conftest redirected."""
|
|
entry: dict[str, object] = {
|
|
"date": date,
|
|
"outcome": "completed",
|
|
"exempt_until": datetime.fromisoformat(f"{date}T{exempt_until}")
|
|
.astimezone()
|
|
.isoformat(),
|
|
}
|
|
entry["hmac"] = compute_entry_hmac(entry)
|
|
_morning_session.MORNING_SESSION_FILE.write_text(json.dumps(entry))
|
|
|
|
|
|
def test_reads_the_redirected_file() -> None:
|
|
_write("2026-09-19", "11:00")
|
|
skip = morning_skip_today(NOW, wait=False)
|
|
assert skip == MorningSkip("completed", NOW.replace(hour=11))
|
|
assert "no lock until 11:00" in str(skip)
|
|
|
|
|
|
def test_missing_file_is_no_skip() -> None:
|
|
assert morning_skip_today(NOW, wait=False) is None
|
|
|
|
|
|
def test_has_workout_skip_today_uses_the_wall_clock() -> None:
|
|
_write(datetime.now(tz=UTC).astimezone().strftime("%Y-%m-%d"), "23:59")
|
|
assert has_workout_skip_today() is True
|
|
|
|
|
|
def test_the_retry_budget_is_screen_lockers_own() -> None:
|
|
"""The conftest zeroes it; raising it here makes the shared reader wait."""
|
|
naps: list[float] = []
|
|
assert morning_skip_today(NOW, wait=True, sleep=naps.append) is None
|
|
assert naps == []
|
|
with patch.object(_morning_session, "MORNING_RETRY_SECONDS", 10.0):
|
|
assert morning_skip_today(NOW, wait=True, sleep=naps.append) is None
|
|
assert naps
|