3 # Tests for shrinking images
5 # Copyright (c) 2016-2017 Parallels International GmbH
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.
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.
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/>.
21 import os
, random
, iotests
, struct
, qcow2
22 from iotests
import qemu_img
, qemu_io
, image_size
24 test_img
= os
.path
.join(iotests
.test_dir
, 'test.img')
25 check_img
= os
.path
.join(iotests
.test_dir
, 'check.img')
28 suff
= ['B', 'K', 'M', 'G', 'T']
29 return int(str[:-1]) * 1024**suff
.index(str[-1:])
31 class ShrinkBaseClass(iotests
.QMPTestCase
):
37 def __qcow2_check(self
, filename
):
39 entry_size
= 1 << entry_bits
40 l1_mask
= 0x00fffffffffffe00
41 div_roundup
= lambda n
, d
: (n
+ d
- 1) / d
43 def split_by_n(data
, n
):
44 for x
in xrange(0, len(data
), n
):
45 yield struct
.unpack('>Q', data
[x
:x
+ n
])[0] & l1_mask
47 def check_l1_table(h
, l1_data
):
48 l1_list
= list(split_by_n(l1_data
, entry_size
))
49 real_l1_size
= div_roundup(h
.size
,
50 1 << (h
.cluster_bits
*2 - entry_size
))
51 used
, unused
= l1_list
[:real_l1_size
], l1_list
[real_l1_size
:]
53 self
.assertTrue(len(used
) != 0, "Verifying l1 table content")
54 self
.assertFalse(any(unused
), "Verifying l1 table content")
56 def check_reftable(fd
, h
, reftable
):
57 for offset
in split_by_n(reftable
, entry_size
):
60 cluster
= fd
.read(1 << h
.cluster_bits
)
61 self
.assertTrue(any(cluster
), "Verifying reftable content")
63 with
open(filename
, "rb") as fd
:
64 h
= qcow2
.QcowHeader(fd
)
66 fd
.seek(h
.l1_table_offset
)
67 l1_table
= fd
.read(h
.l1_size
<< entry_bits
)
69 fd
.seek(h
.refcount_table_offset
)
70 reftable
= fd
.read(h
.refcount_table_clusters
<< h
.cluster_bits
)
72 check_l1_table(h
, l1_table
)
73 check_reftable(fd
, h
, reftable
)
75 def __raw_check(self
, filename
):
79 'qcow2' : __qcow2_check
,
84 if iotests
.imgfmt
== 'raw':
85 qemu_img('create', '-f', iotests
.imgfmt
, test_img
, self
.image_len
)
86 qemu_img('create', '-f', iotests
.imgfmt
, check_img
,
89 qemu_img('create', '-f', iotests
.imgfmt
,
90 '-o', 'cluster_size=' + self
.cluster_size
+
91 ',refcount_bits=' + self
.refcount_bits
,
92 test_img
, self
.image_len
)
93 qemu_img('create', '-f', iotests
.imgfmt
,
94 '-o', 'cluster_size=%s'% self
.cluster_size
,
95 check_img
, self
.shrink_size
)
96 qemu_io('-c', 'write -P 0xff 0 ' + self
.shrink_size
, check_img
)
102 def image_verify(self
):
103 self
.assertEqual(image_size(test_img
), image_size(check_img
),
104 "Verifying image size")
105 self
.image_check
[iotests
.imgfmt
](self
, test_img
)
107 if iotests
.imgfmt
== 'raw':
109 self
.assertEqual(qemu_img('check', test_img
), 0,
110 "Verifying image corruption")
112 def test_empty_image(self
):
113 qemu_img('resize', '-f', iotests
.imgfmt
, '--shrink', test_img
,
117 qemu_io('-c', 'read -P 0x00 %s'%self
.shrink_size
, test_img
),
118 qemu_io('-c', 'read -P 0x00 %s'%self
.shrink_size
, check_img
),
119 "Verifying image content")
123 def test_sequential_write(self
):
124 for offs
in range(0, size_to_int(self
.image_len
),
125 size_to_int(self
.chunk_size
)):
126 qemu_io('-c', 'write -P 0xff %d %s' % (offs
, self
.chunk_size
),
129 qemu_img('resize', '-f', iotests
.imgfmt
, '--shrink', test_img
,
132 self
.assertEqual(qemu_img("compare", test_img
, check_img
), 0,
133 "Verifying image content")
137 def test_random_write(self
):
138 offs_list
= range(0, size_to_int(self
.image_len
),
139 size_to_int(self
.chunk_size
))
140 random
.shuffle(offs_list
)
141 for offs
in offs_list
:
142 qemu_io('-c', 'write -P 0xff %d %s' % (offs
, self
.chunk_size
),
145 qemu_img('resize', '-f', iotests
.imgfmt
, '--shrink', test_img
,
148 self
.assertEqual(qemu_img("compare", test_img
, check_img
), 0,
149 "Verifying image content")
153 class TestShrink512(ShrinkBaseClass
):
160 class TestShrink64K(ShrinkBaseClass
):
163 class TestShrink1M(ShrinkBaseClass
):
167 ShrinkBaseClass
= None
169 if __name__
== '__main__':
170 iotests
.main(supported_fmts
=['raw', 'qcow2'])