From b419329aeb4dfea7f32e31a39dc5fbd9e96a0571 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sun, 26 Dec 2021 13:48:36 -0800 Subject: Test argument parsing for entry point --- tests/test_main.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_main.py (limited to 'tests/test_main.py') diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..1017123 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,51 @@ +import contextlib +import io +import unittest +from argparse import Namespace +from unittest.mock import patch + +import snekbox.__main__ as snekbox_main + + +class ArgParseTests(unittest.TestCase): + def test_parse_args(self): + subtests = ( + ( + ["", "code"], + Namespace(code="code", nsjail_args=[], py_args=["-c"]) + ), + ( + ["", "code", "--time_limit", "0"], + Namespace(code="code", nsjail_args=["--time_limit", "0"], py_args=["-c"]) + ), + ( + ["", "code", "---", "-m", "timeit"], + Namespace(code="code", nsjail_args=[], py_args=["-m", "timeit"]) + ), + ( + ["", "code", "--time_limit", "0", "---", "-m", "timeit"], + Namespace(code="code", nsjail_args=["--time_limit", "0"], py_args=["-m", "timeit"]) + ), + ( + ["", "code", "--time_limit", "0", "---"], + Namespace(code="code", nsjail_args=["--time_limit", "0"], py_args=[]) + ), + ( + ["", "code", "---"], + Namespace(code="code", nsjail_args=[], py_args=[]) + ) + ) + + for argv, expected in subtests: + with self.subTest(argv=argv, expected=expected), patch("sys.argv", argv): + args = snekbox_main.parse_args() + self.assertEqual(args, expected) + + @patch("sys.argv", [""]) + def test_parse_args_code_missing_exits(self): + with self.assertRaises(SystemExit) as cm: + with contextlib.redirect_stderr(io.StringIO()) as stderr: + snekbox_main.parse_args() + + self.assertEqual(cm.exception.code, 2) + self.assertIn("the following arguments are required: code", stderr.getvalue()) -- cgit v1.2.3 From 3043b34abb8271504665c5412880e2bdcf7e44f9 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sun, 26 Dec 2021 15:11:28 -0800 Subject: Add tests for main() --- tests/test_main.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'tests/test_main.py') diff --git a/tests/test_main.py b/tests/test_main.py index 1017123..196c196 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -2,6 +2,7 @@ import contextlib import io import unittest from argparse import Namespace +from subprocess import CompletedProcess from unittest.mock import patch import snekbox.__main__ as snekbox_main @@ -49,3 +50,51 @@ class ArgParseTests(unittest.TestCase): self.assertEqual(cm.exception.code, 2) self.assertIn("the following arguments are required: code", stderr.getvalue()) + + +class EntrypointTests(unittest.TestCase): + @patch("sys.argv", ["", "code"]) + @patch("snekbox.__main__.NsJail", autospec=True) + def test_main_prints_stdout(self, mock_nsjail): + mock_nsjail.return_value.python3.return_value = CompletedProcess( + args=[], + returncode=0, + stdout="output", + stderr=None + ) + + with contextlib.redirect_stdout(io.StringIO()) as stdout: + snekbox_main.main() + + self.assertEqual(stdout.getvalue(), "output\n") + + @patch("sys.argv", ["", "code"]) + @patch("snekbox.__main__.NsJail", autospec=True) + def test_main_exits_with_returncode(self, mock_nsjail): + mock_nsjail.return_value.python3.return_value = CompletedProcess( + args=[], + returncode=137, + stdout="output", + stderr=None + ) + + with self.assertRaises(SystemExit) as cm: + snekbox_main.main() + + self.assertEqual(cm.exception.code, 137) + + @patch("sys.argv", ["", "code", "--time_limit", "0", "---", "-m", "timeit"]) + @patch("snekbox.__main__.NsJail", autospec=True) + def test_main_forwards_args(self, mock_nsjail): + mock_nsjail.return_value.python3.return_value = CompletedProcess( + args=[], + returncode=0, + stdout="output", + stderr=None + ) + + snekbox_main.main() + + mock_nsjail.return_value.python3.assert_called_once_with( + "code", nsjail_args=["--time_limit", "0"], py_args=["-m", "timeit"] + ) -- cgit v1.2.3 From 591cd6623a7e18d0ceb0fa65f14a4ad29cd332e5 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Mon, 27 Dec 2021 15:19:14 -0800 Subject: Change entrypoint tests to integration tests No more mocks! --- tests/test_main.py | 60 +++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) (limited to 'tests/test_main.py') diff --git a/tests/test_main.py b/tests/test_main.py index 196c196..5b5bfcb 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,8 +1,9 @@ +import ast import contextlib import io +import logging import unittest from argparse import Namespace -from subprocess import CompletedProcess from unittest.mock import patch import snekbox.__main__ as snekbox_main @@ -53,48 +54,37 @@ class ArgParseTests(unittest.TestCase): class EntrypointTests(unittest.TestCase): - @patch("sys.argv", ["", "code"]) - @patch("snekbox.__main__.NsJail", autospec=True) - def test_main_prints_stdout(self, mock_nsjail): - mock_nsjail.return_value.python3.return_value = CompletedProcess( - args=[], - returncode=0, - stdout="output", - stderr=None - ) + """Integration tests of the CLI entrypoint.""" + + def setUp(self): + logging.getLogger("snekbox.nsjail").setLevel(logging.WARNING) + @patch("sys.argv", ["", "print('hello'); import sys; print('error', file=sys.stderr)"]) + def test_main_prints_stdout(self): + """Should print the stdout of the subprocess followed by its stderr.""" with contextlib.redirect_stdout(io.StringIO()) as stdout: snekbox_main.main() - self.assertEqual(stdout.getvalue(), "output\n") - - @patch("sys.argv", ["", "code"]) - @patch("snekbox.__main__.NsJail", autospec=True) - def test_main_exits_with_returncode(self, mock_nsjail): - mock_nsjail.return_value.python3.return_value = CompletedProcess( - args=[], - returncode=137, - stdout="output", - stderr=None - ) + self.assertEqual(stdout.getvalue(), "hello\nerror\n\n") + @patch("sys.argv", ["", "import sys; sys.exit(22)"]) + def test_main_exits_with_returncode(self): + """Should exit with the subprocess's returncode if it's non-zero.""" with self.assertRaises(SystemExit) as cm: snekbox_main.main() - self.assertEqual(cm.exception.code, 137) + self.assertEqual(cm.exception.code, 22) - @patch("sys.argv", ["", "code", "--time_limit", "0", "---", "-m", "timeit"]) - @patch("snekbox.__main__.NsJail", autospec=True) - def test_main_forwards_args(self, mock_nsjail): - mock_nsjail.return_value.python3.return_value = CompletedProcess( - args=[], - returncode=0, - stdout="output", - stderr=None - ) + def test_main_forwards_args(self): + """Should forward NsJail args to NsJail and Python args to the Python subprocess.""" + code = "import sys, time; print(sys.orig_argv); time.sleep(2)" + py_args = ["-R", "-dc"] + args = ["", code, "--time_limit", "1", "---", *py_args] - snekbox_main.main() + with patch("sys.argv", args), self.assertRaises(SystemExit) as cm: + with contextlib.redirect_stdout(io.StringIO()) as stdout: + snekbox_main.main() - mock_nsjail.return_value.python3.assert_called_once_with( - "code", nsjail_args=["--time_limit", "0"], py_args=["-m", "timeit"] - ) + orig_argv = ast.literal_eval(stdout.getvalue().strip()) + self.assertListEqual([*py_args, code], orig_argv[-3:]) + self.assertEqual(cm.exception.code, 137, "The time_limit NsJail arg was not respected.") -- cgit v1.2.3