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"]