209 lines
7.6 KiB
Python
209 lines
7.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Tests for Gitea API module."""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import patch, MagicMock
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
import threading
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
from tools.gitea_api import GiteaClient, GiteaAPIError
|
|
|
|
|
|
class TestGiteaClientInit(unittest.TestCase):
|
|
"""Test client initialization."""
|
|
|
|
def test_init_with_explicit_params(self):
|
|
c = GiteaClient(base_url="http://localhost:3000", token="test123")
|
|
self.assertEqual(c.base_url, "http://localhost:3000")
|
|
self.assertEqual(c.token, "test123")
|
|
|
|
def test_init_strips_trailing_slash(self):
|
|
c = GiteaClient(base_url="http://localhost:3000/", token="test")
|
|
self.assertEqual(c.base_url, "http://localhost:3000")
|
|
|
|
def test_init_no_token_raises(self):
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
os.environ.pop("GITEA_TOKEN", None)
|
|
with self.assertRaises(ValueError):
|
|
GiteaClient(token="")
|
|
|
|
@patch.dict(os.environ, {"GITEA_TOKEN": "envtoken123", "GITEA_URL": "http://env:3000"})
|
|
def test_init_from_env(self):
|
|
c = GiteaClient()
|
|
self.assertEqual(c.token, "envtoken123")
|
|
self.assertEqual(c.base_url, "http://env:3000")
|
|
|
|
def test_headers(self):
|
|
c = GiteaClient(base_url="http://test", token="tok123")
|
|
h = c._headers()
|
|
self.assertEqual(h["Authorization"], "token tok123")
|
|
self.assertEqual(h["Content-Type"], "application/json")
|
|
|
|
|
|
class TestGiteaAPIError(unittest.TestCase):
|
|
"""Test error class."""
|
|
|
|
def test_error_message(self):
|
|
e = GiteaAPIError(401, "Unauthorized", "http://test/api")
|
|
self.assertEqual(e.status_code, 401)
|
|
self.assertIn("401", str(e))
|
|
self.assertIn("Unauthorized", str(e))
|
|
|
|
def test_error_no_url(self):
|
|
e = GiteaAPIError(500, "Server Error")
|
|
self.assertEqual(e.url, "")
|
|
|
|
|
|
class MockGiteaHandler(BaseHTTPRequestHandler):
|
|
"""Mock Gitea API server for integration tests."""
|
|
|
|
def do_GET(self):
|
|
if self.path == "/api/v1/user":
|
|
self._json_response(200, {"login": "ezra", "id": 19})
|
|
elif self.path.startswith("/api/v1/repos/ezra/test/issues"):
|
|
self._json_response(200, [
|
|
{"number": 1, "title": "Test issue", "state": "open", "labels": []},
|
|
])
|
|
elif self.path.startswith("/api/v1/repos/ezra/test/labels"):
|
|
self._json_response(200, [
|
|
{"id": 1, "name": "bug", "color": "#e11d48"},
|
|
])
|
|
elif self.path.startswith("/api/v1/repos/ezra/test/milestones"):
|
|
self._json_response(200, [])
|
|
elif self.path == "/api/v1/user/repos?limit=50":
|
|
self._json_response(200, [{"full_name": "ezra/test", "description": "test repo"}])
|
|
elif self.path == "/api/v1/repos/ezra/test":
|
|
self._json_response(200, {"full_name": "ezra/test"})
|
|
elif self.path == "/api/v1/repos/ezra/notfound":
|
|
self._json_response(404, {"message": "not found"})
|
|
else:
|
|
self._json_response(404, {"message": "not found"})
|
|
|
|
def do_POST(self):
|
|
content_len = int(self.headers.get("Content-Length", 0))
|
|
body = json.loads(self.rfile.read(content_len)) if content_len else {}
|
|
|
|
if self.path == "/api/v1/repos/ezra/test/issues":
|
|
self._json_response(201, {
|
|
"number": 42, "title": body.get("title", ""), "state": "open",
|
|
})
|
|
elif self.path.startswith("/api/v1/repos/ezra/test/issues/") and "/comments" in self.path:
|
|
self._json_response(201, {"id": 1, "body": body.get("body", "")})
|
|
elif self.path == "/api/v1/repos/ezra/test/labels":
|
|
self._json_response(201, {"id": 2, "name": body.get("name", ""), "color": body.get("color", "")})
|
|
elif self.path == "/api/v1/repos/ezra/test/milestones":
|
|
self._json_response(201, {"id": 1, "title": body.get("title", "")})
|
|
else:
|
|
self._json_response(404, {"message": "not found"})
|
|
|
|
def do_PATCH(self):
|
|
content_len = int(self.headers.get("Content-Length", 0))
|
|
body = json.loads(self.rfile.read(content_len)) if content_len else {}
|
|
|
|
if "/issues/" in self.path:
|
|
self._json_response(200, {"number": 1, "state": body.get("state", "open")})
|
|
else:
|
|
self._json_response(404, {"message": "not found"})
|
|
|
|
def _json_response(self, code, data):
|
|
self.send_response(code)
|
|
self.send_header("Content-Type", "application/json")
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps(data).encode())
|
|
|
|
def log_message(self, *args):
|
|
pass # Silence request logging
|
|
|
|
|
|
class TestGiteaClientIntegration(unittest.TestCase):
|
|
"""Integration tests with mock HTTP server."""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.server = HTTPServer(("127.0.0.1", 0), MockGiteaHandler)
|
|
cls.port = cls.server.server_address[1]
|
|
cls.thread = threading.Thread(target=cls.server.serve_forever)
|
|
cls.thread.daemon = True
|
|
cls.thread.start()
|
|
cls.client = GiteaClient(
|
|
base_url=f"http://127.0.0.1:{cls.port}",
|
|
token="testtoken",
|
|
max_retries=1,
|
|
)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
cls.server.shutdown()
|
|
|
|
def test_whoami(self):
|
|
user = self.client.whoami()
|
|
self.assertEqual(user["login"], "ezra")
|
|
|
|
def test_validate_token(self):
|
|
ok, name = self.client.validate_token()
|
|
self.assertTrue(ok)
|
|
self.assertEqual(name, "ezra")
|
|
|
|
def test_list_issues(self):
|
|
issues = self.client.list_issues("ezra", "test")
|
|
self.assertEqual(len(issues), 1)
|
|
self.assertEqual(issues[0]["title"], "Test issue")
|
|
|
|
def test_create_issue(self):
|
|
issue = self.client.create_issue("ezra", "test", "New issue", "Body text")
|
|
self.assertEqual(issue["number"], 42)
|
|
|
|
def test_close_issue(self):
|
|
result = self.client.close_issue("ezra", "test", 1)
|
|
self.assertEqual(result["state"], "closed")
|
|
|
|
def test_add_comment(self):
|
|
result = self.client.add_comment("ezra", "test", 1, "test comment")
|
|
self.assertEqual(result["body"], "test comment")
|
|
|
|
def test_list_labels(self):
|
|
labels = self.client.list_labels("ezra", "test")
|
|
self.assertEqual(len(labels), 1)
|
|
self.assertEqual(labels[0]["name"], "bug")
|
|
|
|
def test_create_label(self):
|
|
label = self.client.create_label("ezra", "test", "feature", "0ea5e9")
|
|
self.assertEqual(label["name"], "feature")
|
|
|
|
def test_ensure_label_existing(self):
|
|
label = self.client.ensure_label("ezra", "test", "bug", "e11d48")
|
|
self.assertEqual(label["name"], "bug")
|
|
|
|
def test_ensure_label_new(self):
|
|
label = self.client.ensure_label("ezra", "test", "newlabel", "00ff00")
|
|
self.assertEqual(label["name"], "newlabel")
|
|
|
|
def test_list_repos(self):
|
|
repos = self.client.list_repos()
|
|
self.assertEqual(len(repos), 1)
|
|
|
|
def test_get_repo(self):
|
|
repo = self.client.get_repo("ezra", "test")
|
|
self.assertEqual(repo["full_name"], "ezra/test")
|
|
|
|
def test_404_raises(self):
|
|
with self.assertRaises(GiteaAPIError) as ctx:
|
|
self.client.get_repo("ezra", "notfound")
|
|
self.assertEqual(ctx.exception.status_code, 404)
|
|
|
|
def test_create_milestone(self):
|
|
ms = self.client.create_milestone("ezra", "test", "v1.0")
|
|
self.assertEqual(ms["title"], "v1.0")
|
|
|
|
def test_ensure_milestone_new(self):
|
|
ms = self.client.ensure_milestone("ezra", "test", "v2.0")
|
|
self.assertEqual(ms["title"], "v2.0")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|