""" Test suite for Gitea backend functionality. These tests ensure the Gitea backend works correctly with the API. """ import pytest import json from datetime import datetime, timezone from unittest.mock import Mock, patch, MagicMock from issue_core.backends.gitea.backend import GiteaBackend, GiteaAPIError from issue_core.core.models import Issue, IssueState, Label class TestGiteaBackend: """Test Gitea backend implementation.""" def setup_method(self): """Set up test environment.""" self.backend = GiteaBackend() self.test_config = { 'type': 'gitea', 'base_url': 'https://git.example.com', 'owner': 'testorg', 'repo': 'testrepo', 'token': 'test-token' } def test_backend_initialization(self): """Test backend initializes correctly.""" assert self.backend.base_url is None assert self.backend.token is None assert self.backend.owner is None assert self.backend.repo is None assert self.backend.session is not None @patch('issue_core.backends.gitea.backend.requests.Session') def test_connect_success(self, mock_session_class): """Test successful connection to Gitea API.""" mock_session = MagicMock() mock_session_class.return_value = mock_session # Mock successful API response mock_response = Mock() mock_response.status_code = 200 mock_session.request.return_value = mock_response backend = GiteaBackend() backend.session = mock_session backend.connect(self.test_config) # Verify configuration is set assert backend.base_url == 'https://git.example.com' assert backend.token == 'test-token' assert backend.owner == 'testorg' assert backend.repo == 'testrepo' # Verify headers are set mock_session.headers.update.assert_called_once_with({ 'Authorization': 'token test-token', 'Content-Type': 'application/json', 'Accept': 'application/json' }) @patch('issue_core.backends.gitea.backend.requests.Session') def test_connect_failure(self, mock_session_class): """Test failed connection raises appropriate error.""" mock_session = MagicMock() mock_session_class.return_value = mock_session # Mock failed API response mock_response = Mock() mock_response.status_code = 404 mock_session.request.return_value = mock_response backend = GiteaBackend() backend.session = mock_session with pytest.raises(GiteaAPIError, match="Failed to connect to Gitea API"): backend.connect(self.test_config) def test_url_construction_fix(self): """Test that URL construction properly handles urljoin edge cases.""" backend = GiteaBackend() backend.base_url = 'https://git.example.com' # Test the fixed _api_request URL construction with patch.object(backend.session, 'request') as mock_request: mock_response = Mock() mock_response.status_code = 200 mock_request.return_value = mock_response backend._api_request('GET', '/repos/owner/repo') # Verify the correct URL was called mock_request.assert_called_once() called_url = mock_request.call_args[1]['url'] if 'url' in mock_request.call_args[1] else mock_request.call_args[0][1] assert called_url == 'https://git.example.com/api/v1/repos/owner/repo' def test_gitea_payload_omits_name_only_labels(self): """Gitea issue payloads only include numeric label IDs.""" now = datetime.now(timezone.utc) issue = Issue( id="", number=0, title="Test issue", description="Test description", state=IssueState.OPEN, created_at=now, updated_at=now, labels=[ Label(name="priority:low"), Label(name="source:rule", backend_id="not-a-number"), Label(name="existing", backend_id="42"), ], ) payload = self.backend._unified_issue_to_gitea(issue) assert payload["labels"] == [42] assert payload["title"] == "Test issue" @patch('issue_core.backends.gitea.backend.requests.Session') def test_test_connection_success(self, mock_session_class): """Test test_connection method works correctly.""" mock_session = MagicMock() mock_session_class.return_value = mock_session # Mock successful API response mock_response = Mock() mock_response.status_code = 200 mock_session.request.return_value = mock_response backend = GiteaBackend() backend.session = mock_session backend.base_url = 'https://git.example.com' backend.owner = 'testorg' backend.repo = 'testrepo' backend.token = 'test-token' result = backend.test_connection() assert result is True @patch('issue_core.backends.gitea.backend.requests.Session') def test_test_connection_failure(self, mock_session_class): """Test test_connection handles failures gracefully.""" mock_session = MagicMock() mock_session_class.return_value = mock_session # Mock failed API response mock_response = Mock() mock_response.status_code = 404 mock_response.raise_for_status.side_effect = Exception("404 Not Found") mock_session.request.return_value = mock_response backend = GiteaBackend() backend.session = mock_session backend.base_url = 'https://git.example.com' backend.owner = 'testorg' backend.repo = 'testrepo' backend.token = 'test-token' result = backend.test_connection() assert result is False @patch('issue_core.backends.gitea.backend.requests.Session') def test_get_issue_success(self, mock_session_class): """Test successful issue retrieval.""" mock_session = MagicMock() mock_session_class.return_value = mock_session # Mock Gitea issue response gitea_issue = { "id": 123, "number": 42, "title": "Test Issue", "body": "Test description", "state": "open", "user": {"login": "testuser", "email": "test@example.com"}, "created_at": "2023-01-01T12:00:00Z", "updated_at": "2023-01-01T12:00:00Z", "labels": [], "assignees": [], "milestone": None, "comments": 0 } mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = gitea_issue mock_session.request.return_value = mock_response backend = GiteaBackend() backend.session = mock_session backend.base_url = 'https://git.example.com' backend.owner = 'testorg' backend.repo = 'testrepo' backend.token = 'test-token' issue = backend.get_issue(42) assert issue.number == 42 assert issue.title == "Test Issue" assert issue.description == "Test description" assert issue.state.value == "open" def test_disconnect(self): """Test disconnect method cleans up properly.""" self.backend.base_url = 'https://git.example.com' self.backend.token = 'test-token' self.backend.owner = 'testorg' self.backend.repo = 'testrepo' self.backend.disconnect() assert self.backend.base_url is None assert self.backend.token is None assert self.backend.owner is None assert self.backend.repo is None