def start(self): """Start the process and the logger pipes for its stdout and stderr.""" creation_flags = 0 if sys.platform == "win32" and _JOB_OBJECT is not None: creation_flags |= win32process.CREATE_BREAKAWAY_FROM_JOB # Tests fail if a process takes too long to startup and listen to a socket. Use buffered # I/O pipes to give the process some leeway. buffer_size = 1024 * 1024 # Close file descriptors in the child process before executing the program. This prevents # file descriptors that were inherited due to multiple calls to fork() -- either within one # thread, or concurrently from multiple threads -- from causing another subprocess to wait # for the completion of the newly spawned child process. Closing other file descriptors # isn't supported on Windows when stdout and stderr are redirected. close_fds = (sys.platform != "win32") with _POPEN_LOCK: self._process = subprocess.Popen(self.args, bufsize=buffer_size, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=close_fds, env=self.env, creationflags=creation_flags, cwd=self._cwd) self.pid = self._process.pid if _config.UNDO_RECORDER_PATH is not None and ( "mongod" in self.args[0] or "mongos" in self.args[0]): recorder_args = [ _config.UNDO_RECORDER_PATH, "--thread-fuzzing", "-p", str(self.pid) ] self._recorder = subprocess.Popen(recorder_args, bufsize=buffer_size, env=self.env, creationflags=creation_flags) self._stdout_pipe = pipe.LoggerPipe(self.logger, logging.INFO, self._process.stdout) self._stderr_pipe = pipe.LoggerPipe(self.logger, logging.ERROR, self._process.stderr) self._stdout_pipe.wait_until_started() self._stderr_pipe.wait_until_started() if sys.platform == "win32" and _JOB_OBJECT is not None: try: win32job.AssignProcessToJobObject(_JOB_OBJECT, self._process._handle) except win32job.error as err: # ERROR_ACCESS_DENIED (winerror=5) is received when the process has already died. if err.winerror != winerror.ERROR_ACCESS_DENIED: raise return_code = win32process.GetExitCodeProcess( self._process._handle) if return_code == win32con.STILL_ACTIVE: raise
def _get_log_calls(cls, output): logger = logging.Logger("for_testing") logger.log = mock.MagicMock() logger_pipe = _pipe.LoggerPipe(logger=logger, level=cls.LOG_LEVEL, pipe_out=io.BytesIO(output)) logger_pipe.wait_until_started() logger_pipe.wait_until_finished() return logger.log.call_args_list
def start(self): """Start the process and the logger pipes for its stdout and stderr.""" creation_flags = 0 if sys.platform == "win32" and _JOB_OBJECT is not None: creation_flags |= win32process.CREATE_BREAKAWAY_FROM_JOB # Tests fail if a process takes too long to startup and listen to a socket. Use buffered # I/O pipes to give the process some leeway. buffer_size = 1024 * 1024 # Close file descriptors in the child process before executing the program. This prevents # file descriptors that were inherited due to multiple calls to fork() -- either within one # thread, or concurrently from multiple threads -- from causing another subprocess to wait # for the completion of the newly spawned child process. Closing other file descriptors # isn't supported on Windows when stdout and stderr are redirected. close_fds = (sys.platform != "win32") with _POPEN_LOCK: # Record unittests directly since resmoke doesn't not interact with them and they can finish # too quickly for the recorder to have a chance at attaching. recorder_args = [] if _config.UNDO_RECORDER_PATH is not None and self.args[ 0].endswith("_test"): now_str = datetime.now().strftime("%Y-%m-%dT%H-%M-%S") # Only use the process name since we have to be able to correlate the recording name # with the binary name easily. recorder_output_file = "{process}-{t}.undo".format( process=os.path.basename(self.args[0]), t=now_str) recorder_args = [ _config.UNDO_RECORDER_PATH, "-o", recorder_output_file ] self._process = subprocess.Popen(recorder_args + self.args, bufsize=buffer_size, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=close_fds, env=self.env, creationflags=creation_flags, cwd=self._cwd) self.pid = self._process.pid if _config.UNDO_RECORDER_PATH is not None and ( not self.args[0].endswith("_test")) and ( "mongod" in self.args[0] or "mongos" in self.args[0]): now_str = datetime.now().strftime("%Y-%m-%dT%H-%M-%S") recorder_output_file = "{logger}-{process}-{pid}-{t}.undo".format( logger=self.logger.name.replace('/', '-'), process=os.path.basename(self.args[0]), pid=self.pid, t=now_str) recorder_args = [ _config.UNDO_RECORDER_PATH, "-p", str(self.pid), "-o", recorder_output_file ] self._recorder = subprocess.Popen(recorder_args, bufsize=buffer_size, env=self.env, creationflags=creation_flags) self._stdout_pipe = pipe.LoggerPipe(self.logger, logging.INFO, self._process.stdout) self._stderr_pipe = pipe.LoggerPipe(self.logger, logging.ERROR, self._process.stderr) self._stdout_pipe.wait_until_started() self._stderr_pipe.wait_until_started() if sys.platform == "win32" and _JOB_OBJECT is not None: try: win32job.AssignProcessToJobObject(_JOB_OBJECT, self._process._handle) except win32job.error as err: # ERROR_ACCESS_DENIED (winerror=5) is received when the process has already died. if err.winerror != winerror.ERROR_ACCESS_DENIED: raise return_code = win32process.GetExitCodeProcess( self._process._handle) if return_code == win32con.STILL_ACTIVE: raise