diff --git a/cms/grading/Sandbox.py b/cms/grading/Sandbox.py index 7867006902..a09aeb27e8 100644 --- a/cms/grading/Sandbox.py +++ b/cms/grading/Sandbox.py @@ -970,20 +970,19 @@ def __init__(self, file_cacher, name=None, temp_dir=None): # between sandboxes. self.dirs.append((None, "/dev/shm", "tmp")) - # Set common environment variables. + # Set common configuration that is relevant for multiple + # languages. + + self.set_env["PATH"] = "/usr/local/bin:/usr/bin:/bin" + # Specifically needed by Python, that searches the home for # packages. self.set_env["HOME"] = self._home_dest - # Needed on Ubuntu by PHP (and more), since /usr/bin only contains a - # symlink to one out of many alternatives. + # Needed on Ubuntu by PHP, Java, Pascal etc, since /usr/bin + # only contains a symlink to one out of many alternatives. self.maybe_add_mapped_directory("/etc/alternatives") - # Likewise, needed by C# programs. The Mono runtime looks in - # /etc/mono/config to obtain the default DllMap, which includes, in - # particular, the System.Native assembly. - self.maybe_add_mapped_directory("/etc/mono", options="noexec") - # Tell isolate to get the sandbox ready. We do our best to cleanup # after ourselves, but we might have missed something if a previous # worker was interrupted in the middle of an execution, so we issue an diff --git a/cms/grading/language.py b/cms/grading/language.py index e74652f40f..128964f0ac 100644 --- a/cms/grading/language.py +++ b/cms/grading/language.py @@ -21,6 +21,7 @@ import logging import os from abc import ABCMeta, abstractmethod +from cms.grading.Sandbox import Sandbox logger = logging.getLogger(__name__) @@ -135,6 +136,13 @@ def get_compilation_commands( """ pass + def configure_compilation_sandbox(self, sandbox: Sandbox): + """ + Set sandbox parameters necessary for running the compilation + commands. + """ + pass + @abstractmethod def get_evaluation_commands( self, @@ -156,6 +164,13 @@ def get_evaluation_commands( """ pass + def configure_evaluation_sandbox(self, sandbox: Sandbox): + """ + Set sandbox parameters necessary for running the evaluation + commands. + """ + pass + # It's sometimes handy to use Language objects in sets or as dict # keys. Since they have no state (they are just collections of # constants and static methods) and are designed to be used as diff --git a/cms/grading/languages/csharp_mono.py b/cms/grading/languages/csharp_mono.py index f200ff4c66..87f3269a89 100644 --- a/cms/grading/languages/csharp_mono.py +++ b/cms/grading/languages/csharp_mono.py @@ -67,3 +67,12 @@ def get_evaluation_commands( self, executable_filename, main=None, args=None): """See Language.get_evaluation_commands.""" return [["/usr/bin/mono", executable_filename]] + + def configure_compilation_sandbox(self, sandbox): + # The Mono runtime looks in /etc/mono/config to obtain the + # default DllMap, which includes, in particular, the + # System.Native assembly. + sandbox.maybe_add_mapped_directory("/etc/mono", options="noexec") + + def configure_evaluation_sandbox(self, sandbox): + sandbox.maybe_add_mapped_directory("/etc/mono", options="noexec") diff --git a/cms/grading/languages/haskell_ghc.py b/cms/grading/languages/haskell_ghc.py index 9762d60055..ca9e87ba91 100644 --- a/cms/grading/languages/haskell_ghc.py +++ b/cms/grading/languages/haskell_ghc.py @@ -64,6 +64,13 @@ def get_compilation_commands(self, executable_filename, source_filenames[0]]) return commands + def configure_compilation_sandbox(self, sandbox): + # Directory required to be visible during a compilation with GHC. + # GHC looks for the Haskell's package database in + # "/usr/lib/ghc/package.conf.d" (already visible by isolate's default, + # but it is a symlink to "/var/lib/ghc/package.conf.d") + sandbox.maybe_add_mapped_directory("/var/lib/ghc") + @staticmethod def _capitalize(string: str): dirname, basename = os.path.split(string) diff --git a/cms/grading/languages/java_jdk.py b/cms/grading/languages/java_jdk.py index 78381e2009..9b48f87647 100644 --- a/cms/grading/languages/java_jdk.py +++ b/cms/grading/languages/java_jdk.py @@ -21,6 +21,7 @@ """ +import os from shlex import quote as shell_quote from cms.grading import Language @@ -91,3 +92,10 @@ def get_evaluation_commands( command = ["/usr/bin/java", "-Deval=true", "-Xmx512M", "-Xss64M", main] + args return [unzip_command, command] + + def configure_compilation_sandbox(self, sandbox): + # the jvm conf directory is often symlinked to /etc in + # distributions, but the location of it in /etc is inconsistent. + for path in os.listdir("/etc"): + if path == "java" or path.startswith("java-"): + sandbox.add_mapped_directory(f"/etc/{path}") diff --git a/cms/grading/languages/pascal_fpc.py b/cms/grading/languages/pascal_fpc.py index 12df846fc8..aa710d8091 100644 --- a/cms/grading/languages/pascal_fpc.py +++ b/cms/grading/languages/pascal_fpc.py @@ -60,3 +60,7 @@ def get_compilation_commands(self, command += ["-O2", "-XSs", "-o%s" % executable_filename] command += [source_filenames[0]] return [command] + + def configure_compilation_sandbox(self, sandbox): + # Needed for /etc/fpc.cfg. + sandbox.maybe_add_mapped_directory("/etc") diff --git a/cms/grading/languages/python3_pypy.py b/cms/grading/languages/python3_pypy.py index e87b29ab01..64c28de174 100644 --- a/cms/grading/languages/python3_pypy.py +++ b/cms/grading/languages/python3_pypy.py @@ -79,3 +79,11 @@ def get_evaluation_commands( """See Language.get_evaluation_commands.""" args = args if args is not None else [] return [["/usr/bin/pypy3", executable_filename] + args] + + def configure_compilation_sandbox(self, sandbox): + # Needed on Arch, where /usr/bin/pypy3 is a symlink into + # /opt/pypy3. + sandbox.maybe_add_mapped_directory("/opt/pypy3") + + def configure_evaluation_sandbox(self, sandbox): + sandbox.maybe_add_mapped_directory("/opt/pypy3") diff --git a/cms/grading/steps/compilation.py b/cms/grading/steps/compilation.py index 3b56f2eaad..a8ba12be9b 100644 --- a/cms/grading/steps/compilation.py +++ b/cms/grading/steps/compilation.py @@ -29,6 +29,7 @@ from cms import config from cms.grading.Sandbox import Sandbox +from cms.grading.language import Language from cms.grading.steps.stats import StatsDict from .messages import HumanMessage, MessageCollection from .utils import generic_step @@ -66,7 +67,7 @@ def N_(message: str): def compilation_step( - sandbox: Sandbox, commands: list[list[str]] + sandbox: Sandbox, commands: list[list[str]], language: Language ) -> tuple[bool, bool | None, list[str] | None, StatsDict | None]: """Execute some compilation commands in the sandbox. @@ -79,6 +80,7 @@ def compilation_step( sandbox: the sandbox we consider, already created. commands: compilation commands to execute. + language: language of the submission return: a tuple with four items: * success: True if the sandbox did not fail, in any command; @@ -93,18 +95,14 @@ def compilation_step( """ # Set sandbox parameters suitable for compilation. - sandbox.add_mapped_directory("/etc") - # Directory required to be visible during a compilation with GHC. - # GHC looks for the Haskell's package database in - # "/usr/lib/ghc/package.conf.d" (already visible by isolate's default, - # but it is a symlink to "/var/lib/ghc/package.conf.d" - sandbox.maybe_add_mapped_directory("/var/lib/ghc") - sandbox.preserve_env = True sandbox.max_processes = config.sandbox.compilation_sandbox_max_processes sandbox.timeout = config.sandbox.compilation_sandbox_max_time_s sandbox.wallclock_timeout = 2 * sandbox.timeout + 1 sandbox.address_space = config.sandbox.compilation_sandbox_max_memory_kib * 1024 + # Set per-language sandbox parameters. + language.configure_compilation_sandbox(sandbox) + # Run the compilation commands, copying stdout and stderr to stats. stats = generic_step(sandbox, commands, "compilation", collect_output=True) if stats is None: diff --git a/cms/grading/steps/evaluation.py b/cms/grading/steps/evaluation.py index adbe507b32..15a4aa9f47 100644 --- a/cms/grading/steps/evaluation.py +++ b/cms/grading/steps/evaluation.py @@ -30,6 +30,7 @@ from cms import config from cms.grading.Sandbox import Sandbox +from cms.grading.language import Language from .messages import HumanMessage, MessageCollection from .stats import StatsDict, execution_stats @@ -83,6 +84,7 @@ def N_(message: str): def evaluation_step( sandbox: Sandbox, commands: list[list[str]], + language: Language | None, time_limit: float | None = None, memory_limit: int | None = None, dirs_map: dict[str, tuple[str | None, str | None]] | None = None, @@ -101,6 +103,8 @@ def evaluation_step( sandbox: the sandbox we consider, already created. commands: evaluation commands to execute. + language: language of the submission (or None if the commands to + execute are not from a Language's get_evaluation_commands). time_limit: time limit in seconds (applied to each command); if None, no time limit is enforced. memory_limit: memory limit in bytes (applied to each command); @@ -135,7 +139,7 @@ def evaluation_step( """ for command in commands: success = evaluation_step_before_run( - sandbox, command, time_limit, memory_limit, + sandbox, command, language, time_limit, memory_limit, dirs_map, writable_files, stdin_redirect, stdout_redirect, multiprocess, wait=True) if not success: @@ -152,6 +156,7 @@ def evaluation_step( def evaluation_step_before_run( sandbox: Sandbox, command: list[str], + language: Language | None, time_limit: float | None = None, memory_limit: int | None = None, dirs_map: dict[str, tuple[str | None, str | None]] | None = None, @@ -216,6 +221,10 @@ def evaluation_step_before_run( sandbox.set_multiprocess(multiprocess) + # Configure per-language sandbox parameters. + if language: + language.configure_evaluation_sandbox(sandbox) + # Actually run the evaluation command. logger.debug("Starting execution step.") return sandbox.execute_without_std(command, wait=wait) diff --git a/cms/grading/tasktypes/Batch.py b/cms/grading/tasktypes/Batch.py index d23ab04e51..8dd3e7d89d 100644 --- a/cms/grading/tasktypes/Batch.py +++ b/cms/grading/tasktypes/Batch.py @@ -25,6 +25,8 @@ import os from cms.db import Executable +from cms.db.filecacher import FileCacher +from cms.grading.Job import EvaluationJob from cms.grading.ParameterTypes import ParameterTypeCollection, \ ParameterTypeChoice, ParameterTypeString from cms.grading.language import Language @@ -242,7 +244,7 @@ def _do_compile(self, job, file_cacher): # Run the compilation. box_success, compilation_success, text, stats = \ - compilation_step(sandbox, commands) + compilation_step(sandbox, commands, language) # Retrieve the compiled executables. job.success = box_success @@ -266,7 +268,7 @@ def compile(self, job, file_cacher): self._do_compile(job, file_cacher) - def _execution_step(self, job, file_cacher): + def _execution_step(self, job: EvaluationJob, file_cacher: FileCacher): # Prepare the execution executable_filename = next(iter(job.executables.keys())) language = get_language(job.language) @@ -308,6 +310,7 @@ def _execution_step(self, job, file_cacher): box_success, evaluation_success, stats = evaluation_step( sandbox, commands, + language, job.time_limit, job.memory_limit, writable_files=files_allowing_write, diff --git a/cms/grading/tasktypes/Communication.py b/cms/grading/tasktypes/Communication.py index 60f53a993b..598b85496f 100644 --- a/cms/grading/tasktypes/Communication.py +++ b/cms/grading/tasktypes/Communication.py @@ -227,7 +227,7 @@ def compile(self, job, file_cacher): # Run the compilation. box_success, compilation_success, text, stats = \ - compilation_step(sandbox, commands) + compilation_step(sandbox, commands, language) # Retrieve the compiled executables. job.success = box_success @@ -320,6 +320,7 @@ def evaluate(self, job, file_cacher): manager_ = evaluation_step_before_run( sandbox_mgr, manager_command, + None, manager_time_limit, config.sandbox.trusted_sandbox_max_memory_kib * 1024, dirs_map=dict((fifo_dir[i], (sandbox_fifo_dir[i], "rw")) for i in indices), @@ -355,11 +356,13 @@ def evaluate(self, job, file_cacher): # Assumes that the actual execution of the user solution is the # last command in commands, and that the previous are "setup" # that don't need tight control. + # TODO: why can't this use normal evaluation step?? if len(commands) > 1: trusted_step(sandbox_user[i], commands[:-1]) the_process = evaluation_step_before_run( sandbox_user[i], commands[-1], + language, job.time_limit, job.memory_limit, dirs_map={fifo_dir[i]: (sandbox_fifo_dir[i], "rw")}, diff --git a/cms/grading/tasktypes/TwoSteps.py b/cms/grading/tasktypes/TwoSteps.py index fbe0ee5ce4..c10925dc8b 100644 --- a/cms/grading/tasktypes/TwoSteps.py +++ b/cms/grading/tasktypes/TwoSteps.py @@ -194,7 +194,7 @@ def compile(self, job, file_cacher): # Run the compilation. box_success, compilation_success, text, stats = \ - compilation_step(sandbox, commands) + compilation_step(sandbox, commands, language) # Retrieve the compiled executables job.success = box_success @@ -249,6 +249,7 @@ def evaluate(self, job, file_cacher): first = evaluation_step_before_run( first_sandbox, first_command, + None, job.time_limit, job.memory_limit, dirs_map={fifo_dir: ("/fifo", "rw")}, @@ -272,6 +273,7 @@ def evaluate(self, job, file_cacher): second = evaluation_step_before_run( second_sandbox, second_command, + None, job.time_limit, job.memory_limit, dirs_map={fifo_dir: ("/fifo", "rw")}, diff --git a/cmstestsuite/unit_tests/grading/steps/compilation_test.py b/cmstestsuite/unit_tests/grading/steps/compilation_test.py index 53e0d6029a..8e6d278e78 100755 --- a/cmstestsuite/unit_tests/grading/steps/compilation_test.py +++ b/cmstestsuite/unit_tests/grading/steps/compilation_test.py @@ -26,6 +26,7 @@ from cmstestsuite.unit_tests.grading.steps.fakeisolatesandbox \ import FakeIsolateSandbox from cmstestsuite.unit_tests.grading.steps.stats_test import get_stats +from cmstestsuite.unit_tests.grading.tasktypes.tasktypetestutils import LANG_1 ONE_COMMAND = [["test", "command"]] @@ -54,7 +55,7 @@ def test_single_command_success(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats) as mock_generic_step: success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) mock_generic_step.assert_called_once_with( self.sandbox, ONE_COMMAND, "compilation", collect_output=True) @@ -73,7 +74,7 @@ def test_single_command_compilation_failed_nonzero_return(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats): success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) # User's fault, no error needs to be logged. self.assertLoggedError(False) @@ -91,7 +92,7 @@ def test_single_command_compilation_failed_timeout(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats): success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) # User's fault, no error needs to be logged. self.assertLoggedError(False) @@ -109,7 +110,7 @@ def test_single_command_compilation_failed_timeout_wall(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats): success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) # User's fault, no error needs to be logged. self.assertLoggedError(False) @@ -127,7 +128,7 @@ def test_single_command_compilation_failed_signal(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats): success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) # User's fault, no error needs to be logged. self.assertLoggedError(False) @@ -141,7 +142,7 @@ def test_single_command_sandbox_failed(self): with patch("cms.grading.steps.compilation.generic_step", return_value=None): success, compilation_success, text, stats = compilation_step( - self.sandbox, ONE_COMMAND) + self.sandbox, ONE_COMMAND, LANG_1) # Sandbox should never fail. If it does, should notify the admin. self.assertLoggedError() @@ -156,7 +157,7 @@ def test_multiple_commands_success(self): with patch("cms.grading.steps.compilation.generic_step", return_value=expected_stats) as mock_generic_step: success, compilation_success, text, stats = compilation_step( - self.sandbox, TWO_COMMANDS) + self.sandbox, TWO_COMMANDS, LANG_1) mock_generic_step.assert_called_once_with( self.sandbox, TWO_COMMANDS, "compilation", collect_output=True) diff --git a/cmstestsuite/unit_tests/grading/tasktypes/BatchTest.py b/cmstestsuite/unit_tests/grading/tasktypes/BatchTest.py index f56935111a..e91e75e0ef 100755 --- a/cmstestsuite/unit_tests/grading/tasktypes/BatchTest.py +++ b/cmstestsuite/unit_tests/grading/tasktypes/BatchTest.py @@ -153,7 +153,7 @@ def test_alone_success(self): # Compilation step called correctly. self.compilation_step.assert_called_once_with( sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["foo.l1"], "foo")) + COMPILATION_COMMAND_1, ["foo.l1"], "foo"), LANG_1) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job) sandbox.get_file_to_storage.assert_called_once_with("foo", ANY) @@ -188,8 +188,12 @@ def test_alone_success_two_files(self): self.assertEqual(sandbox.create_file_from_storage.call_count, 2) # Compilation step called correctly. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["foo.l1", "bar.l1"], "bar_foo")) + sandbox, + fake_compilation_commands( + COMPILATION_COMMAND_1, ["foo.l1", "bar.l1"], "bar_foo" + ), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job) sandbox.get_file_to_storage.assert_called_once_with("bar_foo", ANY) @@ -252,8 +256,12 @@ def test_grader_success(self): self.assertEqual(sandbox.create_file_from_storage.call_count, 3) # Compilation step called correctly. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["foo.l1", "grader.l1"], "foo")) + sandbox, + fake_compilation_commands( + COMPILATION_COMMAND_1, ["foo.l1", "grader.l1"], "foo" + ), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job) sandbox.get_file_to_storage.assert_called_once_with("foo", ANY) @@ -354,6 +362,7 @@ def test_stdio_diff_success(self): self.evaluation_step.assert_called_once_with( sandbox, fake_evaluation_commands(EVALUATION_COMMAND_1, "foo", "foo"), + LANG_1, 2.5, 123 * 1024 * 1024, writable_files=[], stdin_redirect="input.txt", @@ -475,6 +484,7 @@ def test_fileio_diff_success(self): self.evaluation_step.assert_called_once_with( sandbox, fake_evaluation_commands(EVALUATION_COMMAND_1, "foo", "foo"), + LANG_1, 2.5, 123 * 1024 * 1024, writable_files=["myout"], stdin_redirect=None, diff --git a/cmstestsuite/unit_tests/grading/tasktypes/CommunicationTest.py b/cmstestsuite/unit_tests/grading/tasktypes/CommunicationTest.py index bdd298dd0c..aaa21cc512 100755 --- a/cmstestsuite/unit_tests/grading/tasktypes/CommunicationTest.py +++ b/cmstestsuite/unit_tests/grading/tasktypes/CommunicationTest.py @@ -167,8 +167,12 @@ def test_one_file_success(self): self.assertEqual(sandbox.create_file_from_storage.call_count, 2) # Compilation step called correctly. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["stub.l1", "foo.l1"], "foo")) + sandbox, + fake_compilation_commands( + COMPILATION_COMMAND_1, ["stub.l1", "foo.l1"], "foo" + ), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job, True, True, TEXT, STATS_OK) sandbox.get_file_to_storage.assert_called_once_with("foo", ANY) @@ -226,9 +230,12 @@ def test_many_files_success(self): self.assertEqual(sandbox.create_file_from_storage.call_count, 3) # Compilation step called correctly. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["stub.l1", "foo.l1", "bar.l1"], - "bar_foo")) + sandbox, + fake_compilation_commands( + COMPILATION_COMMAND_1, ["stub.l1", "foo.l1", "bar.l1"], "bar_foo" + ), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job, True, True, TEXT, STATS_OK) sandbox.get_file_to_storage.assert_called_once_with("bar_foo", ANY) @@ -250,8 +257,10 @@ def test_no_stub_success(self): "foo.l1", "digest of foo.l1") # Compilation step called correctly, without the stub. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["foo.l1"], "foo")) + sandbox, + fake_compilation_commands(COMPILATION_COMMAND_1, ["foo.l1"], "foo"), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job, True, True, TEXT, STATS_OK) sandbox.get_file_to_storage.assert_called_once_with("foo", ANY) @@ -278,8 +287,10 @@ def test_no_stub_but_stub_given_success(self): self.assertEqual(sandbox.create_file_from_storage.call_count, 2) # Compilation step called correctly, without the stub. self.compilation_step.assert_called_once_with( - sandbox, fake_compilation_commands( - COMPILATION_COMMAND_1, ["foo.l1"], "foo")) + sandbox, + fake_compilation_commands(COMPILATION_COMMAND_1, ["foo.l1"], "foo"), + LANG_1, + ) # Results put in job, executable stored and sandbox deleted. self.assertResultsInJob(job, True, True, TEXT, STATS_OK) sandbox.get_file_to_storage.assert_called_once_with("foo", ANY) @@ -388,11 +399,11 @@ def test_single_process_success(self): cmdline_usr = ["run1", "foo", "stub", "/fifo0/m_to_u0", "/fifo0/u0_to_m"] self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_mgr, cmdline_mgr, 4321, 1234 * 1024 * 1024, + call(sandbox_mgr, cmdline_mgr, None, 4321, 1234 * 1024 * 1024, dirs_map={os.path.join(self.base_dir, "0"): ("/fifo0", "rw")}, writable_files=["output.txt"], stdin_redirect="input.txt", multiprocess=True), - call(sandbox_usr, cmdline_usr, 2.5, 123 * 1024 * 1024, + call(sandbox_usr, cmdline_usr, LANG_1, 2.5, 123 * 1024 * 1024, dirs_map={os.path.join(self.base_dir, "0"): ("/fifo0", "rw")}, stdin_redirect=None, stdout_redirect=None, @@ -418,7 +429,7 @@ def test_single_process_success_long_time_limit(self): tt.evaluate(job, self.file_cacher) self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_mgr, ANY, 2.5 + 1, ANY, dirs_map=ANY, + call(sandbox_mgr, ANY, None, 2.5 + 1, ANY, dirs_map=ANY, writable_files=ANY, stdin_redirect=ANY, multiprocess=ANY)]) def test_single_process_missing_manager(self): @@ -591,7 +602,7 @@ def test_single_process_std_io(self): # redirects and no command line arguments. cmdline_usr = ["run1", "foo", "stub"] self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_usr, cmdline_usr, ANY, ANY, dirs_map=ANY, + call(sandbox_usr, cmdline_usr, LANG_1, ANY, ANY, dirs_map=ANY, stdin_redirect="/fifo0/m_to_u0", stdout_redirect="/fifo0/u0_to_m", multiprocess=ANY)]) @@ -639,19 +650,19 @@ def test_many_processes_success(self): cmdline_usr1 = ["run1", "foo", "stub", "/fifo1/m_to_u1", "/fifo1/u1_to_m", "1"] self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_mgr, cmdline_mgr, 4321, 1234 * 1024 * 1024, + call(sandbox_mgr, cmdline_mgr, None, 4321, 1234 * 1024 * 1024, dirs_map={ os.path.join(self.base_dir, "0"): ("/fifo0", "rw"), os.path.join(self.base_dir, "1"): ("/fifo1", "rw"), }, writable_files=["output.txt"], stdin_redirect="input.txt", multiprocess=True), - call(sandbox_usr0, cmdline_usr0, 2.5, 123 * 1024 * 1024, + call(sandbox_usr0, cmdline_usr0, LANG_1, 2.5, 123 * 1024 * 1024, dirs_map={os.path.join(self.base_dir, "0"): ("/fifo0", "rw")}, stdin_redirect=None, stdout_redirect=None, multiprocess=True), - call(sandbox_usr1, cmdline_usr1, 2.5, 123 * 1024 * 1024, + call(sandbox_usr1, cmdline_usr1, LANG_1, 2.5, 123 * 1024 * 1024, dirs_map={os.path.join(self.base_dir, "1"): ("/fifo1", "rw")}, stdin_redirect=None, stdout_redirect=None, @@ -680,7 +691,7 @@ def test_many_processes_success_long_time_limit(self): tt.evaluate(job, self.file_cacher) self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_mgr, ANY, 2 * (2.5 + 1), ANY, dirs_map=ANY, + call(sandbox_mgr, ANY, None, 2 * (2.5 + 1), ANY, dirs_map=ANY, writable_files=ANY, stdin_redirect=ANY, multiprocess=ANY)]) def test_many_processes_first_user_failure(self): @@ -775,11 +786,11 @@ def test_many_processes_std_io(self): cmdline_usr0 = ["run1", "foo", "stub", "0"] cmdline_usr1 = ["run1", "foo", "stub", "1"] self.evaluation_step_before_run.assert_has_calls([ - call(sandbox_usr0, cmdline_usr0, ANY, ANY, dirs_map=ANY, + call(sandbox_usr0, cmdline_usr0, LANG_1, ANY, ANY, dirs_map=ANY, stdin_redirect="/fifo0/m_to_u0", stdout_redirect="/fifo0/u0_to_m", multiprocess=ANY), - call(sandbox_usr1, cmdline_usr1, ANY, ANY, dirs_map=ANY, + call(sandbox_usr1, cmdline_usr1, LANG_1, ANY, ANY, dirs_map=ANY, stdin_redirect="/fifo1/m_to_u1", stdout_redirect="/fifo1/u1_to_m", multiprocess=ANY)