test-runner: fix UML blocking on wait_for_socket/service

In UML if any process dies while test-runner is waiting for the DBus
service or some socket to be available it will block forever. This
is due to the way the non_block_wait works.

Its not optimal but it essentially polls over some input function
until the conditions are met. And, depending on the input function,
this can cause UML to hang since it never has a chance to go idle
and advance the time clock.

This can be fixed, at least for services/sockets, by sleeping in
the input function allowing time to pass. This will then allow
test-runner to bail out with an exception.

This patch adds a new wait_for_service function which handles this
automatically, and wait_for_socket was refactored to behave
similarly.
This commit is contained in:
James Prestwood 2022-06-24 16:07:36 -07:00 committed by Denis Kenzior
parent 3e5ce99e82
commit 1ecadc3952
3 changed files with 26 additions and 8 deletions

View File

@ -1097,9 +1097,6 @@ class IWD(AsyncOpAbstract):
self._iwd_proc = self.namespace.start_iwd(iwd_config_dir,
iwd_storage_dir)
ctx.non_block_wait(self._bus.name_has_owner, 20, IWD_SERVICE,
exception=TimeoutError('IWD has failed to start'))
self._devices = DeviceList(self)
# Weak to make sure the test's reference to @self is the only counted

View File

@ -326,9 +326,8 @@ class TestContext(Namespace):
# register hwsim as medium
args.extend(['--no-register'])
self.start_process(args)
self.non_block_wait(self._bus.name_has_owner, 20, 'net.connman.hwsim',
exception=TimeoutError('net.connman.hwsim did not appear'))
proc = self.start_process(args)
proc.wait_for_service(self, 'net.connman.hwsim', 20)
for i in range(nradios):
name = 'rad%u' % i

View File

@ -9,6 +9,7 @@ import dbus
from gi.repository import GLib
from weakref import WeakValueDictionary
from re import fullmatch
from time import sleep
from runner import RunnerCoreArgParse
@ -213,7 +214,24 @@ class Process(subprocess.Popen):
self.write_fds.append(f)
def wait_for_socket(self, socket, wait):
Namespace.non_block_wait(os.path.exists, wait, socket)
def _wait(socket):
if not os.path.exists(socket):
sleep(0.1)
return False
return True
Namespace.non_block_wait(_wait, wait, socket,
exception=Exception("Timed out waiting for %s" % socket))
def wait_for_service(self, ns, service, wait):
def _wait(ns, service):
if not ns._bus.name_has_owner(service):
sleep(0.1)
return False
return True
Namespace.non_block_wait(_wait, wait, ns, service,
exception=Exception("Timed out waiting for %s" % service))
# Wait for both process termination and HUP signal
def __wait(self, timeout):
@ -423,7 +441,11 @@ class Namespace:
if Process.is_verbose('iwd-rtnl'):
env['IWD_RTNL_DEBUG'] = '1'
return self.start_process(args, env=env)
proc = self.start_process(args, env=env)
proc.wait_for_service(self, 'net.connman.iwd', 20)
return proc
@staticmethod
def non_block_wait(func, timeout, *args, exception=True):