diff --git a/src/procleaning_mcp/__pycache__/server.cpython-311.pyc b/src/procleaning_mcp/__pycache__/server.cpython-311.pyc new file mode 100644 index 0000000..7a192d4 Binary files /dev/null and b/src/procleaning_mcp/__pycache__/server.cpython-311.pyc differ diff --git a/src/procleaning_mcp/server.py b/src/procleaning_mcp/server.py index d08558f..2954849 100644 --- a/src/procleaning_mcp/server.py +++ b/src/procleaning_mcp/server.py @@ -158,9 +158,9 @@ def system_resource_usage(top_n: int = 10, sort_by: str = "cpu") -> str: threads = psutil.cpu_count(logical=True) or 1 key_map = { - "cpu": lambda p: p.cpu_percent(), - "memory": lambda p: p.memory_percent(), - "rss": lambda p: p.memory_info().rss, + "cpu": lambda p: p["cpu_percent"], + "memory": lambda p: p["memory_percent"], + "rss": lambda p: p["memory_rss_mb"], } sort_key = key_map.get(sort_by, key_map["cpu"]) diff --git a/tests/test_server.py b/tests/test_server.py new file mode 100644 index 0000000..34982de --- /dev/null +++ b/tests/test_server.py @@ -0,0 +1,90 @@ +"""Tests for procleaning-mcp server.""" + +import sys +import asyncio +import os + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) + +import pytest +from procleaning_mcp.server import mcp + + +@pytest.fixture +def event_loop(): + """Create a test event loop.""" + loop = asyncio.new_event_loop() + yield loop + loop.close() + + +@pytest.mark.asyncio +async def test_list_processes(): + """Test that list_processes returns valid output.""" + result = await mcp.call_tool( + "list_processes", {"name_filter": "python", "max_processes": 5} + ) + # call_tool returns (content_list, structured_content) + content_list, structured = result + assert isinstance(content_list, list) + assert content_list[0].type == "text" + text = content_list[0].text + assert "Found" in text or "No processes" in text + + +@pytest.mark.asyncio +async def test_system_resource_usage(): + """Test that system_resource_usage returns valid output.""" + result = await mcp.call_tool( + "system_resource_usage", {"top_n": 3, "sort_by": "memory"} + ) + content_list, structured = result + assert isinstance(content_list, list) + assert content_list[0].type == "text" + text = content_list[0].text + assert "CPU Usage" in text + assert "Memory Usage" in text + assert "Top 3" in text + + +@pytest.mark.asyncio +async def test_find_zombies(): + """Test that find_zombies returns valid output.""" + result = await mcp.call_tool("find_zombies", {"include_details": False}) + content_list, structured = result + assert isinstance(content_list, list) + assert content_list[0].type == "text" + + +@pytest.mark.asyncio +async def test_list_processes_empty_filter(): + """Test list_processes with no filter returns processes.""" + result = await mcp.call_tool( + "list_processes", {"max_processes": 3} + ) + content_list, structured = result + assert isinstance(content_list, list) + text = content_list[0].text + assert "Found" in text + + +@pytest.mark.asyncio +async def test_kill_process_no_confirm(): + """Test that kill_process without confirm returns cancellation message.""" + result = await mcp.call_tool( + "kill_process", {"pid": 1, "confirm": False} + ) + content_list, structured = result + text = content_list[0].text + assert "cancelled" in text.lower() + + +@pytest.mark.asyncio +async def test_kill_by_name_no_match(): + """Test kill_by_name with non-existent process name.""" + result = await mcp.call_tool( + "kill_by_name", {"name_pattern": "thisprocessdoesnotexist12345", "confirm": False} + ) + content_list, structured = result + text = content_list[0].text + assert "cancelled" in text.lower()