Skip to content

Commit 7892940

Browse files
committed
test: add unit tests for ShellServer and ShellExecutor to ensure command handling and execution functionality
1 parent 6801312 commit 7892940

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

tests/test_server.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import pytest
2+
from mcp_shell_server.server import ShellServer
3+
4+
@pytest.fixture
5+
def server():
6+
return ShellServer()
7+
8+
@pytest.mark.asyncio
9+
async def test_server_handle_empty_request(server):
10+
response = await server.handle({})
11+
assert response["error"] == "No command provided"
12+
assert response["status"] == 1
13+
14+
@pytest.mark.asyncio
15+
async def test_server_handle_valid_command(server, monkeypatch):
16+
monkeypatch.setenv("ALLOW_COMMANDS", "echo")
17+
response = await server.handle({
18+
"command": ["echo", "hello world"]
19+
})
20+
assert response["stdout"].strip() == "hello world"
21+
assert response["status"] == 0
22+
assert "execution_time" in response
23+
24+
@pytest.mark.asyncio
25+
async def test_server_handle_stdin(server, monkeypatch):
26+
monkeypatch.setenv("ALLOW_COMMANDS", "cat")
27+
response = await server.handle({
28+
"command": ["cat"],
29+
"stdin": "test input"
30+
})
31+
assert response["stdout"].strip() == "test input"
32+
assert response["status"] == 0
33+
34+
@pytest.mark.asyncio
35+
async def test_server_handle_invalid_command(server, monkeypatch):
36+
monkeypatch.setenv("ALLOW_COMMANDS", "echo")
37+
response = await server.handle({
38+
"command": ["invalid_command"]
39+
})
40+
assert response["error"] == "Command not allowed: invalid_command"
41+
assert response["status"] == 1

tests/test_shell_executor.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import os
2+
import pytest
3+
from mcp_shell_server.shell_executor import ShellExecutor
4+
5+
@pytest.fixture
6+
def executor():
7+
return ShellExecutor()
8+
9+
@pytest.mark.asyncio
10+
async def test_basic_command_execution(executor, monkeypatch):
11+
monkeypatch.setenv("ALLOW_COMMANDS", "echo,ls")
12+
result = await executor.execute(["echo", "hello"])
13+
assert result["stdout"].strip() == "hello"
14+
assert result["status"] == 0
15+
assert result["stderr"] == ""
16+
assert "execution_time" in result
17+
18+
@pytest.mark.asyncio
19+
async def test_stdin_input(executor, monkeypatch):
20+
monkeypatch.setenv("ALLOW_COMMANDS", "cat")
21+
result = await executor.execute(["cat"], stdin="hello world")
22+
assert result["stdout"].strip() == "hello world"
23+
assert result["status"] == 0
24+
25+
@pytest.mark.asyncio
26+
async def test_command_not_allowed(executor, monkeypatch):
27+
monkeypatch.setenv("ALLOW_COMMANDS", "ls")
28+
result = await executor.execute(["rm", "-rf", "/"])
29+
assert result["error"] == "Command not allowed: rm"
30+
assert result["status"] == 1
31+
32+
@pytest.mark.asyncio
33+
async def test_empty_command(executor):
34+
result = await executor.execute([])
35+
assert result["error"] == "Empty command"
36+
assert result["status"] == 1
37+
38+
@pytest.mark.asyncio
39+
async def test_command_with_space_in_allow_commands(executor, monkeypatch):
40+
monkeypatch.setenv("ALLOW_COMMANDS", "ls, echo ,cat")
41+
result = await executor.execute(["echo", "test"])
42+
assert result["stdout"].strip() == "test"
43+
assert result["status"] == 0
44+
45+
@pytest.mark.asyncio
46+
async def test_multiple_commands_with_operator(executor, monkeypatch):
47+
monkeypatch.setenv("ALLOW_COMMANDS", "echo,ls")
48+
result = await executor.execute(["echo", "hello", ";", "ls", "-l"])
49+
assert "Command not allowed: ls" in result["error"]
50+
assert result["status"] == 1
51+
52+
@pytest.mark.asyncio
53+
async def test_command_with_error_output(executor, monkeypatch):
54+
monkeypatch.setenv("ALLOW_COMMANDS", "ls")
55+
result = await executor.execute(["ls", "/nonexistent"])
56+
assert result["stderr"] != ""
57+
assert result["status"] != 0

0 commit comments

Comments
 (0)