diff options
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/qemu-iotests/030 | 313 | ||||
-rw-r--r-- | tests/qemu-iotests/030.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/041 | 27 | ||||
-rw-r--r-- | tests/qemu-iotests/139 | 3 | ||||
-rwxr-xr-x | tests/qemu-iotests/171 | 212 | ||||
-rw-r--r-- | tests/qemu-iotests/171.out | 313 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
-rw-r--r-- | tests/qemu-iotests/iotests.py | 5 |
8 files changed, 858 insertions, 20 deletions
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 107049b50f..54db54a1ea 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -36,7 +36,7 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img) - self.vm = iotests.VM().add_drive("blkdebug::" + test_img) + self.vm = iotests.VM().add_drive("blkdebug::" + test_img, "backing.node-name=mid") self.vm.launch() def tearDown(self): @@ -60,6 +60,25 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') + def test_stream_intermediate(self): + self.assert_no_active_block_jobs() + + self.assertNotEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), + 'image file map matches backing file before streaming') + + result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid') + self.assert_qmp(result, 'return', {}) + + self.wait_until_completed(drive='stream-mid') + + self.assert_no_active_block_jobs() + self.vm.shutdown() + + self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), + 'image file map does not match backing file after streaming') + def test_stream_pause(self): self.assert_no_active_block_jobs() @@ -129,6 +148,298 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') +class TestParallelOps(iotests.QMPTestCase): + num_ops = 4 # Number of parallel block-stream operations + num_imgs = num_ops * 2 + 1 + image_len = num_ops * 1024 * 1024 + imgs = [] + + def setUp(self): + opts = [] + self.imgs = [] + + # Initialize file names and command-line options + for i in range(self.num_imgs): + img_depth = self.num_imgs - i - 1 + opts.append("backing." * img_depth + "node-name=node%d" % i) + self.imgs.append(os.path.join(iotests.test_dir, 'img-%d.img' % i)) + + # Create all images + iotests.create_image(self.imgs[0], self.image_len) + for i in range(1, self.num_imgs): + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i]) + + # Put data into the images we are copying data from + for i in range(self.num_imgs / 2): + img_index = i * 2 + 1 + # Alternate between 512k and 1M. + # This way jobs will not finish in the same order they were created + num_kb = 512 + 512 * (i % 2) + qemu_io('-f', iotests.imgfmt, + '-c', 'write -P %d %d %d' % (i, i*1024*1024, num_kb * 1024), + self.imgs[img_index]) + + # Attach the drive to the VM + self.vm = iotests.VM() + self.vm.add_drive(self.imgs[-1], ','.join(opts)) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + for img in self.imgs: + os.remove(img) + + # Test that it's possible to run several block-stream operations + # in parallel in the same snapshot chain + def test_stream_parallel(self): + self.assert_no_active_block_jobs() + + # Check that the maps don't match before the streaming operations + for i in range(2, self.num_imgs, 2): + self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), + 'image file map matches backing file before streaming') + + # Create all streaming jobs + pending_jobs = [] + for i in range(2, self.num_imgs, 2): + node_name = 'node%d' % i + job_id = 'stream-%s' % node_name + pending_jobs.append(job_id) + result = self.vm.qmp('block-stream', device=node_name, job_id=job_id, base=self.imgs[i-2], speed=512*1024) + self.assert_qmp(result, 'return', {}) + + # Wait for all jobs to be finished. + while len(pending_jobs) > 0: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + job_id = self.dictpath(event, 'data/device') + self.assertTrue(job_id in pending_jobs) + self.assert_qmp_absent(event, 'data/error') + pending_jobs.remove(job_id) + + self.assert_no_active_block_jobs() + self.vm.shutdown() + + # Check that all maps match now + for i in range(2, self.num_imgs, 2): + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), + 'image file map does not match backing file after streaming') + + # Test that it's not possible to perform two block-stream + # operations if there are nodes involved in both. + def test_overlapping_1(self): + self.assert_no_active_block_jobs() + + # Set a speed limit to make sure that this job blocks the rest + result = self.vm.qmp('block-stream', device='node4', job_id='stream-node4', base=self.imgs[1], speed=1024*1024) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block-stream', device='node5', job_id='stream-node5', base=self.imgs[2]) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-stream', device='node3', job_id='stream-node3', base=self.imgs[2]) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-stream', device='node4', job_id='stream-node4-v2') + self.assert_qmp(result, 'error/class', 'GenericError') + + # block-commit should also fail if it touches nodes used by the stream job + result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[4], job_id='commit-node4') + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[1], top=self.imgs[3], job_id='commit-node1') + self.assert_qmp(result, 'error/class', 'GenericError') + + # This fails because it needs to modify the backing string in node2, which is blocked + result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[0], top=self.imgs[1], job_id='commit-node0') + self.assert_qmp(result, 'error/class', 'GenericError') + + self.wait_until_completed(drive='stream-node4') + self.assert_no_active_block_jobs() + + # Similar to test_overlapping_1, but with block-commit + # blocking the other jobs + def test_overlapping_2(self): + self.assertLessEqual(9, self.num_imgs) + self.assert_no_active_block_jobs() + + # Set a speed limit to make sure that this job blocks the rest + result = self.vm.qmp('block-commit', device='drive0', top=self.imgs[5], base=self.imgs[3], job_id='commit-node3', speed=1024*1024) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block-stream', device='node3', job_id='stream-node3') + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-stream', device='node6', base=self.imgs[2], job_id='stream-node6') + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-stream', device='node4', base=self.imgs[2], job_id='stream-node4') + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block-stream', device='node6', base=self.imgs[4], job_id='stream-node6-v2') + self.assert_qmp(result, 'error/class', 'GenericError') + + # This fails because block-commit needs to block node6, the overlay of the 'top' image + result = self.vm.qmp('block-stream', device='node7', base=self.imgs[5], job_id='stream-node6-v3') + self.assert_qmp(result, 'error/class', 'GenericError') + + # This fails because block-commit currently blocks the active layer even if it's not used + result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0') + self.assert_qmp(result, 'error/class', 'GenericError') + + self.wait_until_completed(drive='commit-node3') + + # Similar to test_overlapping_2, but here block-commit doesn't use the 'top' parameter. + # Internally this uses a mirror block job, hence the separate test case. + def test_overlapping_3(self): + self.assertLessEqual(8, self.num_imgs) + self.assert_no_active_block_jobs() + + # Set a speed limit to make sure that this job blocks the rest + result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[3], job_id='commit-drive0', speed=1024*1024) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block-stream', device='node5', base=self.imgs[3], job_id='stream-node6') + self.assert_qmp(result, 'error/class', 'GenericError') + + event = self.vm.get_qmp_event(wait=True) + self.assertEqual(event['event'], 'BLOCK_JOB_READY') + self.assert_qmp(event, 'data/device', 'commit-drive0') + self.assert_qmp(event, 'data/type', 'commit') + self.assert_qmp_absent(event, 'data/error') + + result = self.vm.qmp('block-job-complete', device='commit-drive0') + self.assert_qmp(result, 'return', {}) + + self.wait_until_completed(drive='commit-drive0') + + # Test a block-stream and a block-commit job in parallel + def test_stream_commit(self): + self.assertLessEqual(8, self.num_imgs) + self.assert_no_active_block_jobs() + + # Stream from node0 into node2 + result = self.vm.qmp('block-stream', device='node2', job_id='node2') + self.assert_qmp(result, 'return', {}) + + # Commit from the active layer into node3 + result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[3]) + self.assert_qmp(result, 'return', {}) + + # Wait for all jobs to be finished. + pending_jobs = ['node2', 'drive0'] + while len(pending_jobs) > 0: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + node_name = self.dictpath(event, 'data/device') + self.assertTrue(node_name in pending_jobs) + self.assert_qmp_absent(event, 'data/error') + pending_jobs.remove(node_name) + if event['event'] == 'BLOCK_JOB_READY': + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/type', 'commit') + self.assert_qmp_absent(event, 'data/error') + self.assertTrue('drive0' in pending_jobs) + self.vm.qmp('block-job-complete', device='drive0') + + self.assert_no_active_block_jobs() + + # Test the base_node parameter + def test_stream_base_node_name(self): + self.assert_no_active_block_jobs() + + self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]), + 'image file map matches backing file before streaming') + + # Error: the base node does not exist + result = self.vm.qmp('block-stream', device='node4', base_node='none', job_id='stream') + self.assert_qmp(result, 'error/class', 'GenericError') + + # Error: the base node is not a backing file of the top node + result = self.vm.qmp('block-stream', device='node4', base_node='node6', job_id='stream') + self.assert_qmp(result, 'error/class', 'GenericError') + + # Error: the base node is the same as the top node + result = self.vm.qmp('block-stream', device='node4', base_node='node4', job_id='stream') + self.assert_qmp(result, 'error/class', 'GenericError') + + # Error: cannot specify 'base' and 'base-node' at the same time + result = self.vm.qmp('block-stream', device='node4', base=self.imgs[2], base_node='node2', job_id='stream') + self.assert_qmp(result, 'error/class', 'GenericError') + + # Success: the base node is a backing file of the top node + result = self.vm.qmp('block-stream', device='node4', base_node='node2', job_id='stream') + self.assert_qmp(result, 'return', {}) + + self.wait_until_completed(drive='stream') + + self.assert_no_active_block_jobs() + self.vm.shutdown() + + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]), + 'image file map matches backing file after streaming') + +class TestQuorum(iotests.QMPTestCase): + num_children = 3 + children = [] + backing = [] + + def setUp(self): + opts = ['driver=quorum', 'vote-threshold=2'] + + # Initialize file names and command-line options + for i in range(self.num_children): + child_img = os.path.join(iotests.test_dir, 'img-%d.img' % i) + backing_img = os.path.join(iotests.test_dir, 'backing-%d.img' % i) + self.children.append(child_img) + self.backing.append(backing_img) + qemu_img('create', '-f', iotests.imgfmt, backing_img, '1M') + qemu_io('-f', iotests.imgfmt, + '-c', 'write -P 0x55 0 1024', backing_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, child_img) + opts.append("children.%d.file.filename=%s" % (i, child_img)) + opts.append("children.%d.node-name=node%d" % (i, i)) + + # Attach the drive to the VM + self.vm = iotests.VM() + self.vm.add_drive(path = None, opts = ','.join(opts)) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + for img in self.children: + os.remove(img) + for img in self.backing: + os.remove(img) + + def test_stream_quorum(self): + if not iotests.supports_quorum(): + return + + self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]), + 'image file map matches backing file before streaming') + + self.assert_no_active_block_jobs() + + result = self.vm.qmp('block-stream', device='node0', job_id='stream-node0') + self.assert_qmp(result, 'return', {}) + + self.wait_until_completed(drive='stream-node0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() + + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]), + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]), + 'image file map does not match backing file after streaming') + class TestSmallerBackingFile(iotests.QMPTestCase): backing_len = 1 * 1024 * 1024 # MB image_len = 2 * backing_len diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out index 6323079e08..84bfd63fba 100644 --- a/tests/qemu-iotests/030.out +++ b/tests/qemu-iotests/030.out @@ -1,5 +1,5 @@ -.............. +...................... ---------------------------------------------------------------------- -Ran 14 tests +Ran 22 tests OK diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 30e628f0f7..bc6cf782fe 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -760,9 +760,6 @@ class TestRepairQuorum(iotests.QMPTestCase): image_len = 1 * 1024 * 1024 # MB IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ] - def has_quorum(self): - return 'quorum' in iotests.qemu_img_pipe('--help') - def setUp(self): self.vm = iotests.VM() @@ -783,7 +780,7 @@ class TestRepairQuorum(iotests.QMPTestCase): #assemble the quorum block device from the individual files args = { "driver": "quorum", "node-name": "quorum0", "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } - if self.has_quorum(): + if iotests.supports_quorum(): result = self.vm.qmp("blockdev-add", **args) self.assert_qmp(result, 'return', {}) @@ -798,7 +795,7 @@ class TestRepairQuorum(iotests.QMPTestCase): pass def test_complete(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return self.assert_no_active_block_jobs() @@ -817,7 +814,7 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_cancel(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return self.assert_no_active_block_jobs() @@ -834,7 +831,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.vm.shutdown() def test_cancel_after_ready(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return self.assert_no_active_block_jobs() @@ -853,7 +850,7 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_pause(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return self.assert_no_active_block_jobs() @@ -883,7 +880,7 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_medium_not_found(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return if iotests.qemu_default_machine != 'pc': @@ -897,7 +894,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_image_not_found(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -907,7 +904,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_device_not_found(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('drive-mirror', job_id='job0', @@ -918,7 +915,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_wrong_sync_mode(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('drive-mirror', device='quorum0', job_id='job0', @@ -928,7 +925,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_no_node_name(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -937,7 +934,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_nonexistent_replaces(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', @@ -946,7 +943,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_after_a_quorum_snapshot(self): - if not self.has_quorum(): + if not iotests.supports_quorum(): return result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index 6a0f6ca569..6d98e4f879 100644 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -336,8 +336,9 @@ class TestBlockdevDel(iotests.QMPTestCase): self.checkBlockDriverState('node1', False) def testQuorum(self): - if not 'quorum' in iotests.qemu_img_pipe('--help'): + if not iotests.supports_quorum(): return + self.addQuorum('quorum0', 'node0', 'node1') # We cannot remove the children of a Quorum device self.delBlockDriverState('node0', expect_error = True) diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 new file mode 100755 index 0000000000..257be10a0e --- /dev/null +++ b/tests/qemu-iotests/171 @@ -0,0 +1,212 @@ +#!/bin/bash +# +# Test 'offset' and 'size' options of the raw driver. Make sure we can't +# (or can) read and write outside of the image size. +# +# Copyright (C) 2016 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/>. +# + +# creator +owner=tgolembi@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt raw +_supported_proto file +_supported_os Linux + + +# Create JSON with options +img_json() { + echo -n 'json:{"driver":"raw", ' + echo -n "\"offset\":\"$img_offset\", " + if [ "$img_size" -ne -1 ] ; then + echo -n "\"size\":\"$img_size\", " + fi + echo -n '"file": {' + echo -n '"driver":"file", ' + echo -n "\"filename\":\"$TEST_IMG\" " + echo -n "} }" +} + +do_general_test() { + if [ "$img_size" -ge 0 ] ; then + test_size=$img_size + else + test_size=$((size-img_offset)) + fi + + echo + echo "write to image" + $QEMU_IO -c "write -P 0x0a 0 $test_size" "$(img_json)" | _filter_qemu_io + + echo + echo "read the image" + $QEMU_IO -c "read -P 0x0a 0 $test_size" "$(img_json)" | _filter_qemu_io + + echo + echo "check that offset is respected" + $QEMU_IO -c "read -v $((img_offset-2)) 4" $TEST_IMG | _filter_qemu_io + + echo + echo "write before image boundary" + $QEMU_IO -c "write $((test_size-1)) 1" "$(img_json)" | _filter_qemu_io + + echo + echo "write across image boundary" + $QEMU_IO -c "write $((test_size-1)) 2" "$(img_json)" | _filter_qemu_io + + echo + echo "write at image boundary" + $QEMU_IO -c "write $test_size 1" "$(img_json)" | _filter_qemu_io + + echo + echo "write after image boundary" + $QEMU_IO -c "write $((test_size+512)) 1" "$(img_json)" | _filter_qemu_io + + echo + echo "writev before/after image boundary" + $QEMU_IO -c "writev $((test_size-512)) 512 512" "$(img_json)" | _filter_qemu_io + + echo + echo "read before image boundary" + $QEMU_IO -c "read $((test_size-1)) 1" "$(img_json)" | _filter_qemu_io + + echo + echo "read across image boundary" + $QEMU_IO -c "read $((test_size-1)) 2" "$(img_json)" | _filter_qemu_io + + echo + echo "read at image boundary" + $QEMU_IO -c "read $test_size 1" "$(img_json)" | _filter_qemu_io + + echo + echo "read after image boundary" + $QEMU_IO -c "read $((test_size+512)) 1" "$(img_json)" | _filter_qemu_io + + echo + echo "readv before/after image boundary" + $QEMU_IO -c "readv $((test_size-512)) 512 512" "$(img_json)" | _filter_qemu_io + + echo + echo "fill image with pattern" + $QEMU_IO -c "write -P 0x0a 0 $size" $TEST_IMG | _filter_qemu_io + + echo + echo "write zeroes and check" + $QEMU_IO -c "write -z 0 512" "$(img_json)" | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset-2)) 4" $TEST_IMG | _filter_qemu_io + + echo + echo "write zeroes across image boundary" + $QEMU_IO -c "write -z $((test_size-1)) 2" "$(img_json)" | _filter_qemu_io + + echo + echo "write zeroes at image boundary and check" + $QEMU_IO -c "write -z $((test_size-2)) 2" "$(img_json)" | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset+test_size-2)) 2" $TEST_IMG | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset+test_size)) 2" $TEST_IMG | _filter_qemu_io + + echo + echo "fill image with pattern" + $QEMU_IO -c "write -P 0x0a 0 $size" $TEST_IMG | _filter_qemu_io + + echo + echo "discard and check" + $QEMU_IO -c "discard 0 512" "$(img_json)" | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset-2)) 4" $TEST_IMG | _filter_qemu_io + + echo + echo "discard across image boundary" + $QEMU_IO -c "discard $((test_size-1)) 2" "$(img_json)" | _filter_qemu_io + + echo + echo "discard at image boundary and check" + $QEMU_IO -c "discard $((test_size-2)) 2" "$(img_json)" | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset+test_size-2)) 2" $TEST_IMG | _filter_qemu_io + $QEMU_IO -c "read -v $((img_offset+test_size)) 2" $TEST_IMG | _filter_qemu_io +} + +echo +echo "== test 'offset' option ==" +size=4096 +img_offset=512 +img_size=-1 +_make_test_img $size +do_general_test +_cleanup_test_img + +echo +echo "== test 'offset' and 'size' options ==" +size=4096 +img_offset=512 +img_size=2048 +_make_test_img $size +do_general_test +_cleanup_test_img + +echo +echo "== test misaligned 'offset' ==" +size=4096 +img_offset=10 +img_size=2048 +_make_test_img $size +do_general_test +_cleanup_test_img + +echo +echo "== test reopen ==" +size=4096 +img_offset=512 +img_size=512 +_make_test_img $size +( +$QEMU_IO "$(img_json)" <<EOT +write -P 0x0a 0 512 +write -P 0x0a 511 1 +write -P 0x0a 512 1 +reopen -o driver=raw,offset=1536,size=1024 +write -P 0x0a 0 1024 +write -P 0x0a 1023 1 +write -P 0x0a 1024 1 +EOT +) | _filter_qemu_io +echo "checking boundaries" +$QEMU_IO -c "read -v 510 4" $TEST_IMG | _filter_qemu_io +$QEMU_IO -c "read -v 1022 4" $TEST_IMG | _filter_qemu_io +$QEMU_IO -c "read -v 1534 4" $TEST_IMG | _filter_qemu_io +$QEMU_IO -c "read -v 2558 4" $TEST_IMG | _filter_qemu_io +_cleanup_test_img + +# success, all done +echo +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/171.out b/tests/qemu-iotests/171.out new file mode 100644 index 0000000000..ec3363b4f4 --- /dev/null +++ b/tests/qemu-iotests/171.out @@ -0,0 +1,313 @@ +QA output created by 171 + +== test 'offset' option == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 + +write to image +wrote 3584/3584 bytes at offset 0 +3.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read the image +read 3584/3584 bytes at offset 0 +3.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +check that offset is respected +000001fe: 00 00 0a 0a .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write before image boundary +wrote 1/1 bytes at offset 3583 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write across image boundary +write failed: Input/output error + +write at image boundary +write failed: Input/output error + +write after image boundary +write failed: Input/output error + +writev before/after image boundary +writev failed: Input/output error + +read before image boundary +read 1/1 bytes at offset 3583 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read across image boundary +read failed: Input/output error + +read at image boundary +read failed: Input/output error + +read after image boundary +read failed: Input/output error + +readv before/after image boundary +readv failed: Input/output error + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes and check +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000001fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes across image boundary +write failed: Input/output error + +write zeroes at image boundary and check +wrote 2/2 bytes at offset 3582 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000ffe: 00 00 .. +read 2/2 bytes at offset 4094 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read failed: Input/output error + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard and check +discard 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000001fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard across image boundary +discard failed: Input/output error + +discard at image boundary and check +discard 2/2 bytes at offset 3582 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000ffe: 00 00 .. +read 2/2 bytes at offset 4094 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read failed: Input/output error + +== test 'offset' and 'size' options == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 + +write to image +wrote 2048/2048 bytes at offset 0 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read the image +read 2048/2048 bytes at offset 0 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +check that offset is respected +000001fe: 00 00 0a 0a .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write before image boundary +wrote 1/1 bytes at offset 2047 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write across image boundary +write failed: Input/output error + +write at image boundary +write failed: Input/output error + +write after image boundary +write failed: Input/output error + +writev before/after image boundary +writev failed: Input/output error + +read before image boundary +read 1/1 bytes at offset 2047 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read across image boundary +read failed: Input/output error + +read at image boundary +read failed: Input/output error + +read after image boundary +read failed: Input/output error + +readv before/after image boundary +readv failed: Input/output error + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes and check +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000001fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes across image boundary +write failed: Input/output error + +write zeroes at image boundary and check +wrote 2/2 bytes at offset 2046 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000009fe: 00 00 .. +read 2/2 bytes at offset 2558 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000a00: 0a 0a .. +read 2/2 bytes at offset 2560 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard and check +discard 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000001fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard across image boundary +discard failed: Input/output error + +discard at image boundary and check +discard 2/2 bytes at offset 2046 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000009fe: 00 00 .. +read 2/2 bytes at offset 2558 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000a00: 0a 0a .. +read 2/2 bytes at offset 2560 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== test misaligned 'offset' == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 + +write to image +wrote 2048/2048 bytes at offset 0 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read the image +read 2048/2048 bytes at offset 0 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +check that offset is respected +00000008: 00 00 0a 0a .... +read 4/4 bytes at offset 8 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write before image boundary +wrote 1/1 bytes at offset 2047 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write across image boundary +write failed: Input/output error + +write at image boundary +write failed: Input/output error + +write after image boundary +write failed: Input/output error + +writev before/after image boundary +writev failed: Input/output error + +read before image boundary +read 1/1 bytes at offset 2047 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read across image boundary +read failed: Input/output error + +read at image boundary +read failed: Input/output error + +read after image boundary +read failed: Input/output error + +readv before/after image boundary +readv failed: Input/output error + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes and check +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000008: 0a 0a 00 00 .... +read 4/4 bytes at offset 8 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +write zeroes across image boundary +write failed: Input/output error + +write zeroes at image boundary and check +wrote 2/2 bytes at offset 2046 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000808: 00 00 .. +read 2/2 bytes at offset 2056 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +0000080a: 0a 0a .. +read 2/2 bytes at offset 2058 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +fill image with pattern +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard and check +discard 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000008: 0a 0a 00 00 .... +read 4/4 bytes at offset 8 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +discard across image boundary +discard failed: Input/output error + +discard at image boundary and check +discard 2/2 bytes at offset 2046 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +00000808: 00 00 .. +read 2/2 bytes at offset 2056 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +0000080a: 0a 0a .. +read 2/2 bytes at offset 2058 +2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== test reopen == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1/1 bytes at offset 511 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +write failed: Input/output error +wrote 1024/1024 bytes at offset 0 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1/1 bytes at offset 1023 +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +write failed: Input/output error +checking boundaries +000001fe: 00 00 0a 0a .... +read 4/4 bytes at offset 510 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000003fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 1022 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000005fe: 00 00 0a 0a .... +read 4/4 bytes at offset 1534 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +000009fe: 0a 0a 00 00 .... +read 4/4 bytes at offset 2558 +4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 597fc2c952..866c1a032d 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -163,4 +163,5 @@ 160 rw auto quick 162 auto quick 170 rw auto quick +171 rw auto quick 172 auto diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 1f30cfcc75..bec8eb4b8d 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -348,9 +348,12 @@ def verify_platform(supported_oses=['linux']): if True not in [sys.platform.startswith(x) for x in supported_oses]: notrun('not suitable for this OS: %s' % sys.platform) +def supports_quorum(): + return 'quorum' in qemu_img_pipe('--help') + def verify_quorum(): '''Skip test suite if quorum support is not available''' - if 'quorum' not in qemu_img_pipe('--help'): + if not supports_quorum(): notrun('quorum support missing') def main(supported_fmts=[], supported_oses=['linux']): |