diff mbox series

[v14,4/4] iotests: 287: add qcow2 compression type test

Message ID 20200331174455.31792-5-dplotnikov@virtuozzo.com
State New
Headers show
Series qcow2: Implement zstd cluster compression method | expand

Commit Message

Denis Plotnikov March 31, 2020, 5:44 p.m. UTC
The test checks fulfilling qcow2 requiriements for the compression
type feature and zstd compression type operability.

Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 tests/qemu-iotests/287     | 128 +++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/287.out |  43 +++++++++++++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 172 insertions(+)
 create mode 100755 tests/qemu-iotests/287
 create mode 100644 tests/qemu-iotests/287.out

Comments

Eric Blake March 31, 2020, 6:43 p.m. UTC | #1
On 3/31/20 12:44 PM, Denis Plotnikov wrote:
> The test checks fulfilling qcow2 requiriements for the compression
> type feature and zstd compression type operability.
> 
> Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
>   tests/qemu-iotests/287     | 128 +++++++++++++++++++++++++++++++++++++
>   tests/qemu-iotests/287.out |  43 +++++++++++++
>   tests/qemu-iotests/group   |   1 +
>   3 files changed, 172 insertions(+)
>   create mode 100755 tests/qemu-iotests/287
>   create mode 100644 tests/qemu-iotests/287.out
> 

> +
> +# Check if we can run this test.
> +
> +IMGOPTS='compression_type=zstd' _make_test_img 64M | grep "Invalid parameter 'zstd'" 2>&1 1>/dev/null
> +
> +ZSTD_SUPPORTED=$?
> +
> +if (($ZSTD_SUPPORTED==0)); then

This is a bash script, so (()) works; but the bash manual documents that 
(()) is not idiomatic.  Also, what you have is rather verbose...

> +    _notrun "ZSTD is disabled"
> +fi

...I might have written:

if IMGOPTS='compression_type=zstd' _make_test_img 64M |
     grep "Invalid parameter 'zstd'"; then
     _notrun "ZSTD is disabled"
fi


> +# Test: an image can't be openned if compression type is zlib and

opened

> +#       incompatible feature compression type is set
> +echo
> +echo "=== Testing zlib with incompatible bit set  ==="
> +echo
> +
> +IMGOPTS='compression_type=zlib' _make_test_img 64M
> +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
> +# to make sure the bit was actually set
> +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
> +$QEMU_IMG info "$TEST_IMG" 2>1 1>/dev/null
> +if (($?==0)); then
> +    echo "Error: The image openned successfully. The image must not be openned"

twice more

> +fi
> +
> +# Test: an image can't be openned if compression type is NOT zlib and

and again.  Multiple spots in the file, I'll quit pointing them out.

> +#       incompatible feature compression type is UNSET
> +echo
> +echo "=== Testing zstd with incompatible bit unset  ==="

Why the double space?

> +# Test: using zstd compression, write to and read from an image
> +echo
> +echo "=== Testing reading and writing with zstd ==="
> +echo
> +
> +IMGOPTS='compression_type=zstd' _make_test_img 64M
> +$QEMU_IO -c "write -c -P 0xAC 65536 64k " "$TEST_IMG" | _filter_qemu_io

That's only one cluster.  Wouldn't it be better to write more than one, 
to prove that we handle back-to-back compressed clusters resulting from 
back-to-back inputs?

> +$QEMU_IO -c "read -P 0xAC 65536 65536 " "$TEST_IMG" | _filter_qemu_io

And if you do compress more than one cluster, you may also want to use 
different patterns over those various clusters.

> +$QEMU_IO -c "read -v 131070 8 " "$TEST_IMG" | _filter_qemu_io
> +$QEMU_IO -c "read -v 65534 8" "$TEST_IMG" | _filter_qemu_io
> +
> +# success, all done
> +echo "*** done"

Is it also worth trying to generate an image with (pseudo-)random 
contents, and trying qemu-img convert to prove that uncompressable 
clusters are handled sanely?  Ideally, there would be a way to use a 
fixed PRNG and seed that produces a deterministic sequence that cannot 
be compressed, but even if we can't meet the ideal, having a test that 
non-deterministically is likely to generate an uncompressable cluster in 
most runs is better than nothing (such as 1M of data copied from 
/dev/urandom, then qemu-img convert on that data).
Eric Blake March 31, 2020, 6:58 p.m. UTC | #2
On 3/31/20 1:43 PM, Eric Blake wrote:

