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:
@@ -0,0 +1,89 @@
|
||||
import json
|
||||
import pytest
|
||||
import httpx
|
||||
import respx
|
||||
from server.gitea_mcp import list_branches, get_branch, create_branch, delete_branch, list_tags
|
||||
|
||||
BASE = "https://gitea.test/api/v1"
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_list_branches():
|
||||
route = respx.get(f"{BASE}/repos/owner/repo/branches").mock(
|
||||
return_value=httpx.Response(200, json=[{"name": "main"}])
|
||||
)
|
||||
result = list_branches("owner", "repo")
|
||||
assert route.called
|
||||
assert result[0]["name"] == "main"
|
||||
assert dict(route.calls[0].request.url.params)["limit"] == "50"
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_get_branch():
|
||||
route = respx.get(f"{BASE}/repos/owner/repo/branches/main").mock(
|
||||
return_value=httpx.Response(200, json={"name": "main"})
|
||||
)
|
||||
result = get_branch("owner", "repo", "main")
|
||||
assert route.called
|
||||
assert result["name"] == "main"
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_get_branch_with_slash_in_name():
|
||||
route = respx.get(f"{BASE}/repos/owner/repo/branches/feature%2Ffoo").mock(
|
||||
return_value=httpx.Response(200, json={"name": "feature/foo"})
|
||||
)
|
||||
result = get_branch("owner", "repo", "feature/foo")
|
||||
assert route.called
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_get_branch_not_found():
|
||||
respx.get(f"{BASE}/repos/owner/repo/branches/missing").mock(
|
||||
return_value=httpx.Response(404, json={"message": "not found"})
|
||||
)
|
||||
with pytest.raises(RuntimeError, match="404"):
|
||||
get_branch("owner", "repo", "missing")
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_create_branch():
|
||||
route = respx.post(f"{BASE}/repos/owner/repo/branches").mock(
|
||||
return_value=httpx.Response(201, json={"name": "feature/new"})
|
||||
)
|
||||
result = create_branch("owner", "repo", "feature/new")
|
||||
assert route.called
|
||||
body = json.loads(route.calls[0].request.content)
|
||||
assert body["new_branch_name"] == "feature/new"
|
||||
assert "old_branch_name" not in body
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_create_branch_from_specific():
|
||||
route = respx.post(f"{BASE}/repos/owner/repo/branches").mock(
|
||||
return_value=httpx.Response(201, json={"name": "hotfix"})
|
||||
)
|
||||
create_branch("owner", "repo", "hotfix", old_branch_name="main")
|
||||
body = json.loads(route.calls[0].request.content)
|
||||
assert body["old_branch_name"] == "main"
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_delete_branch():
|
||||
route = respx.delete(f"{BASE}/repos/owner/repo/branches/old-branch").mock(
|
||||
return_value=httpx.Response(204)
|
||||
)
|
||||
result = delete_branch("owner", "repo", "old-branch")
|
||||
assert route.called
|
||||
assert result == {"success": True}
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_list_tags():
|
||||
route = respx.get(f"{BASE}/repos/owner/repo/tags").mock(
|
||||
return_value=httpx.Response(200, json=[{"name": "v1.0.0"}])
|
||||
)
|
||||
result = list_tags("owner", "repo")
|
||||
assert route.called
|
||||
assert result[0]["name"] == "v1.0.0"
|
||||
assert dict(route.calls[0].request.url.params)["limit"] == "20"
|
||||
Reference in New Issue
Block a user