Files
shellmcp/test_shellmcp.py
T

58 lines
2.4 KiB
Python

import json
import os
import shutil
import subprocess
import sys
import tempfile
import time
import unittest
from unittest import mock
import shellmcp
HERE = os.path.dirname(os.path.abspath(__file__))
class Run(unittest.TestCase):
def test_exit_code_and_combined_output(self):
self.assertEqual(shellmcp.run("echo hi; echo oops >&2; exit 3", HERE),
"exit code 3\nhi\noops\n")
def test_long_output_keeps_head_and_tail(self):
out = shellmcp.run("printf 'a%.0s' $(seq 100); printf 'b%.0s' $(seq 100)", HERE, limit=20)
self.assertEqual(out, "exit code 0\naaaaaaaaaa\n[... 180 characters cut ...]\nbbbbbbbbbb")
def test_timeout_kills_the_whole_group(self):
start = time.monotonic()
out = shellmcp.run("sleep 30 & sleep 30", HERE, timeout=1)
self.assertLess(time.monotonic() - start, 5)
self.assertEqual(out, "timed out after 1 s, killed\n")
def test_no_stdin_and_no_pager(self):
self.assertEqual(shellmcp.run("cat; echo $PAGER", HERE), "exit code 0\ncat\n")
@unittest.skipUnless(shutil.which("bwrap"), "needs bwrap")
class Sandbox(unittest.TestCase):
def test_readonly_cannot_write_and_hides_paths(self):
with tempfile.TemporaryDirectory(dir=HERE) as d: # not /tmp: the sandbox replaces /tmp
os.mkdir(os.path.join(d, "secret"))
open(os.path.join(d, "secret", "key"), "w").close()
prefix = shellmcp.sandbox(d, [os.path.join(d, "secret")])
out = shellmcp.run("touch new; ls secret; echo > /tmp/x && echo tmp-ok", d,
prefix=prefix)
self.assertIn("Read-only file system", out)
self.assertNotIn("key", out)
self.assertIn("tmp-ok", out)
self.assertFalse(os.path.exists(os.path.join(d, "new")))
class Describe(unittest.TestCase):
def test_names_only_installed_tools_and_the_mode(self):
with mock.patch("shutil.which", lambda name: name in ("fd", "rg")):
text = shellmcp.describe("readonly", "/srv", 60, 8000)
self.assertIn("in /srv.", text)
self.assertIn("Read-only sandbox", text)
self.assertIn("prefer these: rg: search file contents (instead of grep); "
"fd: find files (instead of find).", text)
self.assertNotIn("jq", text)
self.assertIn("full permissions", shellmcp.describe("all", "/srv", 60, 8000))