# retoor from datetime import datetime, timezone import pytest from fastapi.testclient import TestClient from devplacepy.main import app from devplacepy.database import ( get_table, get_primary_admin_uid, invalidate_admins_cache, refresh_snapshot, set_setting, ) from devplacepy.utils import generate_uid, clear_user_cache from devplacepy.services.gitea import runtime from devplacepy.services.gitea.fake import FakeGiteaClient from devplacepy.services.gitea.client import STATE_OPEN from devplacepy.services.gitea.config import GiteaConfig JSON = {"Accept": "application/json"} def _configured() -> GiteaConfig: return GiteaConfig( base_url="https://gitea.test", owner="retoor", repo="devplacepy", token="test-token", ai_enhance=False, ai_model="x", ai_key="x", ) @pytest.fixture def client(): with TestClient(app) as test_client: yield test_client @pytest.fixture def admin_headers(client): users = get_table("users") uid = get_primary_admin_uid() if uid is None: uid = generate_uid() users.insert( { "uid": uid, "username": f"gitea_admin_{uid[:8]}", "terms_version": "1", "email": f"{uid[:8]}@gitea.test", "role": "Admin", "api_key": f"giteakey_{uid}", "is_active": True, "xp": 0, "level": 1, "created_at": datetime.now(timezone.utc).isoformat(), } ) invalidate_admins_cache() refresh_snapshot() admin = users.find_one(uid=uid) key = admin.get("api_key") if not key: key = f"giteakey_{uid}" users.update({"uid": uid, "api_key": key}, ["uid"]) clear_user_cache(uid) refresh_snapshot() return {"X-API-KEY": key, **JSON} @pytest.fixture def member_headers(client): users = get_table("users") uid = generate_uid() key = f"giteamemberkey_{uid}" users.insert( { "uid": uid, "username": f"gitea_member_{uid[:8]}", "terms_version": "1", "email": f"{uid[:8]}@giteamember.test", "role": "Member", "api_key": key, "is_active": True, "xp": 0, "level": 1, "created_at": datetime.now(timezone.utc).isoformat(), } ) refresh_snapshot() return {"X-API-KEY": key, **JSON} @pytest.fixture def gitea(client, monkeypatch): monkeypatch.setattr( "devplacepy.routers.issues.status.gitea_config", _configured ) monkeypatch.setattr( "devplacepy.routers.issues.comment.gitea_config", _configured ) fake = FakeGiteaClient() now = datetime.now(timezone.utc).isoformat() fake._issues[1] = { "number": 1, "title": "Existing issue", "body": "body", "state": STATE_OPEN, "html_url": "https://gitea.test/retoor/devplacepy/issues/1", "user": {"login": "devplace-bot"}, "comments": 0, "created_at": now, "updated_at": now, "closed_at": None, } fake._comments[1] = [] runtime.set_client(fake) yield fake runtime.set_client(None) set_setting("gitea_token", "") def test_admin_closes_issue(client, admin_headers, gitea): r = client.post("/issues/1/status", data={"status": "closed"}, headers=admin_headers) assert r.status_code == 200, r.text[:300] assert gitea._issues[1]["state"] == "closed" def test_admin_reopens_issue(client, admin_headers, gitea): gitea._issues[1]["state"] = "closed" r = client.post("/issues/1/status", data={"status": "open"}, headers=admin_headers) assert r.status_code == 200, r.text[:300] assert gitea._issues[1]["state"] == "open" def test_member_cannot_change_status(client, member_headers, gitea): r = client.post("/issues/1/status", data={"status": "closed"}, headers=member_headers) assert r.status_code == 403 assert gitea._issues[1]["state"] == "open" def test_status_unknown_issue_propagates_gitea_error(client, admin_headers, gitea): r = client.post("/issues/999/status", data={"status": "closed"}, headers=admin_headers) assert r.status_code in (404, 502) def test_status_not_configured_503(client, admin_headers): set_setting("gitea_token", "") runtime.set_client(None) try: r = client.post("/issues/1/status", data={"status": "closed"}, headers=admin_headers) assert r.status_code == 503 finally: set_setting("gitea_token", "") def test_member_posts_comment(client, member_headers, gitea): r = client.post( "/issues/1/comment", data={"body": "a helpful comment"}, headers=member_headers ) assert r.status_code == 200, r.text[:300] assert len(gitea._comments[1]) == 1 assert gitea._comments[1][0]["body"] def test_comment_requires_auth(client, gitea): r = client.post("/issues/1/comment", data={"body": "hi"}, headers=JSON) assert r.status_code in (401, 303)