summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-12 11:43:27 -0500
committerChristian Cleberg <[email protected]>2026-04-12 11:43:27 -0500
commit4390684995c9933f213faec2cb20f39af6d506d2 (patch)
treefac5252756c038e9fdb3444a1a4d68863e1683f3 /tests
parentdaaeba8be8df4d0876312e540bdd420e16ff724c (diff)
downloadhutch-stats-4390684995c9933f213faec2cb20f39af6d506d2.tar.gz
hutch-stats-4390684995c9933f213faec2cb20f39af6d506d2.tar.bz2
hutch-stats-4390684995c9933f213faec2cb20f39af6d506d2.zip
add temporary self-graph indexing priority
Diffstat (limited to 'tests')
-rw-r--r--tests/test_contributions_api.py45
-rw-r--r--tests/test_ingestion.py88
-rw-r--r--tests/test_migrations.py9
-rw-r--r--tests/test_polling_api.py4
4 files changed, 143 insertions, 3 deletions
diff --git a/tests/test_contributions_api.py b/tests/test_contributions_api.py
index e568feb..29b19fb 100644
--- a/tests/test_contributions_api.py
+++ b/tests/test_contributions_api.py
@@ -7,6 +7,11 @@ from srht_contrib.main import create_app
from srht_contrib.models import ContributionEvent, TrackedActor
+class _Closable:
+ def close(self) -> None:
+ return None
+
+
def test_read_only_contribution_routes_are_public_and_write_routes_require_api_key(settings, db_engine, session_factory) -> None:
app = create_app(settings, engine=db_engine, session_factory=session_factory)
with TestClient(app) as open_client:
@@ -72,6 +77,24 @@ def test_public_read_registers_actor_for_lazy_indexing(client: TestClient, db_se
assert tracked_actor is not None
assert tracked_actor.is_active is True
assert tracked_actor.last_requested_at is not None
+ assert tracked_actor.priority_boosted_at is None
+
+
+class RecordingPriorityPoller:
+ def __init__(self) -> None:
+ service = type("Service", (), {"client": _Closable()})()
+ self.todo_service = service
+ self.git_service = service
+ self.calls: list[tuple[str, bool]] = []
+
+ def track_actor_request(self, db, actor: str, *, update_last_requested: bool = True, prioritize: bool = False):
+ self.calls.append((actor, prioritize))
+
+ def poll_all(self, db, actor: str) -> int:
+ return 0
+
+ def poll_tracked_actors(self, db, default_actor: str | None = None) -> dict[str, int]:
+ return {}
def test_contribution_stats_api(client: TestClient, db_session) -> None:
@@ -148,3 +171,25 @@ def test_contribution_routes_use_settings_backed_alias_resolution(settings, db_e
assert response.status_code == 200
assert response.json()["actor"] == "~ccleberg"
+
+
+def test_contribution_route_passes_explicit_priority_signal(settings, db_engine, session_factory) -> None:
+ poller = RecordingPriorityPoller()
+ app = create_app(settings, engine=db_engine, session_factory=session_factory, poller=poller)
+
+ with TestClient(app) as client:
+ response = client.get("/api/contributions/~ccleberg?from=2026-03-28&to=2026-03-30&prioritize_self=true")
+
+ assert response.status_code == 200
+ assert poller.calls == [("~ccleberg", True)]
+
+
+def test_contribution_stats_route_keeps_non_prioritized_registration_by_default(settings, db_engine, session_factory) -> None:
+ poller = RecordingPriorityPoller()
+ app = create_app(settings, engine=db_engine, session_factory=session_factory, poller=poller)
+
+ with TestClient(app) as client:
+ response = client.get("/api/contributions/~ccleberg/stats?from=2026-03-28&to=2026-03-30")
+
+ assert response.status_code == 200
+ assert poller.calls == [("~ccleberg", False)]
diff --git a/tests/test_ingestion.py b/tests/test_ingestion.py
index 6a1a162..6c06359 100644
--- a/tests/test_ingestion.py
+++ b/tests/test_ingestion.py
@@ -711,6 +711,94 @@ def test_poll_tracked_actors_limits_to_due_batch_size(db_session) -> None:
assert actors["~c"].poll_attempts == 0
+def test_track_actor_request_prioritize_marks_actor_boosted_and_due_now(db_session) -> None:
+ settings = make_settings(INDEXED_ACTOR_REPOLL_SECONDS=3600)
+ poller = PollerService(todo_service=RecordingTodoService(events_by_call=[[]]), git_service=EmptyGitService(), settings=settings)
+ future_due = datetime.now(tz=UTC) + timedelta(hours=2)
+ db_session.add(
+ TrackedActor(
+ actor="~self",
+ is_active=True,
+ discovery_state="indexed",
+ queued_for_discovery_at=datetime.now(tz=UTC) - timedelta(hours=1),
+ next_poll_after=future_due,
+ recent_backfill_status="completed",
+ )
+ )
+ db_session.commit()
+
+ tracked_actor = poller.track_actor_request(db_session, "~self", prioritize=True)
+
+ assert tracked_actor.priority_boosted_at is not None
+ assert tracked_actor.next_poll_after is not None
+ assert tracked_actor.next_poll_after <= tracked_actor.priority_boosted_at
+
+
+def test_poll_tracked_actors_prioritizes_boosted_due_actor_first(db_session) -> None:
+ settings = make_settings(DISCOVERY_BATCH_SIZE=1, INDEXED_ACTOR_REPOLL_SECONDS=3600)
+ todo_service = RecordingTodoService(events_by_call=[[]])
+ poller = PollerService(todo_service=todo_service, git_service=EmptyGitService(), settings=settings)
+
+ now = datetime.now(tz=UTC)
+ db_session.add_all(
+ [
+ TrackedActor(
+ actor="~normal",
+ is_active=True,
+ discovery_state="queued",
+ queued_for_discovery_at=now - timedelta(minutes=10),
+ next_poll_after=now - timedelta(minutes=10),
+ recent_backfill_status="completed",
+ ),
+ TrackedActor(
+ actor="~self",
+ is_active=True,
+ discovery_state="queued",
+ queued_for_discovery_at=now - timedelta(minutes=1),
+ next_poll_after=now - timedelta(minutes=1),
+ priority_boosted_at=now,
+ recent_backfill_status="completed",
+ ),
+ ]
+ )
+ db_session.commit()
+
+ results = poller.poll_tracked_actors(db_session)
+
+ assert list(results) == ["~self"]
+ remaining = {
+ actor.actor: actor.discovery_state
+ for actor in db_session.scalars(select(TrackedActor).order_by(TrackedActor.actor)).all()
+ }
+ assert remaining["~self"] == "indexed"
+ assert remaining["~normal"] == "queued"
+
+
+def test_successful_poll_clears_temporary_priority_boost(db_session) -> None:
+ settings = make_settings(INDEXED_ACTOR_REPOLL_SECONDS=3600)
+ poller = PollerService(todo_service=RecordingTodoService(events_by_call=[[]]), git_service=EmptyGitService(), settings=settings)
+ now = datetime.now(tz=UTC)
+ db_session.add(
+ TrackedActor(
+ actor="~self",
+ is_active=True,
+ discovery_state="queued",
+ queued_for_discovery_at=now - timedelta(minutes=1),
+ next_poll_after=now - timedelta(minutes=1),
+ priority_boosted_at=now - timedelta(seconds=30),
+ recent_backfill_status="completed",
+ )
+ )
+ db_session.commit()
+
+ poller.poll_all(db_session, "~self")
+
+ tracked_actor = db_session.scalar(select(TrackedActor).where(TrackedActor.actor == "~self"))
+ assert tracked_actor is not None
+ assert tracked_actor.discovery_state == "indexed"
+ assert tracked_actor.priority_boosted_at is None
+
+
def test_enqueue_actors_staggers_without_polling(tmp_path, monkeypatch) -> None:
database_path = tmp_path / "enqueue.db"
username_path = tmp_path / "srht_usernames.txt"
diff --git a/tests/test_migrations.py b/tests/test_migrations.py
index 3ce842b..e646ccf 100644
--- a/tests/test_migrations.py
+++ b/tests/test_migrations.py
@@ -122,7 +122,14 @@ def test_alembic_upgrade_adopts_legacy_schema(tmp_path) -> None:
assert "discovered_repositories" in inspector.get_table_names()
assert "tracked_actors" in inspector.get_table_names()
assert "service_backfill_states" in inspector.get_table_names()
- assert {"discovery_state", "queued_for_discovery_at", "next_poll_after", "last_claimed_at", "poll_attempts"} <= tracked_actor_columns
+ assert {
+ "discovery_state",
+ "queued_for_discovery_at",
+ "priority_boosted_at",
+ "next_poll_after",
+ "last_claimed_at",
+ "poll_attempts",
+ } <= tracked_actor_columns
def test_alembic_prefers_database_url_from_environment(tmp_path, monkeypatch) -> None:
diff --git a/tests/test_polling_api.py b/tests/test_polling_api.py
index b752524..94188da 100644
--- a/tests/test_polling_api.py
+++ b/tests/test_polling_api.py
@@ -21,7 +21,7 @@ class InsertingPoller:
self.git_service = service
self.tracked_poll_calls: list[str] = []
- def track_actor_request(self, db, actor: str, *, update_last_requested: bool = True):
+ def track_actor_request(self, db, actor: str, *, update_last_requested: bool = True, prioritize: bool = False):
tracked_actor = db.scalar(select(TrackedActor).where(TrackedActor.actor == actor))
if tracked_actor is None:
tracked_actor = TrackedActor(actor=actor, is_active=True)
@@ -61,7 +61,7 @@ class FailingPoller:
self.todo_service = service
self.git_service = service
- def track_actor_request(self, db, actor: str, *, update_last_requested: bool = True):
+ def track_actor_request(self, db, actor: str, *, update_last_requested: bool = True, prioritize: bool = False):
tracked_actor = db.scalar(select(TrackedActor).where(TrackedActor.actor == actor))
if tracked_actor is None:
tracked_actor = TrackedActor(actor=actor, is_active=True)