diff options
Diffstat (limited to 'servers/gitlab_glab/tests')
| -rw-r--r-- | servers/gitlab_glab/tests/conftest.py | 105 | ||||
| -rw-r--r-- | servers/gitlab_glab/tests/test_cli.py | 159 | ||||
| -rw-r--r-- | servers/gitlab_glab/tests/test_cli_integration.py | 133 | ||||
| -rw-r--r-- | servers/gitlab_glab/tests/test_integration.py | 85 | ||||
| -rw-r--r-- | servers/gitlab_glab/tests/test_main.py | 15 | ||||
| -rw-r--r-- | servers/gitlab_glab/tests/test_server.py | 221 |
6 files changed, 718 insertions, 0 deletions
diff --git a/servers/gitlab_glab/tests/conftest.py b/servers/gitlab_glab/tests/conftest.py new file mode 100644 index 0000000..c7afaf9 --- /dev/null +++ b/servers/gitlab_glab/tests/conftest.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Pytest configuration and fixtures for GitLab CLI MCP server tests.""" + +from unittest.mock import MagicMock, patch + +import pytest + +from mcp_server_gitlab_glab.server import GitLabServer, create_server + + +@pytest.fixture +def gitlab_server() -> GitLabServer: + """Fixture for a GitLabServer instance.""" + return GitLabServer() + + +@pytest.fixture +def mock_subprocess_run() -> MagicMock: + """Fixture for mocking subprocess.run.""" + with patch("subprocess.run") as mock_run: + yield mock_run + + +@pytest.fixture +def mock_successful_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking a successful command execution.""" + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = "command output" + mock_process.stderr = "" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_failed_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking a failed command execution.""" + mock_process = MagicMock() + mock_process.returncode = 1 + mock_process.stdout = "" + mock_process.stderr = "command failed" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_auth_error_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking an authentication error command execution.""" + mock_process = MagicMock() + mock_process.returncode = 1 + mock_process.stdout = "" + mock_process.stderr = "authentication required" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_successful_api_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking a successful API command execution.""" + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = '[{"id": 1, "name": "test-project"}]' + mock_process.stderr = "" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_empty_api_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking an API command with empty results.""" + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = "[]" + mock_process.stderr = "" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_invalid_json_api_command(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking an API command with invalid JSON response.""" + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = "invalid json" + mock_process.stderr = "" + mock_subprocess_run.return_value = mock_process + return mock_subprocess_run + + +@pytest.fixture +def mock_command_not_found(mock_subprocess_run: MagicMock) -> MagicMock: + """Fixture for mocking a command not found error.""" + mock_subprocess_run.side_effect = FileNotFoundError( + "No such file or directory: 'glab'" + ) + return mock_subprocess_run + + +@pytest.fixture +def mcp_server() -> MagicMock: + """Fixture for a mocked MCP server.""" + with patch("mcp.server.fastmcp.FastMCP") as mock_fastmcp: + mock_server = MagicMock() + mock_fastmcp.return_value = mock_server + yield create_server() diff --git a/servers/gitlab_glab/tests/test_cli.py b/servers/gitlab_glab/tests/test_cli.py new file mode 100644 index 0000000..316556c --- /dev/null +++ b/servers/gitlab_glab/tests/test_cli.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +"""Tests for the GitLab CLI MCP server CLI functionality.""" + +import argparse +import logging +from unittest.mock import MagicMock, patch + +from mcp_server_gitlab_glab.cli import parse_args, setup_logging, validate_args + + +class TestCli: + """Tests for the CLI functionality.""" + + def test_parse_args_defaults(self) -> None: + """Test parsing command-line arguments with defaults.""" + # Mock sys.argv + with patch("sys.argv", ["mcp-gitlab-glab"]): + args = parse_args() + assert args.transport == "stdio" + assert args.host == "127.0.0.1" + assert args.port == 8080 + assert args.log_level == "INFO" + + def test_parse_args_custom(self) -> None: + """Test parsing command-line arguments with custom values.""" + # Mock sys.argv + with patch( + "sys.argv", + [ + "mcp-gitlab-glab", + "--transport", + "remote", + "--host", + "0.0.0.0", + "--port", + "9000", + "--log-level", + "DEBUG", + ], + ): + args = parse_args() + assert args.transport == "remote" + assert args.host == "0.0.0.0" + assert args.port == 9000 + assert args.log_level == "DEBUG" + + def test_validate_args_low_port_warning(self) -> None: + """Test validation warning for low port on Unix-like systems.""" + # Create args with low port + args = argparse.Namespace(transport="remote", port=80, host="0.0.0.0") + + # Mock logger and platform + with patch("mcp_server_gitlab_glab.cli.logger") as mock_logger: + with patch("sys.platform", "linux"): + validate_args(args) + mock_logger.warning.assert_called_once() + + def test_validate_args_no_warning_windows(self) -> None: + """Test no validation warning for low port on Windows.""" + # Create args with low port + args = argparse.Namespace(transport="remote", port=80, host="0.0.0.0") + + # Mock logger and platform + with patch("mcp_server_gitlab_glab.cli.logger") as mock_logger: + with patch("sys.platform", "win32"): + validate_args(args) + mock_logger.warning.assert_not_called() + + def test_validate_args_no_warning_high_port(self) -> None: + """Test no validation warning for high port.""" + # Create args with high port + args = argparse.Namespace(transport="remote", port=8080, host="0.0.0.0") + + # Mock logger + with patch("mcp_server_gitlab_glab.cli.logger") as mock_logger: + validate_args(args) + mock_logger.warning.assert_not_called() + + def test_setup_logging_stdio(self) -> None: + """Test logging setup for stdio transport.""" + # Mock os.makedirs and logging configuration + with patch("os.makedirs") as mock_makedirs: + with patch("logging.FileHandler") as mock_file_handler: + with patch("logging.StreamHandler") as mock_stream_handler: + with patch("logging.getLogger") as mock_get_logger: + # Mock root logger + mock_root_logger = MagicMock() + mock_get_logger.return_value = mock_root_logger + + # Mock handlers + mock_file_handler_instance = MagicMock() + mock_file_handler.return_value = mock_file_handler_instance + mock_stream_handler_instance = MagicMock() + mock_stream_handler.return_value = mock_stream_handler_instance + + # Call setup_logging + setup_logging("INFO", "stdio") + + # Verify logs directory creation + mock_makedirs.assert_called_once_with("logs", exist_ok=True) + + # Verify file handler setup + mock_file_handler.assert_called_once_with("logs/mcp_server.log") + mock_file_handler_instance.setLevel.assert_called_once_with( + logging.INFO + ) + mock_file_handler_instance.setFormatter.assert_called_once() + + # Verify stream handler setup for stdio + mock_stream_handler_instance.setLevel.assert_called_once_with( + logging.WARNING + ) + mock_stream_handler_instance.setFormatter.assert_called_once() + + # Verify root logger setup + mock_root_logger.setLevel.assert_called_once_with(logging.INFO) + assert mock_root_logger.handlers == [] + assert mock_root_logger.addHandler.call_count == 2 + + def test_setup_logging_remote(self) -> None: + """Test logging setup for remote transport.""" + # Mock os.makedirs and logging configuration + with patch("os.makedirs") as mock_makedirs: + with patch("logging.FileHandler") as mock_file_handler: + with patch("logging.StreamHandler") as mock_stream_handler: + with patch("logging.getLogger") as mock_get_logger: + # Mock root logger + mock_root_logger = MagicMock() + mock_get_logger.return_value = mock_root_logger + + # Mock handlers + mock_file_handler_instance = MagicMock() + mock_file_handler.return_value = mock_file_handler_instance + mock_stream_handler_instance = MagicMock() + mock_stream_handler.return_value = mock_stream_handler_instance + + # Call setup_logging + setup_logging("DEBUG", "remote") + + # Verify logs directory creation + mock_makedirs.assert_called_once_with("logs", exist_ok=True) + + # Verify file handler setup + mock_file_handler.assert_called_once_with("logs/mcp_server.log") + mock_file_handler_instance.setLevel.assert_called_once_with( + logging.DEBUG + ) + mock_file_handler_instance.setFormatter.assert_called_once() + + # Verify stream handler setup for remote + mock_stream_handler_instance.setLevel.assert_called_once_with( + logging.DEBUG + ) + mock_stream_handler_instance.setFormatter.assert_called_once() + + # Verify root logger setup + mock_root_logger.setLevel.assert_called_once_with(logging.DEBUG) + assert mock_root_logger.handlers == [] + assert mock_root_logger.addHandler.call_count == 2 diff --git a/servers/gitlab_glab/tests/test_cli_integration.py b/servers/gitlab_glab/tests/test_cli_integration.py new file mode 100644 index 0000000..c9493ac --- /dev/null +++ b/servers/gitlab_glab/tests/test_cli_integration.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +"""Integration tests for the GitLab CLI MCP server CLI functionality.""" + +from unittest.mock import MagicMock, patch + +from mcp_server_gitlab_glab.cli import run_server + + +class TestCliIntegration: + """Integration tests for the CLI functionality.""" + + @patch("mcp_server_gitlab_glab.cli.validate_args") + @patch("mcp_server_gitlab_glab.cli.parse_args") + @patch("mcp_server_gitlab_glab.cli.setup_logging") + @patch("mcp_server_gitlab_glab.cli.asyncio.run") + def test_run_server_success( + self, + mock_asyncio_run: MagicMock, + mock_setup_logging: MagicMock, + mock_parse_args: MagicMock, + mock_validate_args: MagicMock, + ) -> None: + """Test successful server run.""" + # Mock args + mock_args = MagicMock() + mock_args.transport = "stdio" + mock_args.host = "127.0.0.1" + mock_args.port = 8080 + mock_args.log_level = "INFO" + mock_parse_args.return_value = mock_args + mock_validate_args.return_value = mock_args + + # Call run_server + run_server() + + # Verify args were parsed and validated + mock_parse_args.assert_called_once() + mock_validate_args.assert_called_once_with(mock_args) + + # Verify logging was set up + mock_setup_logging.assert_called_once_with("INFO", "stdio") + + # Verify server was run + mock_asyncio_run.assert_called_once() + + @patch("mcp_server_gitlab_glab.cli.validate_args") + @patch("mcp_server_gitlab_glab.cli.parse_args") + @patch("mcp_server_gitlab_glab.cli.setup_logging") + @patch("mcp_server_gitlab_glab.cli.asyncio.run") + @patch("mcp_server_gitlab_glab.cli.logger") + def test_run_server_keyboard_interrupt( + self, + mock_logger: MagicMock, + mock_asyncio_run: MagicMock, + mock_setup_logging: MagicMock, + mock_parse_args: MagicMock, + mock_validate_args: MagicMock, + ) -> None: + """Test server run with keyboard interrupt.""" + # Mock args + mock_args = MagicMock() + mock_args.transport = "stdio" + mock_args.host = "127.0.0.1" + mock_args.port = 8080 + mock_args.log_level = "INFO" + mock_parse_args.return_value = mock_args + mock_validate_args.return_value = mock_args + + # Mock KeyboardInterrupt + mock_asyncio_run.side_effect = KeyboardInterrupt() + + # Call run_server + run_server() + + # Verify args were parsed and validated + mock_parse_args.assert_called_once() + mock_validate_args.assert_called_once_with(mock_args) + + # Verify logging was set up + mock_setup_logging.assert_called_once_with("INFO", "stdio") + + # Verify server was run + mock_asyncio_run.assert_called_once() + + # Verify keyboard interrupt was logged + mock_logger.info.assert_called_once_with("Server stopped by user") + + @patch("mcp_server_gitlab_glab.cli.validate_args") + @patch("mcp_server_gitlab_glab.cli.parse_args") + @patch("mcp_server_gitlab_glab.cli.setup_logging") + @patch("mcp_server_gitlab_glab.cli.asyncio.run") + @patch("mcp_server_gitlab_glab.cli.logger") + @patch("mcp_server_gitlab_glab.cli.sys.exit") + def test_run_server_exception( + self, + mock_sys_exit: MagicMock, + mock_logger: MagicMock, + mock_asyncio_run: MagicMock, + mock_setup_logging: MagicMock, + mock_parse_args: MagicMock, + mock_validate_args: MagicMock, + ) -> None: + """Test server run with exception.""" + # Mock args + mock_args = MagicMock() + mock_args.transport = "stdio" + mock_args.host = "127.0.0.1" + mock_args.port = 8080 + mock_args.log_level = "INFO" + mock_parse_args.return_value = mock_args + mock_validate_args.return_value = mock_args + + # Mock Exception + mock_asyncio_run.side_effect = Exception("Test error") + + # Call run_server + run_server() + + # Verify args were parsed and validated + mock_parse_args.assert_called_once() + mock_validate_args.assert_called_once_with(mock_args) + + # Verify logging was set up + mock_setup_logging.assert_called_once_with("INFO", "stdio") + + # Verify server was run + mock_asyncio_run.assert_called_once() + + # Verify exception was logged + mock_logger.error.assert_called_once_with("Error running server: Test error") + + # Verify sys.exit was called + mock_sys_exit.assert_called_once_with(1) diff --git a/servers/gitlab_glab/tests/test_integration.py b/servers/gitlab_glab/tests/test_integration.py new file mode 100644 index 0000000..3bad1cc --- /dev/null +++ b/servers/gitlab_glab/tests/test_integration.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +"""Integration tests for the GitLab CLI MCP server.""" + +from unittest.mock import AsyncMock, MagicMock, patch + +from mcp_server_gitlab_glab.server import create_server, main + + +class TestIntegration: + """Integration tests for the GitLab CLI MCP server.""" + + @patch("mcp_server_gitlab_glab.server.FastMCP") + def test_create_server(self, mock_fastmcp: MagicMock) -> None: + """Test server creation with default parameters.""" + # Mock FastMCP instance + mock_server = MagicMock() + mock_fastmcp.return_value = mock_server + + # Call create_server + create_server() + + # Verify FastMCP was created with correct parameters + mock_fastmcp.assert_called_once_with("GitLab CLI", host="127.0.0.1", port=8080) + + # Verify tools were registered + assert mock_server.tool.call_count == 2 + + @patch("mcp_server_gitlab_glab.server.FastMCP") + def test_create_server_custom_params(self, mock_fastmcp: MagicMock) -> None: + """Test server creation with custom parameters.""" + # Mock FastMCP instance + mock_server = MagicMock() + mock_fastmcp.return_value = mock_server + + # Call create_server with custom parameters + create_server(host="0.0.0.0", port=9000) + + # Verify FastMCP was created with correct parameters + mock_fastmcp.assert_called_once_with("GitLab CLI", host="0.0.0.0", port=9000) + + @patch("mcp_server_gitlab_glab.server.create_server") + @patch("mcp_server_gitlab_glab.server.logger") + async def test_main_stdio( + self, mock_logger: MagicMock, mock_create_server: MagicMock + ) -> None: + """Test main function with stdio transport.""" + # Mock server + mock_server = AsyncMock() + mock_create_server.return_value = mock_server + + # Call main with stdio transport + await main("stdio", "127.0.0.1", 8080) + + # Verify server was created with correct parameters + mock_create_server.assert_called_once_with(host="127.0.0.1", port=8080) + + # Verify stdio transport was used + mock_server.run_stdio_async.assert_called_once() + mock_server.run_sse_async.assert_not_called() + + # Verify logging + assert mock_logger.info.call_count >= 2 + + @patch("mcp_server_gitlab_glab.server.create_server") + @patch("mcp_server_gitlab_glab.server.logger") + async def test_main_remote( + self, mock_logger: MagicMock, mock_create_server: MagicMock + ) -> None: + """Test main function with remote transport.""" + # Mock server + mock_server = AsyncMock() + mock_create_server.return_value = mock_server + + # Call main with remote transport + await main("remote", "0.0.0.0", 9000) + + # Verify server was created with correct parameters + mock_create_server.assert_called_once_with(host="0.0.0.0", port=9000) + + # Verify remote transport was used + mock_server.run_stdio_async.assert_not_called() + mock_server.run_sse_async.assert_called_once() + + # Verify logging + assert mock_logger.info.call_count >= 2 diff --git a/servers/gitlab_glab/tests/test_main.py b/servers/gitlab_glab/tests/test_main.py new file mode 100644 index 0000000..2302018 --- /dev/null +++ b/servers/gitlab_glab/tests/test_main.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +"""Tests for the GitLab CLI MCP server main module.""" + + + +class TestMain: + """Tests for the main module.""" + + def test_main_module_import(self) -> None: + """Test main module can be imported.""" + # Simply import the module to ensure it can be imported without errors + import mcp_server_gitlab_glab.__main__ + + # Verify the module has the expected attributes + assert hasattr(mcp_server_gitlab_glab.__main__, "run_server") diff --git a/servers/gitlab_glab/tests/test_server.py b/servers/gitlab_glab/tests/test_server.py new file mode 100644 index 0000000..1c27ea5 --- /dev/null +++ b/servers/gitlab_glab/tests/test_server.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +"""Tests for the GitLab CLI MCP server implementation.""" + +import json +from unittest.mock import MagicMock, patch + +from mcp_server_gitlab_glab.server import GitLabServer + + +class TestGitLabServer: + """Tests for the GitLabServer class.""" + + def test_init(self) -> None: + """Test initialization of GitLabServer.""" + server = GitLabServer() + assert hasattr(server, "auth_message") + assert "glab auth login" in server.auth_message + + @patch("subprocess.run") + def test_execute_glab_command_success(self, mock_run: MagicMock) -> None: + """Test successful execution of a glab command.""" + # Mock successful command execution + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = "command output" + mock_process.stderr = "" + mock_run.return_value = mock_process + + server = GitLabServer() + success, result = server.execute_glab_command(["--version"]) + + assert success is True + assert result == "command output" + mock_run.assert_called_once_with( + ["glab", "--version"], + capture_output=True, + text=True, + check=False, + ) + + @patch("subprocess.run") + def test_execute_glab_command_failure(self, mock_run: MagicMock) -> None: + """Test failed execution of a glab command.""" + # Mock failed command execution + mock_process = MagicMock() + mock_process.returncode = 1 + mock_process.stdout = "" + mock_process.stderr = "command failed" + mock_run.return_value = mock_process + + server = GitLabServer() + success, result = server.execute_glab_command(["--version"]) + + assert success is False + assert result == {"error": "command failed"} + mock_run.assert_called_once_with( + ["glab", "--version"], + capture_output=True, + text=True, + check=False, + ) + + @patch("subprocess.run") + def test_execute_glab_command_auth_error(self, mock_run: MagicMock) -> None: + """Test authentication error during glab command execution.""" + # Mock authentication error + mock_process = MagicMock() + mock_process.returncode = 1 + mock_process.stdout = "" + mock_process.stderr = "authentication required" + mock_run.return_value = mock_process + + server = GitLabServer() + success, result = server.execute_glab_command(["api", "/projects"]) + + assert success is False + assert "error" in result + assert "auth login" in result["error"] + mock_run.assert_called_once_with( + ["glab", "api", "/projects"], + capture_output=True, + text=True, + check=False, + ) + + @patch("subprocess.run") + def test_execute_glab_command_not_found(self, mock_run: MagicMock) -> None: + """Test glab command not found error.""" + # Mock FileNotFoundError + mock_run.side_effect = FileNotFoundError("No such file or directory: 'glab'") + + server = GitLabServer() + success, result = server.execute_glab_command(["--version"]) + + assert success is False + assert "error" in result + assert "glab command not found" in result["error"] + + @patch("subprocess.run") + def test_execute_glab_api_command_success(self, mock_run: MagicMock) -> None: + """Test successful execution of a glab api command with JSON response.""" + # Mock successful API command execution with JSON response + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = json.dumps([{"id": 1, "name": "test-project"}]) + mock_process.stderr = "" + mock_run.return_value = mock_process + + server = GitLabServer() + success, result = server.execute_glab_command(["api", "/projects"]) + + assert success is True + assert isinstance(result, list) + assert len(result) == 1 + assert result[0]["id"] == 1 + assert result[0]["name"] == "test-project" + mock_run.assert_called_once_with( + ["glab", "api", "/projects"], + capture_output=True, + text=True, + check=False, + ) + + @patch("subprocess.run") + def test_execute_glab_api_command_invalid_json(self, mock_run: MagicMock) -> None: + """Test glab api command with invalid JSON response.""" + # Mock API command execution with invalid JSON response + mock_process = MagicMock() + mock_process.returncode = 0 + mock_process.stdout = "invalid json" + mock_process.stderr = "" + mock_run.return_value = mock_process + + server = GitLabServer() + success, result = server.execute_glab_command(["api", "/projects"]) + + assert success is False + assert "error" in result + assert "Failed to parse JSON response" in result["error"] + + @patch.object(GitLabServer, "execute_glab_command") + def test_check_availability_success(self, mock_execute: MagicMock) -> None: + """Test successful check_availability.""" + # Mock successful command execution + mock_execute.return_value = (True, "glab version 1.0.0") + + server = GitLabServer() + result = server.check_availability() + + assert result["available"] is True + assert result["version"] == "glab version 1.0.0" + mock_execute.assert_called_once_with(["--version"]) + + @patch.object(GitLabServer, "execute_glab_command") + def test_check_availability_failure(self, mock_execute: MagicMock) -> None: + """Test failed check_availability.""" + # Mock failed command execution + mock_execute.return_value = (False, {"error": "glab command not found"}) + + server = GitLabServer() + result = server.check_availability() + + assert result["available"] is False + assert result["error"] == "glab command not found" + mock_execute.assert_called_once_with(["--version"]) + + @patch.object(GitLabServer, "execute_glab_command") + def test_find_project_success(self, mock_execute: MagicMock) -> None: + """Test successful find_project.""" + # Mock successful API response with a project + mock_execute.return_value = ( + True, + [ + { + "id": 1, + "name": "test-project", + "path_with_namespace": "group/test-project", + "web_url": "https://gitlab.com/group/test-project", + "description": "A test project", + } + ], + ) + + server = GitLabServer() + result = server.find_project("test-project") + + assert "id" in result + assert result["id"] == 1 + assert result["name"] == "test-project" + assert result["path_with_namespace"] == "group/test-project" + assert result["web_url"] == "https://gitlab.com/group/test-project" + assert result["description"] == "A test project" + mock_execute.assert_called_once_with(["api", "/projects?search=test-project"]) + + @patch.object(GitLabServer, "execute_glab_command") + def test_find_project_not_found(self, mock_execute: MagicMock) -> None: + """Test find_project with no results.""" + # Mock API response with no projects + mock_execute.return_value = (True, []) + + server = GitLabServer() + result = server.find_project("nonexistent-project") + + assert "error" in result + assert "not found" in result["error"] + mock_execute.assert_called_once_with( + ["api", "/projects?search=nonexistent-project"] + ) + + @patch.object(GitLabServer, "execute_glab_command") + def test_find_project_api_error(self, mock_execute: MagicMock) -> None: + """Test find_project with API error.""" + # Mock API error + mock_execute.return_value = (False, {"error": "API error"}) + + server = GitLabServer() + result = server.find_project("test-project") + + assert "error" in result + assert result["error"] == "API error" + mock_execute.assert_called_once_with(["api", "/projects?search=test-project"]) |
