mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 20:27:13 +01:00
Some checks are pending
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
Tests / lock-popup-safety (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
Two gaps against the 100% bar. The first is mine: --log-manual-workout's dispatch branch had no test, so nothing checked that the flag's own name is stripped before the args are forwarded, or that the exit code is the logger's. The second predates this work. `_record_decision` annotates the DECISION line with any backend it could not read, which is the thing that distinguishes "weekly=0/5, measured" from "weekly=0/5, unreadable" -- the exact confusion that hid the 2026-08 outage -- and that branch was never exercised. Now both directions are: named when a source is degraded, absent when none are. test_sync_degradation.py was at the 250-line cap, so the new class lives in test_sync_degradation_part2.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWq9MRemX9ZWvNmnhNWUP2
74 lines
2.7 KiB
Python
74 lines
2.7 KiB
Python
"""The DECISION line must name a backend it could not read.
|
|
|
|
Split from ``test_sync_degradation.py`` to keep both files under the 250-line
|
|
cap; same subject, which is that "could not check" and "did not train" are
|
|
different claims and only one of them justifies locking the screen.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from screen_locker import _startup_checks, _sync_client
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
|
|
class TestDecisionLineNamesTheDeadBackend:
|
|
"""A degraded read must be named on the DECISION line itself.
|
|
|
|
A warning logged 90 seconds earlier is not enough: the line that says
|
|
``weekly=0/5`` has to say whether that zero was measured or merely
|
|
unreadable, or a reader tracing the journal draws the wrong conclusion
|
|
about the user (see this module's docstring).
|
|
"""
|
|
|
|
def _locker(self, tmp_path: Path) -> object:
|
|
"""A StartupChecksMixin with __init__ bypassed, as the CLI builds it."""
|
|
locker = object.__new__(_startup_checks.StartupChecksMixin)
|
|
locker.log_file = tmp_path / "log.json"
|
|
# Stubbed: the ladder annotation is its own concern, tested elsewhere.
|
|
locker._other_conditions = lambda _reason: {}
|
|
return locker
|
|
|
|
def test_annotates_the_decision_with_the_unreadable_source(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""The dead backend's name reaches the recorded decision."""
|
|
recorded: list[object] = []
|
|
monkeypatch.setattr(
|
|
_startup_checks,
|
|
"degraded_sources",
|
|
lambda: (_sync_client.DegradedSource("firebase", "HTTP 401"),),
|
|
)
|
|
monkeypatch.setattr(_startup_checks, "count_weekly_workouts", lambda _: 0)
|
|
monkeypatch.setattr(
|
|
_startup_checks, "record_decision", lambda d, **_: recorded.append(d)
|
|
)
|
|
|
|
self._locker(tmp_path)._record_decision(
|
|
locked=False, reason="weekly_minimum_met", detail=""
|
|
)
|
|
|
|
assert recorded[0].extra["unreadable_sources"] == "firebase"
|
|
|
|
def test_healthy_sources_add_no_annotation(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""With every backend answering, the line stays unannotated."""
|
|
recorded: list[object] = []
|
|
monkeypatch.setattr(_startup_checks, "degraded_sources", tuple)
|
|
monkeypatch.setattr(_startup_checks, "count_weekly_workouts", lambda _: 0)
|
|
monkeypatch.setattr(
|
|
_startup_checks, "record_decision", lambda d, **_: recorded.append(d)
|
|
)
|
|
|
|
self._locker(tmp_path)._record_decision(
|
|
locked=False, reason="weekly_minimum_met", detail=""
|
|
)
|
|
|
|
assert "unreadable_sources" not in recorded[0].extra
|