xref: /openbmc/qemu/tests/qemu-iotests/055 (revision 1b111dc1)
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        self.vm.pause_drive('drive0')
67        result = self.vm.qmp('drive-backup', device='drive0',
68                             target=target_img, sync='full')
69        self.assert_qmp(result, 'return', {})
70
71        result = self.vm.qmp('block-job-pause', device='drive0')
72        self.assert_qmp(result, 'return', {})
73
74        self.vm.resume_drive('drive0')
75        time.sleep(1)
76        result = self.vm.qmp('query-block-jobs')
77        offset = self.dictpath(result, 'return[0]/offset')
78
79        time.sleep(1)
80        result = self.vm.qmp('query-block-jobs')
81        self.assert_qmp(result, 'return[0]/offset', offset)
82
83        result = self.vm.qmp('block-job-resume', device='drive0')
84        self.assert_qmp(result, 'return', {})
85
86        self.wait_until_completed()
87
88        self.vm.shutdown()
89        self.assertTrue(iotests.compare_images(test_img, target_img),
90                        'target image does not match source after backup')
91
92    def test_medium_not_found(self):
93        result = self.vm.qmp('drive-backup', device='ide1-cd0',
94                             target=target_img, sync='full')
95        self.assert_qmp(result, 'error/class', 'GenericError')
96
97    def test_image_not_found(self):
98        result = self.vm.qmp('drive-backup', device='drive0',
99                             target=target_img, sync='full', mode='existing')
100        self.assert_qmp(result, 'error/class', 'GenericError')
101
102    def test_invalid_format(self):
103        result = self.vm.qmp('drive-backup', device='drive0',
104                             target=target_img, sync='full',
105                             format='spaghetti-noodles')
106        self.assert_qmp(result, 'error/class', 'GenericError')
107
108    def test_device_not_found(self):
109        result = self.vm.qmp('drive-backup', device='nonexistent',
110                             target=target_img, sync='full')
111        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
112
113class TestSetSpeed(iotests.QMPTestCase):
114    image_len = 80 * 1024 * 1024 # MB
115
116    def setUp(self):
117        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len))
118        qemu_io('-c', 'write -P1 0 512', test_img)
119        self.vm = iotests.VM().add_drive(test_img)
120        self.vm.launch()
121
122    def tearDown(self):
123        self.vm.shutdown()
124        os.remove(test_img)
125        os.remove(target_img)
126
127    def test_set_speed(self):
128        self.assert_no_active_block_jobs()
129
130        self.vm.pause_drive('drive0')
131        result = self.vm.qmp('drive-backup', device='drive0',
132                             target=target_img, sync='full')
133        self.assert_qmp(result, 'return', {})
134
135        # Default speed is 0
136        result = self.vm.qmp('query-block-jobs')
137        self.assert_qmp(result, 'return[0]/device', 'drive0')
138        self.assert_qmp(result, 'return[0]/speed', 0)
139
140        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
141        self.assert_qmp(result, 'return', {})
142
143        # Ensure the speed we set was accepted
144        result = self.vm.qmp('query-block-jobs')
145        self.assert_qmp(result, 'return[0]/device', 'drive0')
146        self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
147
148        event = self.cancel_and_wait(resume=True)
149        self.assert_qmp(event, 'data/type', 'backup')
150
151        # Check setting speed in drive-backup works
152        self.vm.pause_drive('drive0')
153        result = self.vm.qmp('drive-backup', device='drive0',
154                             target=target_img, sync='full', speed=4*1024*1024)
155        self.assert_qmp(result, 'return', {})
156
157        result = self.vm.qmp('query-block-jobs')
158        self.assert_qmp(result, 'return[0]/device', 'drive0')
159        self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
160
161        event = self.cancel_and_wait(resume=True)
162        self.assert_qmp(event, 'data/type', 'backup')
163
164    def test_set_speed_invalid(self):
165        self.assert_no_active_block_jobs()
166
167        result = self.vm.qmp('drive-backup', device='drive0',
168                             target=target_img, sync='full', speed=-1)
169        self.assert_qmp(result, 'error/class', 'GenericError')
170
171        self.assert_no_active_block_jobs()
172
173        self.vm.pause_drive('drive0')
174        result = self.vm.qmp('drive-backup', device='drive0',
175                             target=target_img, sync='full')
176        self.assert_qmp(result, 'return', {})
177
178        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
179        self.assert_qmp(result, 'error/class', 'GenericError')
180
181        event = self.cancel_and_wait(resume=True)
182        self.assert_qmp(event, 'data/type', 'backup')
183
184class TestSingleTransaction(iotests.QMPTestCase):
185    image_len = 64 * 1024 * 1024 # MB
186
187    def setUp(self):
188        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len))
189        qemu_io('-c', 'write -P0x5d 0 64k', test_img)
190        qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
191        qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
192        qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
193
194        self.vm = iotests.VM().add_drive(test_img)
195        self.vm.launch()
196
197    def tearDown(self):
198        self.vm.shutdown()
199        os.remove(test_img)
200        try:
201            os.remove(target_img)
202        except OSError:
203            pass
204
205    def test_cancel(self):
206        self.assert_no_active_block_jobs()
207
208        result = self.vm.qmp('transaction', actions=[{
209                'type': 'drive-backup',
210                'data': { 'device': 'drive0',
211                          'target': target_img,
212                          'sync': 'full' },
213            }
214        ])
215        self.assert_qmp(result, 'return', {})
216
217        event = self.cancel_and_wait()
218        self.assert_qmp(event, 'data/type', 'backup')
219
220    def test_pause(self):
221        self.assert_no_active_block_jobs()
222
223        self.vm.pause_drive('drive0')
224        result = self.vm.qmp('transaction', actions=[{
225                'type': 'drive-backup',
226                'data': { 'device': 'drive0',
227                          'target': target_img,
228                          'sync': 'full' },
229            }
230        ])
231        self.assert_qmp(result, 'return', {})
232
233        result = self.vm.qmp('block-job-pause', device='drive0')
234        self.assert_qmp(result, 'return', {})
235
236        self.vm.resume_drive('drive0')
237        time.sleep(1)
238        result = self.vm.qmp('query-block-jobs')
239        offset = self.dictpath(result, 'return[0]/offset')
240
241        time.sleep(1)
242        result = self.vm.qmp('query-block-jobs')
243        self.assert_qmp(result, 'return[0]/offset', offset)
244
245        result = self.vm.qmp('block-job-resume', device='drive0')
246        self.assert_qmp(result, 'return', {})
247
248        self.wait_until_completed()
249
250        self.vm.shutdown()
251        self.assertTrue(iotests.compare_images(test_img, target_img),
252                        'target image does not match source after backup')
253
254    def test_medium_not_found(self):
255        result = self.vm.qmp('transaction', actions=[{
256                'type': 'drive-backup',
257                'data': { 'device': 'ide1-cd0',
258                          'target': target_img,
259                          'sync': 'full' },
260            }
261        ])
262        self.assert_qmp(result, 'error/class', 'GenericError')
263
264    def test_image_not_found(self):
265        result = self.vm.qmp('transaction', actions=[{
266                'type': 'drive-backup',
267                'data': { 'device': 'drive0',
268                          'mode': 'existing',
269                          'target': target_img,
270                          'sync': 'full' },
271            }
272        ])
273        self.assert_qmp(result, 'error/class', 'GenericError')
274
275    def test_device_not_found(self):
276        result = self.vm.qmp('transaction', actions=[{
277                'type': 'drive-backup',
278                'data': { 'device': 'nonexistent',
279                          'mode': 'existing',
280                          'target': target_img,
281                          'sync': 'full' },
282            }
283        ])
284        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
285
286    def test_abort(self):
287        result = self.vm.qmp('transaction', actions=[{
288                'type': 'drive-backup',
289                'data': { 'device': 'nonexistent',
290                          'mode': 'existing',
291                          'target': target_img,
292                          'sync': 'full' },
293            }, {
294                'type': 'Abort',
295                'data': {},
296            }
297        ])
298        self.assert_qmp(result, 'error/class', 'GenericError')
299        self.assert_no_active_block_jobs()
300
301if __name__ == '__main__':
302    iotests.main(supported_fmts=['raw', 'qcow2'])
303