144c7ca5eSPaolo Bonzini#!/usr/bin/env python 244c7ca5eSPaolo Bonzini# 344c7ca5eSPaolo Bonzini# Tests for image mirroring. 444c7ca5eSPaolo Bonzini# 544c7ca5eSPaolo Bonzini# Copyright (C) 2012 Red Hat, Inc. 644c7ca5eSPaolo Bonzini# 744c7ca5eSPaolo Bonzini# This program is free software; you can redistribute it and/or modify 844c7ca5eSPaolo Bonzini# it under the terms of the GNU General Public License as published by 944c7ca5eSPaolo Bonzini# the Free Software Foundation; either version 2 of the License, or 1044c7ca5eSPaolo Bonzini# (at your option) any later version. 1144c7ca5eSPaolo Bonzini# 1244c7ca5eSPaolo Bonzini# This program is distributed in the hope that it will be useful, 1344c7ca5eSPaolo Bonzini# but WITHOUT ANY WARRANTY; without even the implied warranty of 1444c7ca5eSPaolo Bonzini# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1544c7ca5eSPaolo Bonzini# GNU General Public License for more details. 1644c7ca5eSPaolo Bonzini# 1744c7ca5eSPaolo Bonzini# You should have received a copy of the GNU General Public License 1844c7ca5eSPaolo Bonzini# along with this program. If not, see <http://www.gnu.org/licenses/>. 1944c7ca5eSPaolo Bonzini# 2044c7ca5eSPaolo Bonzini 2144c7ca5eSPaolo Bonziniimport time 2244c7ca5eSPaolo Bonziniimport os 2344c7ca5eSPaolo Bonziniimport iotests 2444c7ca5eSPaolo Bonzinifrom iotests import qemu_img, qemu_io 2544c7ca5eSPaolo Bonzini 2644c7ca5eSPaolo Bonzinibacking_img = os.path.join(iotests.test_dir, 'backing.img') 2744c7ca5eSPaolo Bonzinitarget_backing_img = os.path.join(iotests.test_dir, 'target-backing.img') 2844c7ca5eSPaolo Bonzinitest_img = os.path.join(iotests.test_dir, 'test.img') 2944c7ca5eSPaolo Bonzinitarget_img = os.path.join(iotests.test_dir, 'target.img') 3044c7ca5eSPaolo Bonzini 31d88964aeSBenoît Canetquorum_img1 = os.path.join(iotests.test_dir, 'quorum1.img') 32d88964aeSBenoît Canetquorum_img2 = os.path.join(iotests.test_dir, 'quorum2.img') 33d88964aeSBenoît Canetquorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img') 34d88964aeSBenoît Canetquorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img') 35d88964aeSBenoît Canetquorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img') 36d88964aeSBenoît Canet 37866323f3SFam Zhengclass TestSingleDrive(iotests.QMPTestCase): 3844c7ca5eSPaolo Bonzini image_len = 1 * 1024 * 1024 # MB 3994ca2c73SFam Zheng qmp_cmd = 'drive-mirror' 4094ca2c73SFam Zheng qmp_target = target_img 4194ca2c73SFam Zheng not_found_error = 'DeviceNotFound' 4244c7ca5eSPaolo Bonzini 4344c7ca5eSPaolo Bonzini def setUp(self): 443b9f27d2SFam Zheng iotests.create_image(backing_img, self.image_len) 4544c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 4644c7ca5eSPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 470ed82f7aSMax Reitz if iotests.qemu_default_machine == 'pc': 480ed82f7aSMax Reitz self.vm.add_drive(None, 'media=cdrom', 'ide') 4944c7ca5eSPaolo Bonzini self.vm.launch() 5044c7ca5eSPaolo Bonzini 5144c7ca5eSPaolo Bonzini def tearDown(self): 5244c7ca5eSPaolo Bonzini self.vm.shutdown() 5344c7ca5eSPaolo Bonzini os.remove(test_img) 5444c7ca5eSPaolo Bonzini os.remove(backing_img) 5544c7ca5eSPaolo Bonzini try: 5644c7ca5eSPaolo Bonzini os.remove(target_img) 5744c7ca5eSPaolo Bonzini except OSError: 5844c7ca5eSPaolo Bonzini pass 5944c7ca5eSPaolo Bonzini 6044c7ca5eSPaolo Bonzini def test_complete(self): 61ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 6244c7ca5eSPaolo Bonzini 6394ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 6494ca2c73SFam Zheng target=self.qmp_target) 6544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 6644c7ca5eSPaolo Bonzini 6744c7ca5eSPaolo Bonzini self.complete_and_wait() 6844c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 6944c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 7044c7ca5eSPaolo Bonzini self.vm.shutdown() 713a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 7244c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 7344c7ca5eSPaolo Bonzini 7444c7ca5eSPaolo Bonzini def test_cancel(self): 75ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 7644c7ca5eSPaolo Bonzini 7794ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 7894ca2c73SFam Zheng target=self.qmp_target) 7944c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 8044c7ca5eSPaolo Bonzini 812575fe16SStefan Hajnoczi self.cancel_and_wait(force=True) 8244c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 8344c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', test_img) 8444c7ca5eSPaolo Bonzini self.vm.shutdown() 8544c7ca5eSPaolo Bonzini 8644c7ca5eSPaolo Bonzini def test_cancel_after_ready(self): 87ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 8844c7ca5eSPaolo Bonzini 8994ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 9094ca2c73SFam Zheng target=self.qmp_target) 9144c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 9244c7ca5eSPaolo Bonzini 932575fe16SStefan Hajnoczi self.wait_ready_and_cancel() 9444c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 9544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', test_img) 9644c7ca5eSPaolo Bonzini self.vm.shutdown() 973a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 9844c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 9944c7ca5eSPaolo Bonzini 10044c7ca5eSPaolo Bonzini def test_pause(self): 101ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 10244c7ca5eSPaolo Bonzini 10394ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 10494ca2c73SFam Zheng target=self.qmp_target) 10544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 10644c7ca5eSPaolo Bonzini 10744c7ca5eSPaolo Bonzini result = self.vm.qmp('block-job-pause', device='drive0') 10844c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 10944c7ca5eSPaolo Bonzini 11044c7ca5eSPaolo Bonzini time.sleep(1) 11144c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block-jobs') 11244c7ca5eSPaolo Bonzini offset = self.dictpath(result, 'return[0]/offset') 11344c7ca5eSPaolo Bonzini 11444c7ca5eSPaolo Bonzini time.sleep(1) 11544c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block-jobs') 11644c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', offset) 11744c7ca5eSPaolo Bonzini 11844c7ca5eSPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 11944c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 12044c7ca5eSPaolo Bonzini 12144c7ca5eSPaolo Bonzini self.complete_and_wait() 12244c7ca5eSPaolo Bonzini self.vm.shutdown() 1233a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 12444c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 12544c7ca5eSPaolo Bonzini 12608e4ed6cSPaolo Bonzini def test_small_buffer(self): 127ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 12808e4ed6cSPaolo Bonzini 12908e4ed6cSPaolo Bonzini # A small buffer is rounded up automatically 13094ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 13194ca2c73SFam Zheng buf_size=4096, target=self.qmp_target) 13208e4ed6cSPaolo Bonzini self.assert_qmp(result, 'return', {}) 13308e4ed6cSPaolo Bonzini 13408e4ed6cSPaolo Bonzini self.complete_and_wait() 13508e4ed6cSPaolo Bonzini result = self.vm.qmp('query-block') 13608e4ed6cSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 13708e4ed6cSPaolo Bonzini self.vm.shutdown() 1383a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 13908e4ed6cSPaolo Bonzini 'target image does not match source after mirroring') 14008e4ed6cSPaolo Bonzini 14108e4ed6cSPaolo Bonzini def test_small_buffer2(self): 142ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 14308e4ed6cSPaolo Bonzini 14408e4ed6cSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' 1453b9f27d2SFam Zheng % (self.image_len, self.image_len), target_img) 14694ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 14794ca2c73SFam Zheng buf_size=65536, mode='existing', target=self.qmp_target) 14808e4ed6cSPaolo Bonzini self.assert_qmp(result, 'return', {}) 14908e4ed6cSPaolo Bonzini 15008e4ed6cSPaolo Bonzini self.complete_and_wait() 15108e4ed6cSPaolo Bonzini result = self.vm.qmp('query-block') 15208e4ed6cSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 15308e4ed6cSPaolo Bonzini self.vm.shutdown() 1543a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 15508e4ed6cSPaolo Bonzini 'target image does not match source after mirroring') 15608e4ed6cSPaolo Bonzini 15744c7ca5eSPaolo Bonzini def test_large_cluster(self): 158ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 15944c7ca5eSPaolo Bonzini 16044c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' 1613b9f27d2SFam Zheng % (self.image_len, backing_img), target_img) 16294ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 16394ca2c73SFam Zheng mode='existing', target=self.qmp_target) 16444c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 16544c7ca5eSPaolo Bonzini 16644c7ca5eSPaolo Bonzini self.complete_and_wait() 16744c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 16844c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 16944c7ca5eSPaolo Bonzini self.vm.shutdown() 1703a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 17144c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 17244c7ca5eSPaolo Bonzini 17344c7ca5eSPaolo Bonzini def test_medium_not_found(self): 174d8683155SBo Tu if iotests.qemu_default_machine != 'pc': 175d8683155SBo Tu return 176d8683155SBo Tu 17794ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full', 17894ca2c73SFam Zheng target=self.qmp_target) 17994ca2c73SFam Zheng self.assert_qmp(result, 'error/class', self.not_found_error) 18044c7ca5eSPaolo Bonzini 18144c7ca5eSPaolo Bonzini def test_image_not_found(self): 18294ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', 18394ca2c73SFam Zheng mode='existing', target=self.qmp_target) 18444c7ca5eSPaolo Bonzini self.assert_qmp(result, 'error/class', 'GenericError') 18544c7ca5eSPaolo Bonzini 18644c7ca5eSPaolo Bonzini def test_device_not_found(self): 18794ca2c73SFam Zheng result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full', 18894ca2c73SFam Zheng target=self.qmp_target) 18994ca2c73SFam Zheng self.assert_qmp(result, 'error/class', self.not_found_error) 19094ca2c73SFam Zheng 19194ca2c73SFam Zhengclass TestSingleBlockdev(TestSingleDrive): 19294ca2c73SFam Zheng qmp_cmd = 'blockdev-mirror' 19394ca2c73SFam Zheng qmp_target = 'node1' 19494ca2c73SFam Zheng not_found_error = 'GenericError' 19594ca2c73SFam Zheng 19694ca2c73SFam Zheng def setUp(self): 19794ca2c73SFam Zheng TestSingleDrive.setUp(self) 19894ca2c73SFam Zheng qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) 19994ca2c73SFam Zheng args = {'options': 20094ca2c73SFam Zheng {'driver': iotests.imgfmt, 20194ca2c73SFam Zheng 'node-name': self.qmp_target, 20294ca2c73SFam Zheng 'file': { 'filename': target_img, 'driver': 'file' } } } 20394ca2c73SFam Zheng result = self.vm.qmp("blockdev-add", **args) 20494ca2c73SFam Zheng self.assert_qmp(result, 'return', {}) 20594ca2c73SFam Zheng 20694ca2c73SFam Zheng test_large_cluster = None 20794ca2c73SFam Zheng test_image_not_found = None 20894ca2c73SFam Zheng test_small_buffer2 = None 20994ca2c73SFam Zheng 2103b9f27d2SFam Zhengclass TestSingleDriveZeroLength(TestSingleDrive): 2113b9f27d2SFam Zheng image_len = 0 2123b9f27d2SFam Zheng test_small_buffer2 = None 2133b9f27d2SFam Zheng test_large_cluster = None 2143b9f27d2SFam Zheng 21594ca2c73SFam Zhengclass TestSingleBlockdevZeroLength(TestSingleBlockdev): 21694ca2c73SFam Zheng image_len = 0 21794ca2c73SFam Zheng 2185a0f6fd5SKevin Wolfclass TestSingleDriveUnalignedLength(TestSingleDrive): 2195a0f6fd5SKevin Wolf image_len = 1025 * 1024 2205a0f6fd5SKevin Wolf test_small_buffer2 = None 2215a0f6fd5SKevin Wolf test_large_cluster = None 2225a0f6fd5SKevin Wolf 22394ca2c73SFam Zhengclass TestSingleBlockdevUnalignedLength(TestSingleBlockdev): 22494ca2c73SFam Zheng image_len = 1025 * 1024 22594ca2c73SFam Zheng 226866323f3SFam Zhengclass TestMirrorNoBacking(iotests.QMPTestCase): 22744c7ca5eSPaolo Bonzini image_len = 2 * 1024 * 1024 # MB 22844c7ca5eSPaolo Bonzini 22944c7ca5eSPaolo Bonzini def setUp(self): 2302499a096SStefan Hajnoczi iotests.create_image(backing_img, TestMirrorNoBacking.image_len) 23144c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 23244c7ca5eSPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 23344c7ca5eSPaolo Bonzini self.vm.launch() 23444c7ca5eSPaolo Bonzini 23544c7ca5eSPaolo Bonzini def tearDown(self): 23644c7ca5eSPaolo Bonzini self.vm.shutdown() 23744c7ca5eSPaolo Bonzini os.remove(test_img) 23844c7ca5eSPaolo Bonzini os.remove(backing_img) 239866323f3SFam Zheng try: 24044c7ca5eSPaolo Bonzini os.remove(target_backing_img) 241866323f3SFam Zheng except: 242866323f3SFam Zheng pass 24344c7ca5eSPaolo Bonzini os.remove(target_img) 24444c7ca5eSPaolo Bonzini 24544c7ca5eSPaolo Bonzini def test_complete(self): 246ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 24744c7ca5eSPaolo Bonzini 24844c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) 24944c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 25044c7ca5eSPaolo Bonzini mode='existing', target=target_img) 25144c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 25244c7ca5eSPaolo Bonzini 25344c7ca5eSPaolo Bonzini self.complete_and_wait() 25444c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 25544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 25644c7ca5eSPaolo Bonzini self.vm.shutdown() 257866323f3SFam Zheng self.assertTrue(iotests.compare_images(test_img, target_img), 25844c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 25944c7ca5eSPaolo Bonzini 26044c7ca5eSPaolo Bonzini def test_cancel(self): 261ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 26244c7ca5eSPaolo Bonzini 26344c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) 26444c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 26544c7ca5eSPaolo Bonzini mode='existing', target=target_img) 26644c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 26744c7ca5eSPaolo Bonzini 2682575fe16SStefan Hajnoczi self.wait_ready_and_cancel() 26944c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block') 27044c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', test_img) 27144c7ca5eSPaolo Bonzini self.vm.shutdown() 272866323f3SFam Zheng self.assertTrue(iotests.compare_images(test_img, target_img), 27344c7ca5eSPaolo Bonzini 'target image does not match source after mirroring') 27444c7ca5eSPaolo Bonzini 275b812f671SPaolo Bonzini def test_large_cluster(self): 276ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 277b812f671SPaolo Bonzini 278b812f671SPaolo Bonzini # qemu-img create fails if the image is not there 279b812f671SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' 280b812f671SPaolo Bonzini %(TestMirrorNoBacking.image_len), target_backing_img) 281b812f671SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' 282b812f671SPaolo Bonzini % (TestMirrorNoBacking.image_len, target_backing_img), target_img) 283b812f671SPaolo Bonzini 284b812f671SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 285b812f671SPaolo Bonzini mode='existing', target=target_img) 286b812f671SPaolo Bonzini self.assert_qmp(result, 'return', {}) 287b812f671SPaolo Bonzini 288b812f671SPaolo Bonzini self.complete_and_wait() 289b812f671SPaolo Bonzini result = self.vm.qmp('query-block') 290b812f671SPaolo Bonzini self.assert_qmp(result, 'return[0]/inserted/file', target_img) 291b812f671SPaolo Bonzini self.vm.shutdown() 292866323f3SFam Zheng self.assertTrue(iotests.compare_images(test_img, target_img), 293b812f671SPaolo Bonzini 'target image does not match source after mirroring') 294b812f671SPaolo Bonzini 295866323f3SFam Zhengclass TestMirrorResized(iotests.QMPTestCase): 296a04eca10SVishvananda Ishaya backing_len = 1 * 1024 * 1024 # MB 297a04eca10SVishvananda Ishaya image_len = 2 * 1024 * 1024 # MB 298a04eca10SVishvananda Ishaya 299a04eca10SVishvananda Ishaya def setUp(self): 3002499a096SStefan Hajnoczi iotests.create_image(backing_img, TestMirrorResized.backing_len) 301a04eca10SVishvananda Ishaya qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 302a04eca10SVishvananda Ishaya qemu_img('resize', test_img, '2M') 303a04eca10SVishvananda Ishaya self.vm = iotests.VM().add_drive(test_img) 304a04eca10SVishvananda Ishaya self.vm.launch() 305a04eca10SVishvananda Ishaya 306a04eca10SVishvananda Ishaya def tearDown(self): 307a04eca10SVishvananda Ishaya self.vm.shutdown() 308a04eca10SVishvananda Ishaya os.remove(test_img) 309a04eca10SVishvananda Ishaya os.remove(backing_img) 310a04eca10SVishvananda Ishaya try: 311a04eca10SVishvananda Ishaya os.remove(target_img) 312a04eca10SVishvananda Ishaya except OSError: 313a04eca10SVishvananda Ishaya pass 314a04eca10SVishvananda Ishaya 315a04eca10SVishvananda Ishaya def test_complete_top(self): 316ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 317a04eca10SVishvananda Ishaya 318a04eca10SVishvananda Ishaya result = self.vm.qmp('drive-mirror', device='drive0', sync='top', 319a04eca10SVishvananda Ishaya target=target_img) 320a04eca10SVishvananda Ishaya self.assert_qmp(result, 'return', {}) 321a04eca10SVishvananda Ishaya 322a04eca10SVishvananda Ishaya self.complete_and_wait() 323a04eca10SVishvananda Ishaya result = self.vm.qmp('query-block') 324a04eca10SVishvananda Ishaya self.assert_qmp(result, 'return[0]/inserted/file', target_img) 325a04eca10SVishvananda Ishaya self.vm.shutdown() 3263a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 327a04eca10SVishvananda Ishaya 'target image does not match source after mirroring') 328a04eca10SVishvananda Ishaya 329a04eca10SVishvananda Ishaya def test_complete_full(self): 330ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 331a04eca10SVishvananda Ishaya 332a04eca10SVishvananda Ishaya result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 333a04eca10SVishvananda Ishaya target=target_img) 334a04eca10SVishvananda Ishaya self.assert_qmp(result, 'return', {}) 335a04eca10SVishvananda Ishaya 336a04eca10SVishvananda Ishaya self.complete_and_wait() 337a04eca10SVishvananda Ishaya result = self.vm.qmp('query-block') 338a04eca10SVishvananda Ishaya self.assert_qmp(result, 'return[0]/inserted/file', target_img) 339a04eca10SVishvananda Ishaya self.vm.shutdown() 3403a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 341a04eca10SVishvananda Ishaya 'target image does not match source after mirroring') 342a04eca10SVishvananda Ishaya 343866323f3SFam Zhengclass TestReadErrors(iotests.QMPTestCase): 3449dfa9f59SPaolo Bonzini image_len = 2 * 1024 * 1024 # MB 3459dfa9f59SPaolo Bonzini 3469dfa9f59SPaolo Bonzini # this should be a multiple of twice the default granularity 3479dfa9f59SPaolo Bonzini # so that we hit this offset first in state 1 3489dfa9f59SPaolo Bonzini MIRROR_GRANULARITY = 1024 * 1024 3499dfa9f59SPaolo Bonzini 3509dfa9f59SPaolo Bonzini def create_blkdebug_file(self, name, event, errno): 3519dfa9f59SPaolo Bonzini file = open(name, 'w') 3529dfa9f59SPaolo Bonzini file.write(''' 3539dfa9f59SPaolo Bonzini[inject-error] 3549dfa9f59SPaolo Bonzinistate = "1" 3559dfa9f59SPaolo Bonzinievent = "%s" 3569dfa9f59SPaolo Bonzinierrno = "%d" 3579dfa9f59SPaolo Bonziniimmediately = "off" 3589dfa9f59SPaolo Bonzinionce = "on" 3599dfa9f59SPaolo Bonzinisector = "%d" 3609dfa9f59SPaolo Bonzini 3619dfa9f59SPaolo Bonzini[set-state] 3629dfa9f59SPaolo Bonzinistate = "1" 3639dfa9f59SPaolo Bonzinievent = "%s" 3649dfa9f59SPaolo Bonzininew_state = "2" 3659dfa9f59SPaolo Bonzini 3669dfa9f59SPaolo Bonzini[set-state] 3679dfa9f59SPaolo Bonzinistate = "2" 3689dfa9f59SPaolo Bonzinievent = "%s" 3699dfa9f59SPaolo Bonzininew_state = "1" 3709dfa9f59SPaolo Bonzini''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) 3719dfa9f59SPaolo Bonzini file.close() 3729dfa9f59SPaolo Bonzini 3739dfa9f59SPaolo Bonzini def setUp(self): 3749dfa9f59SPaolo Bonzini self.blkdebug_file = backing_img + ".blkdebug" 3752499a096SStefan Hajnoczi iotests.create_image(backing_img, TestReadErrors.image_len) 3769dfa9f59SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) 3779dfa9f59SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, 3789dfa9f59SPaolo Bonzini '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 3799dfa9f59SPaolo Bonzini % (self.blkdebug_file, backing_img), 3809dfa9f59SPaolo Bonzini test_img) 381b812f671SPaolo Bonzini # Write something for tests that use sync='top' 382b812f671SPaolo Bonzini qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536), 383b812f671SPaolo Bonzini test_img) 3849dfa9f59SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 3859dfa9f59SPaolo Bonzini self.vm.launch() 3869dfa9f59SPaolo Bonzini 3879dfa9f59SPaolo Bonzini def tearDown(self): 3889dfa9f59SPaolo Bonzini self.vm.shutdown() 3899dfa9f59SPaolo Bonzini os.remove(test_img) 3909dfa9f59SPaolo Bonzini os.remove(backing_img) 3919dfa9f59SPaolo Bonzini os.remove(self.blkdebug_file) 3929dfa9f59SPaolo Bonzini 3939dfa9f59SPaolo Bonzini def test_report_read(self): 394ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 3959dfa9f59SPaolo Bonzini 3969dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 3979dfa9f59SPaolo Bonzini target=target_img) 3989dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 3999dfa9f59SPaolo Bonzini 4009dfa9f59SPaolo Bonzini completed = False 4019dfa9f59SPaolo Bonzini error = False 4029dfa9f59SPaolo Bonzini while not completed: 4039dfa9f59SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 4049dfa9f59SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 4059dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 4069dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 4079dfa9f59SPaolo Bonzini error = True 4089dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_READY': 4099dfa9f59SPaolo Bonzini self.assertTrue(False, 'job completed unexpectedly') 4109dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 4119dfa9f59SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 4129dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/type', 'mirror') 4139dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 4149dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 4159dfa9f59SPaolo Bonzini completed = True 4169dfa9f59SPaolo Bonzini 417ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 4189dfa9f59SPaolo Bonzini self.vm.shutdown() 4199dfa9f59SPaolo Bonzini 4209dfa9f59SPaolo Bonzini def test_ignore_read(self): 421ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 4229dfa9f59SPaolo Bonzini 4239dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 4249dfa9f59SPaolo Bonzini target=target_img, on_source_error='ignore') 4259dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 4269dfa9f59SPaolo Bonzini 4279dfa9f59SPaolo Bonzini event = self.vm.get_qmp_event(wait=True) 4289dfa9f59SPaolo Bonzini self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 4299dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 4309dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 4319dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 4329dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 4339dfa9f59SPaolo Bonzini self.complete_and_wait() 4349dfa9f59SPaolo Bonzini self.vm.shutdown() 4359dfa9f59SPaolo Bonzini 436b812f671SPaolo Bonzini def test_large_cluster(self): 437ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 438b812f671SPaolo Bonzini 439b812f671SPaolo Bonzini # Test COW into the target image. The first half of the 440b812f671SPaolo Bonzini # cluster at MIRROR_GRANULARITY has to be copied from 441b812f671SPaolo Bonzini # backing_img, even though sync='top'. 442b812f671SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img) 443b812f671SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='top', 444b812f671SPaolo Bonzini on_source_error='ignore', 445b812f671SPaolo Bonzini mode='existing', target=target_img) 446b812f671SPaolo Bonzini self.assert_qmp(result, 'return', {}) 447b812f671SPaolo Bonzini 448b812f671SPaolo Bonzini event = self.vm.get_qmp_event(wait=True) 449b812f671SPaolo Bonzini self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 450b812f671SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 451b812f671SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 452b812f671SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 453b812f671SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 454b812f671SPaolo Bonzini self.complete_and_wait() 455b812f671SPaolo Bonzini self.vm.shutdown() 456b812f671SPaolo Bonzini 457b812f671SPaolo Bonzini # Detach blkdebug to compare images successfully 458b812f671SPaolo Bonzini qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) 4593a3918c3SStefan Hajnoczi self.assertTrue(iotests.compare_images(test_img, target_img), 460b812f671SPaolo Bonzini 'target image does not match source after mirroring') 461b812f671SPaolo Bonzini 4629dfa9f59SPaolo Bonzini def test_stop_read(self): 463ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 4649dfa9f59SPaolo Bonzini 4659dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 4669dfa9f59SPaolo Bonzini target=target_img, on_source_error='stop') 4679dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 4689dfa9f59SPaolo Bonzini 4699dfa9f59SPaolo Bonzini error = False 4709dfa9f59SPaolo Bonzini ready = False 4719dfa9f59SPaolo Bonzini while not ready: 4729dfa9f59SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 4739dfa9f59SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 4749dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 4759dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 4769dfa9f59SPaolo Bonzini 4779dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 4789dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 4799dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'failed') 4809dfa9f59SPaolo Bonzini 4819dfa9f59SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 4829dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 4839dfa9f59SPaolo Bonzini error = True 4849dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_READY': 4859dfa9f59SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 4869dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 4879dfa9f59SPaolo Bonzini ready = True 4889dfa9f59SPaolo Bonzini 4899dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 4909dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 4919dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 4929dfa9f59SPaolo Bonzini 4939dfa9f59SPaolo Bonzini self.complete_and_wait(wait_ready=False) 494ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 4959dfa9f59SPaolo Bonzini self.vm.shutdown() 4969dfa9f59SPaolo Bonzini 497866323f3SFam Zhengclass TestWriteErrors(iotests.QMPTestCase): 4989dfa9f59SPaolo Bonzini image_len = 2 * 1024 * 1024 # MB 4999dfa9f59SPaolo Bonzini 5009dfa9f59SPaolo Bonzini # this should be a multiple of twice the default granularity 5019dfa9f59SPaolo Bonzini # so that we hit this offset first in state 1 5029dfa9f59SPaolo Bonzini MIRROR_GRANULARITY = 1024 * 1024 5039dfa9f59SPaolo Bonzini 5049dfa9f59SPaolo Bonzini def create_blkdebug_file(self, name, event, errno): 5059dfa9f59SPaolo Bonzini file = open(name, 'w') 5069dfa9f59SPaolo Bonzini file.write(''' 5079dfa9f59SPaolo Bonzini[inject-error] 5089dfa9f59SPaolo Bonzinistate = "1" 5099dfa9f59SPaolo Bonzinievent = "%s" 5109dfa9f59SPaolo Bonzinierrno = "%d" 5119dfa9f59SPaolo Bonziniimmediately = "off" 5129dfa9f59SPaolo Bonzinionce = "on" 5139dfa9f59SPaolo Bonzinisector = "%d" 5149dfa9f59SPaolo Bonzini 5159dfa9f59SPaolo Bonzini[set-state] 5169dfa9f59SPaolo Bonzinistate = "1" 5179dfa9f59SPaolo Bonzinievent = "%s" 5189dfa9f59SPaolo Bonzininew_state = "2" 5199dfa9f59SPaolo Bonzini 5209dfa9f59SPaolo Bonzini[set-state] 5219dfa9f59SPaolo Bonzinistate = "2" 5229dfa9f59SPaolo Bonzinievent = "%s" 5239dfa9f59SPaolo Bonzininew_state = "1" 5249dfa9f59SPaolo Bonzini''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) 5259dfa9f59SPaolo Bonzini file.close() 5269dfa9f59SPaolo Bonzini 5279dfa9f59SPaolo Bonzini def setUp(self): 5289dfa9f59SPaolo Bonzini self.blkdebug_file = target_img + ".blkdebug" 5292499a096SStefan Hajnoczi iotests.create_image(backing_img, TestWriteErrors.image_len) 5309dfa9f59SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) 5319dfa9f59SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) 5329dfa9f59SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 5339dfa9f59SPaolo Bonzini self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img) 5349dfa9f59SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img) 5359dfa9f59SPaolo Bonzini self.vm.launch() 5369dfa9f59SPaolo Bonzini 5379dfa9f59SPaolo Bonzini def tearDown(self): 5389dfa9f59SPaolo Bonzini self.vm.shutdown() 5399dfa9f59SPaolo Bonzini os.remove(test_img) 5409dfa9f59SPaolo Bonzini os.remove(backing_img) 5419dfa9f59SPaolo Bonzini os.remove(self.blkdebug_file) 5429dfa9f59SPaolo Bonzini 5439dfa9f59SPaolo Bonzini def test_report_write(self): 544ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 5459dfa9f59SPaolo Bonzini 5469dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 5479dfa9f59SPaolo Bonzini mode='existing', target=self.target_img) 5489dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 5499dfa9f59SPaolo Bonzini 5509dfa9f59SPaolo Bonzini completed = False 5519dfa9f59SPaolo Bonzini error = False 5529dfa9f59SPaolo Bonzini while not completed: 5539dfa9f59SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 5549dfa9f59SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 5559dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 5569dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'write') 5579dfa9f59SPaolo Bonzini error = True 5589dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_READY': 5599dfa9f59SPaolo Bonzini self.assertTrue(False, 'job completed unexpectedly') 5609dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 5619dfa9f59SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 5629dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/type', 'mirror') 5639dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 5649dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 5659dfa9f59SPaolo Bonzini completed = True 5669dfa9f59SPaolo Bonzini 567ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 5689dfa9f59SPaolo Bonzini self.vm.shutdown() 5699dfa9f59SPaolo Bonzini 5709dfa9f59SPaolo Bonzini def test_ignore_write(self): 571ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 5729dfa9f59SPaolo Bonzini 5739dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 5749dfa9f59SPaolo Bonzini mode='existing', target=self.target_img, 5759dfa9f59SPaolo Bonzini on_target_error='ignore') 5769dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 5779dfa9f59SPaolo Bonzini 5789dfa9f59SPaolo Bonzini event = self.vm.get_qmp_event(wait=True) 5799dfa9f59SPaolo Bonzini self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 5809dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 5819dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'write') 5829dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 5839dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 5849dfa9f59SPaolo Bonzini self.complete_and_wait() 5859dfa9f59SPaolo Bonzini self.vm.shutdown() 5869dfa9f59SPaolo Bonzini 5879dfa9f59SPaolo Bonzini def test_stop_write(self): 588ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 5899dfa9f59SPaolo Bonzini 5909dfa9f59SPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 5919dfa9f59SPaolo Bonzini mode='existing', target=self.target_img, 5929dfa9f59SPaolo Bonzini on_target_error='stop') 5939dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 5949dfa9f59SPaolo Bonzini 5959dfa9f59SPaolo Bonzini error = False 5969dfa9f59SPaolo Bonzini ready = False 5979dfa9f59SPaolo Bonzini while not ready: 5989dfa9f59SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 5999dfa9f59SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 6009dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 6019dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'write') 6029dfa9f59SPaolo Bonzini 6039dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 6049dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 6059dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'failed') 6069dfa9f59SPaolo Bonzini 6079dfa9f59SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 6089dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return', {}) 6099dfa9f59SPaolo Bonzini 6109dfa9f59SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 6119dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 6129dfa9f59SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 6139dfa9f59SPaolo Bonzini error = True 6149dfa9f59SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_READY': 6159dfa9f59SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 6169dfa9f59SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 6179dfa9f59SPaolo Bonzini ready = True 6189dfa9f59SPaolo Bonzini 6199dfa9f59SPaolo Bonzini self.complete_and_wait(wait_ready=False) 620ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 6219dfa9f59SPaolo Bonzini self.vm.shutdown() 6229dfa9f59SPaolo Bonzini 623866323f3SFam Zhengclass TestSetSpeed(iotests.QMPTestCase): 62444c7ca5eSPaolo Bonzini image_len = 80 * 1024 * 1024 # MB 62544c7ca5eSPaolo Bonzini 62644c7ca5eSPaolo Bonzini def setUp(self): 62744c7ca5eSPaolo Bonzini qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 62844c7ca5eSPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 62944c7ca5eSPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 63044c7ca5eSPaolo Bonzini self.vm.launch() 63144c7ca5eSPaolo Bonzini 63244c7ca5eSPaolo Bonzini def tearDown(self): 63344c7ca5eSPaolo Bonzini self.vm.shutdown() 63444c7ca5eSPaolo Bonzini os.remove(test_img) 63544c7ca5eSPaolo Bonzini os.remove(backing_img) 63644c7ca5eSPaolo Bonzini os.remove(target_img) 63744c7ca5eSPaolo Bonzini 63844c7ca5eSPaolo Bonzini def test_set_speed(self): 639ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 64044c7ca5eSPaolo Bonzini 64144c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 64244c7ca5eSPaolo Bonzini target=target_img) 64344c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 64444c7ca5eSPaolo Bonzini 64544c7ca5eSPaolo Bonzini # Default speed is 0 64644c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block-jobs') 64744c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/device', 'drive0') 64844c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/speed', 0) 64944c7ca5eSPaolo Bonzini 65044c7ca5eSPaolo Bonzini result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 65144c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 65244c7ca5eSPaolo Bonzini 65344c7ca5eSPaolo Bonzini # Ensure the speed we set was accepted 65444c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block-jobs') 65544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/device', 'drive0') 65644c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 65744c7ca5eSPaolo Bonzini 6582575fe16SStefan Hajnoczi self.wait_ready_and_cancel() 65944c7ca5eSPaolo Bonzini 66044c7ca5eSPaolo Bonzini # Check setting speed in drive-mirror works 66144c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 66244c7ca5eSPaolo Bonzini target=target_img, speed=4*1024*1024) 66344c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 66444c7ca5eSPaolo Bonzini 66544c7ca5eSPaolo Bonzini result = self.vm.qmp('query-block-jobs') 66644c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/device', 'drive0') 66744c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 66844c7ca5eSPaolo Bonzini 6692575fe16SStefan Hajnoczi self.wait_ready_and_cancel() 67044c7ca5eSPaolo Bonzini 67144c7ca5eSPaolo Bonzini def test_set_speed_invalid(self): 672ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 67344c7ca5eSPaolo Bonzini 67444c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 67544c7ca5eSPaolo Bonzini target=target_img, speed=-1) 67644c7ca5eSPaolo Bonzini self.assert_qmp(result, 'error/class', 'GenericError') 67744c7ca5eSPaolo Bonzini 678ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 67944c7ca5eSPaolo Bonzini 68044c7ca5eSPaolo Bonzini result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 68144c7ca5eSPaolo Bonzini target=target_img) 68244c7ca5eSPaolo Bonzini self.assert_qmp(result, 'return', {}) 68344c7ca5eSPaolo Bonzini 68444c7ca5eSPaolo Bonzini result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 68544c7ca5eSPaolo Bonzini self.assert_qmp(result, 'error/class', 'GenericError') 68644c7ca5eSPaolo Bonzini 6872575fe16SStefan Hajnoczi self.wait_ready_and_cancel() 68844c7ca5eSPaolo Bonzini 689866323f3SFam Zhengclass TestUnbackedSource(iotests.QMPTestCase): 690c15badeeSMax Reitz image_len = 2 * 1024 * 1024 # MB 691c15badeeSMax Reitz 692c15badeeSMax Reitz def setUp(self): 693c15badeeSMax Reitz qemu_img('create', '-f', iotests.imgfmt, test_img, 694c15badeeSMax Reitz str(TestUnbackedSource.image_len)) 695c15badeeSMax Reitz self.vm = iotests.VM().add_drive(test_img) 696c15badeeSMax Reitz self.vm.launch() 697c15badeeSMax Reitz 698c15badeeSMax Reitz def tearDown(self): 699c15badeeSMax Reitz self.vm.shutdown() 700c15badeeSMax Reitz os.remove(test_img) 701c15badeeSMax Reitz os.remove(target_img) 702c15badeeSMax Reitz 703171d6431SMax Reitz def test_absolute_paths_full(self): 704171d6431SMax Reitz self.assert_no_active_block_jobs() 705171d6431SMax Reitz result = self.vm.qmp('drive-mirror', device='drive0', 706171d6431SMax Reitz sync='full', target=target_img, 707171d6431SMax Reitz mode='absolute-paths') 708171d6431SMax Reitz self.assert_qmp(result, 'return', {}) 709171d6431SMax Reitz self.complete_and_wait() 710c15badeeSMax Reitz self.assert_no_active_block_jobs() 711c15badeeSMax Reitz 712171d6431SMax Reitz def test_absolute_paths_top(self): 713171d6431SMax Reitz self.assert_no_active_block_jobs() 714c15badeeSMax Reitz result = self.vm.qmp('drive-mirror', device='drive0', 715171d6431SMax Reitz sync='top', target=target_img, 716171d6431SMax Reitz mode='absolute-paths') 717171d6431SMax Reitz self.assert_qmp(result, 'return', {}) 718171d6431SMax Reitz self.complete_and_wait() 719171d6431SMax Reitz self.assert_no_active_block_jobs() 720171d6431SMax Reitz 721171d6431SMax Reitz def test_absolute_paths_none(self): 722171d6431SMax Reitz self.assert_no_active_block_jobs() 723171d6431SMax Reitz result = self.vm.qmp('drive-mirror', device='drive0', 724171d6431SMax Reitz sync='none', target=target_img, 725c15badeeSMax Reitz mode='absolute-paths') 726c15badeeSMax Reitz self.assert_qmp(result, 'return', {}) 727c15badeeSMax Reitz self.complete_and_wait() 728c15badeeSMax Reitz self.assert_no_active_block_jobs() 729c15badeeSMax Reitz 730*ccee3d8fSJohn Snowclass TestGranularity(iotests.QMPTestCase): 731*ccee3d8fSJohn Snow image_len = 10 * 1024 * 1024 # MB 732*ccee3d8fSJohn Snow 733*ccee3d8fSJohn Snow def setUp(self): 734*ccee3d8fSJohn Snow qemu_img('create', '-f', iotests.imgfmt, test_img, 735*ccee3d8fSJohn Snow str(TestGranularity.image_len)) 736*ccee3d8fSJohn Snow qemu_io('-c', 'write 0 %d' % (self.image_len), 737*ccee3d8fSJohn Snow test_img) 738*ccee3d8fSJohn Snow self.vm = iotests.VM().add_drive(test_img) 739*ccee3d8fSJohn Snow self.vm.launch() 740*ccee3d8fSJohn Snow 741*ccee3d8fSJohn Snow def tearDown(self): 742*ccee3d8fSJohn Snow self.vm.shutdown() 743*ccee3d8fSJohn Snow self.assertTrue(iotests.compare_images(test_img, target_img), 744*ccee3d8fSJohn Snow 'target image does not match source after mirroring') 745*ccee3d8fSJohn Snow os.remove(test_img) 746*ccee3d8fSJohn Snow os.remove(target_img) 747*ccee3d8fSJohn Snow 748*ccee3d8fSJohn Snow def test_granularity(self): 749*ccee3d8fSJohn Snow self.assert_no_active_block_jobs() 750*ccee3d8fSJohn Snow result = self.vm.qmp('drive-mirror', device='drive0', 751*ccee3d8fSJohn Snow sync='full', target=target_img, 752*ccee3d8fSJohn Snow mode='absolute-paths', granularity=8192) 753*ccee3d8fSJohn Snow self.assert_qmp(result, 'return', {}) 754*ccee3d8fSJohn Snow event = self.vm.get_qmp_event(wait=60.0) 755*ccee3d8fSJohn Snow # Failures will manifest as COMPLETED/ERROR. 756*ccee3d8fSJohn Snow self.assert_qmp(event, 'event', 'BLOCK_JOB_READY') 757*ccee3d8fSJohn Snow self.complete_and_wait(drive='drive0', wait_ready=False) 758*ccee3d8fSJohn Snow self.assert_no_active_block_jobs() 759*ccee3d8fSJohn Snow 760866323f3SFam Zhengclass TestRepairQuorum(iotests.QMPTestCase): 761d88964aeSBenoît Canet """ This class test quorum file repair using drive-mirror. 762d88964aeSBenoît Canet It's mostly a fork of TestSingleDrive """ 763d88964aeSBenoît Canet image_len = 1 * 1024 * 1024 # MB 764d88964aeSBenoît Canet IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ] 765d88964aeSBenoît Canet 766a42a1facSBenoît Canet def has_quorum(self): 767a42a1facSBenoît Canet return 'quorum' in iotests.qemu_img_pipe('--help') 768a42a1facSBenoît Canet 769d88964aeSBenoît Canet def setUp(self): 770d88964aeSBenoît Canet self.vm = iotests.VM() 771d88964aeSBenoît Canet 7720ed82f7aSMax Reitz if iotests.qemu_default_machine == 'pc': 7730ed82f7aSMax Reitz self.vm.add_drive(None, 'media=cdrom', 'ide') 7740ed82f7aSMax Reitz 775d88964aeSBenoît Canet # Add each individual quorum images 776d88964aeSBenoît Canet for i in self.IMAGES: 777d88964aeSBenoît Canet qemu_img('create', '-f', iotests.imgfmt, i, 778d88964aeSBenoît Canet str(TestSingleDrive.image_len)) 779d88964aeSBenoît Canet # Assign a node name to each quorum image in order to manipulate 780d88964aeSBenoît Canet # them 781d88964aeSBenoît Canet opts = "node-name=img%i" % self.IMAGES.index(i) 782d88964aeSBenoît Canet self.vm = self.vm.add_drive(i, opts) 783d88964aeSBenoît Canet 784d88964aeSBenoît Canet self.vm.launch() 785d88964aeSBenoît Canet 786d88964aeSBenoît Canet #assemble the quorum block device from the individual files 787d88964aeSBenoît Canet args = { "options" : { "driver": "quorum", "id": "quorum0", 788d88964aeSBenoît Canet "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } } 789a42a1facSBenoît Canet if self.has_quorum(): 790d88964aeSBenoît Canet result = self.vm.qmp("blockdev-add", **args) 791d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 792d88964aeSBenoît Canet 793d88964aeSBenoît Canet 794d88964aeSBenoît Canet def tearDown(self): 795d88964aeSBenoît Canet self.vm.shutdown() 796d88964aeSBenoît Canet for i in self.IMAGES + [ quorum_repair_img ]: 797d88964aeSBenoît Canet # Do a try/except because the test may have deleted some images 798d88964aeSBenoît Canet try: 799d88964aeSBenoît Canet os.remove(i) 800d88964aeSBenoît Canet except OSError: 801d88964aeSBenoît Canet pass 802d88964aeSBenoît Canet 803d88964aeSBenoît Canet def test_complete(self): 804a42a1facSBenoît Canet if not self.has_quorum(): 805a42a1facSBenoît Canet return 806a42a1facSBenoît Canet 807d88964aeSBenoît Canet self.assert_no_active_block_jobs() 808d88964aeSBenoît Canet 809d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 810d88964aeSBenoît Canet node_name="repair0", 811d88964aeSBenoît Canet replaces="img1", 812d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 813d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 814d88964aeSBenoît Canet 815d88964aeSBenoît Canet self.complete_and_wait(drive="quorum0") 816e71fc0baSFam Zheng self.assert_has_block_node("repair0", quorum_repair_img) 817d88964aeSBenoît Canet # TODO: a better test requiring some QEMU infrastructure will be added 818d88964aeSBenoît Canet # to check that this file is really driven by quorum 819d88964aeSBenoît Canet self.vm.shutdown() 820d88964aeSBenoît Canet self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), 821d88964aeSBenoît Canet 'target image does not match source after mirroring') 822d88964aeSBenoît Canet 823d88964aeSBenoît Canet def test_cancel(self): 824a42a1facSBenoît Canet if not self.has_quorum(): 825a42a1facSBenoît Canet return 826a42a1facSBenoît Canet 827d88964aeSBenoît Canet self.assert_no_active_block_jobs() 828d88964aeSBenoît Canet 829d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 830d88964aeSBenoît Canet node_name="repair0", 831d88964aeSBenoît Canet replaces="img1", 832d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 833d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 834d88964aeSBenoît Canet 835d88964aeSBenoît Canet self.cancel_and_wait(drive="quorum0", force=True) 836d88964aeSBenoît Canet # here we check that the last registered quorum file has not been 837d88964aeSBenoît Canet # swapped out and unref 838e71fc0baSFam Zheng self.assert_has_block_node(None, quorum_img3) 839d88964aeSBenoît Canet self.vm.shutdown() 840d88964aeSBenoît Canet 841d88964aeSBenoît Canet def test_cancel_after_ready(self): 842a42a1facSBenoît Canet if not self.has_quorum(): 843a42a1facSBenoît Canet return 844a42a1facSBenoît Canet 845d88964aeSBenoît Canet self.assert_no_active_block_jobs() 846d88964aeSBenoît Canet 847d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 848d88964aeSBenoît Canet node_name="repair0", 849d88964aeSBenoît Canet replaces="img1", 850d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 851d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 852d88964aeSBenoît Canet 853d88964aeSBenoît Canet self.wait_ready_and_cancel(drive="quorum0") 854d88964aeSBenoît Canet # here we check that the last registered quorum file has not been 855d88964aeSBenoît Canet # swapped out and unref 856e71fc0baSFam Zheng self.assert_has_block_node(None, quorum_img3) 857d88964aeSBenoît Canet self.vm.shutdown() 858d88964aeSBenoît Canet self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), 859d88964aeSBenoît Canet 'target image does not match source after mirroring') 860d88964aeSBenoît Canet 861d88964aeSBenoît Canet def test_pause(self): 862a42a1facSBenoît Canet if not self.has_quorum(): 863a42a1facSBenoît Canet return 864a42a1facSBenoît Canet 865d88964aeSBenoît Canet self.assert_no_active_block_jobs() 866d88964aeSBenoît Canet 867d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 868d88964aeSBenoît Canet node_name="repair0", 869d88964aeSBenoît Canet replaces="img1", 870d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 871d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 872d88964aeSBenoît Canet 873d88964aeSBenoît Canet result = self.vm.qmp('block-job-pause', device='quorum0') 874d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 875d88964aeSBenoît Canet 876d88964aeSBenoît Canet time.sleep(1) 877d88964aeSBenoît Canet result = self.vm.qmp('query-block-jobs') 878d88964aeSBenoît Canet offset = self.dictpath(result, 'return[0]/offset') 879d88964aeSBenoît Canet 880d88964aeSBenoît Canet time.sleep(1) 881d88964aeSBenoît Canet result = self.vm.qmp('query-block-jobs') 882d88964aeSBenoît Canet self.assert_qmp(result, 'return[0]/offset', offset) 883d88964aeSBenoît Canet 884d88964aeSBenoît Canet result = self.vm.qmp('block-job-resume', device='quorum0') 885d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 886d88964aeSBenoît Canet 887d88964aeSBenoît Canet self.complete_and_wait(drive="quorum0") 888d88964aeSBenoît Canet self.vm.shutdown() 889d88964aeSBenoît Canet self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), 890d88964aeSBenoît Canet 'target image does not match source after mirroring') 891d88964aeSBenoît Canet 892d88964aeSBenoît Canet def test_medium_not_found(self): 893a42a1facSBenoît Canet if not self.has_quorum(): 894a42a1facSBenoît Canet return 895a42a1facSBenoît Canet 896d8683155SBo Tu if iotests.qemu_default_machine != 'pc': 897d8683155SBo Tu return 898d8683155SBo Tu 8990ed82f7aSMax Reitz result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM 9000ed82f7aSMax Reitz sync='full', 901d88964aeSBenoît Canet node_name='repair0', 902d88964aeSBenoît Canet replaces='img1', 903d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 904d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 905d88964aeSBenoît Canet 906d88964aeSBenoît Canet def test_image_not_found(self): 907a42a1facSBenoît Canet if not self.has_quorum(): 908a42a1facSBenoît Canet return 909a42a1facSBenoît Canet 910d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 911d88964aeSBenoît Canet node_name='repair0', 912d88964aeSBenoît Canet replaces='img1', 913d88964aeSBenoît Canet mode='existing', 914d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 915d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 916d88964aeSBenoît Canet 917d88964aeSBenoît Canet def test_device_not_found(self): 918a42a1facSBenoît Canet if not self.has_quorum(): 919a42a1facSBenoît Canet return 920a42a1facSBenoît Canet 921d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full', 922d88964aeSBenoît Canet node_name='repair0', 923d88964aeSBenoît Canet replaces='img1', 924d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 925d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'DeviceNotFound') 926d88964aeSBenoît Canet 927d88964aeSBenoît Canet def test_wrong_sync_mode(self): 928a42a1facSBenoît Canet if not self.has_quorum(): 929a42a1facSBenoît Canet return 930a42a1facSBenoît Canet 931d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', 932d88964aeSBenoît Canet node_name='repair0', 933d88964aeSBenoît Canet replaces='img1', 934d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 935d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 936d88964aeSBenoît Canet 937d88964aeSBenoît Canet def test_no_node_name(self): 938a42a1facSBenoît Canet if not self.has_quorum(): 939a42a1facSBenoît Canet return 940a42a1facSBenoît Canet 941d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 942d88964aeSBenoît Canet replaces='img1', 943d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 944d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 945d88964aeSBenoît Canet 94667cc32ebSVeres Lajos def test_nonexistent_replaces(self): 947a42a1facSBenoît Canet if not self.has_quorum(): 948a42a1facSBenoît Canet return 949a42a1facSBenoît Canet 950d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 951d88964aeSBenoît Canet node_name='repair0', 952d88964aeSBenoît Canet replaces='img77', 953d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 954d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 955d88964aeSBenoît Canet 956d88964aeSBenoît Canet def test_after_a_quorum_snapshot(self): 957a42a1facSBenoît Canet if not self.has_quorum(): 958a42a1facSBenoît Canet return 959a42a1facSBenoît Canet 960d88964aeSBenoît Canet result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', 961d88964aeSBenoît Canet snapshot_file=quorum_snapshot_file, 962d88964aeSBenoît Canet snapshot_node_name="snap1"); 963d88964aeSBenoît Canet 964d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 965d88964aeSBenoît Canet node_name='repair0', 966d88964aeSBenoît Canet replaces="img1", 967d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 968d88964aeSBenoît Canet self.assert_qmp(result, 'error/class', 'GenericError') 969d88964aeSBenoît Canet 970d88964aeSBenoît Canet result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', 971d88964aeSBenoît Canet node_name='repair0', 972d88964aeSBenoît Canet replaces="snap1", 973d88964aeSBenoît Canet target=quorum_repair_img, format=iotests.imgfmt) 974d88964aeSBenoît Canet self.assert_qmp(result, 'return', {}) 975d88964aeSBenoît Canet 976d88964aeSBenoît Canet self.complete_and_wait(drive="quorum0") 977e71fc0baSFam Zheng self.assert_has_block_node("repair0", quorum_repair_img) 978d88964aeSBenoît Canet # TODO: a better test requiring some QEMU infrastructure will be added 979d88964aeSBenoît Canet # to check that this file is really driven by quorum 980d88964aeSBenoît Canet self.vm.shutdown() 981d88964aeSBenoît Canet 98244c7ca5eSPaolo Bonziniif __name__ == '__main__': 98344c7ca5eSPaolo Bonzini iotests.main(supported_fmts=['qcow2', 'qed']) 984