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

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:
2026-06-23 00:47:40 +00:00
parent 34e33995c4
commit e773067106
28 changed files with 2737 additions and 0 deletions
+170
View File
@@ -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)
+77
View File
@@ -0,0 +1,77 @@
# retoor <retoor@molodetz.nl>
import time
import pytest
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table, refresh_snapshot, set_setting
JSON = {"Accept": "application/json"}
_counter_st = [0]
@pytest.fixture(scope="module", autouse=True)
def _settings(app_server):
set_setting("rate_limit_per_minute", "1000000")
set_setting("registration_open", "1")
yield
def _admin(seeded_db):
refresh_snapshot()
key = get_table("users").find_one(username="alice_test")["api_key"]
s = requests.Session()
s.headers.update({"X-API-KEY": key, **JSON})
return s
def _member():
_counter_st[0] += 1
name = f"stmem{int(time.time() * 1000)}{_counter_st[0]}"
requests.post(
f"{BASE_URL}/auth/signup",
data={
"username": name,
"email": f"{name}@t.dev",
"password": "secret123",
"confirm_password": "secret123",
},
allow_redirects=True,
)
refresh_snapshot()
s = requests.Session()
s.headers.update(
{"X-API-KEY": get_table("users").find_one(username=name)["api_key"], **JSON}
)
return s
def test_member_cannot_change_status(app_server):
member = _member()
r = member.post(
f"{BASE_URL}/issues/1/status", data={"status": "closed"}
)
assert r.status_code == 403
def test_guest_cannot_change_status(app_server):
r = requests.post(
f"{BASE_URL}/issues/1/status",
headers=JSON,
data={"status": "closed"},
allow_redirects=False,
)
assert r.status_code in (401, 303)
def test_invalid_status_value_rejected(seeded_db):
admin = _admin(seeded_db)
r = admin.post(f"{BASE_URL}/issues/1/status", data={"status": "banana"})
assert r.status_code == 422
def test_admin_passes_authz_gate(seeded_db):
admin = _admin(seeded_db)
r = admin.post(f"{BASE_URL}/issues/1/status", data={"status": "closed"})
assert r.status_code != 403
assert r.status_code in (200, 502, 503, 404)