19f7264f5SJohn Snow#!/usr/bin/env python 29f7264f5SJohn Snow# 39f7264f5SJohn Snow# Tests for incremental drive-backup 49f7264f5SJohn Snow# 59f7264f5SJohn Snow# Copyright (C) 2015 John Snow for Red Hat, Inc. 69f7264f5SJohn Snow# 79f7264f5SJohn Snow# Based on 056. 89f7264f5SJohn Snow# 99f7264f5SJohn Snow# This program is free software; you can redistribute it and/or modify 109f7264f5SJohn Snow# it under the terms of the GNU General Public License as published by 119f7264f5SJohn Snow# the Free Software Foundation; either version 2 of the License, or 129f7264f5SJohn Snow# (at your option) any later version. 139f7264f5SJohn Snow# 149f7264f5SJohn Snow# This program is distributed in the hope that it will be useful, 159f7264f5SJohn Snow# but WITHOUT ANY WARRANTY; without even the implied warranty of 169f7264f5SJohn Snow# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179f7264f5SJohn Snow# GNU General Public License for more details. 189f7264f5SJohn Snow# 199f7264f5SJohn Snow# You should have received a copy of the GNU General Public License 209f7264f5SJohn Snow# along with this program. If not, see <http://www.gnu.org/licenses/>. 219f7264f5SJohn Snow# 229f7264f5SJohn Snow 239f7264f5SJohn Snowimport os 249f7264f5SJohn Snowimport iotests 259f7264f5SJohn Snow 269f7264f5SJohn Snow 279f7264f5SJohn Snowdef io_write_patterns(img, patterns): 289f7264f5SJohn Snow for pattern in patterns: 299f7264f5SJohn Snow iotests.qemu_io('-c', 'write -P%s %s %s' % pattern, img) 309f7264f5SJohn Snow 319f7264f5SJohn Snow 32a3d71595SJohn Snowdef try_remove(img): 33a3d71595SJohn Snow try: 34a3d71595SJohn Snow os.remove(img) 35a3d71595SJohn Snow except OSError: 36a3d71595SJohn Snow pass 37a3d71595SJohn Snow 38a3d71595SJohn Snow 39*749ad5e8SJohn Snowdef transaction_action(action, **kwargs): 40*749ad5e8SJohn Snow return { 41*749ad5e8SJohn Snow 'type': action, 42*749ad5e8SJohn Snow 'data': kwargs 43*749ad5e8SJohn Snow } 44*749ad5e8SJohn Snow 45*749ad5e8SJohn Snow 46*749ad5e8SJohn Snowdef transaction_bitmap_clear(node, name, **kwargs): 47*749ad5e8SJohn Snow return transaction_action('block-dirty-bitmap-clear', 48*749ad5e8SJohn Snow node=node, name=name, **kwargs) 49*749ad5e8SJohn Snow 50*749ad5e8SJohn Snow 51*749ad5e8SJohn Snowdef transaction_drive_backup(device, target, **kwargs): 52*749ad5e8SJohn Snow return transaction_action('drive-backup', device=device, target=target, 53*749ad5e8SJohn Snow **kwargs) 54*749ad5e8SJohn Snow 55*749ad5e8SJohn Snow 56a3d71595SJohn Snowclass Bitmap: 57a3d71595SJohn Snow def __init__(self, name, drive): 58a3d71595SJohn Snow self.name = name 59a3d71595SJohn Snow self.drive = drive 60a3d71595SJohn Snow self.num = 0 61a3d71595SJohn Snow self.backups = list() 62a3d71595SJohn Snow 63a3d71595SJohn Snow def base_target(self): 64a3d71595SJohn Snow return (self.drive['backup'], None) 65a3d71595SJohn Snow 66a3d71595SJohn Snow def new_target(self, num=None): 67a3d71595SJohn Snow if num is None: 68a3d71595SJohn Snow num = self.num 69a3d71595SJohn Snow self.num = num + 1 70a3d71595SJohn Snow base = os.path.join(iotests.test_dir, 71a3d71595SJohn Snow "%s.%s." % (self.drive['id'], self.name)) 72a3d71595SJohn Snow suff = "%i.%s" % (num, self.drive['fmt']) 73a3d71595SJohn Snow target = base + "inc" + suff 74a3d71595SJohn Snow reference = base + "ref" + suff 75a3d71595SJohn Snow self.backups.append((target, reference)) 76a3d71595SJohn Snow return (target, reference) 77a3d71595SJohn Snow 78a3d71595SJohn Snow def last_target(self): 79a3d71595SJohn Snow if self.backups: 80a3d71595SJohn Snow return self.backups[-1] 81a3d71595SJohn Snow return self.base_target() 82a3d71595SJohn Snow 83a3d71595SJohn Snow def del_target(self): 84a3d71595SJohn Snow for image in self.backups.pop(): 85a3d71595SJohn Snow try_remove(image) 86a3d71595SJohn Snow self.num -= 1 87a3d71595SJohn Snow 88a3d71595SJohn Snow def cleanup(self): 89a3d71595SJohn Snow for backup in self.backups: 90a3d71595SJohn Snow for image in backup: 91a3d71595SJohn Snow try_remove(image) 92a3d71595SJohn Snow 93a3d71595SJohn Snow 949f7264f5SJohn Snowclass TestIncrementalBackup(iotests.QMPTestCase): 959f7264f5SJohn Snow def setUp(self): 969f7264f5SJohn Snow self.bitmaps = list() 979f7264f5SJohn Snow self.files = list() 989f7264f5SJohn Snow self.drives = list() 999f7264f5SJohn Snow self.vm = iotests.VM() 1009f7264f5SJohn Snow self.err_img = os.path.join(iotests.test_dir, 'err.%s' % iotests.imgfmt) 1019f7264f5SJohn Snow 1029f7264f5SJohn Snow # Create a base image with a distinctive patterning 1039f7264f5SJohn Snow drive0 = self.add_node('drive0') 1049f7264f5SJohn Snow self.img_create(drive0['file'], drive0['fmt']) 1059f7264f5SJohn Snow self.vm.add_drive(drive0['file']) 1069f7264f5SJohn Snow io_write_patterns(drive0['file'], (('0x41', 0, 512), 1079f7264f5SJohn Snow ('0xd5', '1M', '32k'), 1089f7264f5SJohn Snow ('0xdc', '32M', '124k'))) 1099f7264f5SJohn Snow self.vm.launch() 1109f7264f5SJohn Snow 1119f7264f5SJohn Snow 1129f7264f5SJohn Snow def add_node(self, node_id, fmt=iotests.imgfmt, path=None, backup=None): 1139f7264f5SJohn Snow if path is None: 1149f7264f5SJohn Snow path = os.path.join(iotests.test_dir, '%s.%s' % (node_id, fmt)) 1159f7264f5SJohn Snow if backup is None: 1169f7264f5SJohn Snow backup = os.path.join(iotests.test_dir, 1179f7264f5SJohn Snow '%s.full.backup.%s' % (node_id, fmt)) 1189f7264f5SJohn Snow 1199f7264f5SJohn Snow self.drives.append({ 1209f7264f5SJohn Snow 'id': node_id, 1219f7264f5SJohn Snow 'file': path, 1229f7264f5SJohn Snow 'backup': backup, 1239f7264f5SJohn Snow 'fmt': fmt }) 1249f7264f5SJohn Snow return self.drives[-1] 1259f7264f5SJohn Snow 1269f7264f5SJohn Snow 1279f7264f5SJohn Snow def img_create(self, img, fmt=iotests.imgfmt, size='64M', 1289f7264f5SJohn Snow parent=None, parentFormat=None): 1299f7264f5SJohn Snow if parent: 1309f7264f5SJohn Snow if parentFormat is None: 1319f7264f5SJohn Snow parentFormat = fmt 1329f7264f5SJohn Snow iotests.qemu_img('create', '-f', fmt, img, size, 1339f7264f5SJohn Snow '-b', parent, '-F', parentFormat) 1349f7264f5SJohn Snow else: 1359f7264f5SJohn Snow iotests.qemu_img('create', '-f', fmt, img, size) 1369f7264f5SJohn Snow self.files.append(img) 1379f7264f5SJohn Snow 138a3d71595SJohn Snow 139a3d71595SJohn Snow def do_qmp_backup(self, error='Input/output error', **kwargs): 140a3d71595SJohn Snow res = self.vm.qmp('drive-backup', **kwargs) 141a3d71595SJohn Snow self.assert_qmp(res, 'return', {}) 142a3d71595SJohn Snow 143a3d71595SJohn Snow event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED", 144a3d71595SJohn Snow match={'data': {'device': kwargs['device']}}) 145ff793890SJohn Snow self.assertNotEqual(event, None) 146a3d71595SJohn Snow 147a3d71595SJohn Snow try: 148a3d71595SJohn Snow failure = self.dictpath(event, 'data/error') 149a3d71595SJohn Snow except AssertionError: 150a3d71595SJohn Snow # Backup succeeded. 151a3d71595SJohn Snow self.assert_qmp(event, 'data/offset', event['data']['len']) 152a3d71595SJohn Snow return True 153a3d71595SJohn Snow else: 154a3d71595SJohn Snow # Backup failed. 155a3d71595SJohn Snow self.assert_qmp(event, 'data/error', error) 156a3d71595SJohn Snow return False 157a3d71595SJohn Snow 158a3d71595SJohn Snow 159a3d71595SJohn Snow def create_anchor_backup(self, drive=None): 160a3d71595SJohn Snow if drive is None: 161a3d71595SJohn Snow drive = self.drives[-1] 162a3d71595SJohn Snow res = self.do_qmp_backup(device=drive['id'], sync='full', 163a3d71595SJohn Snow format=drive['fmt'], target=drive['backup']) 164a3d71595SJohn Snow self.assertTrue(res) 165a3d71595SJohn Snow self.files.append(drive['backup']) 166a3d71595SJohn Snow return drive['backup'] 167a3d71595SJohn Snow 168a3d71595SJohn Snow 169a3d71595SJohn Snow def make_reference_backup(self, bitmap=None): 170a3d71595SJohn Snow if bitmap is None: 171a3d71595SJohn Snow bitmap = self.bitmaps[-1] 172a3d71595SJohn Snow _, reference = bitmap.last_target() 173a3d71595SJohn Snow res = self.do_qmp_backup(device=bitmap.drive['id'], sync='full', 174a3d71595SJohn Snow format=bitmap.drive['fmt'], target=reference) 175a3d71595SJohn Snow self.assertTrue(res) 176a3d71595SJohn Snow 177a3d71595SJohn Snow 17859fc5d84SJohn Snow def add_bitmap(self, name, drive, **kwargs): 179a3d71595SJohn Snow bitmap = Bitmap(name, drive) 180a3d71595SJohn Snow self.bitmaps.append(bitmap) 181a3d71595SJohn Snow result = self.vm.qmp('block-dirty-bitmap-add', node=drive['id'], 18259fc5d84SJohn Snow name=bitmap.name, **kwargs) 183a3d71595SJohn Snow self.assert_qmp(result, 'return', {}) 184a3d71595SJohn Snow return bitmap 185a3d71595SJohn Snow 186a3d71595SJohn Snow 187a3d71595SJohn Snow def prepare_backup(self, bitmap=None, parent=None): 188a3d71595SJohn Snow if bitmap is None: 189a3d71595SJohn Snow bitmap = self.bitmaps[-1] 190a3d71595SJohn Snow if parent is None: 191a3d71595SJohn Snow parent, _ = bitmap.last_target() 192a3d71595SJohn Snow 193a3d71595SJohn Snow target, _ = bitmap.new_target() 194a3d71595SJohn Snow self.img_create(target, bitmap.drive['fmt'], parent=parent) 195a3d71595SJohn Snow return target 196a3d71595SJohn Snow 197a3d71595SJohn Snow 198a3d71595SJohn Snow def create_incremental(self, bitmap=None, parent=None, 199a3d71595SJohn Snow parentFormat=None, validate=True): 200a3d71595SJohn Snow if bitmap is None: 201a3d71595SJohn Snow bitmap = self.bitmaps[-1] 202a3d71595SJohn Snow if parent is None: 203a3d71595SJohn Snow parent, _ = bitmap.last_target() 204a3d71595SJohn Snow 205a3d71595SJohn Snow target = self.prepare_backup(bitmap, parent) 206a3d71595SJohn Snow res = self.do_qmp_backup(device=bitmap.drive['id'], 2074b80ab2bSJohn Snow sync='incremental', bitmap=bitmap.name, 208a3d71595SJohn Snow format=bitmap.drive['fmt'], target=target, 209a3d71595SJohn Snow mode='existing') 210a3d71595SJohn Snow if not res: 211a3d71595SJohn Snow bitmap.del_target(); 212a3d71595SJohn Snow self.assertFalse(validate) 213a3d71595SJohn Snow else: 214a3d71595SJohn Snow self.make_reference_backup(bitmap) 215a3d71595SJohn Snow return res 216a3d71595SJohn Snow 217a3d71595SJohn Snow 218a3d71595SJohn Snow def check_backups(self): 219a3d71595SJohn Snow for bitmap in self.bitmaps: 220a3d71595SJohn Snow for incremental, reference in bitmap.backups: 221a3d71595SJohn Snow self.assertTrue(iotests.compare_images(incremental, reference)) 222a3d71595SJohn Snow last = bitmap.last_target()[0] 223a3d71595SJohn Snow self.assertTrue(iotests.compare_images(last, bitmap.drive['file'])) 224a3d71595SJohn Snow 225a3d71595SJohn Snow 226a3d71595SJohn Snow def hmp_io_writes(self, drive, patterns): 227a3d71595SJohn Snow for pattern in patterns: 228a3d71595SJohn Snow self.vm.hmp_qemu_io(drive, 'write -P%s %s %s' % pattern) 229a3d71595SJohn Snow self.vm.hmp_qemu_io(drive, 'flush') 230a3d71595SJohn Snow 231a3d71595SJohn Snow 23259fc5d84SJohn Snow def do_incremental_simple(self, **kwargs): 233a3d71595SJohn Snow self.create_anchor_backup() 23459fc5d84SJohn Snow self.add_bitmap('bitmap0', self.drives[0], **kwargs) 235a3d71595SJohn Snow 236a3d71595SJohn Snow # Sanity: Create a "hollow" incremental backup 237a3d71595SJohn Snow self.create_incremental() 238a3d71595SJohn Snow # Three writes: One complete overwrite, one new segment, 239a3d71595SJohn Snow # and one partial overlap. 240a3d71595SJohn Snow self.hmp_io_writes(self.drives[0]['id'], (('0xab', 0, 512), 241a3d71595SJohn Snow ('0xfe', '16M', '256k'), 242a3d71595SJohn Snow ('0x64', '32736k', '64k'))) 243a3d71595SJohn Snow self.create_incremental() 244a3d71595SJohn Snow # Three more writes, one of each kind, like above 245a3d71595SJohn Snow self.hmp_io_writes(self.drives[0]['id'], (('0x9a', 0, 512), 246a3d71595SJohn Snow ('0x55', '8M', '352k'), 247a3d71595SJohn Snow ('0x78', '15872k', '1M'))) 248a3d71595SJohn Snow self.create_incremental() 249a3d71595SJohn Snow self.vm.shutdown() 250a3d71595SJohn Snow self.check_backups() 251a3d71595SJohn Snow 252a3d71595SJohn Snow 25359fc5d84SJohn Snow def test_incremental_simple(self): 25459fc5d84SJohn Snow ''' 25559fc5d84SJohn Snow Test: Create and verify three incremental backups. 25659fc5d84SJohn Snow 25759fc5d84SJohn Snow Create a bitmap and a full backup before VM execution begins, 25859fc5d84SJohn Snow then create a series of three incremental backups "during execution," 25959fc5d84SJohn Snow i.e.; after IO requests begin modifying the drive. 26059fc5d84SJohn Snow ''' 26159fc5d84SJohn Snow return self.do_incremental_simple() 26259fc5d84SJohn Snow 26359fc5d84SJohn Snow 26459fc5d84SJohn Snow def test_small_granularity(self): 26559fc5d84SJohn Snow ''' 26659fc5d84SJohn Snow Test: Create and verify backups made with a small granularity bitmap. 26759fc5d84SJohn Snow 26859fc5d84SJohn Snow Perform the same test as test_incremental_simple, but with a granularity 26959fc5d84SJohn Snow of only 32KiB instead of the present default of 64KiB. 27059fc5d84SJohn Snow ''' 27159fc5d84SJohn Snow return self.do_incremental_simple(granularity=32768) 27259fc5d84SJohn Snow 27359fc5d84SJohn Snow 27459fc5d84SJohn Snow def test_large_granularity(self): 27559fc5d84SJohn Snow ''' 27659fc5d84SJohn Snow Test: Create and verify backups made with a large granularity bitmap. 27759fc5d84SJohn Snow 27859fc5d84SJohn Snow Perform the same test as test_incremental_simple, but with a granularity 27959fc5d84SJohn Snow of 128KiB instead of the present default of 64KiB. 28059fc5d84SJohn Snow ''' 28159fc5d84SJohn Snow return self.do_incremental_simple(granularity=131072) 28259fc5d84SJohn Snow 28359fc5d84SJohn Snow 284*749ad5e8SJohn Snow def test_incremental_transaction(self): 285*749ad5e8SJohn Snow '''Test: Verify backups made from transactionally created bitmaps. 286*749ad5e8SJohn Snow 287*749ad5e8SJohn Snow Create a bitmap "before" VM execution begins, then create a second 288*749ad5e8SJohn Snow bitmap AFTER writes have already occurred. Use transactions to create 289*749ad5e8SJohn Snow a full backup and synchronize both bitmaps to this backup. 290*749ad5e8SJohn Snow Create an incremental backup through both bitmaps and verify that 291*749ad5e8SJohn Snow both backups match the current drive0 image. 292*749ad5e8SJohn Snow ''' 293*749ad5e8SJohn Snow 294*749ad5e8SJohn Snow drive0 = self.drives[0] 295*749ad5e8SJohn Snow bitmap0 = self.add_bitmap('bitmap0', drive0) 296*749ad5e8SJohn Snow self.hmp_io_writes(drive0['id'], (('0xab', 0, 512), 297*749ad5e8SJohn Snow ('0xfe', '16M', '256k'), 298*749ad5e8SJohn Snow ('0x64', '32736k', '64k'))) 299*749ad5e8SJohn Snow bitmap1 = self.add_bitmap('bitmap1', drive0) 300*749ad5e8SJohn Snow 301*749ad5e8SJohn Snow result = self.vm.qmp('transaction', actions=[ 302*749ad5e8SJohn Snow transaction_bitmap_clear(bitmap0.drive['id'], bitmap0.name), 303*749ad5e8SJohn Snow transaction_bitmap_clear(bitmap1.drive['id'], bitmap1.name), 304*749ad5e8SJohn Snow transaction_drive_backup(drive0['id'], drive0['backup'], 305*749ad5e8SJohn Snow sync='full', format=drive0['fmt']) 306*749ad5e8SJohn Snow ]) 307*749ad5e8SJohn Snow self.assert_qmp(result, 'return', {}) 308*749ad5e8SJohn Snow self.wait_until_completed(drive0['id']) 309*749ad5e8SJohn Snow self.files.append(drive0['backup']) 310*749ad5e8SJohn Snow 311*749ad5e8SJohn Snow self.hmp_io_writes(drive0['id'], (('0x9a', 0, 512), 312*749ad5e8SJohn Snow ('0x55', '8M', '352k'), 313*749ad5e8SJohn Snow ('0x78', '15872k', '1M'))) 314*749ad5e8SJohn Snow # Both bitmaps should be correctly in sync. 315*749ad5e8SJohn Snow self.create_incremental(bitmap0) 316*749ad5e8SJohn Snow self.create_incremental(bitmap1) 317*749ad5e8SJohn Snow self.vm.shutdown() 318*749ad5e8SJohn Snow self.check_backups() 319*749ad5e8SJohn Snow 320*749ad5e8SJohn Snow 32124618f53SJohn Snow def test_incremental_failure(self): 32224618f53SJohn Snow '''Test: Verify backups made after a failure are correct. 32324618f53SJohn Snow 32424618f53SJohn Snow Simulate a failure during an incremental backup block job, 32524618f53SJohn Snow emulate additional writes, then create another incremental backup 32624618f53SJohn Snow afterwards and verify that the backup created is correct. 32724618f53SJohn Snow ''' 32824618f53SJohn Snow 32924618f53SJohn Snow # Create a blkdebug interface to this img as 'drive1', 33024618f53SJohn Snow # but don't actually create a new image. 33124618f53SJohn Snow drive1 = self.add_node('drive1', self.drives[0]['fmt'], 33224618f53SJohn Snow path=self.drives[0]['file'], 33324618f53SJohn Snow backup=self.drives[0]['backup']) 33424618f53SJohn Snow result = self.vm.qmp('blockdev-add', options={ 33524618f53SJohn Snow 'id': drive1['id'], 33624618f53SJohn Snow 'driver': drive1['fmt'], 33724618f53SJohn Snow 'file': { 33824618f53SJohn Snow 'driver': 'blkdebug', 33924618f53SJohn Snow 'image': { 34024618f53SJohn Snow 'driver': 'file', 34124618f53SJohn Snow 'filename': drive1['file'] 34224618f53SJohn Snow }, 34324618f53SJohn Snow 'set-state': [{ 34424618f53SJohn Snow 'event': 'flush_to_disk', 34524618f53SJohn Snow 'state': 1, 34624618f53SJohn Snow 'new_state': 2 34724618f53SJohn Snow }], 34824618f53SJohn Snow 'inject-error': [{ 34924618f53SJohn Snow 'event': 'read_aio', 35024618f53SJohn Snow 'errno': 5, 35124618f53SJohn Snow 'state': 2, 35224618f53SJohn Snow 'immediately': False, 35324618f53SJohn Snow 'once': True 35424618f53SJohn Snow }], 35524618f53SJohn Snow } 35624618f53SJohn Snow }) 35724618f53SJohn Snow self.assert_qmp(result, 'return', {}) 35824618f53SJohn Snow 35924618f53SJohn Snow self.create_anchor_backup(self.drives[0]) 36024618f53SJohn Snow self.add_bitmap('bitmap0', drive1) 36124618f53SJohn Snow # Note: at this point, during a normal execution, 36224618f53SJohn Snow # Assume that the VM resumes and begins issuing IO requests here. 36324618f53SJohn Snow 36424618f53SJohn Snow self.hmp_io_writes(drive1['id'], (('0xab', 0, 512), 36524618f53SJohn Snow ('0xfe', '16M', '256k'), 36624618f53SJohn Snow ('0x64', '32736k', '64k'))) 36724618f53SJohn Snow 36824618f53SJohn Snow result = self.create_incremental(validate=False) 36924618f53SJohn Snow self.assertFalse(result) 37024618f53SJohn Snow self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512), 37124618f53SJohn Snow ('0x55', '8M', '352k'), 37224618f53SJohn Snow ('0x78', '15872k', '1M'))) 37324618f53SJohn Snow self.create_incremental() 37424618f53SJohn Snow self.vm.shutdown() 37524618f53SJohn Snow self.check_backups() 37624618f53SJohn Snow 37724618f53SJohn Snow 3789f7264f5SJohn Snow def test_sync_dirty_bitmap_missing(self): 3799f7264f5SJohn Snow self.assert_no_active_block_jobs() 3809f7264f5SJohn Snow self.files.append(self.err_img) 3819f7264f5SJohn Snow result = self.vm.qmp('drive-backup', device=self.drives[0]['id'], 3824b80ab2bSJohn Snow sync='incremental', format=self.drives[0]['fmt'], 3839f7264f5SJohn Snow target=self.err_img) 3849f7264f5SJohn Snow self.assert_qmp(result, 'error/class', 'GenericError') 3859f7264f5SJohn Snow 3869f7264f5SJohn Snow 3879f7264f5SJohn Snow def test_sync_dirty_bitmap_not_found(self): 3889f7264f5SJohn Snow self.assert_no_active_block_jobs() 3899f7264f5SJohn Snow self.files.append(self.err_img) 3909f7264f5SJohn Snow result = self.vm.qmp('drive-backup', device=self.drives[0]['id'], 3914b80ab2bSJohn Snow sync='incremental', bitmap='unknown', 3929f7264f5SJohn Snow format=self.drives[0]['fmt'], target=self.err_img) 3939f7264f5SJohn Snow self.assert_qmp(result, 'error/class', 'GenericError') 3949f7264f5SJohn Snow 3959f7264f5SJohn Snow 39659fc5d84SJohn Snow def test_sync_dirty_bitmap_bad_granularity(self): 39759fc5d84SJohn Snow ''' 39859fc5d84SJohn Snow Test: Test what happens if we provide an improper granularity. 39959fc5d84SJohn Snow 40059fc5d84SJohn Snow The granularity must always be a power of 2. 40159fc5d84SJohn Snow ''' 40259fc5d84SJohn Snow self.assert_no_active_block_jobs() 40359fc5d84SJohn Snow self.assertRaises(AssertionError, self.add_bitmap, 40459fc5d84SJohn Snow 'bitmap0', self.drives[0], 40559fc5d84SJohn Snow granularity=64000) 40659fc5d84SJohn Snow 40759fc5d84SJohn Snow 4089f7264f5SJohn Snow def tearDown(self): 4099f7264f5SJohn Snow self.vm.shutdown() 410a3d71595SJohn Snow for bitmap in self.bitmaps: 411a3d71595SJohn Snow bitmap.cleanup() 4129f7264f5SJohn Snow for filename in self.files: 413a3d71595SJohn Snow try_remove(filename) 4149f7264f5SJohn Snow 4159f7264f5SJohn Snow 4169f7264f5SJohn Snowif __name__ == '__main__': 4179f7264f5SJohn Snow iotests.main(supported_fmts=['qcow2']) 418