|
6 | 6 | import os.path |
7 | 7 | import textwrap |
8 | 8 | import unittest |
| 9 | +from unittest.mock import patch |
9 | 10 |
|
10 | 11 | import pytest |
11 | 12 | import random2 as random |
|
20 | 21 |
|
21 | 22 | from openedx.core.djangolib.testing.utils import skip_unless_lms |
22 | 23 | from xmodule.capa.safe_exec import safe_exec, update_hash |
23 | | -from xmodule.capa.safe_exec.remote_exec import is_codejail_rest_service_enabled |
| 24 | +from xmodule.capa.safe_exec.remote_exec import is_codejail_in_darklaunch, is_codejail_rest_service_enabled |
24 | 25 |
|
25 | 26 |
|
26 | 27 | class TestSafeExec(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring |
@@ -125,6 +126,70 @@ def test_can_do_something_forbidden_if_run_unsafely(self): |
125 | 126 | assert "SystemExit" in str(cm) |
126 | 127 |
|
127 | 128 |
|
| 129 | +class TestCodeJailDarkLaunch(unittest.TestCase): |
| 130 | + """ |
| 131 | + Test that the behavior of the dark launched code behaves as expected. |
| 132 | + """ |
| 133 | + @patch('xmodule.capa.safe_exec.safe_exec.get_remote_exec') |
| 134 | + @patch('xmodule.capa.safe_exec.safe_exec.codejail_safe_exec') |
| 135 | + def test_default_code_execution(self, local_exec, remote_exec): |
| 136 | + |
| 137 | + # Test default only runs local exec. |
| 138 | + g = {} |
| 139 | + safe_exec('a=1', g) |
| 140 | + assert local_exec.called |
| 141 | + assert not remote_exec.called |
| 142 | + |
| 143 | + @override_settings(ENABLE_CODEJAIL_REST_SERVICE=True) |
| 144 | + @patch('xmodule.capa.safe_exec.safe_exec.get_remote_exec') |
| 145 | + @patch('xmodule.capa.safe_exec.safe_exec.codejail_safe_exec') |
| 146 | + def test_code_execution_only_codejail_service(self, local_exec, remote_exec): |
| 147 | + # Set return values to empty values to indicate no error. |
| 148 | + remote_exec.return_value = (None, None) |
| 149 | + # Test with only the service enabled. |
| 150 | + g = {} |
| 151 | + safe_exec('a=1', g) |
| 152 | + assert not local_exec.called |
| 153 | + assert remote_exec.called |
| 154 | + |
| 155 | + @override_settings(ENABLE_CODEJAIL_DARKLAUNCH=True) |
| 156 | + @patch('xmodule.capa.safe_exec.safe_exec.get_remote_exec') |
| 157 | + @patch('xmodule.capa.safe_exec.safe_exec.codejail_safe_exec') |
| 158 | + def test_code_execution_darklaunch(self, local_exec, remote_exec): |
| 159 | + # Set return values to empty values to indicate no error. |
| 160 | + remote_exec.return_value = (None, None) |
| 161 | + g = {} |
| 162 | + |
| 163 | + # Verify that incorrect config runs only remote and not both. |
| 164 | + with override_settings(ENABLE_CODEJAIL_REST_SERVICE=True): |
| 165 | + safe_exec('a=1', g) |
| 166 | + assert not local_exec.called |
| 167 | + assert remote_exec.called |
| 168 | + |
| 169 | + local_exec.reset_mock() |
| 170 | + remote_exec.reset_mock() |
| 171 | + |
| 172 | + # Set up side effects to mimic the real behavior of modifying the globals_dict. |
| 173 | + def local_side_effect(*args, **kwargs): |
| 174 | + test_globals = args[1] |
| 175 | + test_globals['test'] = 'local_test' |
| 176 | + |
| 177 | + def remote_side_effect(*args, **kwargs): |
| 178 | + test_globals = args[0]['globals_dict'] |
| 179 | + test_globals['test'] = 'remote_test' |
| 180 | + |
| 181 | + local_exec.side_effect = local_side_effect |
| 182 | + remote_exec.side_effect = remote_side_effect |
| 183 | + |
| 184 | + assert is_codejail_in_darklaunch() |
| 185 | + safe_exec('a=1', g) |
| 186 | + |
| 187 | + assert local_exec.called |
| 188 | + assert remote_exec.called |
| 189 | + # Verify that the local/default behavior currently wins out. |
| 190 | + assert g['test'] == 'local_test' |
| 191 | + |
| 192 | + |
128 | 193 | class TestLimitConfiguration(unittest.TestCase): |
129 | 194 | """ |
130 | 195 | Test that resource limits can be configured and overriden via Django settings. |
|
0 commit comments