""" Test configuration and fixtures for Git Operations MCP Server. """ import os import shutil import tempfile from collections.abc import AsyncIterator, Iterator from pathlib import Path from unittest.mock import AsyncMock, MagicMock import pytest from git import Repo as GitRepo # Set test environment os.environ["IS_TEST"] = "true" os.environ["GIT_OPS_WORKSPACE_BASE_PATH"] = "/tmp/test-workspaces" os.environ["GIT_OPS_GITEA_BASE_URL"] = "https://gitea.test.com" os.environ["GIT_OPS_GITEA_TOKEN"] = "test-token" @pytest.fixture(scope="session", autouse=True) def reset_settings_session(): """Reset settings at start and end of test session.""" from config import reset_settings reset_settings() yield reset_settings() @pytest.fixture def reset_settings(): """Reset settings before each test that needs it.""" from config import reset_settings reset_settings() yield reset_settings() @pytest.fixture def test_settings(): """Get test settings.""" from config import Settings return Settings( workspace_base_path=Path("/tmp/test-workspaces"), gitea_base_url="https://gitea.test.com", gitea_token="test-token", github_token="github-test-token", git_author_name="Test Agent", git_author_email="test@syndarix.ai", enable_force_push=False, debug=True, ) @pytest.fixture def temp_dir() -> Iterator[Path]: """Create a temporary directory for tests.""" temp_path = Path(tempfile.mkdtemp()) yield temp_path if temp_path.exists(): shutil.rmtree(temp_path) @pytest.fixture def temp_workspace(temp_dir: Path) -> Path: """Create a temporary workspace directory.""" workspace = temp_dir / "workspace" workspace.mkdir(parents=True, exist_ok=True) return workspace @pytest.fixture def git_repo(temp_workspace: Path) -> GitRepo: """Create a git repository in the temp workspace.""" # Initialize with main branch (Git 2.28+) repo = GitRepo.init(temp_workspace, initial_branch="main") # Configure git with repo.config_writer() as cw: cw.set_value("user", "name", "Test User") cw.set_value("user", "email", "test@example.com") # Create initial commit test_file = temp_workspace / "README.md" test_file.write_text("# Test Repository\n") repo.index.add(["README.md"]) repo.index.commit("Initial commit") return repo @pytest.fixture def git_repo_with_remote(git_repo: GitRepo, temp_dir: Path) -> tuple[GitRepo, GitRepo]: """Create a git repository with a 'remote' (bare repo).""" # Create bare repo as remote remote_path = temp_dir / "remote.git" remote_repo = GitRepo.init(remote_path, bare=True) # Add remote to main repo git_repo.create_remote("origin", str(remote_path)) # Push initial commit git_repo.remotes.origin.push("main:main") # Set up tracking git_repo.heads.main.set_tracking_branch(git_repo.remotes.origin.refs.main) return git_repo, remote_repo @pytest.fixture def workspace_manager(temp_dir: Path, test_settings): """Create a WorkspaceManager with test settings.""" from workspace import WorkspaceManager test_settings.workspace_base_path = temp_dir / "workspaces" return WorkspaceManager(test_settings) @pytest.fixture def git_wrapper(temp_workspace: Path, test_settings): """Create a GitWrapper for the temp workspace.""" from git_wrapper import GitWrapper return GitWrapper(temp_workspace, test_settings) @pytest.fixture def git_wrapper_with_repo(git_repo: GitRepo, test_settings): """Create a GitWrapper for a repo that's already initialized.""" from git_wrapper import GitWrapper return GitWrapper(Path(git_repo.working_dir), test_settings) @pytest.fixture def mock_gitea_provider(): """Create a mock Gitea provider.""" provider = AsyncMock() provider.name = "gitea" provider.is_connected = AsyncMock(return_value=True) provider.get_authenticated_user = AsyncMock(return_value="test-user") provider.parse_repo_url = MagicMock(return_value=("owner", "repo")) return provider @pytest.fixture def mock_httpx_client(): """Create a mock httpx client for provider tests.""" from unittest.mock import AsyncMock mock_response = AsyncMock() mock_response.status_code = 200 mock_response.json = MagicMock(return_value={}) mock_response.text = "" mock_client = AsyncMock() mock_client.request = AsyncMock(return_value=mock_response) mock_client.get = AsyncMock(return_value=mock_response) mock_client.post = AsyncMock(return_value=mock_response) mock_client.patch = AsyncMock(return_value=mock_response) mock_client.delete = AsyncMock(return_value=mock_response) return mock_client @pytest.fixture async def gitea_provider(test_settings, mock_httpx_client): """Create a GiteaProvider with mocked HTTP client.""" from providers.gitea import GiteaProvider provider = GiteaProvider( base_url=test_settings.gitea_base_url, token=test_settings.gitea_token, settings=test_settings, ) provider._client = mock_httpx_client yield provider await provider.close() @pytest.fixture def sample_pr_data(): """Sample PR data from Gitea API.""" return { "number": 42, "title": "Test PR", "body": "This is a test pull request", "state": "open", "head": {"ref": "feature-branch"}, "base": {"ref": "main"}, "user": {"login": "test-user"}, "created_at": "2024-01-15T10:00:00Z", "updated_at": "2024-01-15T12:00:00Z", "merged_at": None, "closed_at": None, "html_url": "https://gitea.test.com/owner/repo/pull/42", "labels": [{"name": "enhancement"}], "assignees": [{"login": "assignee1"}], "requested_reviewers": [{"login": "reviewer1"}], "mergeable": True, "draft": False, } @pytest.fixture def sample_commit_data(): """Sample commit data.""" return { "sha": "abc123def456", "short_sha": "abc123d", "message": "Test commit message", "author": { "name": "Test Author", "email": "author@test.com", "date": "2024-01-15T10:00:00Z", }, "committer": { "name": "Test Committer", "email": "committer@test.com", "date": "2024-01-15T10:00:00Z", }, } @pytest.fixture def mock_fastapi_app(): """Create a test FastAPI app.""" from fastapi import FastAPI from fastapi.testclient import TestClient app = FastAPI() @app.get("/health") def health(): return {"status": "healthy"} return TestClient(app) # Async fixtures @pytest.fixture async def async_workspace_manager(temp_dir: Path, test_settings) -> AsyncIterator: """Async fixture for workspace manager.""" from workspace import WorkspaceManager test_settings.workspace_base_path = temp_dir / "workspaces" manager = WorkspaceManager(test_settings) yield manager # Test data fixtures @pytest.fixture def valid_project_id() -> str: """Valid project ID for tests.""" return "test-project-123" @pytest.fixture def valid_agent_id() -> str: """Valid agent ID for tests.""" return "agent-456" @pytest.fixture def invalid_ids() -> list[str]: """Invalid IDs for validation tests.""" return [ "", " ", "a" * 200, # Too long "test@invalid", # Invalid character "test!invalid", "../path/traversal", ] @pytest.fixture def sample_repo_url() -> str: """Sample repository URL.""" return "https://gitea.test.com/owner/repo.git" @pytest.fixture def sample_ssh_repo_url() -> str: """Sample SSH repository URL.""" return "git@gitea.test.com:owner/repo.git"