diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 18eddcc734..98595d47fe 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -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 diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 index 9bb96d6a1d..2ae318f16f 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -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]) diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 index c0e107328f..15f798288a 100755 --- a/tests/qemu-iotests/205 +++ b/tests/qemu-iotests/205 @@ -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() diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 8cbed7821b..edaf29094b 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -20,11 +20,13 @@ # along with this program. If not, see . # -import os -import re -import iotests import copy import json +import os +import re +from subprocess import CalledProcessError + +import iotests 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) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 6800c67bea..06d35af21a 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -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): diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions index 6be02581c7..c7afb1bd2c 100755 --- a/tests/qemu-iotests/tests/migration-permissions +++ b/tests/qemu-iotests/tests/migration-permissions @@ -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')