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