]>
Commit | Line | Data |
---|---|---|
44c7ca5e PB |
1 | #!/usr/bin/env python |
2 | # | |
3 | # Tests for image mirroring. | |
4 | # | |
5 | # Copyright (C) 2012 Red Hat, Inc. | |
6 | # | |
7 | # This program is free software; you can redistribute it and/or modify | |
8 | # it under the terms of the GNU General Public License as published by | |
9 | # the Free Software Foundation; either version 2 of the License, or | |
10 | # (at your option) any later version. | |
11 | # | |
12 | # This program is distributed in the hope that it will be useful, | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | # GNU General Public License for more details. | |
16 | # | |
17 | # You should have received a copy of the GNU General Public License | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | # | |
20 | ||
21 | import time | |
22 | import os | |
23 | import iotests | |
24 | from iotests import qemu_img, qemu_io | |
44c7ca5e PB |
25 | |
26 | backing_img = os.path.join(iotests.test_dir, 'backing.img') | |
27 | target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img') | |
28 | test_img = os.path.join(iotests.test_dir, 'test.img') | |
29 | target_img = os.path.join(iotests.test_dir, 'target.img') | |
30 | ||
d88964ae BC |
31 | quorum_img1 = os.path.join(iotests.test_dir, 'quorum1.img') |
32 | quorum_img2 = os.path.join(iotests.test_dir, 'quorum2.img') | |
33 | quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img') | |
34 | quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img') | |
35 | quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img') | |
36 | ||
866323f3 | 37 | class TestSingleDrive(iotests.QMPTestCase): |
44c7ca5e | 38 | image_len = 1 * 1024 * 1024 # MB |
94ca2c73 FZ |
39 | qmp_cmd = 'drive-mirror' |
40 | qmp_target = target_img | |
44c7ca5e PB |
41 | |
42 | def setUp(self): | |
3b9f27d2 | 43 | iotests.create_image(backing_img, self.image_len) |
44c7ca5e PB |
44 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) |
45 | self.vm = iotests.VM().add_drive(test_img) | |
0ed82f7a HR |
46 | if iotests.qemu_default_machine == 'pc': |
47 | self.vm.add_drive(None, 'media=cdrom', 'ide') | |
44c7ca5e PB |
48 | self.vm.launch() |
49 | ||
50 | def tearDown(self): | |
51 | self.vm.shutdown() | |
52 | os.remove(test_img) | |
53 | os.remove(backing_img) | |
54 | try: | |
55 | os.remove(target_img) | |
56 | except OSError: | |
57 | pass | |
58 | ||
59 | def test_complete(self): | |
ecc1c88e | 60 | self.assert_no_active_block_jobs() |
44c7ca5e | 61 | |
94ca2c73 FZ |
62 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
63 | target=self.qmp_target) | |
44c7ca5e PB |
64 | self.assert_qmp(result, 'return', {}) |
65 | ||
66 | self.complete_and_wait() | |
67 | result = self.vm.qmp('query-block') | |
68 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
69 | self.vm.shutdown() | |
3a3918c3 | 70 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
71 | 'target image does not match source after mirroring') |
72 | ||
73 | def test_cancel(self): | |
ecc1c88e | 74 | self.assert_no_active_block_jobs() |
44c7ca5e | 75 | |
94ca2c73 FZ |
76 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
77 | target=self.qmp_target) | |
44c7ca5e PB |
78 | self.assert_qmp(result, 'return', {}) |
79 | ||
2575fe16 | 80 | self.cancel_and_wait(force=True) |
44c7ca5e PB |
81 | result = self.vm.qmp('query-block') |
82 | self.assert_qmp(result, 'return[0]/inserted/file', test_img) | |
83 | self.vm.shutdown() | |
84 | ||
85 | def test_cancel_after_ready(self): | |
ecc1c88e | 86 | self.assert_no_active_block_jobs() |
44c7ca5e | 87 | |
94ca2c73 FZ |
88 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
89 | target=self.qmp_target) | |
44c7ca5e PB |
90 | self.assert_qmp(result, 'return', {}) |
91 | ||
2575fe16 | 92 | self.wait_ready_and_cancel() |
44c7ca5e PB |
93 | result = self.vm.qmp('query-block') |
94 | self.assert_qmp(result, 'return[0]/inserted/file', test_img) | |
95 | self.vm.shutdown() | |
3a3918c3 | 96 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
97 | 'target image does not match source after mirroring') |
98 | ||
99 | def test_pause(self): | |
ecc1c88e | 100 | self.assert_no_active_block_jobs() |
44c7ca5e | 101 | |
94ca2c73 FZ |
102 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
103 | target=self.qmp_target) | |
44c7ca5e PB |
104 | self.assert_qmp(result, 'return', {}) |
105 | ||
106 | result = self.vm.qmp('block-job-pause', device='drive0') | |
107 | self.assert_qmp(result, 'return', {}) | |
108 | ||
109 | time.sleep(1) | |
110 | result = self.vm.qmp('query-block-jobs') | |
111 | offset = self.dictpath(result, 'return[0]/offset') | |
112 | ||
113 | time.sleep(1) | |
114 | result = self.vm.qmp('query-block-jobs') | |
115 | self.assert_qmp(result, 'return[0]/offset', offset) | |
116 | ||
117 | result = self.vm.qmp('block-job-resume', device='drive0') | |
118 | self.assert_qmp(result, 'return', {}) | |
119 | ||
120 | self.complete_and_wait() | |
121 | self.vm.shutdown() | |
3a3918c3 | 122 | self.assertTrue(iotests.compare_images(test_img, target_img), |
08e4ed6c PB |
123 | 'target image does not match source after mirroring') |
124 | ||
125 | def test_small_buffer(self): | |
ecc1c88e | 126 | self.assert_no_active_block_jobs() |
08e4ed6c PB |
127 | |
128 | # A small buffer is rounded up automatically | |
94ca2c73 FZ |
129 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
130 | buf_size=4096, target=self.qmp_target) | |
08e4ed6c PB |
131 | self.assert_qmp(result, 'return', {}) |
132 | ||
133 | self.complete_and_wait() | |
134 | result = self.vm.qmp('query-block') | |
135 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
136 | self.vm.shutdown() | |
3a3918c3 | 137 | self.assertTrue(iotests.compare_images(test_img, target_img), |
08e4ed6c PB |
138 | 'target image does not match source after mirroring') |
139 | ||
140 | def test_small_buffer2(self): | |
ecc1c88e | 141 | self.assert_no_active_block_jobs() |
08e4ed6c PB |
142 | |
143 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' | |
3b9f27d2 | 144 | % (self.image_len, self.image_len), target_img) |
94ca2c73 FZ |
145 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
146 | buf_size=65536, mode='existing', target=self.qmp_target) | |
08e4ed6c PB |
147 | self.assert_qmp(result, 'return', {}) |
148 | ||
149 | self.complete_and_wait() | |
150 | result = self.vm.qmp('query-block') | |
151 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
152 | self.vm.shutdown() | |
3a3918c3 | 153 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
154 | 'target image does not match source after mirroring') |
155 | ||
156 | def test_large_cluster(self): | |
ecc1c88e | 157 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
158 | |
159 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' | |
3b9f27d2 | 160 | % (self.image_len, backing_img), target_img) |
94ca2c73 FZ |
161 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
162 | mode='existing', target=self.qmp_target) | |
44c7ca5e PB |
163 | self.assert_qmp(result, 'return', {}) |
164 | ||
165 | self.complete_and_wait() | |
166 | result = self.vm.qmp('query-block') | |
167 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
168 | self.vm.shutdown() | |
3a3918c3 | 169 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
170 | 'target image does not match source after mirroring') |
171 | ||
172 | def test_medium_not_found(self): | |
d8683155 BT |
173 | if iotests.qemu_default_machine != 'pc': |
174 | return | |
175 | ||
94ca2c73 FZ |
176 | result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full', |
177 | target=self.qmp_target) | |
0524e93a | 178 | self.assert_qmp(result, 'error/class', 'GenericError') |
44c7ca5e PB |
179 | |
180 | def test_image_not_found(self): | |
94ca2c73 FZ |
181 | result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', |
182 | mode='existing', target=self.qmp_target) | |
44c7ca5e PB |
183 | self.assert_qmp(result, 'error/class', 'GenericError') |
184 | ||
185 | def test_device_not_found(self): | |
94ca2c73 FZ |
186 | result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full', |
187 | target=self.qmp_target) | |
0524e93a | 188 | self.assert_qmp(result, 'error/class', 'GenericError') |
94ca2c73 FZ |
189 | |
190 | class TestSingleBlockdev(TestSingleDrive): | |
191 | qmp_cmd = 'blockdev-mirror' | |
192 | qmp_target = 'node1' | |
94ca2c73 FZ |
193 | |
194 | def setUp(self): | |
195 | TestSingleDrive.setUp(self) | |
196 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) | |
0153d2f5 KW |
197 | args = {'driver': iotests.imgfmt, |
198 | 'node-name': self.qmp_target, | |
199 | 'file': { 'filename': target_img, 'driver': 'file' } } | |
94ca2c73 FZ |
200 | result = self.vm.qmp("blockdev-add", **args) |
201 | self.assert_qmp(result, 'return', {}) | |
202 | ||
203 | test_large_cluster = None | |
204 | test_image_not_found = None | |
205 | test_small_buffer2 = None | |
206 | ||
3b9f27d2 FZ |
207 | class TestSingleDriveZeroLength(TestSingleDrive): |
208 | image_len = 0 | |
209 | test_small_buffer2 = None | |
210 | test_large_cluster = None | |
211 | ||
94ca2c73 FZ |
212 | class TestSingleBlockdevZeroLength(TestSingleBlockdev): |
213 | image_len = 0 | |
214 | ||
5a0f6fd5 KW |
215 | class TestSingleDriveUnalignedLength(TestSingleDrive): |
216 | image_len = 1025 * 1024 | |
217 | test_small_buffer2 = None | |
218 | test_large_cluster = None | |
219 | ||
94ca2c73 FZ |
220 | class TestSingleBlockdevUnalignedLength(TestSingleBlockdev): |
221 | image_len = 1025 * 1024 | |
222 | ||
866323f3 | 223 | class TestMirrorNoBacking(iotests.QMPTestCase): |
44c7ca5e PB |
224 | image_len = 2 * 1024 * 1024 # MB |
225 | ||
44c7ca5e | 226 | def setUp(self): |
2499a096 | 227 | iotests.create_image(backing_img, TestMirrorNoBacking.image_len) |
44c7ca5e PB |
228 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) |
229 | self.vm = iotests.VM().add_drive(test_img) | |
230 | self.vm.launch() | |
231 | ||
232 | def tearDown(self): | |
233 | self.vm.shutdown() | |
234 | os.remove(test_img) | |
235 | os.remove(backing_img) | |
866323f3 FZ |
236 | try: |
237 | os.remove(target_backing_img) | |
238 | except: | |
239 | pass | |
44c7ca5e PB |
240 | os.remove(target_img) |
241 | ||
242 | def test_complete(self): | |
ecc1c88e | 243 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
244 | |
245 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) | |
246 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
247 | mode='existing', target=target_img) | |
248 | self.assert_qmp(result, 'return', {}) | |
249 | ||
250 | self.complete_and_wait() | |
251 | result = self.vm.qmp('query-block') | |
252 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
253 | self.vm.shutdown() | |
866323f3 | 254 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
255 | 'target image does not match source after mirroring') |
256 | ||
257 | def test_cancel(self): | |
ecc1c88e | 258 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
259 | |
260 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) | |
261 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
262 | mode='existing', target=target_img) | |
263 | self.assert_qmp(result, 'return', {}) | |
264 | ||
2575fe16 | 265 | self.wait_ready_and_cancel() |
44c7ca5e PB |
266 | result = self.vm.qmp('query-block') |
267 | self.assert_qmp(result, 'return[0]/inserted/file', test_img) | |
268 | self.vm.shutdown() | |
866323f3 | 269 | self.assertTrue(iotests.compare_images(test_img, target_img), |
44c7ca5e PB |
270 | 'target image does not match source after mirroring') |
271 | ||
b812f671 | 272 | def test_large_cluster(self): |
ecc1c88e | 273 | self.assert_no_active_block_jobs() |
b812f671 PB |
274 | |
275 | # qemu-img create fails if the image is not there | |
276 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' | |
277 | %(TestMirrorNoBacking.image_len), target_backing_img) | |
278 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' | |
279 | % (TestMirrorNoBacking.image_len, target_backing_img), target_img) | |
b812f671 PB |
280 | |
281 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
282 | mode='existing', target=target_img) | |
283 | self.assert_qmp(result, 'return', {}) | |
284 | ||
285 | self.complete_and_wait() | |
286 | result = self.vm.qmp('query-block') | |
287 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
288 | self.vm.shutdown() | |
866323f3 | 289 | self.assertTrue(iotests.compare_images(test_img, target_img), |
b812f671 PB |
290 | 'target image does not match source after mirroring') |
291 | ||
866323f3 | 292 | class TestMirrorResized(iotests.QMPTestCase): |
a04eca10 VI |
293 | backing_len = 1 * 1024 * 1024 # MB |
294 | image_len = 2 * 1024 * 1024 # MB | |
295 | ||
296 | def setUp(self): | |
2499a096 | 297 | iotests.create_image(backing_img, TestMirrorResized.backing_len) |
a04eca10 VI |
298 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) |
299 | qemu_img('resize', test_img, '2M') | |
300 | self.vm = iotests.VM().add_drive(test_img) | |
301 | self.vm.launch() | |
302 | ||
303 | def tearDown(self): | |
304 | self.vm.shutdown() | |
305 | os.remove(test_img) | |
306 | os.remove(backing_img) | |
307 | try: | |
308 | os.remove(target_img) | |
309 | except OSError: | |
310 | pass | |
311 | ||
312 | def test_complete_top(self): | |
ecc1c88e | 313 | self.assert_no_active_block_jobs() |
a04eca10 VI |
314 | |
315 | result = self.vm.qmp('drive-mirror', device='drive0', sync='top', | |
316 | target=target_img) | |
317 | self.assert_qmp(result, 'return', {}) | |
318 | ||
319 | self.complete_and_wait() | |
320 | result = self.vm.qmp('query-block') | |
321 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
322 | self.vm.shutdown() | |
3a3918c3 | 323 | self.assertTrue(iotests.compare_images(test_img, target_img), |
a04eca10 VI |
324 | 'target image does not match source after mirroring') |
325 | ||
326 | def test_complete_full(self): | |
ecc1c88e | 327 | self.assert_no_active_block_jobs() |
a04eca10 VI |
328 | |
329 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
330 | target=target_img) | |
331 | self.assert_qmp(result, 'return', {}) | |
332 | ||
333 | self.complete_and_wait() | |
334 | result = self.vm.qmp('query-block') | |
335 | self.assert_qmp(result, 'return[0]/inserted/file', target_img) | |
336 | self.vm.shutdown() | |
3a3918c3 | 337 | self.assertTrue(iotests.compare_images(test_img, target_img), |
a04eca10 VI |
338 | 'target image does not match source after mirroring') |
339 | ||
866323f3 | 340 | class TestReadErrors(iotests.QMPTestCase): |
9dfa9f59 PB |
341 | image_len = 2 * 1024 * 1024 # MB |
342 | ||
343 | # this should be a multiple of twice the default granularity | |
344 | # so that we hit this offset first in state 1 | |
345 | MIRROR_GRANULARITY = 1024 * 1024 | |
346 | ||
347 | def create_blkdebug_file(self, name, event, errno): | |
348 | file = open(name, 'w') | |
349 | file.write(''' | |
350 | [inject-error] | |
351 | state = "1" | |
352 | event = "%s" | |
353 | errno = "%d" | |
354 | immediately = "off" | |
355 | once = "on" | |
356 | sector = "%d" | |
357 | ||
358 | [set-state] | |
359 | state = "1" | |
360 | event = "%s" | |
361 | new_state = "2" | |
362 | ||
363 | [set-state] | |
364 | state = "2" | |
365 | event = "%s" | |
366 | new_state = "1" | |
367 | ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) | |
368 | file.close() | |
369 | ||
370 | def setUp(self): | |
371 | self.blkdebug_file = backing_img + ".blkdebug" | |
2499a096 | 372 | iotests.create_image(backing_img, TestReadErrors.image_len) |
9dfa9f59 PB |
373 | self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) |
374 | qemu_img('create', '-f', iotests.imgfmt, | |
375 | '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' | |
376 | % (self.blkdebug_file, backing_img), | |
377 | test_img) | |
b812f671 PB |
378 | # Write something for tests that use sync='top' |
379 | qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536), | |
380 | test_img) | |
9dfa9f59 PB |
381 | self.vm = iotests.VM().add_drive(test_img) |
382 | self.vm.launch() | |
383 | ||
384 | def tearDown(self): | |
385 | self.vm.shutdown() | |
386 | os.remove(test_img) | |
387 | os.remove(backing_img) | |
388 | os.remove(self.blkdebug_file) | |
389 | ||
390 | def test_report_read(self): | |
ecc1c88e | 391 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
392 | |
393 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
394 | target=target_img) | |
395 | self.assert_qmp(result, 'return', {}) | |
396 | ||
397 | completed = False | |
398 | error = False | |
399 | while not completed: | |
400 | for event in self.vm.get_qmp_events(wait=True): | |
401 | if event['event'] == 'BLOCK_JOB_ERROR': | |
402 | self.assert_qmp(event, 'data/device', 'drive0') | |
403 | self.assert_qmp(event, 'data/operation', 'read') | |
404 | error = True | |
405 | elif event['event'] == 'BLOCK_JOB_READY': | |
406 | self.assertTrue(False, 'job completed unexpectedly') | |
407 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
408 | self.assertTrue(error, 'job completed unexpectedly') | |
409 | self.assert_qmp(event, 'data/type', 'mirror') | |
410 | self.assert_qmp(event, 'data/device', 'drive0') | |
411 | self.assert_qmp(event, 'data/error', 'Input/output error') | |
9dfa9f59 PB |
412 | completed = True |
413 | ||
ecc1c88e | 414 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
415 | self.vm.shutdown() |
416 | ||
417 | def test_ignore_read(self): | |
ecc1c88e | 418 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
419 | |
420 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
421 | target=target_img, on_source_error='ignore') | |
422 | self.assert_qmp(result, 'return', {}) | |
423 | ||
424 | event = self.vm.get_qmp_event(wait=True) | |
425 | self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') | |
426 | self.assert_qmp(event, 'data/device', 'drive0') | |
427 | self.assert_qmp(event, 'data/operation', 'read') | |
428 | result = self.vm.qmp('query-block-jobs') | |
429 | self.assert_qmp(result, 'return[0]/paused', False) | |
430 | self.complete_and_wait() | |
431 | self.vm.shutdown() | |
432 | ||
b812f671 | 433 | def test_large_cluster(self): |
ecc1c88e | 434 | self.assert_no_active_block_jobs() |
b812f671 PB |
435 | |
436 | # Test COW into the target image. The first half of the | |
437 | # cluster at MIRROR_GRANULARITY has to be copied from | |
438 | # backing_img, even though sync='top'. | |
439 | qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img) | |
440 | result = self.vm.qmp('drive-mirror', device='drive0', sync='top', | |
441 | on_source_error='ignore', | |
442 | mode='existing', target=target_img) | |
443 | self.assert_qmp(result, 'return', {}) | |
444 | ||
445 | event = self.vm.get_qmp_event(wait=True) | |
446 | self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') | |
447 | self.assert_qmp(event, 'data/device', 'drive0') | |
448 | self.assert_qmp(event, 'data/operation', 'read') | |
449 | result = self.vm.qmp('query-block-jobs') | |
450 | self.assert_qmp(result, 'return[0]/paused', False) | |
451 | self.complete_and_wait() | |
452 | self.vm.shutdown() | |
453 | ||
454 | # Detach blkdebug to compare images successfully | |
455 | qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) | |
3a3918c3 | 456 | self.assertTrue(iotests.compare_images(test_img, target_img), |
b812f671 PB |
457 | 'target image does not match source after mirroring') |
458 | ||
9dfa9f59 | 459 | def test_stop_read(self): |
ecc1c88e | 460 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
461 | |
462 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
463 | target=target_img, on_source_error='stop') | |
464 | self.assert_qmp(result, 'return', {}) | |
465 | ||
466 | error = False | |
467 | ready = False | |
468 | while not ready: | |
469 | for event in self.vm.get_qmp_events(wait=True): | |
470 | if event['event'] == 'BLOCK_JOB_ERROR': | |
471 | self.assert_qmp(event, 'data/device', 'drive0') | |
472 | self.assert_qmp(event, 'data/operation', 'read') | |
473 | ||
474 | result = self.vm.qmp('query-block-jobs') | |
475 | self.assert_qmp(result, 'return[0]/paused', True) | |
476 | self.assert_qmp(result, 'return[0]/io-status', 'failed') | |
477 | ||
478 | result = self.vm.qmp('block-job-resume', device='drive0') | |
479 | self.assert_qmp(result, 'return', {}) | |
480 | error = True | |
481 | elif event['event'] == 'BLOCK_JOB_READY': | |
482 | self.assertTrue(error, 'job completed unexpectedly') | |
483 | self.assert_qmp(event, 'data/device', 'drive0') | |
484 | ready = True | |
485 | ||
486 | result = self.vm.qmp('query-block-jobs') | |
487 | self.assert_qmp(result, 'return[0]/paused', False) | |
488 | self.assert_qmp(result, 'return[0]/io-status', 'ok') | |
489 | ||
490 | self.complete_and_wait(wait_ready=False) | |
ecc1c88e | 491 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
492 | self.vm.shutdown() |
493 | ||
866323f3 | 494 | class TestWriteErrors(iotests.QMPTestCase): |
9dfa9f59 PB |
495 | image_len = 2 * 1024 * 1024 # MB |
496 | ||
497 | # this should be a multiple of twice the default granularity | |
498 | # so that we hit this offset first in state 1 | |
499 | MIRROR_GRANULARITY = 1024 * 1024 | |
500 | ||
501 | def create_blkdebug_file(self, name, event, errno): | |
502 | file = open(name, 'w') | |
503 | file.write(''' | |
504 | [inject-error] | |
505 | state = "1" | |
506 | event = "%s" | |
507 | errno = "%d" | |
508 | immediately = "off" | |
509 | once = "on" | |
510 | sector = "%d" | |
511 | ||
512 | [set-state] | |
513 | state = "1" | |
514 | event = "%s" | |
515 | new_state = "2" | |
516 | ||
517 | [set-state] | |
518 | state = "2" | |
519 | event = "%s" | |
520 | new_state = "1" | |
521 | ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) | |
522 | file.close() | |
523 | ||
524 | def setUp(self): | |
525 | self.blkdebug_file = target_img + ".blkdebug" | |
2499a096 | 526 | iotests.create_image(backing_img, TestWriteErrors.image_len) |
9dfa9f59 PB |
527 | self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) |
528 | qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) | |
529 | self.vm = iotests.VM().add_drive(test_img) | |
530 | self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img) | |
531 | qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img) | |
532 | self.vm.launch() | |
533 | ||
534 | def tearDown(self): | |
535 | self.vm.shutdown() | |
536 | os.remove(test_img) | |
537 | os.remove(backing_img) | |
538 | os.remove(self.blkdebug_file) | |
539 | ||
540 | def test_report_write(self): | |
ecc1c88e | 541 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
542 | |
543 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
544 | mode='existing', target=self.target_img) | |
545 | self.assert_qmp(result, 'return', {}) | |
546 | ||
547 | completed = False | |
548 | error = False | |
549 | while not completed: | |
550 | for event in self.vm.get_qmp_events(wait=True): | |
551 | if event['event'] == 'BLOCK_JOB_ERROR': | |
552 | self.assert_qmp(event, 'data/device', 'drive0') | |
553 | self.assert_qmp(event, 'data/operation', 'write') | |
554 | error = True | |
555 | elif event['event'] == 'BLOCK_JOB_READY': | |
556 | self.assertTrue(False, 'job completed unexpectedly') | |
557 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
558 | self.assertTrue(error, 'job completed unexpectedly') | |
559 | self.assert_qmp(event, 'data/type', 'mirror') | |
560 | self.assert_qmp(event, 'data/device', 'drive0') | |
561 | self.assert_qmp(event, 'data/error', 'Input/output error') | |
9dfa9f59 PB |
562 | completed = True |
563 | ||
ecc1c88e | 564 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
565 | self.vm.shutdown() |
566 | ||
567 | def test_ignore_write(self): | |
ecc1c88e | 568 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
569 | |
570 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
571 | mode='existing', target=self.target_img, | |
572 | on_target_error='ignore') | |
573 | self.assert_qmp(result, 'return', {}) | |
574 | ||
575 | event = self.vm.get_qmp_event(wait=True) | |
576 | self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') | |
577 | self.assert_qmp(event, 'data/device', 'drive0') | |
578 | self.assert_qmp(event, 'data/operation', 'write') | |
579 | result = self.vm.qmp('query-block-jobs') | |
580 | self.assert_qmp(result, 'return[0]/paused', False) | |
581 | self.complete_and_wait() | |
582 | self.vm.shutdown() | |
583 | ||
584 | def test_stop_write(self): | |
ecc1c88e | 585 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
586 | |
587 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
588 | mode='existing', target=self.target_img, | |
589 | on_target_error='stop') | |
590 | self.assert_qmp(result, 'return', {}) | |
591 | ||
592 | error = False | |
593 | ready = False | |
594 | while not ready: | |
595 | for event in self.vm.get_qmp_events(wait=True): | |
596 | if event['event'] == 'BLOCK_JOB_ERROR': | |
597 | self.assert_qmp(event, 'data/device', 'drive0') | |
598 | self.assert_qmp(event, 'data/operation', 'write') | |
599 | ||
600 | result = self.vm.qmp('query-block-jobs') | |
601 | self.assert_qmp(result, 'return[0]/paused', True) | |
602 | self.assert_qmp(result, 'return[0]/io-status', 'failed') | |
603 | ||
604 | result = self.vm.qmp('block-job-resume', device='drive0') | |
605 | self.assert_qmp(result, 'return', {}) | |
606 | ||
607 | result = self.vm.qmp('query-block-jobs') | |
608 | self.assert_qmp(result, 'return[0]/paused', False) | |
609 | self.assert_qmp(result, 'return[0]/io-status', 'ok') | |
610 | error = True | |
611 | elif event['event'] == 'BLOCK_JOB_READY': | |
612 | self.assertTrue(error, 'job completed unexpectedly') | |
613 | self.assert_qmp(event, 'data/device', 'drive0') | |
614 | ready = True | |
615 | ||
616 | self.complete_and_wait(wait_ready=False) | |
ecc1c88e | 617 | self.assert_no_active_block_jobs() |
9dfa9f59 PB |
618 | self.vm.shutdown() |
619 | ||
866323f3 | 620 | class TestSetSpeed(iotests.QMPTestCase): |
44c7ca5e PB |
621 | image_len = 80 * 1024 * 1024 # MB |
622 | ||
623 | def setUp(self): | |
624 | qemu_img('create', backing_img, str(TestSetSpeed.image_len)) | |
625 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) | |
626 | self.vm = iotests.VM().add_drive(test_img) | |
627 | self.vm.launch() | |
628 | ||
629 | def tearDown(self): | |
630 | self.vm.shutdown() | |
631 | os.remove(test_img) | |
632 | os.remove(backing_img) | |
633 | os.remove(target_img) | |
634 | ||
635 | def test_set_speed(self): | |
ecc1c88e | 636 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
637 | |
638 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
639 | target=target_img) | |
640 | self.assert_qmp(result, 'return', {}) | |
641 | ||
642 | # Default speed is 0 | |
643 | result = self.vm.qmp('query-block-jobs') | |
644 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
645 | self.assert_qmp(result, 'return[0]/speed', 0) | |
646 | ||
647 | result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) | |
648 | self.assert_qmp(result, 'return', {}) | |
649 | ||
650 | # Ensure the speed we set was accepted | |
651 | result = self.vm.qmp('query-block-jobs') | |
652 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
653 | self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) | |
654 | ||
2575fe16 | 655 | self.wait_ready_and_cancel() |
44c7ca5e PB |
656 | |
657 | # Check setting speed in drive-mirror works | |
658 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
659 | target=target_img, speed=4*1024*1024) | |
660 | self.assert_qmp(result, 'return', {}) | |
661 | ||
662 | result = self.vm.qmp('query-block-jobs') | |
663 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
664 | self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) | |
665 | ||
2575fe16 | 666 | self.wait_ready_and_cancel() |
44c7ca5e PB |
667 | |
668 | def test_set_speed_invalid(self): | |
ecc1c88e | 669 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
670 | |
671 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
672 | target=target_img, speed=-1) | |
673 | self.assert_qmp(result, 'error/class', 'GenericError') | |
674 | ||
ecc1c88e | 675 | self.assert_no_active_block_jobs() |
44c7ca5e PB |
676 | |
677 | result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | |
678 | target=target_img) | |
679 | self.assert_qmp(result, 'return', {}) | |
680 | ||
681 | result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) | |
682 | self.assert_qmp(result, 'error/class', 'GenericError') | |
683 | ||
2575fe16 | 684 | self.wait_ready_and_cancel() |
44c7ca5e | 685 | |
866323f3 | 686 | class TestUnbackedSource(iotests.QMPTestCase): |
c15badee HR |
687 | image_len = 2 * 1024 * 1024 # MB |
688 | ||
689 | def setUp(self): | |
690 | qemu_img('create', '-f', iotests.imgfmt, test_img, | |
691 | str(TestUnbackedSource.image_len)) | |
692 | self.vm = iotests.VM().add_drive(test_img) | |
693 | self.vm.launch() | |
694 | ||
695 | def tearDown(self): | |
696 | self.vm.shutdown() | |
697 | os.remove(test_img) | |
698 | os.remove(target_img) | |
699 | ||
171d6431 HR |
700 | def test_absolute_paths_full(self): |
701 | self.assert_no_active_block_jobs() | |
702 | result = self.vm.qmp('drive-mirror', device='drive0', | |
703 | sync='full', target=target_img, | |
704 | mode='absolute-paths') | |
705 | self.assert_qmp(result, 'return', {}) | |
706 | self.complete_and_wait() | |
707 | self.assert_no_active_block_jobs() | |
708 | ||
709 | def test_absolute_paths_top(self): | |
710 | self.assert_no_active_block_jobs() | |
711 | result = self.vm.qmp('drive-mirror', device='drive0', | |
712 | sync='top', target=target_img, | |
713 | mode='absolute-paths') | |
714 | self.assert_qmp(result, 'return', {}) | |
715 | self.complete_and_wait() | |
c15badee HR |
716 | self.assert_no_active_block_jobs() |
717 | ||
171d6431 HR |
718 | def test_absolute_paths_none(self): |
719 | self.assert_no_active_block_jobs() | |
720 | result = self.vm.qmp('drive-mirror', device='drive0', | |
721 | sync='none', target=target_img, | |
722 | mode='absolute-paths') | |
723 | self.assert_qmp(result, 'return', {}) | |
724 | self.complete_and_wait() | |
725 | self.assert_no_active_block_jobs() | |
c15badee | 726 | |
ccee3d8f JS |
727 | class TestGranularity(iotests.QMPTestCase): |
728 | image_len = 10 * 1024 * 1024 # MB | |
729 | ||
730 | def setUp(self): | |
731 | qemu_img('create', '-f', iotests.imgfmt, test_img, | |
732 | str(TestGranularity.image_len)) | |
733 | qemu_io('-c', 'write 0 %d' % (self.image_len), | |
734 | test_img) | |
735 | self.vm = iotests.VM().add_drive(test_img) | |
736 | self.vm.launch() | |
737 | ||
738 | def tearDown(self): | |
739 | self.vm.shutdown() | |
740 | self.assertTrue(iotests.compare_images(test_img, target_img), | |
741 | 'target image does not match source after mirroring') | |
742 | os.remove(test_img) | |
743 | os.remove(target_img) | |
744 | ||
745 | def test_granularity(self): | |
746 | self.assert_no_active_block_jobs() | |
747 | result = self.vm.qmp('drive-mirror', device='drive0', | |
748 | sync='full', target=target_img, | |
749 | mode='absolute-paths', granularity=8192) | |
750 | self.assert_qmp(result, 'return', {}) | |
751 | event = self.vm.get_qmp_event(wait=60.0) | |
752 | # Failures will manifest as COMPLETED/ERROR. | |
753 | self.assert_qmp(event, 'event', 'BLOCK_JOB_READY') | |
754 | self.complete_and_wait(drive='drive0', wait_ready=False) | |
755 | self.assert_no_active_block_jobs() | |
756 | ||
866323f3 | 757 | class TestRepairQuorum(iotests.QMPTestCase): |
d88964ae BC |
758 | """ This class test quorum file repair using drive-mirror. |
759 | It's mostly a fork of TestSingleDrive """ | |
760 | image_len = 1 * 1024 * 1024 # MB | |
761 | IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ] | |
762 | ||
763 | def setUp(self): | |
764 | self.vm = iotests.VM() | |
765 | ||
0ed82f7a HR |
766 | if iotests.qemu_default_machine == 'pc': |
767 | self.vm.add_drive(None, 'media=cdrom', 'ide') | |
768 | ||
d88964ae BC |
769 | # Add each individual quorum images |
770 | for i in self.IMAGES: | |
771 | qemu_img('create', '-f', iotests.imgfmt, i, | |
772 | str(TestSingleDrive.image_len)) | |
773 | # Assign a node name to each quorum image in order to manipulate | |
774 | # them | |
775 | opts = "node-name=img%i" % self.IMAGES.index(i) | |
776 | self.vm = self.vm.add_drive(i, opts) | |
777 | ||
778 | self.vm.launch() | |
779 | ||
780 | #assemble the quorum block device from the individual files | |
0153d2f5 KW |
781 | args = { "driver": "quorum", "node-name": "quorum0", |
782 | "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } | |
b0f90495 | 783 | if iotests.supports_quorum(): |
a42a1fac BC |
784 | result = self.vm.qmp("blockdev-add", **args) |
785 | self.assert_qmp(result, 'return', {}) | |
d88964ae BC |
786 | |
787 | ||
788 | def tearDown(self): | |
789 | self.vm.shutdown() | |
790 | for i in self.IMAGES + [ quorum_repair_img ]: | |
791 | # Do a try/except because the test may have deleted some images | |
792 | try: | |
793 | os.remove(i) | |
794 | except OSError: | |
795 | pass | |
796 | ||
797 | def test_complete(self): | |
b0f90495 | 798 | if not iotests.supports_quorum(): |
a42a1fac BC |
799 | return |
800 | ||
d88964ae BC |
801 | self.assert_no_active_block_jobs() |
802 | ||
476fb028 KW |
803 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
804 | sync='full', node_name="repair0", replaces="img1", | |
d88964ae BC |
805 | target=quorum_repair_img, format=iotests.imgfmt) |
806 | self.assert_qmp(result, 'return', {}) | |
807 | ||
476fb028 | 808 | self.complete_and_wait(drive="job0") |
e71fc0ba | 809 | self.assert_has_block_node("repair0", quorum_repair_img) |
d88964ae BC |
810 | # TODO: a better test requiring some QEMU infrastructure will be added |
811 | # to check that this file is really driven by quorum | |
812 | self.vm.shutdown() | |
813 | self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), | |
814 | 'target image does not match source after mirroring') | |
815 | ||
816 | def test_cancel(self): | |
b0f90495 | 817 | if not iotests.supports_quorum(): |
a42a1fac BC |
818 | return |
819 | ||
d88964ae BC |
820 | self.assert_no_active_block_jobs() |
821 | ||
476fb028 KW |
822 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
823 | sync='full', node_name="repair0", replaces="img1", | |
d88964ae BC |
824 | target=quorum_repair_img, format=iotests.imgfmt) |
825 | self.assert_qmp(result, 'return', {}) | |
826 | ||
476fb028 | 827 | self.cancel_and_wait(drive="job0", force=True) |
d88964ae BC |
828 | # here we check that the last registered quorum file has not been |
829 | # swapped out and unref | |
e71fc0ba | 830 | self.assert_has_block_node(None, quorum_img3) |
d88964ae BC |
831 | self.vm.shutdown() |
832 | ||
833 | def test_cancel_after_ready(self): | |
b0f90495 | 834 | if not iotests.supports_quorum(): |
a42a1fac BC |
835 | return |
836 | ||
d88964ae BC |
837 | self.assert_no_active_block_jobs() |
838 | ||
476fb028 KW |
839 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
840 | sync='full', node_name="repair0", replaces="img1", | |
d88964ae BC |
841 | target=quorum_repair_img, format=iotests.imgfmt) |
842 | self.assert_qmp(result, 'return', {}) | |
843 | ||
476fb028 | 844 | self.wait_ready_and_cancel(drive="job0") |
d88964ae BC |
845 | # here we check that the last registered quorum file has not been |
846 | # swapped out and unref | |
e71fc0ba | 847 | self.assert_has_block_node(None, quorum_img3) |
d88964ae BC |
848 | self.vm.shutdown() |
849 | self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), | |
850 | 'target image does not match source after mirroring') | |
851 | ||
852 | def test_pause(self): | |
b0f90495 | 853 | if not iotests.supports_quorum(): |
a42a1fac BC |
854 | return |
855 | ||
d88964ae BC |
856 | self.assert_no_active_block_jobs() |
857 | ||
476fb028 KW |
858 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
859 | sync='full', node_name="repair0", replaces="img1", | |
d88964ae BC |
860 | target=quorum_repair_img, format=iotests.imgfmt) |
861 | self.assert_qmp(result, 'return', {}) | |
862 | ||
476fb028 | 863 | result = self.vm.qmp('block-job-pause', device='job0') |
d88964ae BC |
864 | self.assert_qmp(result, 'return', {}) |
865 | ||
866 | time.sleep(1) | |
867 | result = self.vm.qmp('query-block-jobs') | |
868 | offset = self.dictpath(result, 'return[0]/offset') | |
869 | ||
870 | time.sleep(1) | |
871 | result = self.vm.qmp('query-block-jobs') | |
872 | self.assert_qmp(result, 'return[0]/offset', offset) | |
873 | ||
476fb028 | 874 | result = self.vm.qmp('block-job-resume', device='job0') |
d88964ae BC |
875 | self.assert_qmp(result, 'return', {}) |
876 | ||
476fb028 | 877 | self.complete_and_wait(drive="job0") |
d88964ae BC |
878 | self.vm.shutdown() |
879 | self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), | |
880 | 'target image does not match source after mirroring') | |
881 | ||
882 | def test_medium_not_found(self): | |
b0f90495 | 883 | if not iotests.supports_quorum(): |
a42a1fac BC |
884 | return |
885 | ||
d8683155 BT |
886 | if iotests.qemu_default_machine != 'pc': |
887 | return | |
888 | ||
476fb028 | 889 | result = self.vm.qmp('drive-mirror', job_id='job0', device='drive0', # CD-ROM |
0ed82f7a | 890 | sync='full', |
d88964ae BC |
891 | node_name='repair0', |
892 | replaces='img1', | |
893 | target=quorum_repair_img, format=iotests.imgfmt) | |
894 | self.assert_qmp(result, 'error/class', 'GenericError') | |
895 | ||
896 | def test_image_not_found(self): | |
b0f90495 | 897 | if not iotests.supports_quorum(): |
a42a1fac BC |
898 | return |
899 | ||
476fb028 KW |
900 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
901 | sync='full', node_name='repair0', replaces='img1', | |
902 | mode='existing', target=quorum_repair_img, | |
903 | format=iotests.imgfmt) | |
d88964ae BC |
904 | self.assert_qmp(result, 'error/class', 'GenericError') |
905 | ||
906 | def test_device_not_found(self): | |
b0f90495 | 907 | if not iotests.supports_quorum(): |
a42a1fac BC |
908 | return |
909 | ||
476fb028 KW |
910 | result = self.vm.qmp('drive-mirror', job_id='job0', |
911 | device='nonexistent', sync='full', | |
d88964ae BC |
912 | node_name='repair0', |
913 | replaces='img1', | |
914 | target=quorum_repair_img, format=iotests.imgfmt) | |
0524e93a | 915 | self.assert_qmp(result, 'error/class', 'GenericError') |
d88964ae BC |
916 | |
917 | def test_wrong_sync_mode(self): | |
b0f90495 | 918 | if not iotests.supports_quorum(): |
a42a1fac BC |
919 | return |
920 | ||
476fb028 | 921 | result = self.vm.qmp('drive-mirror', device='quorum0', job_id='job0', |
d88964ae BC |
922 | node_name='repair0', |
923 | replaces='img1', | |
924 | target=quorum_repair_img, format=iotests.imgfmt) | |
925 | self.assert_qmp(result, 'error/class', 'GenericError') | |
926 | ||
927 | def test_no_node_name(self): | |
b0f90495 | 928 | if not iotests.supports_quorum(): |
a42a1fac BC |
929 | return |
930 | ||
476fb028 KW |
931 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
932 | sync='full', replaces='img1', | |
d88964ae BC |
933 | target=quorum_repair_img, format=iotests.imgfmt) |
934 | self.assert_qmp(result, 'error/class', 'GenericError') | |
935 | ||
67cc32eb | 936 | def test_nonexistent_replaces(self): |
b0f90495 | 937 | if not iotests.supports_quorum(): |
a42a1fac BC |
938 | return |
939 | ||
476fb028 KW |
940 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
941 | sync='full', node_name='repair0', replaces='img77', | |
d88964ae BC |
942 | target=quorum_repair_img, format=iotests.imgfmt) |
943 | self.assert_qmp(result, 'error/class', 'GenericError') | |
944 | ||
945 | def test_after_a_quorum_snapshot(self): | |
b0f90495 | 946 | if not iotests.supports_quorum(): |
a42a1fac BC |
947 | return |
948 | ||
d88964ae BC |
949 | result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', |
950 | snapshot_file=quorum_snapshot_file, | |
951 | snapshot_node_name="snap1"); | |
952 | ||
476fb028 KW |
953 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
954 | sync='full', node_name='repair0', replaces="img1", | |
d88964ae BC |
955 | target=quorum_repair_img, format=iotests.imgfmt) |
956 | self.assert_qmp(result, 'error/class', 'GenericError') | |
957 | ||
476fb028 KW |
958 | result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', |
959 | sync='full', node_name='repair0', replaces="snap1", | |
d88964ae BC |
960 | target=quorum_repair_img, format=iotests.imgfmt) |
961 | self.assert_qmp(result, 'return', {}) | |
962 | ||
476fb028 | 963 | self.complete_and_wait('job0') |
e71fc0ba | 964 | self.assert_has_block_node("repair0", quorum_repair_img) |
d88964ae BC |
965 | # TODO: a better test requiring some QEMU infrastructure will be added |
966 | # to check that this file is really driven by quorum | |
967 | self.vm.shutdown() | |
968 | ||
5694923a HR |
969 | # Test mirroring with a source that does not have any parents (not even a |
970 | # BlockBackend) | |
971 | class TestOrphanedSource(iotests.QMPTestCase): | |
972 | def setUp(self): | |
973 | blk0 = { 'node-name': 'src', | |
974 | 'driver': 'null-co' } | |
975 | ||
976 | blk1 = { 'node-name': 'dest', | |
977 | 'driver': 'null-co' } | |
978 | ||
979 | blk2 = { 'node-name': 'dest-ro', | |
980 | 'driver': 'null-co', | |
981 | 'read-only': 'on' } | |
982 | ||
983 | self.vm = iotests.VM() | |
984 | self.vm.add_blockdev(self.qmp_to_opts(blk0)) | |
985 | self.vm.add_blockdev(self.qmp_to_opts(blk1)) | |
986 | self.vm.add_blockdev(self.qmp_to_opts(blk2)) | |
987 | self.vm.launch() | |
988 | ||
989 | def tearDown(self): | |
990 | self.vm.shutdown() | |
991 | ||
992 | def test_no_job_id(self): | |
993 | self.assert_no_active_block_jobs() | |
994 | ||
995 | result = self.vm.qmp('blockdev-mirror', device='src', sync='full', | |
996 | target='dest') | |
997 | self.assert_qmp(result, 'error/class', 'GenericError') | |
998 | ||
999 | def test_success(self): | |
1000 | self.assert_no_active_block_jobs() | |
1001 | ||
1002 | result = self.vm.qmp('blockdev-mirror', job_id='job', device='src', | |
1003 | sync='full', target='dest') | |
1004 | self.assert_qmp(result, 'return', {}) | |
1005 | ||
1006 | self.complete_and_wait('job') | |
1007 | ||
1008 | def test_failing_permissions(self): | |
1009 | self.assert_no_active_block_jobs() | |
1010 | ||
1011 | result = self.vm.qmp('blockdev-mirror', device='src', sync='full', | |
1012 | target='dest-ro') | |
1013 | self.assert_qmp(result, 'error/class', 'GenericError') | |
1014 | ||
44c7ca5e PB |
1015 | if __name__ == '__main__': |
1016 | iotests.main(supported_fmts=['qcow2', 'qed']) |