diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b4192f..86e5cda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -307,6 +307,7 @@ repos: types_or: [yaml, json, markdown] exclude: ^(Bash/|\.venv/|.*\.lock$|C/compile_commands\.json) stages: [pre-push] + args: [--no-cache] # =========================================================================== # SHELLCHECK - Shell script linting @@ -463,7 +464,7 @@ repos: hooks: - id: ts-battery-status-tests name: TS battery-status vitest (100% coverage) - entry: bash -c 'cd TS/battery-status && npx vitest run --coverage' + entry: bash -c 'cd TS/battery-status && NODE_OPTIONS="--max-old-space-size=512" npx vitest run --coverage' language: system files: ^TS/battery-status/ pass_filenames: false @@ -471,7 +472,7 @@ repos: - id: ts-champions-leauge-scores-tests name: TS champions_leauge_scores vitest (100% coverage) - entry: bash -c 'cd TS/champions_leauge_scores && npx vitest run --coverage' + entry: bash -c 'cd TS/champions_leauge_scores && NODE_OPTIONS="--max-old-space-size=512" npx vitest run --coverage' language: system files: ^TS/champions_leauge_scores/ pass_filenames: false @@ -479,7 +480,7 @@ repos: - id: ts-two-inputs-tests name: TS two-inputs vitest (100% coverage) - entry: bash -c 'cd TS/two-inputs && npx vitest run --coverage' + entry: bash -c 'cd TS/two-inputs && NODE_OPTIONS="--max-old-space-size=512" npx vitest run --coverage' language: system files: ^TS/two-inputs/ pass_filenames: false diff --git a/.vscode/settings.json b/.vscode/settings.json index a8e9318..595f7fa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -67,5 +67,6 @@ ], "python.testing.pytestEnabled": true, "python.testing.pytestArgs": ["python_pkg"], - "python-envs.alwaysUseUv": true + "python-envs.alwaysUseUv": true, + "cmake.sourceDirectory": "/home/kuhy/testsAndMisc/pomodoro_app/linux" } diff --git a/python_pkg/screen_locker/_phone_verification.py b/python_pkg/screen_locker/_phone_verification.py index 513632f..869be3f 100644 --- a/python_pkg/screen_locker/_phone_verification.py +++ b/python_pkg/screen_locker/_phone_verification.py @@ -267,7 +267,7 @@ class PhoneVerificationMixin: Returns: True if the latest finish time is within 24 hours of now. """ - max_age_seconds = 24 * 3600 + max_age_seconds = 24 * 3600 # accept same-day workouts try: conn = sqlite3.connect(str(db_path)) try: diff --git a/python_pkg/screen_locker/screen_lock.py b/python_pkg/screen_locker/screen_lock.py index adb9569..f25855c 100755 --- a/python_pkg/screen_locker/screen_lock.py +++ b/python_pkg/screen_locker/screen_lock.py @@ -304,7 +304,9 @@ class ScreenLocker( "HMAC key unavailable — accepting unsigned entry", ) return True - _logger.warning("HMAC verification failed for today's log entry") + _logger.warning( + "HMAC verification failed for today's log entry", + ) return False def _load_existing_logs(self) -> dict: diff --git a/python_pkg/screen_locker/tests/test_adb_and_phone.py b/python_pkg/screen_locker/tests/test_adb_and_phone.py index 17cef56..171adf5 100644 --- a/python_pkg/screen_locker/tests/test_adb_and_phone.py +++ b/python_pkg/screen_locker/tests/test_adb_and_phone.py @@ -795,7 +795,7 @@ class TestIsWorkoutFinishRecent: mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: - """Test returns False for workout that finished >4 hours ago.""" + """Test returns False for workout that finished >24 hours ago.""" locker = create_locker(mock_tk, tmp_path) db_file = tmp_path / "sl_test.db" conn = sqlite3.connect(str(db_file)) @@ -803,9 +803,9 @@ class TestIsWorkoutFinishRecent: "CREATE TABLE workouts " "(id TEXT PRIMARY KEY, start INTEGER, finish INTEGER)", ) - # Finished 5 hours ago (but still "today" in local time) + # Finished 25 hours ago (not "today" in local time either) now_ms = int(time.time() * 1000) - old_finish = now_ms - 5 * 3600 * 1000 + old_finish = now_ms - 25 * 3600 * 1000 # beyond 24h window conn.execute( "INSERT INTO workouts VALUES (?, ?, ?)", ("w1", old_finish - 3600000, old_finish), diff --git a/python_pkg/screen_locker/tests/test_init_and_log.py b/python_pkg/screen_locker/tests/test_init_and_log.py index c74e110..c08e8bb 100644 --- a/python_pkg/screen_locker/tests/test_init_and_log.py +++ b/python_pkg/screen_locker/tests/test_init_and_log.py @@ -154,6 +154,60 @@ class TestHasLoggedToday: ): assert locker.has_logged_today() is False + def test_today_unsigned_entry_no_hmac_key( + self, + mock_tk: MagicMock, + mock_sys_exit: MagicMock, + tmp_path: Path, + ) -> None: + """Accept unsigned entry when HMAC key is unavailable.""" + log_file = tmp_path / "workout_log.json" + today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d") + log_file.write_text( + json.dumps({today: {"workout": "data"}}), + ) + + locker = create_locker(mock_tk, tmp_path) + locker.log_file = log_file + with ( + patch( + "python_pkg.screen_locker.screen_lock.verify_entry_hmac", + return_value=False, + ), + patch( + "python_pkg.screen_locker.screen_lock._load_hmac_key", + return_value=None, + ), + ): + assert locker.has_logged_today() is True + + def test_today_unsigned_entry_with_hmac_key( + self, + mock_tk: MagicMock, + mock_sys_exit: MagicMock, + tmp_path: Path, + ) -> None: + """Reject unsigned entry when HMAC key IS available.""" + log_file = tmp_path / "workout_log.json" + today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d") + log_file.write_text( + json.dumps({today: {"workout": "data"}}), + ) + + locker = create_locker(mock_tk, tmp_path) + locker.log_file = log_file + with ( + patch( + "python_pkg.screen_locker.screen_lock.verify_entry_hmac", + return_value=False, + ), + patch( + "python_pkg.screen_locker.screen_lock._load_hmac_key", + return_value=b"secret-key", + ), + ): + assert locker.has_logged_today() is False + def test_other_day_logged( self, mock_tk: MagicMock, diff --git a/scripts/pytest_changed_packages.py b/scripts/pytest_changed_packages.py index b08a746..e2c0ae8 100755 --- a/scripts/pytest_changed_packages.py +++ b/scripts/pytest_changed_packages.py @@ -12,12 +12,10 @@ all tests are run as a fallback. from __future__ import annotations from pathlib import Path, PurePosixPath -import shutil import subprocess import sys _MIN_SUBPACKAGE_DEPTH = 2 -_MEMORY_CAP = "3G" def _affected_packages(files: list[str]) -> set[str] | None: @@ -90,19 +88,8 @@ def main() -> int: return 0 # Run each package in its own subprocess so memory is freed between runs. - # Wrap in systemd-run cgroup to hard-cap memory per package. - use_cgroup = shutil.which("systemd-run") is not None for pkg in sorted(packages): cmd = _build_pytest_command({pkg}) - if use_cgroup: - cmd = [ - "systemd-run", - "--user", - "--scope", - "-p", - f"MemoryMax={_MEMORY_CAP}", - *cmd, - ] result = subprocess.run(cmd, check=False) if result.returncode != 0: return result.returncode