1*8023090bSWenchao Xia#!/usr/bin/env python 2*8023090bSWenchao Xia# 3*8023090bSWenchao Xia# Tests for internal snapshot. 4*8023090bSWenchao Xia# 5*8023090bSWenchao Xia# Copyright (C) 2013 IBM, Inc. 6*8023090bSWenchao Xia# 7*8023090bSWenchao Xia# Based on 055. 8*8023090bSWenchao Xia# 9*8023090bSWenchao Xia# This program is free software; you can redistribute it and/or modify 10*8023090bSWenchao Xia# it under the terms of the GNU General Public License as published by 11*8023090bSWenchao Xia# the Free Software Foundation; either version 2 of the License, or 12*8023090bSWenchao Xia# (at your option) any later version. 13*8023090bSWenchao Xia# 14*8023090bSWenchao Xia# This program is distributed in the hope that it will be useful, 15*8023090bSWenchao Xia# but WITHOUT ANY WARRANTY; without even the implied warranty of 16*8023090bSWenchao Xia# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*8023090bSWenchao Xia# GNU General Public License for more details. 18*8023090bSWenchao Xia# 19*8023090bSWenchao Xia# You should have received a copy of the GNU General Public License 20*8023090bSWenchao Xia# along with this program. If not, see <http://www.gnu.org/licenses/>. 21*8023090bSWenchao Xia# 22*8023090bSWenchao Xia 23*8023090bSWenchao Xiaimport time 24*8023090bSWenchao Xiaimport os 25*8023090bSWenchao Xiaimport iotests 26*8023090bSWenchao Xiafrom iotests import qemu_img, qemu_io 27*8023090bSWenchao Xia 28*8023090bSWenchao Xiatest_drv_base_name = 'drive' 29*8023090bSWenchao Xia 30*8023090bSWenchao Xiaclass ImageSnapshotTestCase(iotests.QMPTestCase): 31*8023090bSWenchao Xia image_len = 120 * 1024 * 1024 # MB 32*8023090bSWenchao Xia 33*8023090bSWenchao Xia def __init__(self, *args): 34*8023090bSWenchao Xia self.expect = [] 35*8023090bSWenchao Xia super(ImageSnapshotTestCase, self).__init__(*args) 36*8023090bSWenchao Xia 37*8023090bSWenchao Xia def _setUp(self, test_img_base_name, image_num): 38*8023090bSWenchao Xia self.vm = iotests.VM() 39*8023090bSWenchao Xia for i in range(0, image_num): 40*8023090bSWenchao Xia filename = '%s%d' % (test_img_base_name, i) 41*8023090bSWenchao Xia img = os.path.join(iotests.test_dir, filename) 42*8023090bSWenchao Xia device = '%s%d' % (test_drv_base_name, i) 43*8023090bSWenchao Xia qemu_img('create', '-f', iotests.imgfmt, img, str(self.image_len)) 44*8023090bSWenchao Xia self.vm.add_drive(img) 45*8023090bSWenchao Xia self.expect.append({'image': img, 'device': device, 46*8023090bSWenchao Xia 'snapshots': [], 47*8023090bSWenchao Xia 'snapshots_name_counter': 0}) 48*8023090bSWenchao Xia self.vm.launch() 49*8023090bSWenchao Xia 50*8023090bSWenchao Xia def tearDown(self): 51*8023090bSWenchao Xia self.vm.shutdown() 52*8023090bSWenchao Xia for dev_expect in self.expect: 53*8023090bSWenchao Xia os.remove(dev_expect['image']) 54*8023090bSWenchao Xia 55*8023090bSWenchao Xia def createSnapshotInTransaction(self, snapshot_num, abort = False): 56*8023090bSWenchao Xia actions = [] 57*8023090bSWenchao Xia for dev_expect in self.expect: 58*8023090bSWenchao Xia num = dev_expect['snapshots_name_counter'] 59*8023090bSWenchao Xia for j in range(0, snapshot_num): 60*8023090bSWenchao Xia name = '%s_sn%d' % (dev_expect['device'], num) 61*8023090bSWenchao Xia num = num + 1 62*8023090bSWenchao Xia if abort == False: 63*8023090bSWenchao Xia dev_expect['snapshots'].append({'name': name}) 64*8023090bSWenchao Xia dev_expect['snapshots_name_counter'] = num 65*8023090bSWenchao Xia actions.append({ 66*8023090bSWenchao Xia 'type': 'blockdev-snapshot-internal-sync', 67*8023090bSWenchao Xia 'data': { 'device': dev_expect['device'], 68*8023090bSWenchao Xia 'name': name }, 69*8023090bSWenchao Xia }) 70*8023090bSWenchao Xia 71*8023090bSWenchao Xia if abort == True: 72*8023090bSWenchao Xia actions.append({ 73*8023090bSWenchao Xia 'type': 'abort', 74*8023090bSWenchao Xia 'data': {}, 75*8023090bSWenchao Xia }) 76*8023090bSWenchao Xia 77*8023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 78*8023090bSWenchao Xia 79*8023090bSWenchao Xia if abort == True: 80*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 81*8023090bSWenchao Xia else: 82*8023090bSWenchao Xia self.assert_qmp(result, 'return', {}) 83*8023090bSWenchao Xia 84*8023090bSWenchao Xia def verifySnapshotInfo(self): 85*8023090bSWenchao Xia result = self.vm.qmp('query-block') 86*8023090bSWenchao Xia 87*8023090bSWenchao Xia # Verify each expected result 88*8023090bSWenchao Xia for dev_expect in self.expect: 89*8023090bSWenchao Xia # 1. Find the returned image value and snapshot info 90*8023090bSWenchao Xia image_result = None 91*8023090bSWenchao Xia for device in result['return']: 92*8023090bSWenchao Xia if device['device'] == dev_expect['device']: 93*8023090bSWenchao Xia image_result = device['inserted']['image'] 94*8023090bSWenchao Xia break 95*8023090bSWenchao Xia self.assertTrue(image_result != None) 96*8023090bSWenchao Xia # Do not consider zero snapshot case now 97*8023090bSWenchao Xia sn_list_result = image_result['snapshots'] 98*8023090bSWenchao Xia sn_list_expect = dev_expect['snapshots'] 99*8023090bSWenchao Xia 100*8023090bSWenchao Xia # 2. Verify it with expect 101*8023090bSWenchao Xia self.assertTrue(len(sn_list_result) == len(sn_list_expect)) 102*8023090bSWenchao Xia 103*8023090bSWenchao Xia for sn_expect in sn_list_expect: 104*8023090bSWenchao Xia sn_result = None 105*8023090bSWenchao Xia for sn in sn_list_result: 106*8023090bSWenchao Xia if sn_expect['name'] == sn['name']: 107*8023090bSWenchao Xia sn_result = sn 108*8023090bSWenchao Xia break 109*8023090bSWenchao Xia self.assertTrue(sn_result != None) 110*8023090bSWenchao Xia # Fill in the detail info 111*8023090bSWenchao Xia sn_expect.update(sn_result) 112*8023090bSWenchao Xia 113*8023090bSWenchao Xia def deleteSnapshot(self, device, id = None, name = None): 114*8023090bSWenchao Xia sn_list_expect = None 115*8023090bSWenchao Xia sn_expect = None 116*8023090bSWenchao Xia 117*8023090bSWenchao Xia self.assertTrue(id != None or name != None) 118*8023090bSWenchao Xia 119*8023090bSWenchao Xia # Fill in the detail info include ID 120*8023090bSWenchao Xia self.verifySnapshotInfo() 121*8023090bSWenchao Xia 122*8023090bSWenchao Xia #find the expected snapshot list 123*8023090bSWenchao Xia for dev_expect in self.expect: 124*8023090bSWenchao Xia if dev_expect['device'] == device: 125*8023090bSWenchao Xia sn_list_expect = dev_expect['snapshots'] 126*8023090bSWenchao Xia break 127*8023090bSWenchao Xia self.assertTrue(sn_list_expect != None) 128*8023090bSWenchao Xia 129*8023090bSWenchao Xia if id != None and name != None: 130*8023090bSWenchao Xia for sn in sn_list_expect: 131*8023090bSWenchao Xia if sn['id'] == id and sn['name'] == name: 132*8023090bSWenchao Xia sn_expect = sn 133*8023090bSWenchao Xia result = \ 134*8023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 135*8023090bSWenchao Xia device = device, 136*8023090bSWenchao Xia id = id, 137*8023090bSWenchao Xia name = name) 138*8023090bSWenchao Xia break 139*8023090bSWenchao Xia elif id != None: 140*8023090bSWenchao Xia for sn in sn_list_expect: 141*8023090bSWenchao Xia if sn['id'] == id: 142*8023090bSWenchao Xia sn_expect = sn 143*8023090bSWenchao Xia result = \ 144*8023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 145*8023090bSWenchao Xia device = device, 146*8023090bSWenchao Xia id = id) 147*8023090bSWenchao Xia break 148*8023090bSWenchao Xia else: 149*8023090bSWenchao Xia for sn in sn_list_expect: 150*8023090bSWenchao Xia if sn['name'] == name: 151*8023090bSWenchao Xia sn_expect = sn 152*8023090bSWenchao Xia result = \ 153*8023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 154*8023090bSWenchao Xia device = device, 155*8023090bSWenchao Xia name = name) 156*8023090bSWenchao Xia break 157*8023090bSWenchao Xia 158*8023090bSWenchao Xia self.assertTrue(sn_expect != None) 159*8023090bSWenchao Xia 160*8023090bSWenchao Xia self.assert_qmp(result, 'return', sn_expect) 161*8023090bSWenchao Xia sn_list_expect.remove(sn_expect) 162*8023090bSWenchao Xia 163*8023090bSWenchao Xiaclass TestSingleTransaction(ImageSnapshotTestCase): 164*8023090bSWenchao Xia def setUp(self): 165*8023090bSWenchao Xia self._setUp('test_a.img', 1) 166*8023090bSWenchao Xia 167*8023090bSWenchao Xia def test_create(self): 168*8023090bSWenchao Xia self.createSnapshotInTransaction(1) 169*8023090bSWenchao Xia self.verifySnapshotInfo() 170*8023090bSWenchao Xia 171*8023090bSWenchao Xia def test_error_name_empty(self): 172*8023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 173*8023090bSWenchao Xia 'data': { 'device': self.expect[0]['device'], 174*8023090bSWenchao Xia 'name': '' }, 175*8023090bSWenchao Xia }] 176*8023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 177*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 178*8023090bSWenchao Xia 179*8023090bSWenchao Xia def test_error_device(self): 180*8023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 181*8023090bSWenchao Xia 'data': { 'device': 'drive_error', 182*8023090bSWenchao Xia 'name': 'a' }, 183*8023090bSWenchao Xia }] 184*8023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 185*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'DeviceNotFound') 186*8023090bSWenchao Xia 187*8023090bSWenchao Xia def test_error_exist(self): 188*8023090bSWenchao Xia self.createSnapshotInTransaction(1) 189*8023090bSWenchao Xia self.verifySnapshotInfo() 190*8023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 191*8023090bSWenchao Xia 'data': { 'device': self.expect[0]['device'], 192*8023090bSWenchao Xia 'name': self.expect[0]['snapshots'][0] }, 193*8023090bSWenchao Xia }] 194*8023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 195*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 196*8023090bSWenchao Xia 197*8023090bSWenchao Xiaclass TestMultipleTransaction(ImageSnapshotTestCase): 198*8023090bSWenchao Xia def setUp(self): 199*8023090bSWenchao Xia self._setUp('test_b.img', 2) 200*8023090bSWenchao Xia 201*8023090bSWenchao Xia def test_create(self): 202*8023090bSWenchao Xia self.createSnapshotInTransaction(3) 203*8023090bSWenchao Xia self.verifySnapshotInfo() 204*8023090bSWenchao Xia 205*8023090bSWenchao Xia def test_abort(self): 206*8023090bSWenchao Xia self.createSnapshotInTransaction(2) 207*8023090bSWenchao Xia self.verifySnapshotInfo() 208*8023090bSWenchao Xia self.createSnapshotInTransaction(3, abort = True) 209*8023090bSWenchao Xia self.verifySnapshotInfo() 210*8023090bSWenchao Xia 211*8023090bSWenchao Xiaclass TestSnapshotDelete(ImageSnapshotTestCase): 212*8023090bSWenchao Xia def setUp(self): 213*8023090bSWenchao Xia self._setUp('test_c.img', 1) 214*8023090bSWenchao Xia 215*8023090bSWenchao Xia def test_delete_with_id(self): 216*8023090bSWenchao Xia self.createSnapshotInTransaction(2) 217*8023090bSWenchao Xia self.verifySnapshotInfo() 218*8023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 219*8023090bSWenchao Xia id = self.expect[0]['snapshots'][0]['id']) 220*8023090bSWenchao Xia self.verifySnapshotInfo() 221*8023090bSWenchao Xia 222*8023090bSWenchao Xia def test_delete_with_name(self): 223*8023090bSWenchao Xia self.createSnapshotInTransaction(3) 224*8023090bSWenchao Xia self.verifySnapshotInfo() 225*8023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 226*8023090bSWenchao Xia name = self.expect[0]['snapshots'][1]['name']) 227*8023090bSWenchao Xia self.verifySnapshotInfo() 228*8023090bSWenchao Xia 229*8023090bSWenchao Xia def test_delete_with_id_and_name(self): 230*8023090bSWenchao Xia self.createSnapshotInTransaction(4) 231*8023090bSWenchao Xia self.verifySnapshotInfo() 232*8023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 233*8023090bSWenchao Xia id = self.expect[0]['snapshots'][2]['id'], 234*8023090bSWenchao Xia name = self.expect[0]['snapshots'][2]['name']) 235*8023090bSWenchao Xia self.verifySnapshotInfo() 236*8023090bSWenchao Xia 237*8023090bSWenchao Xia 238*8023090bSWenchao Xia def test_error_device(self): 239*8023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 240*8023090bSWenchao Xia device = 'drive_error', 241*8023090bSWenchao Xia id = '0') 242*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'DeviceNotFound') 243*8023090bSWenchao Xia 244*8023090bSWenchao Xia def test_error_no_id_and_name(self): 245*8023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 246*8023090bSWenchao Xia device = self.expect[0]['device']) 247*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 248*8023090bSWenchao Xia 249*8023090bSWenchao Xia def test_error_snapshot_not_exist(self): 250*8023090bSWenchao Xia self.createSnapshotInTransaction(2) 251*8023090bSWenchao Xia self.verifySnapshotInfo() 252*8023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 253*8023090bSWenchao Xia device = self.expect[0]['device'], 254*8023090bSWenchao Xia id = self.expect[0]['snapshots'][0]['id'], 255*8023090bSWenchao Xia name = self.expect[0]['snapshots'][1]['name']) 256*8023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 257*8023090bSWenchao Xia 258*8023090bSWenchao Xiaif __name__ == '__main__': 259*8023090bSWenchao Xia iotests.main(supported_fmts=['qcow2']) 260