test_get_transitions_v3.py•8.18 kB
"""Test cases for get_transitions V3 API conversion"""
import asyncio
from unittest.mock import Mock, patch, AsyncMock
import pytest
from src.mcp_server_jira.jira_v3_api import JiraV3APIClient
from src.mcp_server_jira.server import JiraServer, JiraTransitionResult
class TestGetTransitionsV3APIConversion:
    """Test suite for get_transitions V3 API conversion"""
    @pytest.mark.asyncio
    async def test_v3_api_get_transitions_success(self):
        """Test successful get transitions request with V3 API"""
        # Mock response data matching Jira V3 API format
        mock_response_data = {
            "transitions": [
                {
                    "id": "2",
                    "name": "Close Issue",
                    "to": {
                        "id": "10000",
                        "name": "Done",
                        "description": "Issue is done"
                    },
                    "hasScreen": False,
                    "isAvailable": True
                },
                {
                    "id": "711",
                    "name": "QA Review",
                    "to": {
                        "id": "5",
                        "name": "In Review"
                    },
                    "hasScreen": True,
                    "isAvailable": True
                }
            ]
        }
        # Mock httpx response
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = mock_response_data
        mock_response.text = str(mock_response_data)
        mock_response.raise_for_status.return_value = None
        client = JiraV3APIClient(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with patch.object(client.client, 'request', new_callable=AsyncMock) as mock_request:
            mock_request.return_value = mock_response
            result = await client.get_transitions("PROJ-123")
            # Verify the result structure
            assert "transitions" in result
            assert len(result["transitions"]) == 2
            assert result["transitions"][0]["id"] == "2"
            assert result["transitions"][0]["name"] == "Close Issue"
            assert result["transitions"][1]["id"] == "711"
            assert result["transitions"][1]["name"] == "QA Review"
            # Verify the API call
            mock_request.assert_called_once()
            call_args = mock_request.call_args
            assert call_args[1]["method"] == "GET"
            assert "/rest/api/3/issue/PROJ-123/transitions" in call_args[1]["url"]
    @pytest.mark.asyncio
    async def test_v3_api_get_transitions_with_parameters(self):
        """Test get transitions with query parameters"""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"transitions": []}
        mock_response.text = "{\"transitions\": []}"
        mock_response.raise_for_status.return_value = None
        client = JiraV3APIClient(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with patch.object(client.client, 'request', new_callable=AsyncMock) as mock_request:
            mock_request.return_value = mock_response
            await client.get_transitions(
                issue_id_or_key="PROJ-123",
                expand="transitions.fields",
                transition_id="2",
                skip_remote_only_condition=True
            )
            # Verify the request parameters
            call_args = mock_request.call_args
            params = call_args[1]["params"]
            assert params["expand"] == "transitions.fields"
            assert params["transitionId"] == "2"
            assert params["skipRemoteOnlyCondition"] is True
    @pytest.mark.asyncio
    async def test_v3_api_get_transitions_missing_issue_key(self):
        """Test get transitions with missing issue key"""
        client = JiraV3APIClient(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with pytest.raises(ValueError, match="issue_id_or_key is required"):
            await client.get_transitions("")
    @pytest.mark.asyncio
    async def test_jira_server_get_transitions_success(self):
        """Test JiraServer get_jira_transitions method"""
        mock_api_response = {
            "transitions": [
                {"id": "2", "name": "Close Issue"},
                {"id": "711", "name": "QA Review"},
                {"id": "31", "name": "Reopen Issue"}
            ]
        }
        server = JiraServer(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with patch.object(server._v3_api_client, 'get_transitions', new_callable=AsyncMock) as mock_get_transitions:
            mock_get_transitions.return_value = mock_api_response
            result = await server.get_jira_transitions("PROJ-123")
            # Verify the result type and structure
            assert isinstance(result, list)
            assert len(result) == 3
            assert all(isinstance(t, JiraTransitionResult) for t in result)
            # Check specific transition details
            assert result[0].id == "2"
            assert result[0].name == "Close Issue"
            assert result[1].id == "711"
            assert result[1].name == "QA Review"
            assert result[2].id == "31"
            assert result[2].name == "Reopen Issue"
            # Verify the V3 API was called correctly
            mock_get_transitions.assert_called_once_with(issue_id_or_key="PROJ-123")
    @pytest.mark.asyncio
    async def test_jira_server_get_transitions_error_handling(self):
        """Test error handling in get_jira_transitions"""
        server = JiraServer(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with patch.object(server._v3_api_client, 'get_transitions', new_callable=AsyncMock) as mock_get_transitions:
            mock_get_transitions.side_effect = Exception("API Error")
            with pytest.raises(ValueError) as exc_info:
                await server.get_jira_transitions("PROJ-123")
            assert "Failed to get transitions for PROJ-123" in str(exc_info.value)
            assert "API Error" in str(exc_info.value)
    @pytest.mark.asyncio
    async def test_jira_server_backward_compatibility(self):
        """Test that the new implementation maintains backward compatibility"""
        mock_api_response = {
            "transitions": [
                {"id": "2", "name": "Close Issue"},
                {"id": "711", "name": "QA Review"}
            ]
        }
        server = JiraServer(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        with patch.object(server._v3_api_client, 'get_transitions', new_callable=AsyncMock) as mock_get_transitions:
            mock_get_transitions.return_value = mock_api_response
            result = await server.get_jira_transitions("PROJ-123")
            # Verify the return type matches the original interface
            assert isinstance(result, list)
            assert all(isinstance(t, JiraTransitionResult) for t in result)
            assert all(hasattr(t, 'id') and hasattr(t, 'name') for t in result)
            # Verify specific field types
            assert isinstance(result[0].id, str)
            assert isinstance(result[0].name, str)
    @pytest.mark.asyncio
    async def test_jira_server_method_is_async(self):
        """Test that get_jira_transitions is properly converted to async"""
        server = JiraServer(
            server_url="https://test.atlassian.net",
            username="testuser",
            token="testtoken"
        )
        import inspect
        assert inspect.iscoroutinefunction(server.get_jira_transitions), \
            "get_jira_transitions should be an async method"