def _wait(self): remaining = None if self.timeout: remaining = self.timeout + self._start - _time() try: self._process.wait(remaining) except KeyboardInterrupt: self._process_lock.acquire() self._process.kill() self._process.wait() self._process_lock.release() self.interrupted = True except TimeoutExpired: self._process_lock.acquire() self._process.kill() stdout, stderr = self._process.communicate() self._process_lock.release() self.stdout_data, self.stderr_data = stdout, stderr self.expired = True raise TimeoutExpired(self.args, timeout, stdout, stderr) except: self._process_lock.acquire() self._process.kill() self._process.wait() self._process_lock.release() raise finally: self._end = _time() self.returncode = retcode = self._process.poll() self._cleanup() if not (self.expired or self.interrupted) and self.returncode: stdout, stderr = self.stdout_data, self.stderr_data raise CalledProcessError(retcode, self.args, stdout, stderr)
def run(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs): """Patched of subprocess.run to fix blocking io making timeout=innefective""" if input is not None: if 'stdin' in kwargs: raise ValueError('stdin and input arguments may not both be used.') kwargs['stdin'] = PIPE if capture_output: if ('stdout' in kwargs) or ('stderr' in kwargs): raise ValueError('stdout and stderr arguments may not be used ' 'with capture_output.') kwargs['stdout'] = PIPE kwargs['stderr'] = PIPE with Popen(*popenargs, **kwargs) as process: try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired: process.kill() try: stdout, stderr = process.communicate(input, timeout=2) except: pass raise TimeoutExpired(popenargs[0][0], timeout) except BaseException: process.kill() # We don't call process.wait() as .__exit__ does that for us. raise retcode = process.poll() if check and retcode: raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) return CompletedProcess(process.args, retcode, stdout, stderr)
def test_returns_false_when_unable_to_check_device(self): device = factory.make_name("device") self.mock_check_smart_support.return_value = (device, [42]) self.mock_check_smartctl.side_effect = ( random.choice( [ TimeoutExpired("smartctl", 60), CalledProcessError(42, "smartctl"), ] ), ) device = "%s,42" % device self.assertFalse( smartctl.execute_smartctl(self.blockdevice, self.test) ) self.assertThat( self.mock_check_smart_support, MockCallsMatch( call(self.blockdevice), call(self.blockdevice, device) ), ) self.assertThat( self.mock_run_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device), ) self.assertThat( self.mock_wait_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device), ) self.assertThat( self.mock_check_smartctl, MockCalledOnceWith(self.blockdevice, device), )
def test_list_supported_drives_ignores_iscsiadm_timeout(self): mock_check_output = self.patch(badblocks, 'check_output') drive = self.make_drive() mock_check_output.side_effect = [ TimeoutExpired('iscsiadm', 60), self.make_lsblk_line(drive) ] self.assertDictEqual({ 'PATH': '/dev/%s' % drive['NAME'], **drive }, badblocks.list_drives()[0]) self.assertThat( mock_check_output, MockCallsMatch( call(['sudo', '-n', 'iscsiadm', '-m', 'session', '-P', '3'], timeout=badblocks.TIMEOUT, stderr=DEVNULL), call([ 'lsblk', '--exclude', '1,2,7', '-d', '-P', '-o', 'NAME,RO,MODEL,SERIAL', ], timeout=badblocks.TIMEOUT)))
def _run(*args, env=None, check=False, timeout=None): encoded_args = [a.encode('utf-8') for a in args] if sys.platform != 'win32' else args with subprocess.Popen(encoded_args, env=env, stdout=PIPE, stderr=PIPE) as process: try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired: process.kill() stdout, stderr = process.communicate() raise TimeoutExpired( process.args, timeout, output=stdout, stderr=stderr, ) except Exception: process.kill() process.wait() raise retcode = process.poll() if check and retcode: raise subprocess.CalledProcessError( retcode, process.args, output=stdout, stderr=stderr, ) return subprocess.CompletedProcess(process.args, retcode, stdout, stderr)
async def wait(self, timeout=None): returncode = self.returncode if (returncode is not None): return returncode waiter = Future(self.loop) exit_waiters = self._exit_waiters if exit_waiters is None: self._exit_waiters = exit_waiters = set() exit_waiters.add(waiter) if (timeout is not None): future_or_timeout(waiter, timeout) try: return await waiter except TimeoutError: try: exit_waiters.remove(waiter) except ValueError: pass process = self.process if process is None: args = None else: args = process.args raise TimeoutExpired(args, timeout) from None
def _run(*args, env=None, check=False, timeout=None): with subprocess.Popen(args, env=env, stdout=PIPE, stderr=PIPE) as process: try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired: process.kill() stdout, stderr = process.communicate() raise TimeoutExpired( process.args, timeout, output=stdout, stderr=stderr, ) except: process.kill() process.wait() raise retcode = process.poll() if check and retcode: raise subprocess.CalledProcessError( retcode, process.args, output=stdout, stderr=stderr, ) return subprocess.CompletedProcess(process.args, retcode, stdout, stderr)
def communicate_timeout(self, timeout=None): # pylint: disable=no-self-use,unused-argument """pass this method as a replacement to themocked Popen.communicate method""" process = mock.Mock() process.pid = 0 if timeout: raise TimeoutExpired(process, timeout) return [bytes(self.partial_response, 'utf-8')]
def test_run_script_timed_out_script(self): scripts_dir = self.useFixture(TempDirectory()).path script = make_script(scripts_dir=scripts_dir) self.mock_capture_script_output.side_effect = TimeoutExpired( [factory.make_name('arg') for _ in range(3)], script['timeout_seconds']) self.args.pop('status') self.assertFalse(run_script(script, scripts_dir)) self.assertThat(self.mock_output_and_send, MockCallsMatch( call( 'Starting %s' % script['msg_name'], status='WORKING', **self.args), call( 'Timeout(%s) expired on %s' % ( str(timedelta(seconds=script['timeout_seconds'])), script['msg_name']), files={ script['combined_name']: script['combined'].encode(), script['stdout_name']: script['stdout'].encode(), script['stderr_name']: script['stderr'].encode(), script['result_name']: script['result'].encode(), }, status='TIMEDOUT', **self.args), ))
def run_with_pipes(*popenargs, input=None, timeout=None, check=False, **kwargs): if input is not None: if 'stdin' in kwargs: raise ValueError('stdin and input arguments may not both be used.') kwargs['stdin'] = PIPE with _Popen(*popenargs, **kwargs) as process: try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired: process.kill() stdout, stderr = process.communicate() raise TimeoutExpired(process.args, timeout, output=stdout, stderr=stderr) except: process.kill() process.wait() raise retcode = process.poll() if check and retcode: raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) return CompletedProcess(process.args, retcode, stdout, stderr), process.is_ole
async def run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False): ''' Curio-compatible version of subprocess.run() ''' if input: stdin = subprocess.PIPE else: stdin = None async with Popen(args, stdin=stdin, stdout=stdout, stderr=stderr, shell=shell) as process: try: stdout, stderr = await process.communicate(input, timeout) except TaskTimeout: process.kill() stdout, stderr = await process.communicate() raise TimeoutExpired(process.args, timeout, output=stdout, stderr=stderr) except: process.kill() raise retcode = process.poll() if check and retcode: raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) return CompletedProcess(process.args, retcode, stdout, stderr)
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_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_classA_with_mock(): b = mock.Mock(B) b.get_value.side_effect = [0, TimeoutExpired("ping ya.ru", 5)] a = A(b) assert a.get_param1_value() == 0 with pytest.raises(TimeoutExpired): a.get_param1_value()
def run_win_proc(cmd, timeout=10, out_path=''): """Run a subprocess on Windows. Args: cmd (list): the command to be executed. timeout (float): Minute timeout for the command. Only runs the process if the value is positive. out_path (str): Path to where to write stdout. """ if timeout > 0 and system() == 'Windows': timeout_expired = False timeout *= 60 # minutes to seconds try: if out_path: pr = Popen(cmd, stdout=PIPE) else: pr = Popen(cmd) out, err = pr.communicate(timeout=timeout) except TimeoutExpired: kill = Path(cmd[1]).name kill = "Taskkill /IM {} /F".format(kill) _ = run(kill, capture_output=True) timeout_expired = True out = str.encode('Timeout Achieved.') if out_path: with open(out_path, 'wb') as f: _ = f.write(out) if timeout_expired: raise TimeoutExpired(' '.join(cmd), timeout)
def test_timeout(): """The credential should raise CredentialUnavailableError when the subprocess times out""" from subprocess import TimeoutExpired with mock.patch(CHECK_OUTPUT, mock.Mock(side_effect=TimeoutExpired("", 42))): with pytest.raises(CredentialUnavailableError): AzureCliCredential().get_token("scope")
def test_raises_timeoutexpired(self): mock_run_smartctl = self.patch(smartctl, "run_smartctl") mock_run_smartctl.side_effect = TimeoutExpired("smartctl", 60) self.assertRaises( TimeoutExpired, smartctl.check_SMART_support, factory.make_name("blockdevice"), )
def test_disassociate_user_error_handling(self, mock_subproc_run): # the command should still return a string when an exception is thrown mock_subproc_run.side_effect = TimeoutExpired('x', 5) self._run_disassoc(mock_subproc_run) mock_subproc_run.reset_mock(side_effect=True) mock_subproc_run.side_effect = CalledProcessError(1, 'cmd') self._run_disassoc(mock_subproc_run)
def fake_wait(timeout=None): # The fake implementation is that wait() times out forever until os.killpg is called. if self.mock_kill.call_count == 0 and timeout is not None: raise TimeoutExpired(None, timeout) elif self.mock_kill.call_count > 0: if wait_exception: raise wait_exception return fake_returncode self.fail('Popen.wait() should not be called without a timeout before os.killpg has been called.')
def run_timeout(cmd, timeout, env): with Popen(cmd, stdout=PIPE, stderr=STDOUT, preexec_fn=setsid, env=env) as process: try: return process.communicate(timeout=timeout)[0] except TimeoutExpired: killpg(process.pid, signal.SIGINT) # send signal to the process group raise TimeoutExpired(cmd, timeout)
def test_raises_timeoutexpired(self): mock_run_smartctl = self.patch(smartctl, "run_smartctl") mock_run_smartctl.side_effect = TimeoutExpired("smartctl", 60) mock_print = self.patch(smartctl, "print") blockdevice = factory.make_name("blockdevice") test = factory.make_name("test") self.assertRaises(TimeoutExpired, smartctl.run_smartctl_selftest, blockdevice, test) self.assertThat(mock_print, MockCalledOnce())
def test__raises_timeoutexpired(self): mock_run_smartctl = self.patch(smartctl, 'run_smartctl') mock_run_smartctl.side_effect = TimeoutExpired('smartctl', 60) mock_print = self.patch(smartctl, 'print') blockdevice = factory.make_name('blockdevice') test = factory.make_name('test') self.assertRaises(TimeoutExpired, smartctl.run_smartctl_selftest, blockdevice, test) self.assertThat(mock_print, MockCalledOnce())
def run(*popenargs, **kwargs): """Run command with arguments and return a CompletedProcess instance. The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute, and output & stderr attributes if those streams were captured. If timeout is given, and the process takes too long, a TimeoutExpired exception will be raised. There is an optional argument "input", allowing you to pass a string to the subprocess's stdin. If you use this argument you may not also use the Popen constructor's "stdin" argument, as it will be used internally. The other arguments are the same as for the Popen constructor. If universal_newlines=True is passed, the "input" argument must be a string and stdout/stderr in the returned object will be strings rather than bytes. """ input = kwargs.pop("input", None) timeout = kwargs.pop("timeout", None) check = kwargs.pop("check", False) if input is not None: if "stdin" in kwargs: raise ValueError( "stdin and input arguments may not both be used.") kwargs["stdin"] = PIPE process = Popen(*popenargs, **kwargs) try: process.__enter__() # No-Op really... illustrate "with in 2.4" try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired: process.kill() stdout, stderr = process.communicate() raise TimeoutExpired(process.args, timeout, output=stdout, stderr=stderr) except: process.kill() process.wait() raise retcode = process.poll() if check and retcode: raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) finally: # None because our context manager __exit__ does not use them. process.__exit__(None, None, None) return CompletedProcess(process.args, retcode, stdout, stderr)
def test__returns_false_with_check_smart_support_error(self): self.mock_check_smart_support.side_effect = random.choice([ TimeoutExpired('smartctl', 60), CalledProcessError(42, 'smartctl'), ]) self.assertFalse(smartctl.execute_smartctl(self.blockdevice, self.test)) self.assertThat(self.mock_run_smartctl_selftest, MockNotCalled()) self.assertThat(self.mock_wait_smartctl_selftest, MockNotCalled()) self.assertThat(self.mock_check_smartctl, MockNotCalled())
def test__raises_timeoutexpired(self): blockdevice = factory.make_name('blockdevice') test = factory.make_name('test') device = factory.make_name('device') mock_run_smartctl = self.patch(smartctl, 'run_smartctl') mock_run_smartctl.side_effect = TimeoutExpired('smartctl', 60) mock_sleep = self.patch(smartctl, 'sleep') self.assertRaises(TimeoutExpired, smartctl.wait_smartctl_selftest, blockdevice, test, device) self.assertThat(mock_sleep, MockNotCalled())
def test_package_dependencies_failed(mock_package, tmpdir): with mock.patch('tempfile.TemporaryDirectory') as tmpdir_mock, \ mock.patch('piwheels.slave.builder.Popen') as popen_mock, \ mock.patch('piwheels.slave.builder.apt') as apt_mock: tmpdir_mock().__enter__.return_value = str(tmpdir) popen_mock().communicate.side_effect = [ TimeoutExpired('ldd', 10), (b"", b"")] path = Path('/tmp/abc123/foo-0.1-cp34-cp34m-linux_armv7l.whl') pkg = builder.PiWheelsPackage(path) assert pkg.dependencies == {}
def callSpinfer(cmd,timeout =900,enc='utf-8'): output = '' errors = '' # logging.debug(cmd) my_timer = None with Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True,encoding=enc) as p: try: start = datetime.datetime.now() memusage = getAllChildMe(p.pid) # isExit = False while(memusage != 0.0): end = datetime.datetime.now() elapsed = end - start if(elapsed.seconds > timeout): raise TimeoutExpired(cmd,timeout) memusage = getAllChildMe(p.pid) # print(str(p.pid) + " ; " + str(memusage)) if memusage > 2000: # isExit = True raise TimeoutExpired(cmd,timeout) output, errors = p.communicate(timeout=timeout) # print(output) logging.debug(cmd + '\t' +output) # logging.info(errors) if errors: raise CalledProcessError(errors, '-1') output except CalledProcessError as e: logging.debug(cmd +'\t'+ errors) except TimeoutExpired as t: # my_timer.cancel() childrenProcess = [] getChildMem(p.pid, childrenProcess) [killP(i) for i in childrenProcess] p.terminate() p.communicate() # p.kill() logging.warning(cmd +'\t'+str(t)) return output,errors
def test_run_timeout(self, m_run): host = "example.test" m_run.side_effect = TimeoutExpired("cmd", 300, "output text", "error text") self.b.hosts = [Host(host)] rc = self.b.run() self.assertEqual(rc, 1) self.assertIn(host, " ".join(m_run.call_args[0][0])) m_run.assert_called_once() self.log.error.assert_called()
def communicate(self, input=None, timeout=None): if self.returncode is not None: return (None, None) if input is not None and self.stdin is not None: self.stdin.write(input) if timeout is not None: end_time = time.time() + timeout else: end_time = None stdout = ("" if self.stdout is None or isinstance(self.stdout, TextIOWrapper) else b"") stderr = ("" if self.stderr is None or isinstance(self.stderr, TextIOWrapper) else b"") while self.poll() is None: if end_time is not None and time.time() >= end_time: raise TimeoutExpired(self.args, timeout, stdout) if self.stdout is not None: new_stdout = self.stdout.read(4096) if new_stdout is not None: stdout += new_stdout if self.stderr is not None: new_stderr = self.stderr.read(4096) if new_stderr is not None: stderr += new_stderr if self.stdout is not None: while True: new = self.stdout.read(4096) stdout += new if len(new) == 0: break if self.stderr is not None: while True: new = self.stderr.read(4096) stderr += new if len(new) == 0: break if len(stderr) == 0: stderr = None if len(stdout) == 0: stdout = None self.cleanup() return (stdout, stderr)
def test__returns_false_when_starting_test_fails(self): self.mock_check_smart_support.return_value = (None, []) self.mock_run_smartctl_selftest.side_effect = random.choice([ TimeoutExpired('smartctl', 60), CalledProcessError(42, 'smartctl'), ]) self.assertFalse(smartctl.execute_smartctl(self.blockdevice, self.test)) self.assertThat(self.mock_run_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test)) self.assertThat(self.mock_wait_smartctl_selftest, MockNotCalled()) self.assertThat(self.mock_check_smartctl, MockCalledOnceWith(self.blockdevice))