diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-01-27 18:07:18 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-01-27 18:07:18 +0000 |
commit | 750fe5989f9efffce86368c6feac013f8b7b433c (patch) | |
tree | a59a377c3ba9f1e319e2b4417d09adac850f6397 /tests | |
parent | 105b07f1ba462ec48b27e5cb74ddf81c6a79364c (diff) | |
parent | 5fbf1d56c24018772e900a40a0955175ff82f35c (diff) | |
download | qemu-750fe5989f9efffce86368c6feac013f8b7b433c.zip qemu-750fe5989f9efffce86368c6feac013f8b7b433c.tar.gz qemu-750fe5989f9efffce86368c6feac013f8b7b433c.tar.bz2 |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches:
- iscsi: Cap block count from GET LBA STATUS (CVE-2020-1711)
- AioContext fixes in QMP commands for backup and bitmaps
- iotests fixes
# gpg: Signature made Mon 27 Jan 2020 17:49:58 GMT
# gpg: using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream:
iscsi: Don't access non-existent scsi_lba_status_descriptor
iscsi: Cap block count from GET LBA STATUS (CVE-2020-1711)
block/backup: fix memory leak in bdrv_backup_top_append()
iotests: Test handling of AioContexts with some blockdev actions
blockdev: Return bs to the proper context on snapshot abort
blockdev: Acquire AioContext on dirty bitmap functions
block/backup-top: Don't acquire context while dropping top
blockdev: honor bdrv_try_set_aio_context() context requirements
blockdev: unify qmp_blockdev_backup and blockdev-backup transaction paths
blockdev: unify qmp_drive_backup and drive-backup transaction paths
blockdev: fix coding style issues in drive_backup_prepare
iotests: Add more "skip_if_unsupported" statements to the python tests
iotests.py: Let wait_migration wait even more
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/qemu-iotests/030 | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/040 | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/041 | 39 | ||||
-rw-r--r-- | tests/qemu-iotests/141.out | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/185.out | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/219 | 7 | ||||
-rw-r--r-- | tests/qemu-iotests/219.out | 8 | ||||
-rwxr-xr-x | tests/qemu-iotests/234 | 8 | ||||
-rw-r--r-- | tests/qemu-iotests/245 | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/262 | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/280 | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/281 | 247 | ||||
-rw-r--r-- | tests/qemu-iotests/281.out | 5 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
-rw-r--r-- | tests/qemu-iotests/iotests.py | 6 |
15 files changed, 290 insertions, 49 deletions
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index be35bde..0990681 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -530,6 +530,7 @@ class TestQuorum(iotests.QMPTestCase): children = [] backing = [] + @iotests.skip_if_unsupported(['quorum']) def setUp(self): opts = ['driver=quorum', 'vote-threshold=2'] @@ -560,9 +561,6 @@ class TestQuorum(iotests.QMPTestCase): os.remove(img) def test_stream_quorum(self): - if not iotests.supports_quorum(): - return - 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') diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 762ad1e..74f62c3 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -106,6 +106,7 @@ class TestSingleDrive(ImageCommitTestCase): self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + @iotests.skip_if_unsupported(['throttle']) def test_commit_with_filter_and_quit(self): result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') self.assert_qmp(result, 'return', {}) @@ -125,6 +126,7 @@ class TestSingleDrive(ImageCommitTestCase): self.has_quit = True # Same as above, but this time we add the filter after starting the job + @iotests.skip_if_unsupported(['throttle']) def test_commit_plus_filter_and_quit(self): result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') self.assert_qmp(result, 'return', {}) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index d7be30b..c07437f 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -871,6 +871,7 @@ class TestRepairQuorum(iotests.QMPTestCase): image_len = 1 * 1024 * 1024 # MB IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ] + @iotests.skip_if_unsupported(['quorum']) def setUp(self): self.vm = iotests.VM() @@ -891,9 +892,8 @@ class TestRepairQuorum(iotests.QMPTestCase): #assemble the quorum block device from the individual files args = { "driver": "quorum", "node-name": "quorum0", "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } - if iotests.supports_quorum(): - result = self.vm.qmp("blockdev-add", **args) - self.assert_qmp(result, 'return', {}) + result = self.vm.qmp("blockdev-add", **args) + self.assert_qmp(result, 'return', {}) def tearDown(self): @@ -906,9 +906,6 @@ class TestRepairQuorum(iotests.QMPTestCase): pass def test_complete(self): - if not iotests.supports_quorum(): - return - self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -925,9 +922,6 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_cancel(self): - if not iotests.supports_quorum(): - return - self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -942,9 +936,6 @@ class TestRepairQuorum(iotests.QMPTestCase): self.vm.shutdown() def test_cancel_after_ready(self): - if not iotests.supports_quorum(): - return - self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -961,9 +952,6 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_pause(self): - if not iotests.supports_quorum(): - return - self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -989,9 +977,6 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_medium_not_found(self): - if not iotests.supports_quorum(): - return - if iotests.qemu_default_machine != 'pc': return @@ -1003,9 +988,6 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_image_not_found(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name='repair0', replaces='img1', mode='existing', target=quorum_repair_img, @@ -1013,9 +995,6 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_device_not_found(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('drive-mirror', job_id='job0', device='nonexistent', sync='full', node_name='repair0', @@ -1024,9 +1003,6 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_wrong_sync_mode(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('drive-mirror', device='quorum0', job_id='job0', node_name='repair0', replaces='img1', @@ -1034,27 +1010,18 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_no_node_name(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', replaces='img1', target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') def test_nonexistent_replaces(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name='repair0', replaces='img77', target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') def test_after_a_quorum_snapshot(self): - if not iotests.supports_quorum(): - return - result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', snapshot_file=quorum_snapshot_file, snapshot_node_name="snap1"); diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out index 3645675..263b680 100644 --- a/tests/qemu-iotests/141.out +++ b/tests/qemu-iotests/141.out @@ -13,6 +13,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m. Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} {'execute': 'blockdev-del', 'arguments': {'node-name': 'drv0'}} {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} {'execute': 'block-job-cancel', 'arguments': {'device': 'job0'}} diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out index 8379ac5..9a3b657 100644 --- a/tests/qemu-iotests/185.out +++ b/tests/qemu-iotests/185.out @@ -65,6 +65,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"return": {}} { 'execute': 'quit' } {"return": {}} diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219 index e0c5166..655f54d 100755 --- a/tests/qemu-iotests/219 +++ b/tests/qemu-iotests/219 @@ -63,7 +63,7 @@ def test_pause_resume(vm): # logged immediately iotests.log(vm.qmp('query-jobs')) -def test_job_lifecycle(vm, job, job_args, has_ready=False): +def test_job_lifecycle(vm, job, job_args, has_ready=False, is_mirror=False): global img_size iotests.log('') @@ -135,6 +135,9 @@ def test_job_lifecycle(vm, job, job_args, has_ready=False): iotests.log('Waiting for PENDING state...') iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) + if is_mirror: + iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) + iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) if not job_args.get('auto-finalize', True): # PENDING state: @@ -218,7 +221,7 @@ with iotests.FilePath('disk.img') as disk_path, \ for auto_finalize in [True, False]: for auto_dismiss in [True, False]: - test_job_lifecycle(vm, 'drive-backup', job_args={ + test_job_lifecycle(vm, 'drive-backup', is_mirror=True, job_args={ 'device': 'drive0-node', 'target': copy_path, 'sync': 'full', diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out index 8ebd3fe..0ea5d0b 100644 --- a/tests/qemu-iotests/219.out +++ b/tests/qemu-iotests/219.out @@ -135,6 +135,8 @@ Pause/resume in RUNNING {"return": {}} Waiting for PENDING state... +{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} @@ -186,6 +188,8 @@ Pause/resume in RUNNING {"return": {}} Waiting for PENDING state... +{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} @@ -245,6 +249,8 @@ Pause/resume in RUNNING {"return": {}} Waiting for PENDING state... +{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} @@ -304,6 +310,8 @@ Pause/resume in RUNNING {"return": {}} Waiting for PENDING state... +{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 index 34c818c..59a7f94 100755 --- a/tests/qemu-iotests/234 +++ b/tests/qemu-iotests/234 @@ -69,9 +69,9 @@ with iotests.FilePath('img') as img_path, \ iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo_a))) with iotests.Timeout(3, 'Migration does not complete'): # Wait for the source first (which includes setup=setup) - vm_a.wait_migration() + vm_a.wait_migration('postmigrate') # Wait for the destination second (which does not) - vm_b.wait_migration() + vm_b.wait_migration('running') iotests.log(vm_a.qmp('query-migrate')['return']['status']) iotests.log(vm_b.qmp('query-migrate')['return']['status']) @@ -98,9 +98,9 @@ with iotests.FilePath('img') as img_path, \ iotests.log(vm_b.qmp('migrate', uri='exec:cat >%s' % (fifo_b))) with iotests.Timeout(3, 'Migration does not complete'): # Wait for the source first (which includes setup=setup) - vm_b.wait_migration() + vm_b.wait_migration('postmigrate') # Wait for the destination second (which does not) - vm_a.wait_migration() + vm_a.wait_migration('running') iotests.log(vm_a.qmp('query-migrate')['return']['status']) iotests.log(vm_b.qmp('query-migrate')['return']['status']) diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index e66a23c..d12b253 100644 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -478,6 +478,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # This test verifies that we can't change the children of a block # device during a reopen operation in a way that would create # cycles in the node graph + @iotests.skip_if_unsupported(['blkverify']) def test_graph_cycles(self): opts = [] @@ -534,6 +535,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) # Misc reopen tests with different block drivers + @iotests.skip_if_unsupported(['quorum', 'throttle']) def test_misc_drivers(self): #################### ###### quorum ###### diff --git a/tests/qemu-iotests/262 b/tests/qemu-iotests/262 index 0963daa..bbcb526 100755 --- a/tests/qemu-iotests/262 +++ b/tests/qemu-iotests/262 @@ -71,9 +71,9 @@ with iotests.FilePath('img') as img_path, \ iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo))) with iotests.Timeout(3, 'Migration does not complete'): # Wait for the source first (which includes setup=setup) - vm_a.wait_migration() + vm_a.wait_migration('postmigrate') # Wait for the destination second (which does not) - vm_b.wait_migration() + vm_b.wait_migration('running') iotests.log(vm_a.qmp('query-migrate')['return']['status']) iotests.log(vm_b.qmp('query-migrate')['return']['status']) diff --git a/tests/qemu-iotests/280 b/tests/qemu-iotests/280 index 0b1fa8e..85e9114 100755 --- a/tests/qemu-iotests/280 +++ b/tests/qemu-iotests/280 @@ -45,7 +45,7 @@ with iotests.FilePath('base') as base_path , \ vm.qmp_log('migrate', uri='exec:cat > /dev/null') with iotests.Timeout(3, 'Migration does not complete'): - vm.wait_migration() + vm.wait_migration('postmigrate') iotests.log('\nVM is now stopped:') iotests.log(vm.qmp('query-migrate')['return']['status']) diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281 new file mode 100755 index 0000000..269d583 --- /dev/null +++ b/tests/qemu-iotests/281 @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# +# Test cases for blockdev + IOThread interactions +# +# Copyright (C) 2019 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import iotests +from iotests import qemu_img + +image_len = 64 * 1024 * 1024 + +# Test for RHBZ#1782175 +class TestDirtyBitmapIOThread(iotests.QMPTestCase): + drive0_img = os.path.join(iotests.test_dir, 'drive0.img') + images = { 'drive0': drive0_img } + + def setUp(self): + for name in self.images: + qemu_img('create', '-f', iotests.imgfmt, + self.images[name], str(image_len)) + + self.vm = iotests.VM() + self.vm.add_object('iothread,id=iothread0') + + for name in self.images: + self.vm.add_blockdev('driver=file,filename=%s,node-name=file_%s' + % (self.images[name], name)) + self.vm.add_blockdev('driver=qcow2,file=file_%s,node-name=%s' + % (name, name)) + + self.vm.launch() + self.vm.qmp('x-blockdev-set-iothread', + node_name='drive0', iothread='iothread0', + force=True) + + def tearDown(self): + self.vm.shutdown() + for name in self.images: + os.remove(self.images[name]) + + def test_add_dirty_bitmap(self): + result = self.vm.qmp( + 'block-dirty-bitmap-add', + node='drive0', + name='bitmap1', + persistent=True, + ) + + self.assert_qmp(result, 'return', {}) + + +# Test for RHBZ#1746217 & RHBZ#1773517 +class TestNBDMirrorIOThread(iotests.QMPTestCase): + nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') + drive0_img = os.path.join(iotests.test_dir, 'drive0.img') + mirror_img = os.path.join(iotests.test_dir, 'mirror.img') + images = { 'drive0': drive0_img, 'mirror': mirror_img } + + def setUp(self): + for name in self.images: + qemu_img('create', '-f', iotests.imgfmt, + self.images[name], str(image_len)) + + self.vm_src = iotests.VM(path_suffix='src') + self.vm_src.add_object('iothread,id=iothread0') + self.vm_src.add_blockdev('driver=file,filename=%s,node-name=file0' + % (self.drive0_img)) + self.vm_src.add_blockdev('driver=qcow2,file=file0,node-name=drive0') + self.vm_src.launch() + self.vm_src.qmp('x-blockdev-set-iothread', + node_name='drive0', iothread='iothread0', + force=True) + + self.vm_tgt = iotests.VM(path_suffix='tgt') + self.vm_tgt.add_object('iothread,id=iothread0') + self.vm_tgt.add_blockdev('driver=file,filename=%s,node-name=file0' + % (self.mirror_img)) + self.vm_tgt.add_blockdev('driver=qcow2,file=file0,node-name=drive0') + self.vm_tgt.launch() + self.vm_tgt.qmp('x-blockdev-set-iothread', + node_name='drive0', iothread='iothread0', + force=True) + + def tearDown(self): + self.vm_src.shutdown() + self.vm_tgt.shutdown() + for name in self.images: + os.remove(self.images[name]) + + def test_nbd_mirror(self): + result = self.vm_tgt.qmp( + 'nbd-server-start', + addr={ + 'type': 'unix', + 'data': { 'path': self.nbd_sock } + } + ) + self.assert_qmp(result, 'return', {}) + + result = self.vm_tgt.qmp( + 'nbd-server-add', + device='drive0', + writable=True + ) + self.assert_qmp(result, 'return', {}) + + result = self.vm_src.qmp( + 'drive-mirror', + device='drive0', + target='nbd+unix:///drive0?socket=' + self.nbd_sock, + sync='full', + mode='existing', + speed=64*1024*1024, + job_id='j1' + ) + self.assert_qmp(result, 'return', {}) + + self.vm_src.event_wait(name="BLOCK_JOB_READY") + + +# Test for RHBZ#1779036 +class TestExternalSnapshotAbort(iotests.QMPTestCase): + drive0_img = os.path.join(iotests.test_dir, 'drive0.img') + snapshot_img = os.path.join(iotests.test_dir, 'snapshot.img') + images = { 'drive0': drive0_img, 'snapshot': snapshot_img } + + def setUp(self): + for name in self.images: + qemu_img('create', '-f', iotests.imgfmt, + self.images[name], str(image_len)) + + self.vm = iotests.VM() + self.vm.add_object('iothread,id=iothread0') + self.vm.add_blockdev('driver=file,filename=%s,node-name=file0' + % (self.drive0_img)) + self.vm.add_blockdev('driver=qcow2,file=file0,node-name=drive0') + self.vm.launch() + self.vm.qmp('x-blockdev-set-iothread', + node_name='drive0', iothread='iothread0', + force=True) + + def tearDown(self): + self.vm.shutdown() + for name in self.images: + os.remove(self.images[name]) + + def test_external_snapshot_abort(self): + # Use a two actions transaction with a bogus values on the second + # one to trigger an abort of the transaction. + result = self.vm.qmp('transaction', actions=[ + { + 'type': 'blockdev-snapshot-sync', + 'data': { 'node-name': 'drive0', + 'snapshot-file': self.snapshot_img, + 'snapshot-node-name': 'snap1', + 'mode': 'absolute-paths', + 'format': 'qcow2' } + }, + { + 'type': 'blockdev-snapshot-sync', + 'data': { 'node-name': 'drive0', + 'snapshot-file': '/fakesnapshot', + 'snapshot-node-name': 'snap2', + 'mode': 'absolute-paths', + 'format': 'qcow2' } + }, + ]) + + # Crashes on failure, we expect this error. + self.assert_qmp(result, 'error/class', 'GenericError') + + +# Test for RHBZ#1782111 +class TestBlockdevBackupAbort(iotests.QMPTestCase): + drive0_img = os.path.join(iotests.test_dir, 'drive0.img') + drive1_img = os.path.join(iotests.test_dir, 'drive1.img') + snap0_img = os.path.join(iotests.test_dir, 'snap0.img') + snap1_img = os.path.join(iotests.test_dir, 'snap1.img') + images = { 'drive0': drive0_img, + 'drive1': drive1_img, + 'snap0': snap0_img, + 'snap1': snap1_img } + + def setUp(self): + for name in self.images: + qemu_img('create', '-f', iotests.imgfmt, + self.images[name], str(image_len)) + + self.vm = iotests.VM() + self.vm.add_object('iothread,id=iothread0') + self.vm.add_device('virtio-scsi,iothread=iothread0') + + for name in self.images: + self.vm.add_blockdev('driver=file,filename=%s,node-name=file_%s' + % (self.images[name], name)) + self.vm.add_blockdev('driver=qcow2,file=file_%s,node-name=%s' + % (name, name)) + + self.vm.add_device('scsi-hd,drive=drive0') + self.vm.add_device('scsi-hd,drive=drive1') + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + for name in self.images: + os.remove(self.images[name]) + + def test_blockdev_backup_abort(self): + # Use a two actions transaction with a bogus values on the second + # one to trigger an abort of the transaction. + result = self.vm.qmp('transaction', actions=[ + { + 'type': 'blockdev-backup', + 'data': { 'device': 'drive0', + 'target': 'snap0', + 'sync': 'full', + 'job-id': 'j1' } + }, + { + 'type': 'blockdev-backup', + 'data': { 'device': 'drive1', + 'target': 'snap1', + 'sync': 'full' } + }, + ]) + + # Hangs on failure, we expect this error. + self.assert_qmp(result, 'error/class', 'GenericError') + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/281.out b/tests/qemu-iotests/281.out new file mode 100644 index 0000000..89968f3 --- /dev/null +++ b/tests/qemu-iotests/281.out @@ -0,0 +1,5 @@ +.... +---------------------------------------------------------------------- +Ran 4 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index cb2b789..e041cc1 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -288,3 +288,4 @@ 277 rw quick 279 rw backing quick 280 rw migration quick +281 rw quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 13fd8b5..0b62c42 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -668,12 +668,16 @@ class VM(qtest.QEMUQtestMachine): } ])) - def wait_migration(self): + def wait_migration(self, expect_runstate): while True: event = self.event_wait('MIGRATION') log(event, filters=[filter_qmp_event]) if event['data']['status'] == 'completed': break + # The event may occur in finish-migrate, so wait for the expected + # post-migration runstate + while self.qmp('query-status')['return']['status'] != expect_runstate: + pass def node_info(self, node_name): nodes = self.qmp('query-named-block-nodes') |