generated from coulomb/repo-seed
Renames the package, distribution, CLI alias, Makefile targets, and working directory from issue-facade to issue-core, signalling its role as the authoritative task lifecycle manager for the Coulomb org (peer to activity-core, rules-core, project-core). Adds POST /issues/ ingestion endpoint for activity-core's IssueSink, under a new optional [api] extra. The endpoint is served by `issue serve`, authenticates via the ISSUE_CORE_API_KEY env var (Bearer or X-API-Key header), and routes the TaskSpec payload to the configured default backend with full traceability metadata embedded in sync_metadata. - T01: Python package issue_tracker -> issue_core, dir rename - T02: registered in state hub under custodian domain - T03: INTENT.md (what it is, what it isn't, how it fits) - T04: SCOPE.md (in/out-of-scope, integration boundaries) - T05: POST /issues/ via FastAPI + Uvicorn, 9 unit tests - T06: docs/nats-task-ingestion.md design stub Closes ISSC-WP-0001. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
195 lines
7.0 KiB
Python
195 lines
7.0 KiB
Python
"""
|
|
Test suite for Gitea backend functionality.
|
|
|
|
These tests ensure the Gitea backend works correctly with the API.
|
|
"""
|
|
|
|
import pytest
|
|
import json
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
from issue_core.backends.gitea.backend import GiteaBackend, GiteaAPIError
|
|
|
|
|
|
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'
|
|
|
|
@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 |