Add qemu 2.4.0
[kvmfornfv.git] / qemu / tests / qemu-iotests / 055
1 #!/usr/bin/env python
2 #
3 # Tests for drive-backup and blockdev-backup
4 #
5 # Copyright (C) 2013, 2014 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
23 import time
24 import os
25 import iotests
26 from iotests import qemu_img, qemu_io
27
28 test_img = os.path.join(iotests.test_dir, 'test.img')
29 target_img = os.path.join(iotests.test_dir, 'target.img')
30 blockdev_target_img = os.path.join(iotests.test_dir, 'blockdev-target.img')
31
32 class TestSingleDrive(iotests.QMPTestCase):
33     image_len = 64 * 1024 * 1024 # MB
34
35     def setUp(self):
36         # Write data to the image so we can compare later
37         qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
38         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img)
39         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img)
40         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img)
41         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img)
42         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len))
43
44         self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
45         self.vm.launch()
46
47     def tearDown(self):
48         self.vm.shutdown()
49         os.remove(test_img)
50         os.remove(blockdev_target_img)
51         try:
52             os.remove(target_img)
53         except OSError:
54             pass
55
56     def do_test_cancel(self, cmd, target):
57         self.assert_no_active_block_jobs()
58
59         result = self.vm.qmp(cmd, device='drive0', target=target, sync='full')
60         self.assert_qmp(result, 'return', {})
61
62         event = self.cancel_and_wait()
63         self.assert_qmp(event, 'data/type', 'backup')
64
65     def test_cancel_drive_backup(self):
66         self.do_test_cancel('drive-backup', target_img)
67
68     def test_cancel_blockdev_backup(self):
69         self.do_test_cancel('blockdev-backup', 'drive1')
70
71     def do_test_pause(self, cmd, target, image):
72         self.assert_no_active_block_jobs()
73
74         self.vm.pause_drive('drive0')
75         result = self.vm.qmp(cmd, device='drive0',
76                              target=target, sync='full')
77         self.assert_qmp(result, 'return', {})
78
79         result = self.vm.qmp('block-job-pause', device='drive0')
80         self.assert_qmp(result, 'return', {})
81
82         self.vm.resume_drive('drive0')
83         time.sleep(1)
84         result = self.vm.qmp('query-block-jobs')
85         offset = self.dictpath(result, 'return[0]/offset')
86
87         time.sleep(1)
88         result = self.vm.qmp('query-block-jobs')
89         self.assert_qmp(result, 'return[0]/offset', offset)
90
91         result = self.vm.qmp('block-job-resume', device='drive0')
92         self.assert_qmp(result, 'return', {})
93
94         self.wait_until_completed()
95
96         self.vm.shutdown()
97         self.assertTrue(iotests.compare_images(test_img, image),
98                         'target image does not match source after backup')
99
100     def test_pause_drive_backup(self):
101         self.do_test_pause('drive-backup', target_img, target_img)
102
103     def test_pause_blockdev_backup(self):
104         self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
105
106     def test_medium_not_found(self):
107         result = self.vm.qmp('drive-backup', device='ide1-cd0',
108                              target=target_img, sync='full')
109         self.assert_qmp(result, 'error/class', 'GenericError')
110
111     def test_medium_not_found_blockdev_backup(self):
112         result = self.vm.qmp('blockdev-backup', device='ide1-cd0',
113                              target='drive1', sync='full')
114         self.assert_qmp(result, 'error/class', 'GenericError')
115
116     def test_image_not_found(self):
117         result = self.vm.qmp('drive-backup', device='drive0',
118                              target=target_img, sync='full', mode='existing')
119         self.assert_qmp(result, 'error/class', 'GenericError')
120
121     def test_invalid_format(self):
122         result = self.vm.qmp('drive-backup', device='drive0',
123                              target=target_img, sync='full',
124                              format='spaghetti-noodles')
125         self.assert_qmp(result, 'error/class', 'GenericError')
126
127     def do_test_device_not_found(self, cmd, **args):
128         result = self.vm.qmp(cmd, **args)
129         if cmd == 'drive-backup':
130             self.assert_qmp(result, 'error/class', 'DeviceNotFound')
131         else:
132             self.assert_qmp(result, 'error/class', 'GenericError')
133
134     def test_device_not_found(self):
135         self.do_test_device_not_found('drive-backup', device='nonexistent',
136                                       target=target_img, sync='full')
137
138         self.do_test_device_not_found('blockdev-backup', device='nonexistent',
139                                       target='drive0', sync='full')
140
141         self.do_test_device_not_found('blockdev-backup', device='drive0',
142                                       target='nonexistent', sync='full')
143
144         self.do_test_device_not_found('blockdev-backup', device='nonexistent',
145                                       target='nonexistent', sync='full')
146
147     def test_target_is_source(self):
148         result = self.vm.qmp('blockdev-backup', device='drive0',
149                              target='drive0', sync='full')
150         self.assert_qmp(result, 'error/class', 'GenericError')
151
152 class TestSetSpeed(iotests.QMPTestCase):
153     image_len = 80 * 1024 * 1024 # MB
154
155     def setUp(self):
156         qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len))
157         qemu_io('-f', iotests.imgfmt, '-c', 'write -P1 0 512', test_img)
158         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len))
159
160         self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
161         self.vm.launch()
162
163     def tearDown(self):
164         self.vm.shutdown()
165         os.remove(test_img)
166         os.remove(blockdev_target_img)
167         try:
168             os.remove(target_img)
169         except OSError:
170             pass
171
172     def do_test_set_speed(self, cmd, target):
173         self.assert_no_active_block_jobs()
174
175         self.vm.pause_drive('drive0')
176         result = self.vm.qmp(cmd, device='drive0', target=target, sync='full')
177         self.assert_qmp(result, 'return', {})
178
179         # Default speed is 0
180         result = self.vm.qmp('query-block-jobs')
181         self.assert_qmp(result, 'return[0]/device', 'drive0')
182         self.assert_qmp(result, 'return[0]/speed', 0)
183
184         result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
185         self.assert_qmp(result, 'return', {})
186
187         # Ensure the speed we set was accepted
188         result = self.vm.qmp('query-block-jobs')
189         self.assert_qmp(result, 'return[0]/device', 'drive0')
190         self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
191
192         event = self.cancel_and_wait(resume=True)
193         self.assert_qmp(event, 'data/type', 'backup')
194
195         # Check setting speed option works
196         self.vm.pause_drive('drive0')
197         result = self.vm.qmp(cmd, device='drive0',
198                              target=target, sync='full', speed=4*1024*1024)
199         self.assert_qmp(result, 'return', {})
200
201         result = self.vm.qmp('query-block-jobs')
202         self.assert_qmp(result, 'return[0]/device', 'drive0')
203         self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
204
205         event = self.cancel_and_wait(resume=True)
206         self.assert_qmp(event, 'data/type', 'backup')
207
208     def test_set_speed_drive_backup(self):
209         self.do_test_set_speed('drive-backup', target_img)
210
211     def test_set_speed_blockdev_backup(self):
212         self.do_test_set_speed('blockdev-backup', 'drive1')
213
214     def do_test_set_speed_invalid(self, cmd, target):
215         self.assert_no_active_block_jobs()
216
217         result = self.vm.qmp(cmd, device='drive0',
218                              target=target, sync='full', speed=-1)
219         self.assert_qmp(result, 'error/class', 'GenericError')
220
221         self.assert_no_active_block_jobs()
222
223         self.vm.pause_drive('drive0')
224         result = self.vm.qmp(cmd, device='drive0',
225                              target=target, sync='full')
226         self.assert_qmp(result, 'return', {})
227
228         result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
229         self.assert_qmp(result, 'error/class', 'GenericError')
230
231         event = self.cancel_and_wait(resume=True)
232         self.assert_qmp(event, 'data/type', 'backup')
233
234     def test_set_speed_invalid_drive_backup(self):
235         self.do_test_set_speed_invalid('drive-backup', target_img)
236
237     def test_set_speed_invalid_blockdev_backup(self):
238         self.do_test_set_speed_invalid('blockdev-backup',  'drive1')
239
240 class TestSingleTransaction(iotests.QMPTestCase):
241     image_len = 64 * 1024 * 1024 # MB
242
243     def setUp(self):
244         qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len))
245         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img)
246         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img)
247         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img)
248         qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img)
249         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len))
250
251         self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
252         self.vm.launch()
253
254     def tearDown(self):
255         self.vm.shutdown()
256         os.remove(test_img)
257         os.remove(blockdev_target_img)
258         try:
259             os.remove(target_img)
260         except OSError:
261             pass
262
263     def do_test_cancel(self, cmd, target):
264         self.assert_no_active_block_jobs()
265
266         result = self.vm.qmp('transaction', actions=[{
267                 'type': cmd,
268                 'data': { 'device': 'drive0',
269                           'target': target,
270                           'sync': 'full' },
271             }
272         ])
273
274         self.assert_qmp(result, 'return', {})
275
276         event = self.cancel_and_wait()
277         self.assert_qmp(event, 'data/type', 'backup')
278
279     def test_cancel_drive_backup(self):
280         self.do_test_cancel('drive-backup', target_img)
281
282     def test_cancel_blockdev_backup(self):
283         self.do_test_cancel('blockdev-backup', 'drive1')
284
285     def do_test_pause(self, cmd, target, image):
286         self.assert_no_active_block_jobs()
287
288         self.vm.pause_drive('drive0')
289         result = self.vm.qmp('transaction', actions=[{
290                 'type': cmd,
291                 'data': { 'device': 'drive0',
292                           'target': target,
293                           'sync': 'full' },
294             }
295         ])
296         self.assert_qmp(result, 'return', {})
297
298         result = self.vm.qmp('block-job-pause', device='drive0')
299         self.assert_qmp(result, 'return', {})
300
301         self.vm.resume_drive('drive0')
302         time.sleep(1)
303         result = self.vm.qmp('query-block-jobs')
304         offset = self.dictpath(result, 'return[0]/offset')
305
306         time.sleep(1)
307         result = self.vm.qmp('query-block-jobs')
308         self.assert_qmp(result, 'return[0]/offset', offset)
309
310         result = self.vm.qmp('block-job-resume', device='drive0')
311         self.assert_qmp(result, 'return', {})
312
313         self.wait_until_completed()
314
315         self.vm.shutdown()
316         self.assertTrue(iotests.compare_images(test_img, image),
317                         'target image does not match source after backup')
318
319     def test_pause_drive_backup(self):
320         self.do_test_pause('drive-backup', target_img, target_img)
321
322     def test_pause_blockdev_backup(self):
323         self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
324
325     def do_test_medium_not_found(self, cmd, target):
326         result = self.vm.qmp('transaction', actions=[{
327                 'type': cmd,
328                 'data': { 'device': 'ide1-cd0',
329                           'target': target,
330                           'sync': 'full' },
331             }
332         ])
333         self.assert_qmp(result, 'error/class', 'GenericError')
334
335     def test_medium_not_found_drive_backup(self):
336         self.do_test_medium_not_found('drive-backup', target_img)
337
338     def test_medium_not_found_blockdev_backup(self):
339         self.do_test_medium_not_found('blockdev-backup', 'drive1')
340
341     def test_image_not_found(self):
342         result = self.vm.qmp('transaction', actions=[{
343                 'type': 'drive-backup',
344                 'data': { 'device': 'drive0',
345                           'mode': 'existing',
346                           'target': target_img,
347                           'sync': 'full' },
348             }
349         ])
350         self.assert_qmp(result, 'error/class', 'GenericError')
351
352     def test_device_not_found(self):
353         result = self.vm.qmp('transaction', actions=[{
354                 'type': 'drive-backup',
355                 'data': { 'device': 'nonexistent',
356                           'mode': 'existing',
357                           'target': target_img,
358                           'sync': 'full' },
359             }
360         ])
361         self.assert_qmp(result, 'error/class', 'DeviceNotFound')
362
363         result = self.vm.qmp('transaction', actions=[{
364                 'type': 'blockdev-backup',
365                 'data': { 'device': 'nonexistent',
366                           'target': 'drive1',
367                           'sync': 'full' },
368             }
369         ])
370         self.assert_qmp(result, 'error/class', 'GenericError')
371
372         result = self.vm.qmp('transaction', actions=[{
373                 'type': 'blockdev-backup',
374                 'data': { 'device': 'drive0',
375                           'target': 'nonexistent',
376                           'sync': 'full' },
377             }
378         ])
379         self.assert_qmp(result, 'error/class', 'GenericError')
380
381         result = self.vm.qmp('transaction', actions=[{
382                 'type': 'blockdev-backup',
383                 'data': { 'device': 'nonexistent',
384                           'target': 'nonexistent',
385                           'sync': 'full' },
386             }
387         ])
388         self.assert_qmp(result, 'error/class', 'GenericError')
389
390     def test_target_is_source(self):
391         result = self.vm.qmp('transaction', actions=[{
392                 'type': 'blockdev-backup',
393                 'data': { 'device': 'drive0',
394                           'target': 'drive0',
395                           'sync': 'full' },
396             }
397         ])
398         self.assert_qmp(result, 'error/class', 'GenericError')
399
400     def test_abort(self):
401         result = self.vm.qmp('transaction', actions=[{
402                 'type': 'drive-backup',
403                 'data': { 'device': 'nonexistent',
404                           'mode': 'existing',
405                           'target': target_img,
406                           'sync': 'full' },
407             }, {
408                 'type': 'Abort',
409                 'data': {},
410             }
411         ])
412         self.assert_qmp(result, 'error/class', 'GenericError')
413         self.assert_no_active_block_jobs()
414
415         result = self.vm.qmp('transaction', actions=[{
416                 'type': 'blockdev-backup',
417                 'data': { 'device': 'nonexistent',
418                           'target': 'drive1',
419                           'sync': 'full' },
420             }, {
421                 'type': 'Abort',
422                 'data': {},
423             }
424         ])
425         self.assert_qmp(result, 'error/class', 'GenericError')
426         self.assert_no_active_block_jobs()
427
428         result = self.vm.qmp('transaction', actions=[{
429                 'type': 'blockdev-backup',
430                 'data': { 'device': 'drive0',
431                           'target': 'nonexistent',
432                           'sync': 'full' },
433             }, {
434                 'type': 'Abort',
435                 'data': {},
436             }
437         ])
438         self.assert_qmp(result, 'error/class', 'GenericError')
439         self.assert_no_active_block_jobs()
440
441 if __name__ == '__main__':
442     iotests.main(supported_fmts=['raw', 'qcow2'])