Files
devplacepy/tests/unit/services/community/service.py
T

96 lines
3.9 KiB
Python
Raw Normal View History

2026-10-16 07:20:44 +02:00
# retoor <retoor@molodetz.nl>
from tests.conftest import run_async
import pytest
from devplacepy.database import get_setting, get_table, init_db, set_setting
from devplacepy.services.community.runner import CommunityRunner
from devplacepy.services.community.service import DRY_RUN_KEY, CommunityService
from devplacepy.services.community.spec import LIMITS, RUN_SKIPPED, STATUS_FAILING, STATUS_READY
2026-10-16 07:20:44 +02:00
from devplacepy.services.community.store import store
from tests.unit.services.community.fakes import FakeFetcher, json_community, no_sleep
@pytest.fixture
def world():
init_db()
previous = {key: get_setting(key, "") for key in ("sync_enabled", "sync_origins", DRY_RUN_KEY)}
set_setting("sync_enabled", "1")
set_setting("sync_origins", "")
get_table("communities").delete()
get_table("community_runs").delete()
get_table("sync_links").delete(origin="forum.test")
routes = json_community()
runner = CommunityRunner(fetcher_factory=lambda: FakeFetcher(routes), sleep=no_sleep)
yield routes, runner
for key, value in previous.items():
set_setting(key, value)
def seed(runner) -> dict:
store.create("forum-test", "https://forum.test/api/posts", "tester", name="forum")
run_async(runner.discover("https://forum.test/api/posts", "tester", relearn_slug="forum-test"))
return store.get("forum-test")
def test_dry_run_service_tick_learns_nothing_and_runs_nothing(world):
_, runner = world
store.create("forum-test", "https://forum.test/api/posts", "tester", name="forum")
set_setting(DRY_RUN_KEY, "1")
service = CommunityService(runner)
run_async(service.run_once())
assert store.get("forum-test")["status"] == "pending"
assert any("DRY RUN" in line for line in service.log_buffer)
def test_live_tick_learns_pending_then_runs_due(world):
_, runner = world
store.create("forum-test", "https://forum.test/api/posts", "tester", name="forum")
set_setting(DRY_RUN_KEY, "0")
service = CommunityService(runner)
run_async(service.run_once())
assert store.get("forum-test")["status"] == STATUS_READY
run_async(service.run_once())
row = store.get("forum-test")
assert row["run_count"] == 1
assert get_table("sync_links").count(origin="forum.test", kind="posts") == 10
run_async(service.run_once())
assert store.get("forum-test")["run_count"] == 1
def test_repeated_failures_disable_and_flag_the_community(world):
routes, runner = world
row = seed(runner)
routes["https://forum.test/api/posts"] = (500, "down")
failing = CommunityRunner(fetcher_factory=lambda: FakeFetcher(routes), sleep=no_sleep)
for _ in range(6):
current = store.get("forum-test")
report = run_async(failing.run(current, dry_run=False, trigger="test"))
assert report.status == "failed"
final = store.get("forum-test")
assert final["status"] == STATUS_FAILING and not final["enabled"]
assert "relearn" in "".join(store.runs(row["uid"])[0]["log"]).lower() or final["failure_count"] >= 5
def test_run_history_is_bounded(world):
_, runner = world
row = seed(runner)
for _ in range(35):
run_async(runner.run(store.get("forum-test"), dry_run=True, trigger="test"))
assert len(store.runs(row["uid"], limit=100)) == 30
def test_gate_refusal_skips_the_run_without_counting_a_failure(world):
_, runner = world
row = seed(runner)
set_setting("sync_enabled", "0")
for _ in range(LIMITS.max_failures + 1):
report = run_async(runner.run(store.get("forum-test"), dry_run=False, trigger="test"))
assert report.status == RUN_SKIPPED
final = store.get("forum-test")
assert final["status"] == STATUS_READY and final["enabled"]
assert final["failure_count"] == 0 and final["last_status"] == RUN_SKIPPED
assert final["next_run_at"] and get_table("sync_links").count(origin="forum.test") == 0
assert store.runs(row["uid"])[0]["status"] == RUN_SKIPPED