@@ -64,16 +64,18 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout,
+ 'image file map does not match backing file after streaming')
def test_stream_intermediate(self):
self.assert_no_active_block_jobs()
- self.assertNotEqual(qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img),
- qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img),
- 'image file map matches backing file before streaming')
+ self.assertNotEqual(
+ qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img).stdout,
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img).stdout,
+ 'image file map matches backing file before streaming')
result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid')
self.assert_qmp(result, 'return', {})
@@ -83,9 +85,10 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout,
+ 'image file map does not match backing file after streaming')
def test_stream_pause(self):
self.assert_no_active_block_jobs()
@@ -113,15 +116,17 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout,
+ 'image file map does not match backing file after streaming')
def test_stream_no_op(self):
self.assert_no_active_block_jobs()
# The image map is empty before the operation
- empty_map = qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', test_img)
+ empty_map = qemu_io(
+ '-f', iotests.imgfmt, '-rU', '-c', 'map', test_img).stdout
# This is a no-op: no data should ever be copied from the base image
result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
@@ -132,8 +137,9 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
- empty_map, 'image file map changed after a no-op')
+ self.assertEqual(
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout,
+ empty_map, 'image file map changed after a no-op')
def test_stream_partial(self):
self.assert_no_active_block_jobs()
@@ -146,9 +152,10 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout,
+ 'image file map does not match backing file after streaming')
def test_device_not_found(self):
result = self.vm.qmp('block-stream', device='nonexistent')
@@ -236,9 +243,10 @@ class TestParallelOps(iotests.QMPTestCase):
# Check that the maps don't match before the streaming operations
for i in range(2, self.num_imgs, 2):
- self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]),
- qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]),
- 'image file map matches backing file before streaming')
+ self.assertNotEqual(
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]).stdout,
+ 'image file map matches backing file before streaming')
# Create all streaming jobs
pending_jobs = []
@@ -278,9 +286,10 @@ class TestParallelOps(iotests.QMPTestCase):
# Check that all maps match now
for i in range(2, self.num_imgs, 2):
- self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]).stdout,
+ 'image file map does not match backing file after streaming')
# Test that it's not possible to perform two block-stream
# operations if there are nodes involved in both.
@@ -514,9 +523,10 @@ class TestParallelOps(iotests.QMPTestCase):
def test_stream_base_node_name(self):
self.assert_no_active_block_jobs()
- self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]),
- qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]),
- 'image file map matches backing file before streaming')
+ self.assertNotEqual(
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]).stdout,
+ 'image file map matches backing file before streaming')
# Error: the base node does not exist
result = self.vm.qmp('block-stream', device='node4', base_node='none', job_id='stream')
@@ -547,9 +557,10 @@ class TestParallelOps(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]),
- 'image file map matches backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]).stdout,
+ 'image file map matches backing file after streaming')
class TestQuorum(iotests.QMPTestCase):
num_children = 3
@@ -588,9 +599,10 @@ class TestQuorum(iotests.QMPTestCase):
os.remove(img)
def test_stream_quorum(self):
- self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]),
- qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]),
- 'image file map matches backing file before streaming')
+ self.assertNotEqual(
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]).stdout,
+ 'image file map matches backing file before streaming')
self.assert_no_active_block_jobs()
@@ -602,9 +614,10 @@ class TestQuorum(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
- self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]),
- qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]),
- 'image file map does not match backing file after streaming')
+ self.assertEqual(
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]).stdout,
+ qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]).stdout,
+ 'image file map does not match backing file after streaming')
class TestSmallerBackingFile(iotests.QMPTestCase):
backing_len = 1 * 1024 * 1024 # MB
@@ -295,7 +295,8 @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
args.extend(qemu_io_image_args(config, dev))
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
- iotests.log(check_cipher_support(config, iotests.qemu_io(*args)),
+ output = iotests.qemu_io(*args, check=False).stdout
+ iotests.log(check_cipher_support(config, output),
filters=[iotests.filter_test_dir, iotests.filter_qemu_io])
@@ -307,7 +308,8 @@ def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False):
args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
args.extend(qemu_io_image_args(config, dev))
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
- iotests.log(check_cipher_support(config, iotests.qemu_io(*args)),
+ output = iotests.qemu_io(*args, check=False).stdout
+ iotests.log(check_cipher_support(config, output),
filters=[iotests.filter_test_dir, iotests.filter_qemu_io])
@@ -85,13 +85,13 @@ class TestNbdServerRemove(iotests.QMPTestCase):
def do_test_connect_after_remove(self, mode=None):
args = ('-r', '-f', 'raw', '-c', 'read 0 512', nbd_uri)
- self.assertReadOk(qemu_io(*args))
+ self.assertReadOk(qemu_io(*args).stdout)
result = self.remove_export('exp', mode)
self.assert_qmp(result, 'return', {})
self.assertExportNotFound('exp')
- self.assertConnectFailed(qemu_io(*args))
+ self.assertConnectFailed(qemu_io(*args, check=False).stdout)
def test_connect_after_remove_default(self):
self.do_test_connect_after_remove()
@@ -20,11 +20,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import copy
+import json
import os
import re
+from subprocess import CalledProcessError
+
import iotests
-import copy
-import json
from iotests import qemu_img, qemu_io
hd_path = [
@@ -216,11 +218,14 @@ class TestBlockdevReopen(iotests.QMPTestCase):
# Reopen an image several times changing some of its options
def test_reopen(self):
- # Check whether the filesystem supports O_DIRECT
- if 'O_DIRECT' in qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0]):
- supports_direct = False
- else:
+ try:
+ qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0])
supports_direct = True
+ except CalledProcessError as exc:
+ if 'O_DIRECT' in exc.stdout:
+ supports_direct = False
+ else:
+ raise
# Open the hd1 image passing all backing options
opts = hd_opts(1)
@@ -353,16 +353,23 @@ def qemu_io_wrap_args(args: Sequence[str]) -> List[str]:
def qemu_io_popen(*args):
return qemu_tool_popen(qemu_io_wrap_args(args))
-def qemu_io(*args):
- '''Run qemu-io and return the stdout data'''
- return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))[0]
+def qemu_io(*args: str, check: bool = True, combine_stdio: bool = True
+ ) -> 'subprocess.CompletedProcess[str]':
+ """
+ Run QEMU_IO_PROG and return the status code and console output.
+
+ This function always prepends either QEMU_IO_OPTIONS or
+ QEMU_IO_OPTIONS_NO_FMT.
+ """
+ return qemu_tool(*qemu_io_wrap_args(args),
+ check=check, combine_stdio=combine_stdio)
def qemu_io_pipe_and_status(*args):
return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))
-def qemu_io_log(*args):
- result = qemu_io(*args)
- log(result, filters=[filter_testfiles, filter_qemu_io])
+def qemu_io_log(*args: str) -> 'subprocess.CompletedProcess[str]':
+ result = qemu_io(*args, check=False)
+ log(result.stdout, filters=[filter_testfiles, filter_qemu_io])
return result
def qemu_io_silent(*args):
@@ -69,7 +69,7 @@ class TestMigrationPermissions(iotests.QMPTestCase):
def test_post_migration_permissions(self):
# Try to access the image R/W, which should fail because virtio-blk
# has not been configured with share-rw=on
- log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout
if not log.strip():
print('ERROR (pre-migration): qemu-io should not be able to '
'access this image, but it reported no error')
@@ -84,7 +84,7 @@ class TestMigrationPermissions(iotests.QMPTestCase):
# Try the same qemu-io access again, verifying that the WRITE
# permission remains unshared
- log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout
if not log.strip():
print('ERROR (post-migration): qemu-io should not be able to '
'access this image, but it reported no error')