Re: [Qemu-block] [PATCH v4 18/20] iotests: add QMP event waiting queue

2015-04-02 Thread John Snow



On 04/02/2015 09:57 AM, Stefan Hajnoczi wrote:

On Fri, Mar 20, 2015 at 03:17:01PM -0400, John Snow wrote:

+# Test if 'match' is a recursive subset of 'event'
+def event_match(event, match = None):


Not worth respinning but PEP8 says there should be no spaces around the
'=' for keyword arguments:
https://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements


+def event_wait(self, name='BLOCK_JOB_COMPLETED', maxtries=3, 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
+for _ in range(maxtries):
+event = self._qmp.pull_event(wait=True)
+if (event['event'] == name) and event_match(event, match):
+return event
+self._events.append(event)
+
+return None


I'm not sure if maxtries is useful.  Why is a particular number of
skipped events useful to the caller and how do they pick the magic
number?

If you added the argument because this is a blocking operation then we
should probably use timeouts instead.  Timeouts will bail out even if
QEMU is unresponsive.



Yeah, this was just a poor man's timeout.

I'll make it nicer.



Re: [Qemu-block] [PATCH v4 18/20] iotests: add QMP event waiting queue

2015-04-02 Thread Stefan Hajnoczi
On Fri, Mar 20, 2015 at 03:17:01PM -0400, John Snow wrote:
> +# Test if 'match' is a recursive subset of 'event'
> +def event_match(event, match = None):

Not worth respinning but PEP8 says there should be no spaces around the
'=' for keyword arguments:
https://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements

> +def event_wait(self, name='BLOCK_JOB_COMPLETED', maxtries=3, 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
> +for _ in range(maxtries):
> +event = self._qmp.pull_event(wait=True)
> +if (event['event'] == name) and event_match(event, match):
> +return event
> +self._events.append(event)
> +
> +return None

I'm not sure if maxtries is useful.  Why is a particular number of
skipped events useful to the caller and how do they pick the magic
number?

If you added the argument because this is a blocking operation then we
should probably use timeouts instead.  Timeouts will bail out even if
QEMU is unresponsive.


pgp_sNeWrvfp1.pgp
Description: PGP signature


[Qemu-block] [PATCH v4 18/20] iotests: add QMP event waiting queue

2015-03-20 Thread John Snow
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.

Signed-off-by: John Snow 
Reviewed-by: Max Reitz 
---
 tests/qemu-iotests/iotests.py | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 1402854..ac55813 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', maxtries=3, 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
+for _ in range(maxtries):
+event = self._qmp.pull_event(wait=True)
+if (event['event'] == name) and event_match(event, match):
+return event
+self._events.append(event)
+
+return None
+
 index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
 
 class QMPTestCase(unittest.TestCase):
-- 
2.1.0