From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46832) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yj6Ox-0000kE-J6 for qemu-devel@nongnu.org; Fri, 17 Apr 2015 09:33:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yj6Os-0000kJ-De for qemu-devel@nongnu.org; Fri, 17 Apr 2015 09:33:47 -0400 Message-ID: <55310BB0.3010704@redhat.com> Date: Fri, 17 Apr 2015 15:33:36 +0200 From: Max Reitz MIME-Version: 1.0 References: <1428531604-9428-1-git-send-email-jsnow@redhat.com> <1428531604-9428-19-git-send-email-jsnow@redhat.com> In-Reply-To: <1428531604-9428-19-git-send-email-jsnow@redhat.com> Content-Type: text/plain; charset=iso-8859-15; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v5 18/21] iotests: add QMP event waiting queue List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: John Snow , qemu-block@nongnu.org Cc: kwolf@redhat.com, famz@redhat.com, qemu-devel@nongnu.org, armbru@redhat.com, vsementsov@parallels.com, stefanha@redhat.com On 09.04.2015 00:20, John Snow wrote: > A filter is added to allow callers to request very specific > events to be pulled from the event queue, while leaving undesired > events still in the stream. > > This allows to poll for completion data for multiple asynchronous > events in any arbitrary order. > > A new timeout context is added to the qmp pull_event method's > wait parameter to allow tests to fail if they do not complete > within some expected period of time. > > Signed-off-by: John Snow > --- > scripts/qmp/qmp.py | 6 +++++- > tests/qemu-iotests/iotests.py | 38 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 43 insertions(+), 1 deletion(-) > > diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py > index 20b6ec7..7f9ac1b 100644 > --- a/scripts/qmp/qmp.py > +++ b/scripts/qmp/qmp.py > @@ -140,7 +140,8 @@ class QEMUMonitorProtocol: > """ > Get and delete the first available QMP event. > > - @param wait: block until an event is available (bool) > + @param wait: block until an event is available. If a float is provided, > + use this as a timeout value. (bool, float) Ouch... I guess it works, though... > """ > self.__sock.setblocking(0) > try: > @@ -151,7 +152,10 @@ class QEMUMonitorProtocol: > pass > self.__sock.setblocking(1) > if not self.__events and wait: > + if isinstance(wait, float): > + self.__sock.settimeout(wait) > self.__json_read(only_event=True) > + self.__sock.settimeout(None) If a timeout occurs, __json_read will do nothing and return (I guess...). > event = self.__events[0] This will therefore probably return None... > del self.__events[0] And I don't know what this will do. Will it be a no-op? > return event > diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py > index 1402854..e93e623 100644 > --- a/tests/qemu-iotests/iotests.py > +++ b/tests/qemu-iotests/iotests.py > @@ -78,6 +78,23 @@ def create_image(name, size): > i = i + 512 > file.close() > > +# Test if 'match' is a recursive subset of 'event' > +def event_match(event, match=None): > + if match is None: > + return True > + > + for key in match: > + if key in event: > + if isinstance(event[key], dict): > + if not event_match(event[key], match[key]): > + return False > + elif event[key] != match[key]: > + return False > + else: > + return False > + > + return True > + > class VM(object): > '''A QEMU VM''' > > @@ -92,6 +109,7 @@ class VM(object): > '-machine', 'accel=qtest', > '-display', 'none', '-vga', 'none'] > self._num_drives = 0 > + self._events = [] > > # This can be used to add an unused monitor instance. > def add_monitor_telnet(self, ip, port): > @@ -202,14 +220,34 @@ class VM(object): > > def get_qmp_event(self, wait=False): > '''Poll for one queued QMP events and return it''' > + if len(self._events) > 0: > + return self._events.pop(0) > return self._qmp.pull_event(wait=wait) > > def get_qmp_events(self, wait=False): > '''Poll for queued QMP events and return a list of dicts''' > events = self._qmp.get_events(wait=wait) > + events.extend(self._events) > + del self._events[:] > self._qmp.clear_events() > return events > > + def event_wait(self, name='BLOCK_JOB_COMPLETED', timeout=60.0, match=None): > + # Search cached events > + for event in self._events: > + if (event['event'] == name) and event_match(event, match): > + self._events.remove(event) > + return event > + > + # Poll for new events > + while True: > + event = self._qmp.pull_event(wait=timeout) So if a timeout occurred, event will probably be None. > + if (event['event'] == name) and event_match(event, match): And this (indexing event == None) will probably generate an exception. I guess it's one way to fail the test, but certainly not the best... Max > + return event > + self._events.append(event) > + > + return None > + > index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') > > class QMPTestCase(unittest.TestCase):