def check_process_termination(self, method): """Helper method for process termination tests.""" timer = Timer() # We use Executor to launch an external process. with ExternalCommand('sleep', '60', check=False) as cmd: # Verify that proc.unix.UnixProcess.is_running (which is normally # overridden by proc.core.Process.is_running) works as expected, # even though this property isn't actively used in the `proc' # package because we want to deal with not-yet-reclaimed # processes and zombie processes which is very much a Linux # specific thing (hence the override). unix_process = UnixProcess(pid=cmd.pid) assert unix_process.is_running, "UnixProcess.is_running is broken!" # We don't use Executor to control the process, instead we take the # process ID and use it to create a Process object that doesn't # know about Python's subprocess module. linux_process = Process.from_pid(cmd.pid) # We terminate the process using a positive but very low timeout so # that all of the code involved gets a chance to run, but without # significantly slowing down the test suite. getattr(linux_process, method)(timeout=0.1) # Now we can verify our assertions. assert not linux_process.is_running, "Child still running despite graceful termination request!" assert timer.elapsed_time < 10, "It look too long to terminate the child!" # Now comes a hairy bit of Linux implementation details that most # people can thankfully ignore (blissful ignorance :-). Parent # processes are responsible for reclaiming child processes and # until this happens the /proc/[pid] entry remains, which means # the `kill -0' trick used by UnixProcess to detect running # processes doesn't work as expected. Basically this means we # _must_ make sure that waitpid() is called before we can expect # UnixProcess.is_running to behave as expected. cmd.wait() # Now that we've called waitpid() things should work as expected. assert not unix_process.is_running, "UnixProcess.is_running is broken!"
def test_environ(self): """Test that parsing of process environments works as expected.""" unique_value = str(random.random()) with ExternalCommand( 'sleep', '30', environment=dict(unique_value=unique_value)) as sleep_cmd: sleep_proc = Process.from_pid(sleep_cmd.pid) assert sleep_proc.environ['unique_value'] == unique_value
def process(self): """ The :class:`proc.core.Process` object for this worker process (or :data:`None`). If :attr:`pid` is set then the value of :attr:`process` defaults to the result of :func:`proc.core.Process.from_pid()`. If the worker process disappears before the process information is requested :attr:`process` will be :data:`None`. """ return Process.from_pid(self.pid) if self.pid else None
def test_wait_for_processes(self): """Test the :func:`proc.cron.wait_for_processes()` function.""" children = [ subprocess.Popen(['sleep', str(int(5 + random.random() * 5))]) for i in range(5) ] wait_for_processes([Process.from_pid(c.pid) for c in children]) assert sum(c.poll() is None for c in children) == 0, \ "wait_for_processes() returned before all processes ended!"
def test_is_alive(self): """Test the :func:`proc.core.Process.is_alive` property.""" # Spawn a child that will live for a minute. with ExternalCommand('sleep', '60', check=False) as child: # Construct a process object for the child. process = Process.from_pid(child.pid) # Make sure the process object agrees the child is alive. assert process.is_alive, "Child died before Process.is_alive was called?!" # Kill the child process and give it a moment to terminate # (significantly less time then the process is normally expected to # run, otherwise there's no point in the test below). child.terminate(timeout=10) # Make sure the process object agrees the child is dead. assert not process.is_alive, "Child is still alive even though we killed it?!"
def verify_app(self, s): creds = s.getsockopt( SOL_SOCKET, self.SO_PEERCRED, struct.calcsize('3i')) pid, uid, gid = struct.unpack('3i', creds) proc = Process.from_pid(pid) file_hash = filehash.file_sha1(proc.exe) connected_app = SingleApp(proc.exe, file_hash) if (self.client_apps and connected_app in self.client_apps) \ or self.extra_approver(connected_app): return True, connected_app return False, None
def test_suspend_and_resume_signals(self): """Test the sending of ``SIGSTOP``, ``SIGCONT`` and ``SIGTERM`` signals.""" # Spawn a child that will live for a minute. with ExternalCommand('sleep', '60', check=False) as cmd: process = Process.from_pid(cmd.pid) # Suspend the execution of the child process using SIGSTOP. process.suspend() # Test that the child process doesn't respond to SIGTERM once suspended. process.terminate(wait=False) assert process.is_running, "Child responded to signal even though it was suspended?!" # Resume the execution of the child process using SIGCONT. process.resume() # Test that the child process responds to signals again after # having been resumed, but give it a moment to terminate # (significantly less time then the process is normally expected # to run, otherwise there's no point in the test below). process.kill(wait=True, timeout=5) assert not process.is_running, "Child didn't respond to signal even though it was resumed?!"
def process(self): return Process.from_pid(self.pid) if self.pid else None