mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 10:31:50 +01:00
feat: speed up and stabilise test suite (#676)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue # - Describe the motivation and context for this change. Refactors the test harness for faster and more reliable feedback: adds deterministic time freezing for update checks, accelerates and refactors smoke tests to run in-process, defaults pytest to xdist with durations tracking, and adjusts CI triggers so PRs run the test matrix only once. ## 📋 Changes Summary - add pytest-xdist + durations reporting defaults, force deterministic locale and slow markers, and document the workflow adjustments - run smoke tests in-process (no subprocess churn), mock update checks/logging, and mark slow specs appropriately - deflake update check interval tests by freezing datetime and simplify FixedDateTime helper - limit GitHub Actions `push` trigger to `main` so feature branches rely on the single pull_request run ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Ensure tests run in a consistent English locale and restore prior locale after each run * Mark integration scraping tests as slow for clearer categorization * Replace subprocess-based CLI tests with an in-process runner that returns structured results and captures combined stdout/stderr/logs; disable update checks during smoke tests * Freeze current time in update-check tests for deterministic assertions * Add mock for process enumeration in web‑scraping unit tests to stabilize macOS-specific warnings <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime, timedelta, timezone, tzinfo
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
@@ -18,11 +18,47 @@ import requests
|
||||
if TYPE_CHECKING:
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from kleinanzeigen_bot.model import update_check_state as update_check_state_module
|
||||
from kleinanzeigen_bot.model.config_model import Config
|
||||
from kleinanzeigen_bot.model.update_check_state import UpdateCheckState
|
||||
from kleinanzeigen_bot.update_checker import UpdateChecker
|
||||
|
||||
|
||||
def _freeze_update_state_datetime(monkeypatch:pytest.MonkeyPatch, fixed_now:datetime) -> None:
|
||||
"""Patch UpdateCheckState to return a deterministic datetime.now/utcnow."""
|
||||
|
||||
class FixedDateTime(datetime):
|
||||
@classmethod
|
||||
def now(cls, tz:tzinfo | None = None) -> "FixedDateTime":
|
||||
base = fixed_now.replace(tzinfo = None) if tz is None else fixed_now.astimezone(tz)
|
||||
return cls(
|
||||
base.year,
|
||||
base.month,
|
||||
base.day,
|
||||
base.hour,
|
||||
base.minute,
|
||||
base.second,
|
||||
base.microsecond,
|
||||
tzinfo = base.tzinfo
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def utcnow(cls) -> "FixedDateTime":
|
||||
base = fixed_now.astimezone(timezone.utc).replace(tzinfo = None)
|
||||
return cls(
|
||||
base.year,
|
||||
base.month,
|
||||
base.day,
|
||||
base.hour,
|
||||
base.minute,
|
||||
base.second,
|
||||
base.microsecond
|
||||
)
|
||||
|
||||
datetime_module = getattr(update_check_state_module, "datetime")
|
||||
monkeypatch.setattr(datetime_module, "datetime", FixedDateTime)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config() -> Config:
|
||||
return Config.model_validate({
|
||||
@@ -256,10 +292,12 @@ class TestUpdateChecker:
|
||||
# Should not raise an exception
|
||||
state.save(state_file)
|
||||
|
||||
def test_update_check_state_interval_units(self) -> None:
|
||||
def test_update_check_state_interval_units(self, monkeypatch:pytest.MonkeyPatch) -> None:
|
||||
"""Test that different interval units are handled correctly."""
|
||||
state = UpdateCheckState()
|
||||
now = datetime.now(timezone.utc)
|
||||
fixed_now = datetime(2025, 1, 15, 8, 0, tzinfo = timezone.utc)
|
||||
_freeze_update_state_datetime(monkeypatch, fixed_now)
|
||||
now = fixed_now
|
||||
|
||||
# Test seconds (should always be too short, fallback to 7d, only 2 days elapsed, so should_check is False)
|
||||
state.last_check = now - timedelta(seconds = 30)
|
||||
@@ -303,10 +341,14 @@ class TestUpdateChecker:
|
||||
state.last_check = now - timedelta(days = 6)
|
||||
assert state.should_check("1z") is False
|
||||
|
||||
def test_update_check_state_interval_validation(self) -> None:
|
||||
def test_update_check_state_interval_validation(self, monkeypatch:pytest.MonkeyPatch) -> None:
|
||||
"""Test that interval validation works correctly."""
|
||||
state = UpdateCheckState()
|
||||
now = datetime.now(timezone.utc)
|
||||
fixed_now = datetime(2025, 1, 1, 12, 0, tzinfo = timezone.utc)
|
||||
|
||||
_freeze_update_state_datetime(monkeypatch, fixed_now)
|
||||
|
||||
now = fixed_now
|
||||
state.last_check = now - timedelta(days = 1)
|
||||
|
||||
# Test minimum value (1d)
|
||||
|
||||
Reference in New Issue
Block a user