> Is it also worth trying to generate an image with (pseudo-)random 
> contents, and trying qemu-img convert to prove that uncompressable 
> clusters are handled sanely?  Ideally, there would be a way to use a 
> fixed PRNG and seed that produces a deterministic sequence that cannot 
> be compressed, but even if we can't meet the ideal, having a test that 
> non-deterministically is likely to generate an uncompressable cluster in 
> most runs is better than nothing (such as 1M of data copied from 
> /dev/urandom, then qemu-img convert on that data).

For an example,

nbdkit -U - random 1M seed=1234 --run 'qemu-img convert $nbd file'

produces 'file' containing deterministic pseudo-random data.  And 'zstd 
file' proves that the data was non-compressible in bulk:
$ zstd file
file                  :100.00%   (1048576 => 1048613 bytes, file.zst)

In fact, inspecting od output, I can see that the first few bytes of the 
original file are replayed verbatim after a 12-byte header in the .zst file.

But we don't have any other uses of nbdkit in our iotests, so I'm not 
sure if making this the first test to depend on that is ideal.
Denis Plotnikov April 1, 2020, 7:13 a.m. UTC | #3
On 31.03.2020 21:43, Eric Blake wrote:
> On 3/31/20 12:44 PM, Denis Plotnikov wrote:
>> The test checks fulfilling qcow2 requiriements for the compression
>> type feature and zstd compression type operability.
>>
>> Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
>> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> ---
>>   tests/qemu-iotests/287     | 128 +++++++++++++++++++++++++++++++++++++
>>   tests/qemu-iotests/287.out |  43 +++++++++++++
>>   tests/qemu-iotests/group   |   1 +
>>   3 files changed, 172 insertions(+)
>>   create mode 100755 tests/qemu-iotests/287
>>   create mode 100644 tests/qemu-iotests/287.out
>>
>
>> +
>> +# Check if we can run this test.
>> +
>> +IMGOPTS='compression_type=zstd' _make_test_img 64M | grep "Invalid 
>> parameter 'zstd'" 2>&1 1>/dev/null
>> +
>> +ZSTD_SUPPORTED=$?
>> +
>> +if (($ZSTD_SUPPORTED==0)); then
>
> This is a bash script, so (()) works; but the bash manual documents 
> that (()) is not idiomatic.  Also, what you have is rather verbose...
>
>> +    _notrun "ZSTD is disabled"
>> +fi
>
> ...I might have written:
>
> if IMGOPTS='compression_type=zstd' _make_test_img 64M |
>     grep "Invalid parameter 'zstd'"; then
>     _notrun "ZSTD is disabled"
> fi
yes, this on is shorter
>
>
>> +# Test: an image can't be openned if compression type is zlib and
>
> opened
>
>> +#       incompatible feature compression type is set
>> +echo
>> +echo "=== Testing zlib with incompatible bit set  ==="
>> +echo
>> +
>> +IMGOPTS='compression_type=zlib' _make_test_img 64M
>> +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
>> +# to make sure the bit was actually set
>> +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
>> +$QEMU_IMG info "$TEST_IMG" 2>1 1>/dev/null
>> +if (($?==0)); then
>> +    echo "Error: The image openned successfully. The image must not 
>> be openned"
>
> twice more
>
>> +fi
>> +
>> +# Test: an image can't be openned if compression type is NOT zlib and
>
> and again.  Multiple spots in the file, I'll quit pointing them out.
>
>> +#       incompatible feature compression type is UNSET
>> +echo
>> +echo "=== Testing zstd with incompatible bit unset  ==="
>
> Why the double space?
>
>> +# Test: using zstd compression, write to and read from an image
>> +echo
>> +echo "=== Testing reading and writing with zstd ==="
>> +echo
>> +
>> +IMGOPTS='compression_type=zstd' _make_test_img 64M
>> +$QEMU_IO -c "write -c -P 0xAC 65536 64k " "$TEST_IMG" | _filter_qemu_io
>
> That's only one cluster.  Wouldn't it be better to write more than 
> one, to prove that we handle back-to-back compressed clusters 
> resulting from back-to-back inputs?
I'll add a case for back-to-back compressed clusters
>
>
>> +$QEMU_IO -c "read -P 0xAC 65536 65536 " "$TEST_IMG" | _filter_qemu_io
>
> And if you do compress more than one cluster, you may also want to use 
> different patterns over those various clusters.
>
>> +$QEMU_IO -c "read -v 131070 8 " "$TEST_IMG" | _filter_qemu_io
>> +$QEMU_IO -c "read -v 65534 8" "$TEST_IMG" | _filter_qemu_io
>> +
>> +# success, all done
>> +echo "*** done"
>
> Is it also worth trying to generate an image with (pseudo-)random 
> contents, and trying qemu-img convert to prove that uncompressable 
> clusters are handled sanely?  Ideally, there would be a way to use a 
> fixed PRNG and seed that produces a deterministic sequence that cannot 
> be compressed, but even if we can't meet the ideal, having a test that 
> non-deterministically is likely to generate an uncompressable cluster 
> in most runs is better than nothing (such as 1M of data copied from 
> /dev/urandom, then qemu-img convert on that data).
And, I'll try to add a case for incompressible data.

