krz/hutch-stats
Server-side utility for calculating contributions for sourcehut users.
clone: git clone https://gitbay.org/krz/hutch-stats.git
main: tests/test_git_repository_cache.py · raw
1from datetime import UTC, datetime
2
3from sqlalchemy import select
4
5from srht_contrib.config import Settings
6from srht_contrib.jobs.poller import PollerService
7from srht_contrib.models import DiscoveredRepository
8from srht_contrib.services.git import GitIngestionService
9from srht_contrib.services.todo import TodoIngestionService
10
11
12class StubClient:
13 def __init__(self, payload: dict | None = None, payloads_by_query: dict[str, dict] | None = None) -> None:
14 self.payload = payload or {}
15 self.payloads_by_query = payloads_by_query or {}
16 self.calls: list[tuple[str, dict | None]] = []
17
18 def execute(self, query: str, variables: dict | None = None) -> dict:
19 self.calls.append((query, variables))
20 for marker, payload in self.payloads_by_query.items():
21 if marker in query:
22 return payload
23 return self.payload
24
25
26def make_settings(**overrides) -> Settings:
27 values = {
28 "API_KEY": "test-api-key",
29 "ENABLE_SCHEDULER": False,
30 "SRHT_TOKEN": "x",
31 "DATABASE_URL": "sqlite://",
32 "DEFAULT_ACTOR": "~ccleberg",
33 "TODO_SRHT_ENDPOINT": "https://todo.sr.ht/query",
34 "GIT_SRHT_ENDPOINT": "https://git.sr.ht/query",
35 "POLL_INTERVAL_SECONDS": 60,
36 "GIT_TRACKED_REPOSITORIES": [],
37 "ACTOR_ALIASES_JSON": {"~ccleberg": ["cmc@example.com", "Chris Cleberg"]},
38 }
39 values.update(overrides)
40 return Settings(**values)
41
42
43def branch_payload(*branches: str) -> dict:
44 return {
45 "user": {
46 "repository": {
47 "references": {
48 "results": [{"name": branch, "target": "abc123"} for branch in branches],
49 "cursor": None,
50 }
51 }
52 }
53 }
54
55
56def test_git_poll_reuses_cached_discovered_repositories(db_session) -> None:
57 settings = make_settings()
58 client = StubClient(
59 payloads_by_query={
60 "query UserRepositories": {
61 "user": {
62 "repositories": {
63 "results": [
64 {
65 "name": "Hutch",
66 "visibility": "PUBLIC",
67 "owner": {"canonicalName": "~ccleberg"},
68 }
69 ],
70 "cursor": None,
71 }
72 }
73 },
74 "query RepositoryBranches": branch_payload("refs/heads/main"),
75 "query RepositoryLog": {
76 "user": {
77 "repository": {
78 "name": "Hutch",
79 "owner": {"canonicalName": "~ccleberg"},
80 "log": {
81 "results": [
82 {
83 "id": "abc123",
84 "shortId": "abc123",
85 "author": {
86 "name": "Chris Cleberg",
87 "email": "cmc@example.com",
88 "time": "2026-03-30T12:00:00Z",
89 },
90 "committer": {
91 "name": "Chris Cleberg",
92 "email": "cmc@example.com",
93 "time": "2026-03-30T12:00:00Z",
94 },
95 "message": "Auto-discovered repo commit",
96 }
97 ],
98 "cursor": None,
99 },
100 }
101 }
102 },
103 }
104 )
105 todo_service = TodoIngestionService(
106 StubClient(payload={"me": {"canonicalName": "~ccleberg"}, "events": {"results": [], "cursor": None}}),
107 settings,
108 )
109 git_service = GitIngestionService(client, settings)
110 poller = PollerService(todo_service=todo_service, git_service=git_service, settings=settings)
111
112 first_inserted = poller.poll_all(db_session, "~ccleberg")
113 first_poll_user_repository_calls = [call for call in client.calls if "query UserRepositories" in call[0]]
114 second_inserted = poller.poll_all(db_session, "~ccleberg")
115
116 user_repository_calls = [call for call in client.calls if "query UserRepositories" in call[0]]
117 cached_names = db_session.scalars(select(DiscoveredRepository.name)).all()
118
119 assert first_inserted == 1
120 assert second_inserted == 0
121 assert len(user_repository_calls) == len(first_poll_user_repository_calls)
122 assert cached_names == ["~ccleberg/Hutch"]