test: suite pytest (36 tests) et CI Gitea Actions
Modèles (chemin DB, migration 0.1.0, ordre, réconciliation), classification, client Gitea (pagination, en-tête, écritures), API (CSRF, write-back, codes d'erreur, 502 propre), auth Basic et fail-closed. Tous verts; pyflakes propre.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
"""Gitea client: pagination, auth header, write operations (audit I2/M9)."""
|
||||
|
||||
import httpx
|
||||
|
||||
from app.gitea_client import PAGE_SIZE, GiteaClient
|
||||
|
||||
|
||||
def _client(handler, token=""):
|
||||
return GiteaClient(
|
||||
base_url="http://gitea.test",
|
||||
token=token,
|
||||
cache_ttl=0,
|
||||
transport=httpx.MockTransport(handler),
|
||||
)
|
||||
|
||||
|
||||
async def test_pagination_follows_until_short_page():
|
||||
seen_pages = []
|
||||
|
||||
def handler(request):
|
||||
if request.url.path.endswith("/user"):
|
||||
return httpx.Response(200, json={"id": 7})
|
||||
page = int(request.url.params.get("page", "1"))
|
||||
seen_pages.append(page)
|
||||
count = PAGE_SIZE if page == 1 else 25
|
||||
start = (page - 1) * PAGE_SIZE
|
||||
data = [{"id": start + i} for i in range(count)]
|
||||
return httpx.Response(200, json={"data": data}, headers={"X-Total-Count": "75"})
|
||||
|
||||
client = _client(handler)
|
||||
repos = await client.search_repos()
|
||||
assert len(repos) == 75
|
||||
assert seen_pages.count(1) >= 1 and 2 in seen_pages
|
||||
|
||||
|
||||
async def test_pagination_without_total_header():
|
||||
def handler(request):
|
||||
page = int(request.url.params.get("page", "1"))
|
||||
count = PAGE_SIZE if page == 1 else 10
|
||||
return httpx.Response(200, json=[{"number": i} for i in range(count)])
|
||||
|
||||
client = _client(handler)
|
||||
issues = await client.get_repo_issues("o", "r", state="open")
|
||||
assert len(issues) == PAGE_SIZE + 10
|
||||
|
||||
|
||||
async def test_search_uses_authenticated_user_id_not_hardcoded():
|
||||
seen = {}
|
||||
|
||||
def handler(request):
|
||||
if request.url.path.endswith("/user"):
|
||||
return httpx.Response(200, json={"id": 42})
|
||||
seen["uid"] = request.url.params.get("uid")
|
||||
return httpx.Response(200, json={"data": []})
|
||||
|
||||
client = _client(handler)
|
||||
await client.search_repos()
|
||||
assert seen["uid"] == "42"
|
||||
|
||||
|
||||
async def test_authorization_header_only_with_token():
|
||||
captured = {}
|
||||
|
||||
def handler(request):
|
||||
captured["auth"] = request.headers.get("authorization")
|
||||
return httpx.Response(200, json={"version": "1.27.3"})
|
||||
|
||||
await _client(handler, token="").ping()
|
||||
assert captured["auth"] is None
|
||||
|
||||
await _client(handler, token="sekret").ping()
|
||||
assert captured["auth"] == "token sekret"
|
||||
|
||||
|
||||
async def test_set_issue_state_patches_gitea():
|
||||
captured = {}
|
||||
|
||||
def handler(request):
|
||||
captured["method"] = request.method
|
||||
captured["path"] = request.url.path
|
||||
captured["json"] = request.content.decode()
|
||||
return httpx.Response(200, json={"state": "closed"})
|
||||
|
||||
client = _client(handler, token="x")
|
||||
await client.set_issue_state("Projets", "demo", 3, "closed")
|
||||
assert captured["method"] == "PATCH"
|
||||
assert captured["path"].endswith("/repos/Projets/demo/issues/3")
|
||||
assert '"closed"' in captured["json"]
|
||||
|
||||
|
||||
async def test_create_issue_posts_title():
|
||||
def handler(request):
|
||||
assert request.method == "POST"
|
||||
return httpx.Response(201, json={"number": 9, "title": "Nouvelle"})
|
||||
|
||||
client = _client(handler, token="x")
|
||||
issue = await client.create_issue("Projets", "demo", "Nouvelle")
|
||||
assert issue["number"] == 9
|
||||
Reference in New Issue
Block a user