test: add 106 unit + smoke tests, 93% coverage

- pytest + respx + pytest-cov added as dev dependencies
- tests/smoke/test_registration.py: verify all 66 tools registered and unique
- tests/unit/: 12 files covering every tool — HTTP method, URL, params/body, errors
- tests/config.test.json + conftest.py: zero-network test setup via GITEA_CONFIG
- CLAUDE.md: developer guide with testing philosophy, pyramid, and commands
- server/gitea_mcp.py: get_commit, list_pr_files tools added
- README.md: tool count corrected to 66
This commit is contained in:
2026-06-08 09:09:44 +03:00
parent 50cd8e85e6
commit a6162a855c
23 changed files with 1722 additions and 4 deletions
+68
View File
@@ -0,0 +1,68 @@
import json
import pytest
import httpx
import respx
from server.gitea_mcp import list_repo_webhooks, create_repo_webhook, delete_repo_webhook
BASE = "https://gitea.test/api/v1"
@respx.mock
def test_list_repo_webhooks():
route = respx.get(f"{BASE}/repos/owner/repo/hooks").mock(
return_value=httpx.Response(200, json=[{"id": 1, "type": "gitea"}])
)
result = list_repo_webhooks("owner", "repo")
assert route.called
assert result[0]["id"] == 1
@respx.mock
def test_create_repo_webhook_minimal():
route = respx.post(f"{BASE}/repos/owner/repo/hooks").mock(
return_value=httpx.Response(201, json={"id": 2})
)
create_repo_webhook("owner", "repo", "https://example.com/hook", ["push"])
assert route.called
body = json.loads(route.calls[0].request.content)
assert body["type"] == "gitea"
assert body["config"]["url"] == "https://example.com/hook"
assert body["config"]["content_type"] == "json"
assert "secret" not in body["config"]
assert body["events"] == ["push"]
assert body["active"] is True
@respx.mock
def test_create_repo_webhook_with_secret():
route = respx.post(f"{BASE}/repos/owner/repo/hooks").mock(
return_value=httpx.Response(201, json={"id": 3})
)
create_repo_webhook(
"owner", "repo", "https://ci.example.com/hook",
["push", "pull_request", "issues"],
secret="mysecret", active=False,
)
body = json.loads(route.calls[0].request.content)
assert body["config"]["secret"] == "mysecret"
assert body["events"] == ["push", "pull_request", "issues"]
assert body["active"] is False
@respx.mock
def test_delete_repo_webhook():
route = respx.delete(f"{BASE}/repos/owner/repo/hooks/7").mock(
return_value=httpx.Response(204)
)
result = delete_repo_webhook("owner", "repo", 7)
assert route.called
assert result == {"success": True}
@respx.mock
def test_create_repo_webhook_error():
respx.post(f"{BASE}/repos/owner/repo/hooks").mock(
return_value=httpx.Response(422, json={"message": "invalid url"})
)
with pytest.raises(RuntimeError, match="422"):
create_repo_webhook("owner", "repo", "not-a-url", ["push"])