def test_execute_command_in_project_does_not_choke_on_weird_command_output(self): some_weird_output = b'\xbf\xe2\x98\x82' # the byte \xbf is invalid unicode self.mock_popen.communicate.return_value = (some_weird_output, None) self.mock_popen.returncode = (some_weird_output, None) project_type = ProjectType() project_type.execute_command_in_project('fake command')
def test_timing_out_will_break_out_of_command_execution_wait_loop_and_kill_subprocesses( self): mock_time = self.patch('time.time') mock_time.side_effect = [ 0.0, 100.0, 200.0, 300.0 ] # time increases by 100 seconds with each loop expected_return_code = 1 self._simulate_hanging_popen_process( fake_returncode=expected_return_code) self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b'fake output', b'fake error') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( command='sleep 99', timeout=250) self.assertEqual( self.mock_killpg.call_count, 1, 'os.killpg should be called when execution times out.') self.assertEqual(actual_output, 'fake output\nfake error', 'Output should contain stdout and stderr.') self.assertEqual(actual_return_code, expected_return_code, 'Actual return code should match expected.') self.assertTrue( all([file.close.called for file in self.mock_temporary_files]), 'All created TemporaryFiles should be closed so that they are removed from the filesystem.' )
def test_command_exiting_normally_will_break_out_of_command_execution_wait_loop( self): timeout_exc = TimeoutExpired(cmd=None, timeout=1) expected_return_code = 0 # Simulate Popen.wait() timing out twice before command completes and returns output. self.mock_popen.wait.side_effect = [ timeout_exc, timeout_exc, expected_return_code ] self.mock_popen.returncode = expected_return_code self._mock_stdout_and_stderr(b'fake_output', b'fake_error') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( 'echo The power is yours!') self.assertEqual( self.mock_killpg.call_count, 0, 'os.killpg should not be called when command exits normally.') self.assertEqual(actual_output, 'fake_output\nfake_error', 'Output should contain stdout and stderr.') self.assertEqual(actual_return_code, expected_return_code, 'Actual return code should match expected.') self.assertTrue( all([file.close.called for file in self.mock_temporary_files]), 'All created TemporaryFiles should be closed so that they are removed from the filesystem.' )
def test_exception_raised_while_waiting_causes_termination_and_adds_error_message_to_output( self): exception_message = 'Something terribly horrible just happened!' value_err_exc = ValueError(exception_message) timeout_exc = TimeoutExpired(cmd=None, timeout=1) fake_failing_return_code = -15 # Simulate Popen.wait() timing out twice before raising a ValueError exception. self.mock_popen.wait.side_effect = [ timeout_exc, timeout_exc, value_err_exc, fake_failing_return_code ] self.mock_popen.returncode = fake_failing_return_code self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b'', b'') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( 'echo The power is yours!') self.assertEqual( self.mock_killpg.call_count, 1, 'os.killpg should be called when wait() raises exception.') self.assertIn( exception_message, actual_output, 'ClusterRunner exception message should be included in output.') self.assertEqual(actual_return_code, fake_failing_return_code, 'Actual return code should match expected.')
def test_teardown_build_runs_teardown(self): job_config = JobConfig("name", "setup", "teardown", "command", "atomizer", 10, 10) project_type = ProjectType() project_type.job_config = MagicMock(return_value=job_config) project_type.execute_command_in_project = MagicMock(return_value=("", 0)) project_type.teardown_build() project_type.execute_command_in_project.assert_called_with("teardown", timeout=None)
def test_teardown_build_runs_teardown(self): job_config = JobConfig('name', 'setup', 'teardown', 'command', 'atomizer', 10, 10) project_type = ProjectType() project_type.job_config = MagicMock(return_value=job_config) project_type.execute_command_in_project = MagicMock(return_value=('', 0)) project_type.teardown_build() project_type.execute_command_in_project.assert_called_with('teardown', timeout=None)
def test_teardown_build_runs_teardown(self): job_config = JobConfig('name', 'setup', 'teardown', 'command', 'atomizer', 10) project_type = ProjectType() project_type.job_config = MagicMock(return_value=job_config) project_type.execute_command_in_project = MagicMock(return_value=('', 0)) project_type.teardown_build() project_type.execute_command_in_project.assert_called_with('teardown')
def test_failing_exit_code_is_injected_when_no_return_code_available(self): self.mock_popen.returncode = None # This will happen if we were not able to terminate the process. self._mock_stdout_and_stderr(b'', b'') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project('echo The power is yours!') self.assertIsInstance(actual_return_code, int, 'Returned exit code should always be an int.') self.assertNotEqual(actual_return_code, 0, 'Returned exit code should be failing (non-zero) when subprocess ' 'returncode is not available.')
def test_execute_command_in_project_does_not_choke_on_weird_command_output(self): some_weird_output = b'\xbf\xe2\x98\x82' # the byte \xbf is invalid unicode self._mock_stdout_and_stderr(some_weird_output, b'') self.mock_popen.returncode = 0 project_type = ProjectType() actual_output, _ = project_type.execute_command_in_project('fake command') # Part of this test is just proving that no exception is raised on invalid output. self.assertIsInstance(actual_output, str, 'Invalid output from a process should still be converted to string.')
def test_failing_exit_code_is_injected_when_no_return_code_available(self): self.mock_popen.returncode = None # This will happen if we were not able to terminate the process. self._mock_stdout_and_stderr(b'', b'') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project('echo The power is yours!') self.assertIsInstance(actual_return_code, int, 'Returned exit code should always be an int.') self.assertNotEqual(actual_return_code, 0, 'Returned exit code should be failing (non-zero) when subprocess ' 'returncode is not available.')
def test_execute_command_in_project_does_not_choke_on_weird_command_output(self): some_weird_output = b"\xbf\xe2\x98\x82" # the byte \xbf is invalid unicode self._mock_stdout_and_stderr(some_weird_output, b"") self.mock_popen.returncode = 0 project_type = ProjectType() actual_output, _ = project_type.execute_command_in_project("fake command") # Part of this test is just proving that no exception is raised on invalid output. self.assertIsInstance(actual_output, str, "Invalid output from a process should still be converted to string.")
def test_command_exiting_normally_will_break_out_of_command_execution_wait_loop(self): # Simulate Popen.communicate() timing out twice before command completes and returns output. timeout_exc = TimeoutExpired(None, 1) self.mock_popen.communicate.side_effect = [timeout_exc, timeout_exc, (b'fake_output', b'fake_error')] self.mock_popen.returncode = 0 self.mock_popen.pid = 55555 project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project('echo The power is yours!') self.assertEqual(self.mock_killpg.call_count, 0, 'os.killpg should not be called when command exits normally.') self.assertEqual(actual_output, 'fake_output\nfake_error', 'Output should contain stdout and stderr.')
def test_teardown_build_executes_teardown_command(self, expected_timeout): project_type = ProjectType() mock_execute = MagicMock(return_value=('fake output', 0)) project_type.execute_command_in_project = mock_execute project_type.job_config = MagicMock() if expected_timeout: project_type.teardown_build(timeout=expected_timeout) else: project_type.teardown_build() mock_execute.assert_called_once_with(ANY, timeout=expected_timeout)
def test_teardown_build_executes_teardown_command(self, expected_timeout): project_type = ProjectType() mock_execute = MagicMock(return_value=("fake output", 0)) project_type.execute_command_in_project = mock_execute project_type.job_config = MagicMock() if expected_timeout: project_type.teardown_build(timeout=expected_timeout) else: project_type.teardown_build() mock_execute.assert_called_once_with(ANY, timeout=expected_timeout)
def test_timing_out_will_break_out_of_command_execution_wait_loop_and_kill_subprocesses(self): mock_time = self.patch('time.time') mock_time.side_effect = [0.0, 100.0, 200.0, 300.0] # time increases by 100 seconds with each loop self._mock_out_popen_communicate() project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( command='sleep 99', timeout=250, ) self.assertEqual(self.mock_killpg.call_count, 1, 'os.killpg should be called when execution times out.') self.assertEqual(actual_output, 'fake output\nfake error', 'Output should contain stdout and stderr.')
def test_command_exiting_normally_will_break_out_of_command_execution_wait_loop(self): timeout_exc = TimeoutExpired(cmd=None, timeout=1) expected_return_code = 0 # Simulate Popen.wait() timing out twice before command completes and returns output. self.mock_popen.wait.side_effect = [timeout_exc, timeout_exc, expected_return_code] self.mock_popen.returncode = expected_return_code self._mock_stdout_and_stderr(b'fake_output', b'fake_error') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project('echo The power is yours!') self.assertEqual(self.mock_killpg.call_count, 0, 'os.killpg should not be called when command exits normally.') self.assertEqual(actual_output, 'fake_output\nfake_error', 'Output should contain stdout and stderr.') self.assertEqual(actual_return_code, expected_return_code, 'Actual return code should match expected.') self.assertTrue(all([file.close.called for file in self.mock_temporary_files]), 'All created TemporaryFiles should be closed so that they are removed from the filesystem.')
def test_exception_raised_while_waiting_for_termination_adds_error_message_to_output(self): mock_time = self.patch('time.time') mock_time.side_effect = [0.0, 100.0, 200.0, 300.0] # time increases by 100 seconds with each loop fake_failing_return_code = -15 self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b'', b'') exception_message = 'Something terribly horrible just happened!' self._simulate_hanging_popen_process( fake_returncode=fake_failing_return_code, wait_exception=ValueError(exception_message)) project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( 'echo The power is yours!', timeout=250) self.assertIn(exception_message, actual_output, 'ClusterRunner exception message should be included in output.') self.assertEqual(actual_return_code, fake_failing_return_code, 'Actual return code should match expected.')
def test_exception_raised_while_waiting_for_termination_adds_error_message_to_output(self): mock_time = self.patch('time.time') mock_time.side_effect = [0.0, 100.0, 200.0, 300.0] # time increases by 100 seconds with each loop fake_failing_return_code = -15 self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b'', b'') exception_message = 'Something terribly horrible just happened!' self._simulate_hanging_popen_process( fake_returncode=fake_failing_return_code, wait_exception=ValueError(exception_message)) project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( 'echo The power is yours!', timeout=250) self.assertIn(exception_message, actual_output, 'ClusterRunner exception message should be included in output.') self.assertEqual(actual_return_code, fake_failing_return_code, 'Actual return code should match expected.')
def test_timing_out_will_break_out_of_command_execution_wait_loop_and_kill_subprocesses(self): mock_time = self.patch('time.time') mock_time.side_effect = [0.0, 100.0, 200.0, 300.0] # time increases by 100 seconds with each loop expected_return_code = 1 self._simulate_hanging_popen_process(fake_returncode=expected_return_code) self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b'fake output', b'fake error') project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project( command='sleep 99', timeout=250) self.assertEqual(self.mock_killpg.call_count, 1, 'os.killpg should be called when execution times out.') self.assertEqual(actual_output, 'fake output\nfake error', 'Output should contain stdout and stderr.') self.assertEqual(actual_return_code, expected_return_code, 'Actual return code should match expected.') self.assertTrue(all([file.close.called for file in self.mock_temporary_files]), 'All created TemporaryFiles should be closed so that they are removed from the filesystem.')
def test_exception_raised_while_waiting_causes_termination_and_adds_error_message_to_output(self): exception_message = "Something terribly horrible just happened!" value_err_exc = ValueError(exception_message) timeout_exc = TimeoutExpired(cmd=None, timeout=1) fake_failing_return_code = -15 # Simulate Popen.wait() timing out twice before raising a ValueError exception. self.mock_popen.wait.side_effect = [timeout_exc, timeout_exc, value_err_exc, fake_failing_return_code] self.mock_popen.returncode = fake_failing_return_code self.mock_popen.pid = 55555 self._mock_stdout_and_stderr(b"", b"") project_type = ProjectType() actual_output, actual_return_code = project_type.execute_command_in_project("echo The power is yours!") self.assertEqual(self.mock_kill.call_count, 1, "os.killpg should be called when wait() raises exception.") self.assertIn(exception_message, actual_output, "ClusterRunner exception message should be included in output.") self.assertEqual(actual_return_code, fake_failing_return_code, "Actual return code should match expected.")