Most of our Python unittest-style tests only support the file protocol. You can run them with any other protocol, but the test will simply ignore your choice and use file anyway. We should let them signal that they require the file protocol so they are skipped when you want to test some other protocol. Signed-off-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
147 lines
5.8 KiB
Python
Executable file
147 lines
5.8 KiB
Python
Executable file
#!/usr/bin/env python
|
|
#
|
|
# Tests for active mirroring
|
|
#
|
|
# Copyright (C) 2018 Red Hat, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
import os
|
|
import iotests
|
|
from iotests import qemu_img
|
|
|
|
source_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt)
|
|
target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
|
|
|
|
class TestActiveMirror(iotests.QMPTestCase):
|
|
image_len = 128 * 1024 * 1024 # MB
|
|
potential_writes_in_flight = True
|
|
|
|
def setUp(self):
|
|
qemu_img('create', '-f', iotests.imgfmt, source_img, '128M')
|
|
qemu_img('create', '-f', iotests.imgfmt, target_img, '128M')
|
|
|
|
blk_source = {'id': 'source',
|
|
'if': 'none',
|
|
'node-name': 'source-node',
|
|
'driver': iotests.imgfmt,
|
|
'file': {'driver': 'file',
|
|
'filename': source_img}}
|
|
|
|
blk_target = {'node-name': 'target-node',
|
|
'driver': iotests.imgfmt,
|
|
'file': {'driver': 'file',
|
|
'filename': target_img}}
|
|
|
|
self.vm = iotests.VM()
|
|
self.vm.add_drive_raw(self.vm.qmp_to_opts(blk_source))
|
|
self.vm.add_blockdev(self.vm.qmp_to_opts(blk_target))
|
|
self.vm.add_device('virtio-blk,drive=source')
|
|
self.vm.launch()
|
|
|
|
def tearDown(self):
|
|
self.vm.shutdown()
|
|
|
|
if not self.potential_writes_in_flight:
|
|
self.assertTrue(iotests.compare_images(source_img, target_img),
|
|
'mirror target does not match source')
|
|
|
|
os.remove(source_img)
|
|
os.remove(target_img)
|
|
|
|
def doActiveIO(self, sync_source_and_target):
|
|
# Fill the source image
|
|
self.vm.hmp_qemu_io('source',
|
|
'write -P 1 0 %i' % self.image_len);
|
|
|
|
# Start some background requests
|
|
for offset in range(1 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -P 2 %i 1M' % offset)
|
|
for offset in range(2 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
|
|
|
|
# Start the block job
|
|
result = self.vm.qmp('blockdev-mirror',
|
|
job_id='mirror',
|
|
filter_node_name='mirror-node',
|
|
device='source-node',
|
|
target='target-node',
|
|
sync='full',
|
|
copy_mode='write-blocking')
|
|
self.assert_qmp(result, 'return', {})
|
|
|
|
# Start some more requests
|
|
for offset in range(3 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset)
|
|
for offset in range(4 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
|
|
|
|
# Wait for the READY event
|
|
self.wait_ready(drive='mirror')
|
|
|
|
# Now start some final requests; all of these (which land on
|
|
# the source) should be settled using the active mechanism.
|
|
# The mirror code itself asserts that the source BDS's dirty
|
|
# bitmap will stay clean between READY and COMPLETED.
|
|
for offset in range(5 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset)
|
|
for offset in range(6 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024):
|
|
self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
|
|
|
|
if sync_source_and_target:
|
|
# If source and target should be in sync after the mirror,
|
|
# we have to flush before completion
|
|
self.vm.hmp_qemu_io('source', 'aio_flush')
|
|
self.potential_writes_in_flight = False
|
|
|
|
self.complete_and_wait(drive='mirror', wait_ready=False)
|
|
|
|
def testActiveIO(self):
|
|
self.doActiveIO(False)
|
|
|
|
def testActiveIOFlushed(self):
|
|
self.doActiveIO(True)
|
|
|
|
def testUnalignedActiveIO(self):
|
|
# Fill the source image
|
|
result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M')
|
|
|
|
# Start the block job (very slowly)
|
|
result = self.vm.qmp('blockdev-mirror',
|
|
job_id='mirror',
|
|
filter_node_name='mirror-node',
|
|
device='source-node',
|
|
target='target-node',
|
|
sync='full',
|
|
copy_mode='write-blocking',
|
|
buf_size=(1048576 // 4),
|
|
speed=1)
|
|
self.assert_qmp(result, 'return', {})
|
|
|
|
# Start an unaligned request to a dirty area
|
|
result = self.vm.hmp_qemu_io('source', 'write -P 2 %i 1' % (1048576 + 42))
|
|
|
|
# Let the job finish
|
|
result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0)
|
|
self.assert_qmp(result, 'return', {})
|
|
self.complete_and_wait(drive='mirror')
|
|
|
|
self.potential_writes_in_flight = False
|
|
|
|
|
|
if __name__ == '__main__':
|
|
iotests.main(supported_fmts=['qcow2', 'raw'],
|
|
supported_protocols=['file'])
|