Thanks
diff mbox series

Patch

diff --git a/tests/qemu-iotests/287 b/tests/qemu-iotests/287
new file mode 100755
index 0000000000..49d15b3d43
--- /dev/null
+++ b/tests/qemu-iotests/287
@@ -0,0 +1,128 @@ 
+#!/usr/bin/env bash
+#
+# Test case for an image using zstd compression
+#
+# Copyright (c) 2020 Virtuozzo International GmbH
+#
+# 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=dplotnikov@virtuozzo.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# standard environment
+. ./common.rc
+. ./common.filter
+
+# This tests qocw2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+# for all the cases
+CLUSTER_SIZE=65536
+
+# Check if we can run this test.
+
+IMGOPTS='compression_type=zstd' _make_test_img 64M | grep "Invalid parameter 'zstd'" 2>&1 1>/dev/null
+
+ZSTD_SUPPORTED=$?
+
+if (($ZSTD_SUPPORTED==0)); then
+    _notrun "ZSTD is disabled"
+fi
+
+# Test: when compression is zlib the incompatible bit is unset
+echo
+echo "=== Testing compression type incompatible bit setting for zlib ==="
+echo
+
+IMGOPTS='compression_type=zlib' _make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+
+# Test: when compression differs from zlib the incompatible bit is set
+echo
+echo "=== Testing compression type incompatible bit setting for zstd ==="
+echo
+
+IMGOPTS='compression_type=zstd' _make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+
+# Test: an image can't be openned if compression type is zlib and
+#       incompatible feature compression type is set
+echo
+echo "=== Testing zlib with incompatible bit set  ==="
+echo
+
+IMGOPTS='compression_type=zlib' _make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
+# to make sure the bit was actually set
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+$QEMU_IMG info "$TEST_IMG" 2>1 1>/dev/null
+if (($?==0)); then
+    echo "Error: The image openned successfully. The image must not be openned"
+fi
+
+# Test: an image can't be openned if compression type is NOT zlib and
+#       incompatible feature compression type is UNSET
+echo
+echo "=== Testing zstd with incompatible bit unset  ==="
+echo
+
+IMGOPTS='compression_type=zstd' _make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" set-header incompatible_features 0
+# to make sure the bit was actually unset
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+$QEMU_IMG info "$TEST_IMG" 2>1 1>/dev/null
+if (($?==0)); then
+    echo "Error: The image openned successfully. The image must not be openned"
+fi
+# Test: check compression type values
+echo
+echo "=== Testing compression type values  ==="
+echo
+# zlib=0
+IMGOPTS='compression_type=zlib' _make_test_img 64M
+od -j104 -N1 -An -vtu1 "$TEST_IMG"
+
+# zstd=1
+IMGOPTS='compression_type=zstd' _make_test_img 64M
+od -j104 -N1 -An -vtu1 "$TEST_IMG"
+
+# Test: using zstd compression, write to and read from an image
+echo
+echo "=== Testing reading and writing with zstd ==="
+echo
+
+IMGOPTS='compression_type=zstd' _make_test_img 64M
+$QEMU_IO -c "write -c -P 0xAC 65536 64k " "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "read -P 0xAC 65536 65536 " "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "read -v 131070 8 " "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "read -v 65534 8" "$TEST_IMG" | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/287.out b/tests/qemu-iotests/287.out
new file mode 100644
index 0000000000..8e51c3078d
--- /dev/null
+++ b/tests/qemu-iotests/287.out
@@ -0,0 +1,43 @@ 
+QA output created by 287
+
+=== Testing compression type incompatible bit setting for zlib ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+incompatible_features     []
+
+=== Testing compression type incompatible bit setting for zstd ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+incompatible_features     [3]
+
+=== Testing zlib with incompatible bit set  ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+incompatible_features     [3]
+
+=== Testing zstd with incompatible bit unset  ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+incompatible_features     []
+
+=== Testing compression type values  ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+   0
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+   1
+
+=== Testing reading and writing with zstd ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+0001fffe:  ac ac 00 00 00 00 00 00  ........
+read 8/8 bytes at offset 131070
+8 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+0000fffe:  00 00 ac ac ac ac ac ac  ........
+read 8/8 bytes at offset 65534
+8 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 79c6dfc85d..dacbcfc12d 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -294,5 +294,6 @@ 
 283 auto quick
 284 rw
 286 rw quick
+287 auto quick
 288 quick
 289 rw quick