| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import os
- import shutil
- import tempfile
- import unittest
- import requests
- from sandbox import (
- Error,
- ExecuteResponse,
- ExecutionEventTypeDisplayData,
- ExecutionEventTypeError,
- ExecutionEventTypeStream,
- ExecutionStatusOK,
- ExecutionStatusTimeout,
- )
- # We'll create a temporary directory for the tests to avoid any side effects.
- temp_dir = tempfile.mkdtemp()
- BASE_URL = "http://localhost:8888/"
- def url(path: str) -> str:
- return BASE_URL + path
- class TestExecuteHandler(unittest.TestCase):
- def must_bind_with_execute_response(self, r: requests.Response) -> ExecuteResponse:
- self.assertEqual(r.status_code, 200)
- return ExecuteResponse.model_validate_json(r.content)
- def must_bind_with_error(self, r: requests.Response) -> Error:
- return Error.model_validate_json(r.content)
- def test_execute_hello(self):
- r = requests.post(
- url("execute"), json={"code": "print('hello')", "timeout_secs": 10}
- )
- res = self.must_bind_with_execute_response(r)
- self.assertEqual(len(res.events), 1)
- self.assertEqual(res.events[0].type, ExecutionEventTypeStream)
- self.assertEqual(res.events[0].data.stream, "stdout") # type: ignore
- self.assertEqual(res.events[0].data.text, "hello\n") # type: ignore
- def test_execute_timeout(self):
- r = requests.post(
- url("execute"),
- json={"code": "import time\ntime.sleep(5)", "timeout_secs": 1},
- )
- res = self.must_bind_with_execute_response(r)
- self.assertEqual(len(res.events), 0)
- self.assertEqual(res.status, ExecutionStatusTimeout)
- def test_execute_syntax_error(self):
- r = requests.post(
- url("execute"), json={"code": "print('hello'", "timeout_secs": 10}
- )
- err = self.must_bind_with_execute_response(r)
- self.assertEqual(err.status, ExecutionStatusOK)
- self.assertEqual(len(err.events), 1)
- self.assertEqual(err.events[0].type, ExecutionEventTypeError)
- self.assertEqual(err.events[0].data.ename, "SyntaxError") # type: ignore
- self.assertIsNotNone(err.events[0].data.evalue) # type: ignore
- self.assertGreater(len(err.events[0].data.traceback), 0) # type: ignore
- def test_execute_invalid_timeout(self):
- r = requests.post(
- url("execute"),
- json={"code": "print('hello')", "timeout_secs": -1},
- )
- self.must_bind_with_error(r)
- def test_execute_display_data(self):
- code = """import matplotlib.pyplot as plt
- plt.plot([1, 2, 3, 4])
- plt.ylabel('some numbers')
- plt.show()"""
- r = requests.post(url("execute"), json={"code": code, "timeout_secs": 10})
- res = self.must_bind_with_execute_response(r)
- self.assertEqual(res.status, ExecutionStatusOK)
- self.assertEqual(len(res.events), 1)
- self.assertEqual(res.events[0].type, ExecutionEventTypeDisplayData)
- self.assertIsNotNone(res.events[0].data.variants["image/png"]) # type: ignore
- self.assertIsNotNone(res.events[0].data.variants["text/plain"]) # type: ignore
- def test_execute_pil_image(self):
- code = """from PIL import Image
- img = Image.new('RGB', (60, 30), color = 'red')
- # Override the show method of the Image class
- def new_show(self, *args, **kwargs):
- display(self)
- Image.Image.show = new_show
- img.show()"""
- r = requests.post(url("execute"), json={"code": code, "timeout_secs": 10})
- res = self.must_bind_with_execute_response(r)
- self.assertEqual(res.status, ExecutionStatusOK)
- self.assertEqual(len(res.events), 1)
- self.assertEqual(res.events[0].type, ExecutionEventTypeDisplayData)
- self.assertIsNotNone(res.events[0].data.variants["image/png"]) # type: ignore
- self.assertIsNotNone(res.events[0].data.variants["text/plain"]) # type: ignore
- class FileUploadHandlerTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.temp_dir = tempfile.mkdtemp()
- cls.BASE_URL = f"http://localhost:8888/files/upload/-{cls.temp_dir}/"
- def test_upload_file(self):
- file_path = os.path.join(self.temp_dir, "test.txt")
- large_binary_file = os.urandom(1024 * 1024 * 10) # 10 MB
- r = requests.post(self.BASE_URL + "test.txt", data=large_binary_file)
- self.assertEqual(r.status_code, 201)
- self.assertTrue(os.path.exists(file_path))
- with open(file_path, "rb") as f:
- self.assertEqual(f.read(), large_binary_file)
- def test_upload_existing_file(self):
- file_path = os.path.join(self.temp_dir, "existing.txt")
- with open(file_path, "wb") as f:
- f.write(b"exists")
- with open(file_path, "rb") as f:
- r = requests.post(self.BASE_URL + "existing.txt", data=f.read())
- self.assertEqual(r.status_code, 409)
- error = Error.model_validate_json(r.content)
- self.assertEqual(error.error, "file already exists")
- def test_directory_creation(self):
- file_path = os.path.join(self.temp_dir, "newdir", "test.txt")
- os.makedirs(os.path.dirname(file_path), exist_ok=True)
- r = requests.post(self.BASE_URL + "newdir/test.txt", data=b"test content")
- self.assertEqual(r.status_code, 201)
- self.assertTrue(os.path.exists(file_path))
- with open(file_path, "rb") as f:
- self.assertEqual(f.read(), b"test content")
- @classmethod
- def tearDownClass(cls):
- # Clean up the temp_dir after all tests
- if os.path.exists(cls.temp_dir):
- shutil.rmtree(cls.temp_dir)
- if __name__ == "__main__":
- unittest.main()
|