- Rename marketplace to lm-claude-plugins - Move MCP servers to root with symlinks - Add 6 PR tools to Gitea MCP (list_pull_requests, get_pull_request, get_pr_diff, get_pr_comments, create_pr_review, add_pr_comment) - Add clarity-assist plugin (prompt optimization with ND accommodations) - Add git-flow plugin (workflow automation) - Add pr-review plugin (multi-agent review with confidence scoring) - Centralize configuration docs - Update all documentation for v3.0.0 BREAKING CHANGE: MCP server paths changed, marketplace renamed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
160 lines
5.6 KiB
Python
160 lines
5.6 KiB
Python
"""
|
|
Unit tests for issue tools with branch detection.
|
|
"""
|
|
import pytest
|
|
from unittest.mock import Mock, patch, AsyncMock
|
|
from mcp_server.tools.issues import IssueTools
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_gitea_client():
|
|
"""Fixture providing mocked Gitea client"""
|
|
client = Mock()
|
|
client.mode = 'project'
|
|
return client
|
|
|
|
|
|
@pytest.fixture
|
|
def issue_tools(mock_gitea_client):
|
|
"""Fixture providing IssueTools instance"""
|
|
return IssueTools(mock_gitea_client)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_issues_development_branch(issue_tools):
|
|
"""Test listing issues on development branch (allowed)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='feat/test-feature'):
|
|
issue_tools.gitea.list_issues = Mock(return_value=[{'number': 1}])
|
|
|
|
issues = await issue_tools.list_issues(state='open')
|
|
|
|
assert len(issues) == 1
|
|
issue_tools.gitea.list_issues.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_issue_development_branch(issue_tools):
|
|
"""Test creating issue on development branch (allowed)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='development'):
|
|
issue_tools.gitea.create_issue = Mock(return_value={'number': 1})
|
|
|
|
issue = await issue_tools.create_issue('Test', 'Body')
|
|
|
|
assert issue['number'] == 1
|
|
issue_tools.gitea.create_issue.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_issue_main_branch_blocked(issue_tools):
|
|
"""Test creating issue on main branch (blocked)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='main'):
|
|
with pytest.raises(PermissionError) as exc_info:
|
|
await issue_tools.create_issue('Test', 'Body')
|
|
|
|
assert "Cannot create issues on branch 'main'" in str(exc_info.value)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_issue_staging_branch_allowed(issue_tools):
|
|
"""Test creating issue on staging branch (allowed for documentation)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='staging'):
|
|
issue_tools.gitea.create_issue = Mock(return_value={'number': 1})
|
|
|
|
issue = await issue_tools.create_issue('Test', 'Body')
|
|
|
|
assert issue['number'] == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_issue_main_branch_blocked(issue_tools):
|
|
"""Test updating issue on main branch (blocked)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='main'):
|
|
with pytest.raises(PermissionError) as exc_info:
|
|
await issue_tools.update_issue(1, title='Updated')
|
|
|
|
assert "Cannot update issues on branch 'main'" in str(exc_info.value)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_issues_main_branch_allowed(issue_tools):
|
|
"""Test listing issues on main branch (allowed - read-only)"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='main'):
|
|
issue_tools.gitea.list_issues = Mock(return_value=[{'number': 1}])
|
|
|
|
issues = await issue_tools.list_issues(state='open')
|
|
|
|
assert len(issues) == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_issue(issue_tools):
|
|
"""Test getting specific issue"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='development'):
|
|
issue_tools.gitea.get_issue = Mock(return_value={'number': 1, 'title': 'Test'})
|
|
|
|
issue = await issue_tools.get_issue(1)
|
|
|
|
assert issue['number'] == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_comment(issue_tools):
|
|
"""Test adding comment to issue"""
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='development'):
|
|
issue_tools.gitea.add_comment = Mock(return_value={'body': 'Test comment'})
|
|
|
|
comment = await issue_tools.add_comment(1, 'Test comment')
|
|
|
|
assert comment['body'] == 'Test comment'
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_aggregate_issues_company_mode(issue_tools):
|
|
"""Test aggregating issues in company mode"""
|
|
issue_tools.gitea.mode = 'company'
|
|
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='development'):
|
|
issue_tools.gitea.aggregate_issues = Mock(return_value={
|
|
'repo1': [{'number': 1}],
|
|
'repo2': [{'number': 2}]
|
|
})
|
|
|
|
aggregated = await issue_tools.aggregate_issues()
|
|
|
|
assert 'repo1' in aggregated
|
|
assert 'repo2' in aggregated
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_aggregate_issues_project_mode_error(issue_tools):
|
|
"""Test that aggregate_issues fails in project mode"""
|
|
issue_tools.gitea.mode = 'project'
|
|
|
|
with patch.object(issue_tools, '_get_current_branch', return_value='development'):
|
|
with pytest.raises(ValueError) as exc_info:
|
|
await issue_tools.aggregate_issues()
|
|
|
|
assert "only available in company mode" in str(exc_info.value)
|
|
|
|
|
|
def test_branch_detection():
|
|
"""Test branch detection logic"""
|
|
tools = IssueTools(Mock())
|
|
|
|
# Test development branches
|
|
with patch.object(tools, '_get_current_branch', return_value='development'):
|
|
assert tools._check_branch_permissions('create_issue') is True
|
|
|
|
with patch.object(tools, '_get_current_branch', return_value='feat/new-feature'):
|
|
assert tools._check_branch_permissions('create_issue') is True
|
|
|
|
# Test production branches
|
|
with patch.object(tools, '_get_current_branch', return_value='main'):
|
|
assert tools._check_branch_permissions('create_issue') is False
|
|
assert tools._check_branch_permissions('list_issues') is True
|
|
|
|
# Test staging branches
|
|
with patch.object(tools, '_get_current_branch', return_value='staging'):
|
|
assert tools._check_branch_permissions('create_issue') is True
|
|
assert tools._check_branch_permissions('update_issue') is False
|