18023090bSWenchao Xia#!/usr/bin/env python 28023090bSWenchao Xia# 38023090bSWenchao Xia# Tests for internal snapshot. 48023090bSWenchao Xia# 58023090bSWenchao Xia# Copyright (C) 2013 IBM, Inc. 68023090bSWenchao Xia# 78023090bSWenchao Xia# Based on 055. 88023090bSWenchao Xia# 98023090bSWenchao Xia# This program is free software; you can redistribute it and/or modify 108023090bSWenchao Xia# it under the terms of the GNU General Public License as published by 118023090bSWenchao Xia# the Free Software Foundation; either version 2 of the License, or 128023090bSWenchao Xia# (at your option) any later version. 138023090bSWenchao Xia# 148023090bSWenchao Xia# This program is distributed in the hope that it will be useful, 158023090bSWenchao Xia# but WITHOUT ANY WARRANTY; without even the implied warranty of 168023090bSWenchao Xia# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178023090bSWenchao Xia# GNU General Public License for more details. 188023090bSWenchao Xia# 198023090bSWenchao Xia# You should have received a copy of the GNU General Public License 208023090bSWenchao Xia# along with this program. If not, see <http://www.gnu.org/licenses/>. 218023090bSWenchao Xia# 228023090bSWenchao Xia 238023090bSWenchao Xiaimport time 248023090bSWenchao Xiaimport os 258023090bSWenchao Xiaimport iotests 268023090bSWenchao Xiafrom iotests import qemu_img, qemu_io 278023090bSWenchao Xia 288023090bSWenchao Xiatest_drv_base_name = 'drive' 298023090bSWenchao Xia 308023090bSWenchao Xiaclass ImageSnapshotTestCase(iotests.QMPTestCase): 318023090bSWenchao Xia image_len = 120 * 1024 * 1024 # MB 328023090bSWenchao Xia 338023090bSWenchao Xia def __init__(self, *args): 348023090bSWenchao Xia self.expect = [] 358023090bSWenchao Xia super(ImageSnapshotTestCase, self).__init__(*args) 368023090bSWenchao Xia 378023090bSWenchao Xia def _setUp(self, test_img_base_name, image_num): 388023090bSWenchao Xia self.vm = iotests.VM() 398023090bSWenchao Xia for i in range(0, image_num): 408023090bSWenchao Xia filename = '%s%d' % (test_img_base_name, i) 418023090bSWenchao Xia img = os.path.join(iotests.test_dir, filename) 428023090bSWenchao Xia device = '%s%d' % (test_drv_base_name, i) 438023090bSWenchao Xia qemu_img('create', '-f', iotests.imgfmt, img, str(self.image_len)) 448023090bSWenchao Xia self.vm.add_drive(img) 458023090bSWenchao Xia self.expect.append({'image': img, 'device': device, 468023090bSWenchao Xia 'snapshots': [], 478023090bSWenchao Xia 'snapshots_name_counter': 0}) 488023090bSWenchao Xia self.vm.launch() 498023090bSWenchao Xia 508023090bSWenchao Xia def tearDown(self): 518023090bSWenchao Xia self.vm.shutdown() 528023090bSWenchao Xia for dev_expect in self.expect: 538023090bSWenchao Xia os.remove(dev_expect['image']) 548023090bSWenchao Xia 558023090bSWenchao Xia def createSnapshotInTransaction(self, snapshot_num, abort = False): 568023090bSWenchao Xia actions = [] 578023090bSWenchao Xia for dev_expect in self.expect: 588023090bSWenchao Xia num = dev_expect['snapshots_name_counter'] 598023090bSWenchao Xia for j in range(0, snapshot_num): 608023090bSWenchao Xia name = '%s_sn%d' % (dev_expect['device'], num) 618023090bSWenchao Xia num = num + 1 628023090bSWenchao Xia if abort == False: 638023090bSWenchao Xia dev_expect['snapshots'].append({'name': name}) 648023090bSWenchao Xia dev_expect['snapshots_name_counter'] = num 658023090bSWenchao Xia actions.append({ 668023090bSWenchao Xia 'type': 'blockdev-snapshot-internal-sync', 678023090bSWenchao Xia 'data': { 'device': dev_expect['device'], 688023090bSWenchao Xia 'name': name }, 698023090bSWenchao Xia }) 708023090bSWenchao Xia 718023090bSWenchao Xia if abort == True: 728023090bSWenchao Xia actions.append({ 738023090bSWenchao Xia 'type': 'abort', 748023090bSWenchao Xia 'data': {}, 758023090bSWenchao Xia }) 768023090bSWenchao Xia 778023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 788023090bSWenchao Xia 798023090bSWenchao Xia if abort == True: 808023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 818023090bSWenchao Xia else: 828023090bSWenchao Xia self.assert_qmp(result, 'return', {}) 838023090bSWenchao Xia 848023090bSWenchao Xia def verifySnapshotInfo(self): 858023090bSWenchao Xia result = self.vm.qmp('query-block') 868023090bSWenchao Xia 878023090bSWenchao Xia # Verify each expected result 888023090bSWenchao Xia for dev_expect in self.expect: 898023090bSWenchao Xia # 1. Find the returned image value and snapshot info 908023090bSWenchao Xia image_result = None 918023090bSWenchao Xia for device in result['return']: 928023090bSWenchao Xia if device['device'] == dev_expect['device']: 938023090bSWenchao Xia image_result = device['inserted']['image'] 948023090bSWenchao Xia break 958023090bSWenchao Xia self.assertTrue(image_result != None) 968023090bSWenchao Xia # Do not consider zero snapshot case now 978023090bSWenchao Xia sn_list_result = image_result['snapshots'] 988023090bSWenchao Xia sn_list_expect = dev_expect['snapshots'] 998023090bSWenchao Xia 1008023090bSWenchao Xia # 2. Verify it with expect 1018023090bSWenchao Xia self.assertTrue(len(sn_list_result) == len(sn_list_expect)) 1028023090bSWenchao Xia 1038023090bSWenchao Xia for sn_expect in sn_list_expect: 1048023090bSWenchao Xia sn_result = None 1058023090bSWenchao Xia for sn in sn_list_result: 1068023090bSWenchao Xia if sn_expect['name'] == sn['name']: 1078023090bSWenchao Xia sn_result = sn 1088023090bSWenchao Xia break 1098023090bSWenchao Xia self.assertTrue(sn_result != None) 1108023090bSWenchao Xia # Fill in the detail info 1118023090bSWenchao Xia sn_expect.update(sn_result) 1128023090bSWenchao Xia 1138023090bSWenchao Xia def deleteSnapshot(self, device, id = None, name = None): 1148023090bSWenchao Xia sn_list_expect = None 1158023090bSWenchao Xia sn_expect = None 1168023090bSWenchao Xia 1178023090bSWenchao Xia self.assertTrue(id != None or name != None) 1188023090bSWenchao Xia 1198023090bSWenchao Xia # Fill in the detail info include ID 1208023090bSWenchao Xia self.verifySnapshotInfo() 1218023090bSWenchao Xia 1228023090bSWenchao Xia #find the expected snapshot list 1238023090bSWenchao Xia for dev_expect in self.expect: 1248023090bSWenchao Xia if dev_expect['device'] == device: 1258023090bSWenchao Xia sn_list_expect = dev_expect['snapshots'] 1268023090bSWenchao Xia break 1278023090bSWenchao Xia self.assertTrue(sn_list_expect != None) 1288023090bSWenchao Xia 1298023090bSWenchao Xia if id != None and name != None: 1308023090bSWenchao Xia for sn in sn_list_expect: 1318023090bSWenchao Xia if sn['id'] == id and sn['name'] == name: 1328023090bSWenchao Xia sn_expect = sn 1338023090bSWenchao Xia result = \ 1348023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 1358023090bSWenchao Xia device = device, 1368023090bSWenchao Xia id = id, 1378023090bSWenchao Xia name = name) 1388023090bSWenchao Xia break 1398023090bSWenchao Xia elif id != None: 1408023090bSWenchao Xia for sn in sn_list_expect: 1418023090bSWenchao Xia if sn['id'] == id: 1428023090bSWenchao Xia sn_expect = sn 1438023090bSWenchao Xia result = \ 1448023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 1458023090bSWenchao Xia device = device, 1468023090bSWenchao Xia id = id) 1478023090bSWenchao Xia break 1488023090bSWenchao Xia else: 1498023090bSWenchao Xia for sn in sn_list_expect: 1508023090bSWenchao Xia if sn['name'] == name: 1518023090bSWenchao Xia sn_expect = sn 1528023090bSWenchao Xia result = \ 1538023090bSWenchao Xia self.vm.qmp('blockdev-snapshot-delete-internal-sync', 1548023090bSWenchao Xia device = device, 1558023090bSWenchao Xia name = name) 1568023090bSWenchao Xia break 1578023090bSWenchao Xia 1588023090bSWenchao Xia self.assertTrue(sn_expect != None) 1598023090bSWenchao Xia 1608023090bSWenchao Xia self.assert_qmp(result, 'return', sn_expect) 1618023090bSWenchao Xia sn_list_expect.remove(sn_expect) 1628023090bSWenchao Xia 1638023090bSWenchao Xiaclass TestSingleTransaction(ImageSnapshotTestCase): 1648023090bSWenchao Xia def setUp(self): 1658023090bSWenchao Xia self._setUp('test_a.img', 1) 1668023090bSWenchao Xia 1678023090bSWenchao Xia def test_create(self): 1688023090bSWenchao Xia self.createSnapshotInTransaction(1) 1698023090bSWenchao Xia self.verifySnapshotInfo() 1708023090bSWenchao Xia 1718023090bSWenchao Xia def test_error_name_empty(self): 1728023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 1738023090bSWenchao Xia 'data': { 'device': self.expect[0]['device'], 1748023090bSWenchao Xia 'name': '' }, 1758023090bSWenchao Xia }] 1768023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 1778023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 1788023090bSWenchao Xia 1798023090bSWenchao Xia def test_error_device(self): 1808023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 1818023090bSWenchao Xia 'data': { 'device': 'drive_error', 1828023090bSWenchao Xia 'name': 'a' }, 1838023090bSWenchao Xia }] 1848023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 1858023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'DeviceNotFound') 1868023090bSWenchao Xia 1878023090bSWenchao Xia def test_error_exist(self): 1888023090bSWenchao Xia self.createSnapshotInTransaction(1) 1898023090bSWenchao Xia self.verifySnapshotInfo() 1908023090bSWenchao Xia actions = [{'type': 'blockdev-snapshot-internal-sync', 1918023090bSWenchao Xia 'data': { 'device': self.expect[0]['device'], 1928023090bSWenchao Xia 'name': self.expect[0]['snapshots'][0] }, 1938023090bSWenchao Xia }] 1948023090bSWenchao Xia result = self.vm.qmp('transaction', actions = actions) 1958023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 1968023090bSWenchao Xia 1978023090bSWenchao Xiaclass TestMultipleTransaction(ImageSnapshotTestCase): 1988023090bSWenchao Xia def setUp(self): 1998023090bSWenchao Xia self._setUp('test_b.img', 2) 2008023090bSWenchao Xia 2018023090bSWenchao Xia def test_create(self): 2028023090bSWenchao Xia self.createSnapshotInTransaction(3) 2038023090bSWenchao Xia self.verifySnapshotInfo() 2048023090bSWenchao Xia 2058023090bSWenchao Xia def test_abort(self): 2068023090bSWenchao Xia self.createSnapshotInTransaction(2) 2078023090bSWenchao Xia self.verifySnapshotInfo() 2088023090bSWenchao Xia self.createSnapshotInTransaction(3, abort = True) 2098023090bSWenchao Xia self.verifySnapshotInfo() 2108023090bSWenchao Xia 2118023090bSWenchao Xiaclass TestSnapshotDelete(ImageSnapshotTestCase): 2128023090bSWenchao Xia def setUp(self): 2138023090bSWenchao Xia self._setUp('test_c.img', 1) 2148023090bSWenchao Xia 2158023090bSWenchao Xia def test_delete_with_id(self): 2168023090bSWenchao Xia self.createSnapshotInTransaction(2) 2178023090bSWenchao Xia self.verifySnapshotInfo() 2188023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 2198023090bSWenchao Xia id = self.expect[0]['snapshots'][0]['id']) 2208023090bSWenchao Xia self.verifySnapshotInfo() 2218023090bSWenchao Xia 2228023090bSWenchao Xia def test_delete_with_name(self): 2238023090bSWenchao Xia self.createSnapshotInTransaction(3) 2248023090bSWenchao Xia self.verifySnapshotInfo() 2258023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 2268023090bSWenchao Xia name = self.expect[0]['snapshots'][1]['name']) 2278023090bSWenchao Xia self.verifySnapshotInfo() 2288023090bSWenchao Xia 2298023090bSWenchao Xia def test_delete_with_id_and_name(self): 2308023090bSWenchao Xia self.createSnapshotInTransaction(4) 2318023090bSWenchao Xia self.verifySnapshotInfo() 2328023090bSWenchao Xia self.deleteSnapshot(self.expect[0]['device'], 2338023090bSWenchao Xia id = self.expect[0]['snapshots'][2]['id'], 2348023090bSWenchao Xia name = self.expect[0]['snapshots'][2]['name']) 2358023090bSWenchao Xia self.verifySnapshotInfo() 2368023090bSWenchao Xia 2378023090bSWenchao Xia 2388023090bSWenchao Xia def test_error_device(self): 2398023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 2408023090bSWenchao Xia device = 'drive_error', 2418023090bSWenchao Xia id = '0') 242*2dfb4c03SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 2438023090bSWenchao Xia 2448023090bSWenchao Xia def test_error_no_id_and_name(self): 2458023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 2468023090bSWenchao Xia device = self.expect[0]['device']) 2478023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 2488023090bSWenchao Xia 2498023090bSWenchao Xia def test_error_snapshot_not_exist(self): 2508023090bSWenchao Xia self.createSnapshotInTransaction(2) 2518023090bSWenchao Xia self.verifySnapshotInfo() 2528023090bSWenchao Xia result = self.vm.qmp('blockdev-snapshot-delete-internal-sync', 2538023090bSWenchao Xia device = self.expect[0]['device'], 2548023090bSWenchao Xia id = self.expect[0]['snapshots'][0]['id'], 2558023090bSWenchao Xia name = self.expect[0]['snapshots'][1]['name']) 2568023090bSWenchao Xia self.assert_qmp(result, 'error/class', 'GenericError') 2578023090bSWenchao Xia 2588023090bSWenchao Xiaif __name__ == '__main__': 2598023090bSWenchao Xia iotests.main(supported_fmts=['qcow2']) 260