From 7a5eb0b5fb9106dd43377231d4ee03c65420bf85 Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Tue, 15 Jul 2025 16:05:19 +0300 Subject: feat: update gitlab-python and cursor rules --- servers/gitlab_python/tests/test_server.py | 207 ++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 2 deletions(-) (limited to 'servers/gitlab_python/tests') diff --git a/servers/gitlab_python/tests/test_server.py b/servers/gitlab_python/tests/test_server.py index ab5a0bb..99cb788 100644 --- a/servers/gitlab_python/tests/test_server.py +++ b/servers/gitlab_python/tests/test_server.py @@ -1,6 +1,209 @@ import pytest -from mcp_server_gitlab_python.server import create_server +from mcp_server_gitlab_python.server import create_server, GitLabPythonServer +from unittest.mock import MagicMock, patch def test_create_server(): server = create_server() - assert server is not None \ No newline at end of file + assert server is not None + +def make_mock_diff(old_path, new_path, diff): + m = MagicMock() + m.old_path = old_path + m.new_path = new_path + m.diff = diff + return m + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_get_mr_diff_small_diff(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + mr = MagicMock() + mock_gitlab.return_value.projects.get.return_value = proj + proj.mergerequests.get.return_value = mr + mr.diffs.list.return_value = [ + make_mock_diff("file1.txt", "file1.txt", "diff content 1"), + make_mock_diff("file2.py", "file2.py", "diff content 2"), + ] + result = server.get_mr_diff("project/path", 1, max_size_kb=100) + assert "diff" in result + assert "file1.txt" in result["diff"] + assert result["temp_file_path"] is None + assert result["size_kb"] < 100 + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +@patch("tempfile.NamedTemporaryFile") +def test_get_mr_diff_large_diff_temp_file(mock_tempfile, mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + mr = MagicMock() + mock_gitlab.return_value.projects.get.return_value = proj + proj.mergerequests.get.return_value = mr + # Create a large diff + large_diff = "x" * (101 * 1024) + mock_diff = make_mock_diff("bigfile.txt", "bigfile.txt", large_diff) + mr.diffs.list.return_value = [mock_diff] + mock_file = MagicMock() + mock_file.name = "/tmp/mr_diff_12345.diff" + mock_tempfile.return_value.__enter__.return_value = mock_file + result = server.get_mr_diff("project/path", 1, max_size_kb=100) + assert result["diff_too_large"] is True + assert result["temp_file_path"] == "/tmp/mr_diff_12345.diff" + assert result["size_kb"] > 100 + assert "message" in result + mock_file.write.assert_called_once() + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_get_mr_diff_filter_extensions(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + mr = MagicMock() + mock_gitlab.return_value.projects.get.return_value = proj + proj.mergerequests.get.return_value = mr + # One file should be filtered out + mr.diffs.list.return_value = [ + make_mock_diff("file.lock", "file.lock", "should be filtered"), + make_mock_diff("file.txt", "file.txt", "should be present"), + ] + result = server.get_mr_diff("project/path", 1, max_size_kb=100, filter_extensions=[".lock"]) + assert "file.lock" not in result["diff"] + assert "file.txt" in result["diff"] + assert "should be present" in result["diff"] + assert "should be filtered" not in result["diff"] + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_get_mr_diff_error_handling(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + mock_gitlab.return_value.projects.get.side_effect = Exception("Not found") + result = server.get_mr_diff("project/path", 1) + assert "error" in result + assert "Not found" in result["error"] + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_run_ci_pipeline_success_with_branch(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + pipeline = MagicMock() + pipeline.id = 123 + pipeline.web_url = "https://gitlab.com/project/-/pipelines/123" + proj.pipelines.create.return_value = pipeline + mock_gitlab.return_value.projects.get.return_value = proj + result = server.run_ci_pipeline( + project="project/path", + branch="main", + variables={"FOO": "bar"}, + web_mode=False, + working_directory="/tmp" + ) + assert result["success"] is True + assert result["pipeline_id"] == 123 + assert result["pipeline_url"] == "https://gitlab.com/project/-/pipelines/123" + assert result["branch"] == "main" + assert result["web_mode"] is False + proj.pipelines.create.assert_called_once() + args = proj.pipelines.create.call_args[0][0] + assert args["ref"] == "main" + assert {"key": "FOO", "value": "bar"} in args["variables"] + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +@patch("subprocess.run") +def test_run_ci_pipeline_success_current_branch(mock_subprocess, mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + pipeline = MagicMock() + pipeline.id = 456 + pipeline.web_url = "https://gitlab.com/project/-/pipelines/456" + proj.pipelines.create.return_value = pipeline + proj.default_branch = "main" + mock_gitlab.return_value.projects.get.return_value = proj + # Simulate git branch detection + mock_git = MagicMock() + mock_git.returncode = 0 + mock_git.stdout = "feature-branch" + mock_subprocess.return_value = mock_git + result = server.run_ci_pipeline( + project="project/path", + branch=None, + variables=None, + web_mode=False, + working_directory="/tmp" + ) + assert result["success"] is True + assert result["pipeline_id"] == 456 + assert result["pipeline_url"] == "https://gitlab.com/project/-/pipelines/456" + assert result["branch"] == "feature-branch" + mock_subprocess.assert_called_once_with([ + "git", "branch", "--show-current" + ], capture_output=True, text=True, check=False, cwd="/tmp") + proj.pipelines.create.assert_called_once() + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +@patch("subprocess.run") +def test_run_ci_pipeline_fallback_to_default_branch(mock_subprocess, mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + pipeline = MagicMock() + pipeline.id = 789 + pipeline.web_url = "https://gitlab.com/project/-/pipelines/789" + proj.pipelines.create.return_value = pipeline + proj.default_branch = "main" + mock_gitlab.return_value.projects.get.return_value = proj + # Simulate git branch detection failure + mock_git = MagicMock() + mock_git.returncode = 1 + mock_git.stdout = "" + mock_subprocess.return_value = mock_git + result = server.run_ci_pipeline( + project="project/path", + branch=None, + variables=None, + web_mode=False, + working_directory="/tmp" + ) + assert result["success"] is True + assert result["branch"] == "main" + proj.pipelines.create.assert_called_once() + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_run_ci_pipeline_web_mode(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + proj = MagicMock() + pipeline = MagicMock() + pipeline.id = 321 + pipeline.web_url = "https://gitlab.com/project/-/pipelines/321" + proj.pipelines.create.return_value = pipeline + mock_gitlab.return_value.projects.get.return_value = proj + result = server.run_ci_pipeline( + project="project/path", + branch="main", + variables={"FOO": "bar"}, + web_mode=True, + working_directory="/tmp" + ) + assert result["success"] is True + assert result["web_mode"] is True + args = proj.pipelines.create.call_args[0][0] + # Should include CI_PIPELINE_SOURCE=web + assert {"key": "CI_PIPELINE_SOURCE", "value": "web"} in args["variables"] + +@patch("mcp_server_gitlab_python.server.get_gitlab_settings", return_value=("https://gitlab.com", "dummy-token")) +@patch("gitlab.Gitlab") +def test_run_ci_pipeline_error_handling(mock_gitlab, mock_settings): + server = GitLabPythonServer(working_directory="/tmp") + mock_gitlab.return_value.projects.get.side_effect = Exception("Not found") + result = server.run_ci_pipeline( + project="project/path", + branch="main", + variables=None, + web_mode=False, + working_directory="/tmp" + ) + assert "error" in result + assert "Not found" in result["error"] \ No newline at end of file -- cgit v1.2.3