import pytest import requests from unittest.mock import patch, MagicMock import server import runpy @pytest.fixture def mock_client(): with patch("server.get_client") as mock: yield mock.return_value def test_list_projects_tool(mock_client): mock_client.get_projects.return_value = [{"id": "1", "name": "P1"}] result = server.list_projects() assert "P1" in result assert "ID: 1" in result def test_list_projects_empty_tool(mock_client): mock_client.get_projects.return_value = [] result = server.list_projects() assert "No projects found" in result def test_list_boards_tool(mock_client): mock_client.get_boards.return_value = [{"id": "b1", "name": "B1"}] result = server.list_boards("p1") assert "B1" in result assert "ID: b1" in result def test_list_boards_empty_tool(mock_client): mock_client.get_boards.return_value = [] result = server.list_boards("p1") assert "No boards found" in result def test_list_board_columns_tool(mock_client): mock_client.get_board_lists.return_value = [{"id": "l1", "name": "L1"}] result = server.list_board_columns("b1") assert "L1" in result assert "ID: l1" in result def test_list_board_columns_empty_tool(mock_client): mock_client.get_board_lists.return_value = [] result = server.list_board_columns("b1") assert "No columns found" in result def test_list_cards_tool(mock_client): mock_client.get_cards.return_value = [{"id": "c1", "name": "C1"}] result = server.list_cards("b1") assert "C1" in result assert "ID: c1" in result def test_list_cards_empty_tool(mock_client): mock_client.get_cards.return_value = [] result = server.list_cards("b1") assert "No cards found" in result def test_create_card_tool(mock_client): mock_client.create_card.return_value = {"id": "c1", "name": "C1"} result = server.create_card("b1", "l1", "C1") assert "Created card: C1" in result def test_list_comments_tool(mock_client): mock_client.get_actions.return_value = [ {"type": "commentCard", "data": {"text": "Hello"}, "userId": "u1", "createdAt": "now"} ] result = server.list_comments("c1") assert "Hello" in result def test_list_comments_empty_tool(mock_client): mock_client.get_actions.return_value = [] result = server.list_comments("c1") assert "No comments found" in result def test_add_comment_tool(mock_client): result = server.add_comment("c1", "Hello") assert "Comment added" in result mock_client.create_comment.assert_called_with("c1", "Hello") def test_check_planka_status_up(): with patch("requests.get") as mock_get: mock_get.return_value.status_code = 200 result = server.check_planka_status() assert "UP and reachable" in result def test_check_planka_status_down(): with patch("requests.get") as mock_get: mock_get.return_value.status_code = 500 result = server.check_planka_status() assert "returned status 500" in result def test_check_planka_status_error(): with patch("requests.get") as mock_get: mock_get.side_effect = Exception("error") result = server.check_planka_status() assert "UNREACHABLE" in result def test_safe_tool_call_timeout(): def _fail(): raise requests.exceptions.Timeout() result = server.safe_tool_call(_fail) assert "timed out" in result def test_safe_tool_call_connection_error(): def _fail(): raise requests.exceptions.ConnectionError() result = server.safe_tool_call(_fail) assert "Could not connect" in result def test_safe_tool_call_http_error(): def _fail(): resp = MagicMock() resp.status_code = 404 raise requests.exceptions.HTTPError("404 Error", response=resp) result = server.safe_tool_call(_fail) assert "API returned an error" in result def test_safe_tool_call_generic_error(): def _fail(): raise Exception("generic error") result = server.safe_tool_call(_fail) assert "unexpected error occurred" in result def test_get_client_no_token(): with patch.dict("os.environ", {"PLANKA_TOKEN": ""}): server.PLANKA_TOKEN = None server.client = None with pytest.raises(ValueError, match="PLANKA_TOKEN is required"): server.get_client() def test_get_client_success(): with patch.dict("os.environ", {"PLANKA_TOKEN": "some_token"}): server.PLANKA_TOKEN = "some_token" server.client = None c = server.get_client() assert c.token == "some_token" def test_cli_list_projects(): with patch("sys.argv", ["server.py", "list_projects"]), \ patch("server.get_client") as mock_get_client, \ patch("server.mcp.run"): mock_get_client.return_value.get_projects.return_value = [{"id": "1", "name": "P1"}] runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__") def test_cli_list_boards(): with patch("sys.argv", ["server.py", "list_boards", "p1"]), \ patch("server.get_client") as mock_get_client, \ patch("server.mcp.run"): mock_get_client.return_value.get_boards.return_value = [{"id": "b1", "name": "B1"}] runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__") def test_cli_list_cards(): with patch("sys.argv", ["server.py", "list_cards", "b1"]), \ patch("server.get_client") as mock_get_client, \ patch("server.mcp.run"): mock_get_client.return_value.get_cards.return_value = [{"id": "c1", "name": "C1"}] runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__") def test_cli_list_columns(): with patch("sys.argv", ["server.py", "list_columns", "b1"]), \ patch("server.get_client") as mock_get_client, \ patch("server.mcp.run"): mock_get_client.return_value.get_board_lists.return_value = [{"id": "l1", "name": "L1"}] runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__") def test_cli_status_main(): with patch("sys.argv", ["server.py", "status"]), \ patch("requests.get") as mock_req_get, \ patch("server.mcp.run"): mock_req_get.return_value.status_code = 200 runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__") def test_cli_run_mcp(): with patch("sys.argv", ["server.py"]), \ patch("mcp.server.fastmcp.FastMCP.run") as mock_run: runpy.run_path("/root/.openclaw/workspace/planka-mcp/server.py", run_name="__main__")