event_loop: Create a global event loop to poll and wait for events
Tweaked-by: nhofmeyr Change-Id: Iaa78bae0f053496377609b24a11ebaef3fd77598
This commit is contained in:
parent
095d1290a6
commit
927344b4dc
|
@ -0,0 +1,64 @@
|
|||
# osmo_gsm_tester: Event loop
|
||||
#
|
||||
# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
|
||||
#
|
||||
# Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# These will be initialized before each test run.
|
||||
# A test script can thus establish its context by doing:
|
||||
# from osmo_gsm_tester.test import *
|
||||
import time
|
||||
poll_funcs = []
|
||||
|
||||
def register_poll_func(func):
|
||||
global poll_funcs
|
||||
poll_funcs.append(func)
|
||||
|
||||
def unregister_poll_func(func):
|
||||
global poll_funcs
|
||||
poll_funcs.remove(func)
|
||||
|
||||
def poll():
|
||||
global poll_funcs
|
||||
for func in poll_funcs:
|
||||
func()
|
||||
|
||||
def wait_no_raise(log_obj, condition, condition_args, condition_kwargs, timeout, timestep):
|
||||
if not timeout or timeout < 0:
|
||||
log_obj.raise_exn('wait() *must* time out at some point. timeout=%r' % timeout)
|
||||
if timestep < 0.1:
|
||||
timestep = 0.1
|
||||
|
||||
started = time.time()
|
||||
while True:
|
||||
poll()
|
||||
if condition(*condition_args, **condition_kwargs):
|
||||
return True
|
||||
waited = time.time() - started
|
||||
if waited > timeout:
|
||||
return False
|
||||
time.sleep(timestep)
|
||||
|
||||
def wait(log_obj, condition, *condition_args, timeout=300, timestep=1, **condition_kwargs):
|
||||
if not wait_no_raise(log_obj, condition, condition_args, condition_kwargs, timeout, timestep):
|
||||
log_obj.raise_exn('Wait timeout')
|
||||
|
||||
def sleep(log_obj, seconds):
|
||||
assert seconds > 0.
|
||||
wait_no_raise(log_obj, lambda: False, [], {}, timeout=seconds, timestep=min(seconds, 1))
|
||||
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -17,7 +17,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from . import log, test, util
|
||||
from . import log, test, util, event_loop
|
||||
|
||||
from pydbus import SystemBus, Variant
|
||||
import time
|
||||
|
@ -57,13 +57,14 @@ def dbus_connect(dbus_iface, handler):
|
|||
DeferredHandling.defer_queue.'''
|
||||
return DeferredHandling(dbus_iface, handler).subscription_id
|
||||
|
||||
|
||||
def poll():
|
||||
def poll_glib():
|
||||
global glib_main_ctx
|
||||
while glib_main_ctx.pending():
|
||||
glib_main_ctx.iteration()
|
||||
DeferredHandling.handle_queue()
|
||||
|
||||
event_loop.register_poll_func(poll_glib)
|
||||
|
||||
def systembus_get(path):
|
||||
global bus
|
||||
return bus.get('org.ofono', path)
|
||||
|
@ -89,7 +90,7 @@ class Modem(log.Origin):
|
|||
self.sms_received_list = []
|
||||
# init interfaces and connect to signals:
|
||||
self.dbus_obj()
|
||||
test.poll()
|
||||
event_loop.poll()
|
||||
|
||||
def set_msisdn(self, msisdn):
|
||||
self.msisdn = msisdn
|
||||
|
@ -106,13 +107,13 @@ class Modem(log.Origin):
|
|||
|
||||
def _dbus_set_bool(self, name, bool_val, iface=I_MODEM):
|
||||
# to make sure any pending signals are received before we send out more DBus requests
|
||||
test.poll()
|
||||
event_loop.poll()
|
||||
|
||||
val = bool(bool_val)
|
||||
self.log('Setting', name, val)
|
||||
self.dbus_obj()[iface].SetProperty(name, Variant('b', val))
|
||||
|
||||
test.wait(self.property_is, name, bool_val)
|
||||
event_loop.wait(self, self.property_is, name, bool_val)
|
||||
|
||||
def property_is(self, name, val):
|
||||
is_val = self.properties().get(name)
|
||||
|
|
|
@ -22,7 +22,7 @@ import time
|
|||
import subprocess
|
||||
import signal
|
||||
|
||||
from . import log, test
|
||||
from . import log, test, event_loop
|
||||
from .util import Dir
|
||||
|
||||
class Process(log.Origin):
|
||||
|
@ -206,7 +206,7 @@ class Process(log.Origin):
|
|||
return self.result is not None
|
||||
|
||||
def wait(self, timeout=300):
|
||||
test.wait(self.terminated, timeout=timeout)
|
||||
event_loop.wait(self, self.terminated, timeout=timeout)
|
||||
|
||||
|
||||
class RemoteProcess(Process):
|
||||
|
|
|
@ -22,7 +22,7 @@ import sys
|
|||
import time
|
||||
import copy
|
||||
import traceback
|
||||
from . import config, log, template, util, resource, schema, ofono_client, osmo_nitb
|
||||
from . import config, log, template, util, resource, schema, ofono_client, osmo_nitb, event_loop
|
||||
from . import test
|
||||
|
||||
class Timeout(Exception):
|
||||
|
@ -114,7 +114,7 @@ class Test(log.Origin):
|
|||
with self:
|
||||
self.status = Test.UNKNOWN
|
||||
self.start_timestamp = time.time()
|
||||
test.setup(suite_run, self, ofono_client, sys.modules[__name__])
|
||||
test.setup(suite_run, self, ofono_client, sys.modules[__name__], event_loop)
|
||||
self.log('START')
|
||||
with self.redirect_stdout():
|
||||
util.run_python_file('%s.%s' % (self.suite.name(), self.name()),
|
||||
|
@ -225,6 +225,7 @@ class SuiteRun(log.Origin):
|
|||
self.log('Suite run start')
|
||||
try:
|
||||
self.mark_start()
|
||||
event_loop.register_poll_func(self.poll)
|
||||
if not self.reserved_resources:
|
||||
self.reserve_resources()
|
||||
for test in self.definition.tests:
|
||||
|
@ -243,6 +244,7 @@ class SuiteRun(log.Origin):
|
|||
# base exception is raised. Make sure to stop processes in this
|
||||
# finally section. Resources are automatically freed with 'atexit'.
|
||||
self.stop_processes()
|
||||
event_loop.unregister_poll_func(self.poll)
|
||||
self.duration = time.time() - self.start_timestamp
|
||||
if self.test_failed_ctr:
|
||||
self.status = SuiteRun.FAIL
|
||||
|
@ -287,32 +289,7 @@ class SuiteRun(log.Origin):
|
|||
self.log('using MSISDN', msisdn)
|
||||
return msisdn
|
||||
|
||||
def _wait(self, condition, condition_args, condition_kwargs, timeout, timestep):
|
||||
if not timeout or timeout < 0:
|
||||
raise RuntimeError('wait() *must* time out at some point. timeout=%r' % timeout)
|
||||
if timestep < 0.1:
|
||||
timestep = 0.1
|
||||
|
||||
started = time.time()
|
||||
while True:
|
||||
self.poll()
|
||||
if condition(*condition_args, **condition_kwargs):
|
||||
return True
|
||||
waited = time.time() - started
|
||||
if waited > timeout:
|
||||
return False
|
||||
time.sleep(timestep)
|
||||
|
||||
def wait(self, condition, *condition_args, timeout=300, timestep=1, **condition_kwargs):
|
||||
if not self._wait(condition, condition_args, condition_kwargs, timeout, timestep):
|
||||
raise Timeout('Timeout expired')
|
||||
|
||||
def sleep(self, seconds):
|
||||
assert seconds > 0.
|
||||
self._wait(lambda: False, [], {}, timeout=seconds, timestep=min(seconds, 1))
|
||||
|
||||
def poll(self):
|
||||
ofono_client.poll()
|
||||
if self._processes:
|
||||
for process in self._processes:
|
||||
if process.terminated():
|
||||
|
|
|
@ -28,14 +28,15 @@ log = None
|
|||
dbg = None
|
||||
err = None
|
||||
wait = None
|
||||
wait_no_raise = None
|
||||
sleep = None
|
||||
poll = None
|
||||
prompt = None
|
||||
Timeout = None
|
||||
Failure = None
|
||||
|
||||
def setup(suite_run, _test, ofono_client, suite_module):
|
||||
global trial, suite, test, resources, log, dbg, err, wait, sleep, poll, prompt, Failure, Timeout
|
||||
def setup(suite_run, _test, ofono_client, suite_module, event_module):
|
||||
global trial, suite, test, resources, log, dbg, err, wait, wait_no_raise, sleep, poll, prompt, Failure, Timeout
|
||||
trial = suite_run.trial
|
||||
suite = suite_run
|
||||
test = _test
|
||||
|
@ -43,9 +44,10 @@ def setup(suite_run, _test, ofono_client, suite_module):
|
|||
log = test.log
|
||||
dbg = test.dbg
|
||||
err = test.err
|
||||
wait = suite_run.wait
|
||||
sleep = suite_run.sleep
|
||||
poll = suite_run.poll
|
||||
wait = lambda *args, **kwargs: event_module.wait(suite_run, *args, **kwargs)
|
||||
wait_no_raise = lambda *args, **kwargs: event_module.wait_no_raise(suite_run, *args, **kwargs)
|
||||
sleep = lambda *args, **kwargs: event_module.sleep(suite_run, *args, **kwargs)
|
||||
poll = event_module.poll
|
||||
prompt = suite_run.prompt
|
||||
Failure = suite_module.Failure
|
||||
Timeout = suite_module.Timeout
|
||||
|
|
Loading…
Reference in New Issue