feat: add test suites for backup schedules, service config, auth token, bookmarks, content permissions, devii adopt, and devrant auth
DevPlace CI / test (push) Successful in 35m0s
DevPlace CI / test (push) Successful in 35m0s
Add comprehensive test coverage for seven new API areas: - Backup schedules CRUD operations in admin panel - Service configuration saving and retrieval for news AI model - Token authentication with email/username and JSON body support - Bookmarking for project and news targets with invalid type validation - Content permissions testing with member and admin session fixtures - Devii adopt endpoint redirect behavior and session cookie handling - Devrant authentication flow with user registration and token retrieval
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
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]}",
|
||||
"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]}",
|
||||
"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)
|
||||
Reference in New Issue
Block a user