Merge "Implement "find_child_pids" natively"
This commit is contained in:
commit
2fba36a88e
|
@ -164,20 +164,14 @@ def find_child_pids(pid, recursive=False):
|
|||
It can also find all children through the hierarchy if recursive=True
|
||||
"""
|
||||
try:
|
||||
raw_pids = execute(['ps', '--ppid', pid, '-o', 'pid='],
|
||||
log_fail_as_error=False)
|
||||
except exceptions.ProcessExecutionError as e:
|
||||
# Unexpected errors are the responsibility of the caller
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
# Exception has already been logged by execute
|
||||
no_children_found = e.returncode == 1
|
||||
if no_children_found:
|
||||
ctxt.reraise = False
|
||||
return []
|
||||
child_pids = [x.strip() for x in raw_pids.split('\n') if x.strip()]
|
||||
process = psutil.Process(pid=int(pid))
|
||||
except psutil.NoSuchProcess:
|
||||
return []
|
||||
|
||||
child_pids = [str(p.pid) for p in process.children()]
|
||||
if recursive:
|
||||
for child in child_pids:
|
||||
child_pids = child_pids + find_child_pids(child, True)
|
||||
child_pids += find_child_pids(child, recursive=True)
|
||||
return child_pids
|
||||
|
||||
|
||||
|
|
|
@ -141,3 +141,34 @@ class TestGetProcessCountByName(functional_base.BaseSudoTestCase):
|
|||
# NOTE(ralonsoh): other tests can spawn sleep processes too, but at
|
||||
# this point we know there are, at least, 20 "sleep" processes running.
|
||||
self.assertLessEqual(20, number_of_sleep)
|
||||
|
||||
|
||||
class TestFindChildPids(functional_base.BaseSudoTestCase):
|
||||
|
||||
def _stop_process(self, process):
|
||||
process.stop(kill_signal=signal.SIGKILL)
|
||||
|
||||
def test_find_child_pids(self):
|
||||
pid = os.getppid()
|
||||
child_pids = utils.find_child_pids(pid)
|
||||
child_pids_recursive = utils.find_child_pids(pid, recursive=True)
|
||||
for _pid in child_pids:
|
||||
self.assertIn(_pid, child_pids_recursive)
|
||||
|
||||
cmd = ['sleep', '100']
|
||||
process = async_process.AsyncProcess(cmd)
|
||||
process.start()
|
||||
common_utils.wait_until_true(lambda: process._process.pid,
|
||||
sleep=0.5, timeout=10)
|
||||
self.addCleanup(self._stop_process, process)
|
||||
|
||||
child_pids_after = utils.find_child_pids(pid)
|
||||
child_pids_recursive_after = utils.find_child_pids(pid, recursive=True)
|
||||
self.assertEqual(child_pids, child_pids_after)
|
||||
for _pid in child_pids + [process.pid]:
|
||||
self.assertIn(_pid, child_pids_recursive_after)
|
||||
|
||||
def test_find_non_existing_process(self):
|
||||
with open('/proc/sys/kernel/pid_max', 'r') as fd:
|
||||
pid_max = int(fd.readline().strip())
|
||||
self.assertEqual([], utils.find_child_pids(pid_max))
|
||||
|
|
|
@ -313,37 +313,6 @@ class TestGetCmdlineFromPid(base.BaseTestCase):
|
|||
self.assertEqual([], cmdline)
|
||||
|
||||
|
||||
class TestFindChildPids(base.BaseTestCase):
|
||||
|
||||
def test_returns_empty_list_for_exit_code_1(self):
|
||||
with mock.patch.object(utils, 'execute',
|
||||
side_effect=exceptions.ProcessExecutionError(
|
||||
'', returncode=1)):
|
||||
self.assertEqual([], utils.find_child_pids(-1))
|
||||
|
||||
def test_returns_empty_list_for_no_output(self):
|
||||
with mock.patch.object(utils, 'execute', return_value=''):
|
||||
self.assertEqual([], utils.find_child_pids(-1))
|
||||
|
||||
def test_returns_list_of_child_process_ids_for_good_ouput(self):
|
||||
with mock.patch.object(utils, 'execute', return_value=' 123 \n 185\n'):
|
||||
self.assertEqual(utils.find_child_pids(-1), ['123', '185'])
|
||||
|
||||
def test_returns_list_of_child_process_ids_recursively(self):
|
||||
with mock.patch.object(utils, 'execute',
|
||||
side_effect=[' 123 \n 185\n',
|
||||
' 40 \n', '\n',
|
||||
'41\n', '\n']):
|
||||
actual = utils.find_child_pids(-1, True)
|
||||
self.assertEqual(actual, ['123', '185', '40', '41'])
|
||||
|
||||
def test_raises_unknown_exception(self):
|
||||
with testtools.ExpectedException(RuntimeError):
|
||||
with mock.patch.object(utils, 'execute',
|
||||
side_effect=RuntimeError()):
|
||||
utils.find_child_pids(-1)
|
||||
|
||||
|
||||
class TestGetRoothelperChildPid(base.BaseTestCase):
|
||||
def _test_get_root_helper_child_pid(self, expected=_marker,
|
||||
run_as_root=False, pids=None,
|
||||
|
|
Loading…
Reference in New Issue