diff options
-rw-r--r-- | snekbox/api/resources/eval.py | 23 | ||||
-rw-r--r-- | tests/api/test_eval.py | 18 |
2 files changed, 31 insertions, 10 deletions
diff --git a/snekbox/api/resources/eval.py b/snekbox/api/resources/eval.py index de54564..c3e553a 100644 --- a/snekbox/api/resources/eval.py +++ b/snekbox/api/resources/eval.py @@ -27,6 +27,7 @@ class EvalResource: REQ_SCHEMA = { "type": "object", "properties": { + "input": {"type": "string"}, "args": {"type": "array", "items": {"type": "string"}}, "files": { "type": "array", @@ -44,7 +45,10 @@ class EvalResource: }, }, }, - "required": ["args"], + "anyOf": [ + {"required": ["input"]}, + {"required": ["args"]}, + ], } def __init__(self, nsjail: NsJail): @@ -57,6 +61,11 @@ class EvalResource: A list of arguments for the Python subprocess can be specified as `args`. + If `input` is specified, it will be appended as the last argument to `args`, + and `args` will have a default argument of `"-c"`. + + Either `input` or `args` must be specified. + The return codes mostly resemble those of a Unix shell. Some noteworthy cases: - None @@ -69,6 +78,10 @@ class EvalResource: Request body: >>> { + ... "input": "print('Hello')" + ... } + + >>> { ... "args": ["-c", "print('Hello')"] ... } @@ -105,10 +118,14 @@ class EvalResource: - 415 Unsupported content type; only application/JSON is supported """ + body: dict[str, str | list[str] | list[dict[str, str]]] = req.media + # If `input` is supplied, default `args` to `-c` + if "input" in body: + body.setdefault("args", ["-c"]) try: result = self.nsjail.python3( - py_args=req.media["args"], - files=[FileAttachment.from_dict(file) for file in req.media.get("files", [])], + py_args=body["args"], + files=[FileAttachment.from_dict(file) for file in body.get("files", [])], ) except ParsingError as e: raise falcon.HTTPBadRequest(title="Request file is invalid", description=str(e)) diff --git a/tests/api/test_eval.py b/tests/api/test_eval.py index 64d7ba6..26ac38a 100644 --- a/tests/api/test_eval.py +++ b/tests/api/test_eval.py @@ -5,12 +5,16 @@ class TestEvalResource(SnekAPITestCase): PATH = "/eval" def test_post_valid_200(self): - body = {"args": ["-c", "print('output')"]} - result = self.simulate_post(self.PATH, json=body) - - self.assertEqual(result.status_code, 200) - self.assertEqual("output", result.json["stdout"]) - self.assertEqual(0, result.json["returncode"]) + cases = [ + {"args": ["-c", "print('output')"]}, + {"input": "print('hello')"}, + ] + for body in cases: + with self.subTest(): + result = self.simulate_post(self.PATH, json=body) + self.assertEqual(result.status_code, 200) + self.assertEqual("output", result.json["stdout"]) + self.assertEqual(0, result.json["returncode"]) def test_post_invalid_schema_400(self): body = {"stuff": "foo"} @@ -20,7 +24,7 @@ class TestEvalResource(SnekAPITestCase): expected = { "title": "Request data failed validation", - "description": "'args' is a required property", + "description": "{'stuff': 'foo'} is not valid under any of the given schemas", } self.assertEqual(expected, result.json) |