Re: [Qemu-devel] [PATCH v5 15/15] test: add image streaming test cases
On Tue, Jan 17, 2012 at 7:07 PM, Lucas Meneghel Rodrigues l...@redhat.com wrote: On 01/13/2012 02:49 PM, Stefan Hajnoczi wrote: Hi Lucas, The Python script below verifies the image streaming feature. It's built on the standard library unittest module, as well as QEMU's qmp.py module. It spawns a qemu process and creates necessary disk image files. The tests themselves issue QMP commands and check their result or wait for QMP events to be raised. I think this sort of test could be done with kvm-autotest but I don't see much usage of cmd_qmp() in client/tests/kvm/tests/. I'm curious how you would approach this. The high-level steps are: 1. Create a backing file. 2. Create a test QED image file using the backing file. 3. Issue block_stream device=drive0 to the running VM. This should return no value. 4. Wait for the BLOCK_JOB_COMPLETED QMP event and check its fields - they must contain expected values. 5. Ensure query-block-job does not show any active jobs anymore. 6. Use qemu-io's map command to verify that the image stays compact and isn't bloated with actual zero bytes (this is kind of unrelated to the rest of the test). The other test cases share much of the same building blocks as TestSingleDrive, so they are less interesting. Would it be possible to look at TestSingleDrive below and give a kvm-autotest equivalent? Yes Stefan, sorry for the late reply. I was in FUDCon, therefore taking care of some Fedora related autotest stuff, but I'm putting on my todo list to create a KVM autotest equivalent of it. Great, thank you! Stefan
Re: [Qemu-devel] [PATCH v5 15/15] test: add image streaming test cases
On 01/13/2012 02:49 PM, Stefan Hajnoczi wrote: Hi Lucas, The Python script below verifies the image streaming feature. It's built on the standard library unittest module, as well as QEMU's qmp.py module. It spawns a qemu process and creates necessary disk image files. The tests themselves issue QMP commands and check their result or wait for QMP events to be raised. I think this sort of test could be done with kvm-autotest but I don't see much usage of cmd_qmp() in client/tests/kvm/tests/. I'm curious how you would approach this. The high-level steps are: 1. Create a backing file. 2. Create a test QED image file using the backing file. 3. Issue block_stream device=drive0 to the running VM. This should return no value. 4. Wait for the BLOCK_JOB_COMPLETED QMP event and check its fields - they must contain expected values. 5. Ensure query-block-job does not show any active jobs anymore. 6. Use qemu-io's map command to verify that the image stays compact and isn't bloated with actual zero bytes (this is kind of unrelated to the rest of the test). The other test cases share much of the same building blocks as TestSingleDrive, so they are less interesting. Would it be possible to look at TestSingleDrive below and give a kvm-autotest equivalent? Yes Stefan, sorry for the late reply. I was in FUDCon, therefore taking care of some Fedora related autotest stuff, but I'm putting on my todo list to create a KVM autotest equivalent of it. Cheers, Lucas
[Qemu-devel] [PATCH v5 15/15] test: add image streaming test cases
python test-stream.py Signed-off-by: Stefan Hajnoczi stefa...@linux.vnet.ibm.com --- test-stream.py | 208 1 files changed, 208 insertions(+), 0 deletions(-) create mode 100644 test-stream.py diff --git a/test-stream.py b/test-stream.py new file mode 100644 index 000..16cbe5d --- /dev/null +++ b/test-stream.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +import unittest +import subprocess +import re +import os +import sys; sys.path.append('QMP/') +import qmp + +def qemu_img(*args): +devnull = open('/dev/null', 'r+') +return subprocess.call(['./qemu-img'] + list(args), stdin=devnull, stdout=devnull) + +def qemu_io(*args): +args = ['./qemu-io'] + list(args) +return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] + +class VM(object): +def __init__(self): +self._monitor_path = '/tmp/qemu-mon.%d' % os.getpid() +self._qemu_log_path = '/tmp/qemu-log.%d' % os.getpid() +self._args = ['x86_64-softmmu/qemu-system-x86_64', + '-chardev', 'socket,id=mon,path=' + self._monitor_path, + '-mon', 'chardev=mon,mode=control', '-nographic'] +self._num_drives = 0 + +def add_drive(self, path, opts=''): +options = ['if=virtio', + 'cache=none', + 'file=%s' % path, + 'id=drive%d' % self._num_drives] +if opts: +options.append(opts) + +self._args.append('-drive') +self._args.append(','.join(options)) +self._num_drives += 1 +return self + +def launch(self): +devnull = open('/dev/null', 'rb') +qemulog = open(self._qemu_log_path, 'wb') +self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True) +self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog, + stderr=subprocess.STDOUT) +self._qmp.accept() + +def shutdown(self): +self._qmp.cmd('quit') +self._popen.wait() +os.remove(self._monitor_path) +os.remove(self._qemu_log_path) + +def qmp(self, cmd, **args): +return self._qmp.cmd(cmd, args=args) + +def get_qmp_events(self, wait=False): +events = self._qmp.get_events(wait=wait) +self._qmp.clear_events() +return events + +index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +class QMPTestCase(unittest.TestCase): +def dictpath(self, d, path): +Traverse a path in a nested dict +for component in path.split('/'): +m = index_re.match(component) +if m: +component, idx = m.groups() +idx = int(idx) + +if not isinstance(d, dict) or component not in d: +self.fail('failed path traversal for %s in %s' % (path, str(d))) +d = d[component] + +if m: +if not isinstance(d, list): +self.fail('path component %s in %s is not a list in %s' % (component, path, str(d))) +try: +d = d[idx] +except IndexError: +self.fail('invalid index %s in path %s in %s' % (idx, path, str(d))) +return d + +def assert_qmp(self, d, path, value): +result = self.dictpath(d, path) +self.assertEqual(result, value, 'values not equal %s and %s' % (str(result), str(value))) + +def assert_no_active_streams(self): +result = self.vm.qmp('query-block-jobs') +self.assert_qmp(result, 'return', []) + +class TestSingleDrive(QMPTestCase): +image_len = 1 * 1024 * 1024 # MB + +def setUp(self): +qemu_img('create', 'backing.img', str(TestSingleDrive.image_len)) +qemu_img('create', '-f', 'qed', '-o', 'backing_file=backing.img', 'test.qed') +self.vm = VM().add_drive('test.qed') +self.vm.launch() + +def tearDown(self): +self.vm.shutdown() +os.remove('test.qed') +os.remove('backing.img') + +def test_stream(self): +self.assert_no_active_streams() + +result = self.vm.qmp('block_stream', device='drive0') +self.assert_qmp(result, 'return', {}) + +completed = False +while not completed: +for event in self.vm.get_qmp_events(wait=True): +if event['event'] == 'BLOCK_JOB_COMPLETED': +self.assert_qmp(event, 'data/type', 'stream') +self.assert_qmp(event, 'data/device', 'drive0') +self.assert_qmp(event, 'data/offset', self.image_len) +self.assert_qmp(event, 'data/len', self.image_len) +completed = True + +self.assert_no_active_streams() + +self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', 'test.qed'), + 'image file not fully populated after streaming') + +def
[Qemu-devel] [PATCH v5 15/15] test: add image streaming test cases
python test-stream.py Signed-off-by: Stefan Hajnoczi stefa...@linux.vnet.ibm.com --- test-stream.py | 208 1 files changed, 208 insertions(+), 0 deletions(-) create mode 100644 test-stream.py diff --git a/test-stream.py b/test-stream.py new file mode 100644 index 000..16cbe5d --- /dev/null +++ b/test-stream.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +import unittest +import subprocess +import re +import os +import sys; sys.path.append('QMP/') +import qmp + +def qemu_img(*args): +devnull = open('/dev/null', 'r+') +return subprocess.call(['./qemu-img'] + list(args), stdin=devnull, stdout=devnull) + +def qemu_io(*args): +args = ['./qemu-io'] + list(args) +return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] + +class VM(object): +def __init__(self): +self._monitor_path = '/tmp/qemu-mon.%d' % os.getpid() +self._qemu_log_path = '/tmp/qemu-log.%d' % os.getpid() +self._args = ['x86_64-softmmu/qemu-system-x86_64', + '-chardev', 'socket,id=mon,path=' + self._monitor_path, + '-mon', 'chardev=mon,mode=control', '-nographic'] +self._num_drives = 0 + +def add_drive(self, path, opts=''): +options = ['if=virtio', + 'cache=none', + 'file=%s' % path, + 'id=drive%d' % self._num_drives] +if opts: +options.append(opts) + +self._args.append('-drive') +self._args.append(','.join(options)) +self._num_drives += 1 +return self + +def launch(self): +devnull = open('/dev/null', 'rb') +qemulog = open(self._qemu_log_path, 'wb') +self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True) +self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog, + stderr=subprocess.STDOUT) +self._qmp.accept() + +def shutdown(self): +self._qmp.cmd('quit') +self._popen.wait() +os.remove(self._monitor_path) +os.remove(self._qemu_log_path) + +def qmp(self, cmd, **args): +return self._qmp.cmd(cmd, args=args) + +def get_qmp_events(self, wait=False): +events = self._qmp.get_events(wait=wait) +self._qmp.clear_events() +return events + +index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +class QMPTestCase(unittest.TestCase): +def dictpath(self, d, path): +Traverse a path in a nested dict +for component in path.split('/'): +m = index_re.match(component) +if m: +component, idx = m.groups() +idx = int(idx) + +if not isinstance(d, dict) or component not in d: +self.fail('failed path traversal for %s in %s' % (path, str(d))) +d = d[component] + +if m: +if not isinstance(d, list): +self.fail('path component %s in %s is not a list in %s' % (component, path, str(d))) +try: +d = d[idx] +except IndexError: +self.fail('invalid index %s in path %s in %s' % (idx, path, str(d))) +return d + +def assert_qmp(self, d, path, value): +result = self.dictpath(d, path) +self.assertEqual(result, value, 'values not equal %s and %s' % (str(result), str(value))) + +def assert_no_active_streams(self): +result = self.vm.qmp('query-block-jobs') +self.assert_qmp(result, 'return', []) + +class TestSingleDrive(QMPTestCase): +image_len = 1 * 1024 * 1024 # MB + +def setUp(self): +qemu_img('create', 'backing.img', str(TestSingleDrive.image_len)) +qemu_img('create', '-f', 'qed', '-o', 'backing_file=backing.img', 'test.qed') +self.vm = VM().add_drive('test.qed') +self.vm.launch() + +def tearDown(self): +self.vm.shutdown() +os.remove('test.qed') +os.remove('backing.img') + +def test_stream(self): +self.assert_no_active_streams() + +result = self.vm.qmp('block_stream', device='drive0') +self.assert_qmp(result, 'return', {}) + +completed = False +while not completed: +for event in self.vm.get_qmp_events(wait=True): +if event['event'] == 'BLOCK_JOB_COMPLETED': +self.assert_qmp(event, 'data/type', 'stream') +self.assert_qmp(event, 'data/device', 'drive0') +self.assert_qmp(event, 'data/offset', self.image_len) +self.assert_qmp(event, 'data/len', self.image_len) +completed = True + +self.assert_no_active_streams() + +self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', 'test.qed'), + 'image file not fully populated after streaming') + +def
Re: [Qemu-devel] [PATCH v5 15/15] test: add image streaming test cases
Hi Lucas, The Python script below verifies the image streaming feature. It's built on the standard library unittest module, as well as QEMU's qmp.py module. It spawns a qemu process and creates necessary disk image files. The tests themselves issue QMP commands and check their result or wait for QMP events to be raised. I think this sort of test could be done with kvm-autotest but I don't see much usage of cmd_qmp() in client/tests/kvm/tests/. I'm curious how you would approach this. The high-level steps are: 1. Create a backing file. 2. Create a test QED image file using the backing file. 3. Issue block_stream device=drive0 to the running VM. This should return no value. 4. Wait for the BLOCK_JOB_COMPLETED QMP event and check its fields - they must contain expected values. 5. Ensure query-block-job does not show any active jobs anymore. 6. Use qemu-io's map command to verify that the image stays compact and isn't bloated with actual zero bytes (this is kind of unrelated to the rest of the test). The other test cases share much of the same building blocks as TestSingleDrive, so they are less interesting. Would it be possible to look at TestSingleDrive below and give a kvm-autotest equivalent? Thanks, Stefan On Fri, Jan 13, 2012 at 1:14 PM, Stefan Hajnoczi stefa...@linux.vnet.ibm.com wrote: python test-stream.py Signed-off-by: Stefan Hajnoczi stefa...@linux.vnet.ibm.com --- test-stream.py | 208 1 files changed, 208 insertions(+), 0 deletions(-) create mode 100644 test-stream.py diff --git a/test-stream.py b/test-stream.py new file mode 100644 index 000..16cbe5d --- /dev/null +++ b/test-stream.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +import unittest +import subprocess +import re +import os +import sys; sys.path.append('QMP/') +import qmp + +def qemu_img(*args): + devnull = open('/dev/null', 'r+') + return subprocess.call(['./qemu-img'] + list(args), stdin=devnull, stdout=devnull) + +def qemu_io(*args): + args = ['./qemu-io'] + list(args) + return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] + +class VM(object): + def __init__(self): + self._monitor_path = '/tmp/qemu-mon.%d' % os.getpid() + self._qemu_log_path = '/tmp/qemu-log.%d' % os.getpid() + self._args = ['x86_64-softmmu/qemu-system-x86_64', + '-chardev', 'socket,id=mon,path=' + self._monitor_path, + '-mon', 'chardev=mon,mode=control', '-nographic'] + self._num_drives = 0 + + def add_drive(self, path, opts=''): + options = ['if=virtio', + 'cache=none', + 'file=%s' % path, + 'id=drive%d' % self._num_drives] + if opts: + options.append(opts) + + self._args.append('-drive') + self._args.append(','.join(options)) + self._num_drives += 1 + return self + + def launch(self): + devnull = open('/dev/null', 'rb') + qemulog = open(self._qemu_log_path, 'wb') + self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True) + self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog, + stderr=subprocess.STDOUT) + self._qmp.accept() + + def shutdown(self): + self._qmp.cmd('quit') + self._popen.wait() + os.remove(self._monitor_path) + os.remove(self._qemu_log_path) + + def qmp(self, cmd, **args): + return self._qmp.cmd(cmd, args=args) + + def get_qmp_events(self, wait=False): + events = self._qmp.get_events(wait=wait) + self._qmp.clear_events() + return events + +index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +class QMPTestCase(unittest.TestCase): + def dictpath(self, d, path): + Traverse a path in a nested dict + for component in path.split('/'): + m = index_re.match(component) + if m: + component, idx = m.groups() + idx = int(idx) + + if not isinstance(d, dict) or component not in d: + self.fail('failed path traversal for %s in %s' % (path, str(d))) + d = d[component] + + if m: + if not isinstance(d, list): + self.fail('path component %s in %s is not a list in %s' % (component, path, str(d))) + try: + d = d[idx] + except IndexError: + self.fail('invalid index %s in path %s in %s' % (idx, path, str(d))) + return d + + def assert_qmp(self, d, path, value): + result = self.dictpath(d, path) + self.assertEqual(result, value, 'values not equal %s and %s' % (str(result), str(value))) + + def assert_no_active_streams(self): + result =