xref: /openbmc/qemu/tests/qemu-iotests/055 (revision 14a650ec)
1#!/usr/bin/env python
2#
3# Tests for drive-backup
4#
5# Copyright (C) 2013 Red Hat, Inc.
6#
7# Based on 041.
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21#
22
23import time
24import os
25import iotests
26from iotests import qemu_img, qemu_io
27
28test_img = os.path.join(iotests.test_dir, 'test.img')
29target_img = os.path.join(iotests.test_dir, 'target.img')
30
31class TestSingleDrive(iotests.QMPTestCase):
32    image_len = 64 * 1024 * 1024 # MB
33
34    def setUp(self):
35        # Write data to the image so we can compare later
36        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
37        qemu_io('-c', 'write -P0x5d 0 64k', test_img)
38        qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
39        qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
40        qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
41
42        self.vm = iotests.VM().add_drive(test_img)
43        self.vm.launch()
44
45    def tearDown(self):
46        self.vm.shutdown()
47        os.remove(test_img)
48        try:
49            os.remove(target_img)
50        except OSError:
51            pass
52
53    def test_cancel(self):
54        self.assert_no_active_block_jobs()
55
56        result = self.vm.qmp('drive-backup', device='drive0',
57                             target=target_img, sync='full')
58        self.assert_qmp(result, 'return', {})
59
60        event = self.cancel_and_wait()
61        self.assert_qmp(event, 'data/type', 'backup')
62
63    def test_pause(self):
64        self.assert_no_active_block_jobs()
65
66        result = self.vm.qmp('drive-backup', device='drive0',
67                             target=target_img, sync='full')
68        self.assert_qmp(result, 'return', {})
69
70        result = self.vm.qmp('block-job-pause', device='drive0')
71        self.assert_qmp(result, 'return', {})
72
73        time.sleep(1)
74        result = self.vm.qmp('query-block-jobs')
75        offset = self.dictpath(result, 'return[0]/offset')
76
77        time.sleep(1)
78        result = self.vm.qmp('query-block-jobs')
79        self.assert_qmp(result, 'return[0]/offset', offset)
80
81        result = self.vm.qmp('block-job-resume', device='drive0')
82        self.assert_qmp(result, 'return', {})
83
84        self.wait_until_completed()
85
86        self.vm.shutdown()
87        self.assertTrue(iotests.compare_images(test_img, target_img),
88                        'target image does not match source after backup')
89
90    def test_medium_not_found(self):
91        result = self.vm.qmp('drive-backup', device='ide1-cd0',
92                             target=target_img, sync='full')
93        self.assert_qmp(result, 'error/class', 'GenericError')
94
95    def test_image_not_found(self):
96        result = self.vm.qmp('drive-backup', device='drive0',
97                             target=target_img, sync='full', mode='existing')
98        self.assert_qmp(result, 'error/class', 'GenericError')
99
100    def test_invalid_format(self):
101        result = self.vm.qmp('drive-backup', device='drive0',
102                             target=target_img, sync='full',
103                             format='spaghetti-noodles')
104        self.assert_qmp(result, 'error/class', 'GenericError')
105
106    def test_device_not_found(self):
107        result = self.vm.qmp('drive-backup', device='nonexistent',
108                             target=target_img, sync='full')
109        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
110
111class TestSetSpeed(iotests.QMPTestCase):
112    image_len = 80 * 1024 * 1024 # MB
113
114    def setUp(self):
115        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len))
116        self.vm = iotests.VM().add_drive(test_img)
117        self.vm.launch()
118
119    def tearDown(self):
120        self.vm.shutdown()
121        os.remove(test_img)
122        os.remove(target_img)
123
124    def test_set_speed(self):
125        self.assert_no_active_block_jobs()
126
127        result = self.vm.qmp('drive-backup', device='drive0',
128                             target=target_img, sync='full')
129        self.assert_qmp(result, 'return', {})
130
131        # Default speed is 0
132        result = self.vm.qmp('query-block-jobs')
133        self.assert_qmp(result, 'return[0]/device', 'drive0')
134        self.assert_qmp(result, 'return[0]/speed', 0)
135
136        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
137        self.assert_qmp(result, 'return', {})
138
139        # Ensure the speed we set was accepted
140        result = self.vm.qmp('query-block-jobs')
141        self.assert_qmp(result, 'return[0]/device', 'drive0')
142        self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
143
144        event = self.cancel_and_wait()
145        self.assert_qmp(event, 'data/type', 'backup')
146
147        # Check setting speed in drive-backup works
148        result = self.vm.qmp('drive-backup', device='drive0',
149                             target=target_img, sync='full', speed=4*1024*1024)
150        self.assert_qmp(result, 'return', {})
151
152        result = self.vm.qmp('query-block-jobs')
153        self.assert_qmp(result, 'return[0]/device', 'drive0')
154        self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
155
156        event = self.cancel_and_wait()
157        self.assert_qmp(event, 'data/type', 'backup')
158
159    def test_set_speed_invalid(self):
160        self.assert_no_active_block_jobs()
161
162        result = self.vm.qmp('drive-backup', device='drive0',
163                             target=target_img, sync='full', speed=-1)
164        self.assert_qmp(result, 'error/class', 'GenericError')
165
166        self.assert_no_active_block_jobs()
167
168        result = self.vm.qmp('drive-backup', device='drive0',
169                             target=target_img, sync='full')
170        self.assert_qmp(result, 'return', {})
171
172        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
173        self.assert_qmp(result, 'error/class', 'GenericError')
174
175        event = self.cancel_and_wait()
176        self.assert_qmp(event, 'data/type', 'backup')
177
178class TestSingleTransaction(iotests.QMPTestCase):
179    image_len = 64 * 1024 * 1024 # MB
180
181    def setUp(self):
182        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len))
183        qemu_io('-c', 'write -P0x5d 0 64k', test_img)
184        qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
185        qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
186        qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
187
188        self.vm = iotests.VM().add_drive(test_img)
189        self.vm.launch()
190
191    def tearDown(self):
192        self.vm.shutdown()
193        os.remove(test_img)
194        try:
195            os.remove(target_img)
196        except OSError:
197            pass
198
199    def test_cancel(self):
200        self.assert_no_active_block_jobs()
201
202        result = self.vm.qmp('transaction', actions=[{
203                'type': 'drive-backup',
204                'data': { 'device': 'drive0',
205                          'target': target_img,
206                          'sync': 'full' },
207            }
208        ])
209        self.assert_qmp(result, 'return', {})
210
211        event = self.cancel_and_wait()
212        self.assert_qmp(event, 'data/type', 'backup')
213
214    def test_pause(self):
215        self.assert_no_active_block_jobs()
216
217        result = self.vm.qmp('transaction', actions=[{
218                'type': 'drive-backup',
219                'data': { 'device': 'drive0',
220                          'target': target_img,
221                          'sync': 'full' },
222            }
223        ])
224        self.assert_qmp(result, 'return', {})
225
226        result = self.vm.qmp('block-job-pause', device='drive0')
227        self.assert_qmp(result, 'return', {})
228
229        time.sleep(1)
230        result = self.vm.qmp('query-block-jobs')
231        offset = self.dictpath(result, 'return[0]/offset')
232
233        time.sleep(1)
234        result = self.vm.qmp('query-block-jobs')
235        self.assert_qmp(result, 'return[0]/offset', offset)
236
237        result = self.vm.qmp('block-job-resume', device='drive0')
238        self.assert_qmp(result, 'return', {})
239
240        self.wait_until_completed()
241
242        self.vm.shutdown()
243        self.assertTrue(iotests.compare_images(test_img, target_img),
244                        'target image does not match source after backup')
245
246    def test_medium_not_found(self):
247        result = self.vm.qmp('transaction', actions=[{
248                'type': 'drive-backup',
249                'data': { 'device': 'ide1-cd0',
250                          'target': target_img,
251                          'sync': 'full' },
252            }
253        ])
254        self.assert_qmp(result, 'error/class', 'GenericError')
255
256    def test_image_not_found(self):
257        result = self.vm.qmp('transaction', actions=[{
258                'type': 'drive-backup',
259                'data': { 'device': 'drive0',
260                          'mode': 'existing',
261                          'target': target_img,
262                          'sync': 'full' },
263            }
264        ])
265        self.assert_qmp(result, 'error/class', 'GenericError')
266
267    def test_device_not_found(self):
268        result = self.vm.qmp('transaction', actions=[{
269                'type': 'drive-backup',
270                'data': { 'device': 'nonexistent',
271                          'mode': 'existing',
272                          'target': target_img,
273                          'sync': 'full' },
274            }
275        ])
276        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
277
278    def test_abort(self):
279        result = self.vm.qmp('transaction', actions=[{
280                'type': 'drive-backup',
281                'data': { 'device': 'nonexistent',
282                          'mode': 'existing',
283                          'target': target_img,
284                          'sync': 'full' },
285            }, {
286                'type': 'Abort',
287                'data': {},
288            }
289        ])
290        self.assert_qmp(result, 'error/class', 'GenericError')
291        self.assert_no_active_block_jobs()
292
293if __name__ == '__main__':
294    iotests.main(supported_fmts=['raw', 'qcow2'])
295