Statistics
| Branch: | Revision:

root / tests / qemu-iotests / 040 @ 915365a9

History | View | Annotate | Download (11.4 kB)

1
#!/usr/bin/env python
2
#
3
# Tests for image block commit.
4
#
5
# Copyright (C) 2012 IBM, Corp.
6
# Copyright (C) 2012 Red Hat, Inc.
7
#
8
# This program is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 2 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
#
21
# Test for live block commit
22
# Derived from Image Streaming Test 030
23

    
24
import time
25
import os
26
import iotests
27
from iotests import qemu_img, qemu_io
28
import struct
29
import errno
30

    
31
backing_img = os.path.join(iotests.test_dir, 'backing.img')
32
mid_img = os.path.join(iotests.test_dir, 'mid.img')
33
test_img = os.path.join(iotests.test_dir, 'test.img')
34

    
35
class ImageCommitTestCase(iotests.QMPTestCase):
36
    '''Abstract base class for image commit test cases'''
37

    
38
    def assert_no_active_commit(self):
39
        result = self.vm.qmp('query-block-jobs')
40
        self.assert_qmp(result, 'return', [])
41

    
42
    def cancel_and_wait(self, drive='drive0'):
43
        '''Cancel a block job and wait for it to finish'''
44
        result = self.vm.qmp('block-job-cancel', device=drive)
45
        self.assert_qmp(result, 'return', {})
46

    
47
        cancelled = False
48
        while not cancelled:
49
            for event in self.vm.get_qmp_events(wait=True):
50
                if event['event'] == 'BLOCK_JOB_CANCELLED':
51
                    self.assert_qmp(event, 'data/type', 'commit')
52
                    self.assert_qmp(event, 'data/device', drive)
53
                    cancelled = True
54

    
55
        self.assert_no_active_commit()
56

    
57
class TestSingleDrive(ImageCommitTestCase):
58
    image_len = 1 * 1024 * 1024
59
    test_len = 1 * 1024 * 256
60

    
61
    def setUp(self):
62
        iotests.create_image(backing_img, TestSingleDrive.image_len)
63
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
64
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
65
        qemu_io('-c', 'write -P 0xab 0 524288', backing_img)
66
        qemu_io('-c', 'write -P 0xef 524288 524288', mid_img)
67
        self.vm = iotests.VM().add_drive(test_img)
68
        self.vm.launch()
69

    
70
    def tearDown(self):
71
        self.vm.shutdown()
72
        os.remove(test_img)
73
        os.remove(mid_img)
74
        os.remove(backing_img)
75

    
76
    def test_commit(self):
77
        self.assert_no_active_commit()
78
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img)
79
        self.assert_qmp(result, 'return', {})
80

    
81
        completed = False
82
        while not completed:
83
            for event in self.vm.get_qmp_events(wait=True):
84
                if event['event'] == 'BLOCK_JOB_COMPLETED':
85
                    self.assert_qmp(event, 'data/type', 'commit')
86
                    self.assert_qmp(event, 'data/device', 'drive0')
87
                    self.assert_qmp(event, 'data/offset', self.image_len)
88
                    self.assert_qmp(event, 'data/len', self.image_len)
89
                    completed = True
90

    
91
        self.assert_no_active_commit()
92
        self.vm.shutdown()
93

    
94
        self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
95
        self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
96

    
97
    def test_device_not_found(self):
98
        result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img)
99
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
100

    
101
    def test_top_same_base(self):
102
        self.assert_no_active_commit()
103
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % backing_img)
104
        self.assert_qmp(result, 'error/class', 'GenericError')
105
        self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % backing_img)
106

    
107
    def test_top_invalid(self):
108
        self.assert_no_active_commit()
109
        result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % backing_img)
110
        self.assert_qmp(result, 'error/class', 'GenericError')
111
        self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')
112

    
113
    def test_base_invalid(self):
114
        self.assert_no_active_commit()
115
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img, base='badfile')
116
        self.assert_qmp(result, 'error/class', 'GenericError')
117
        self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found')
118

    
119
    def test_top_is_active(self):
120
        self.assert_no_active_commit()
121
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % test_img, base='%s' % backing_img)
122
        self.assert_qmp(result, 'error/class', 'GenericError')
123
        self.assert_qmp(result, 'error/desc', 'Top image as the active layer is currently unsupported')
124

    
125
    def test_top_and_base_reversed(self):
126
        self.assert_no_active_commit()
127
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img)
128
        self.assert_qmp(result, 'error/class', 'GenericError')
129
        self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img)
130

    
131
    def test_top_omitted(self):
132
        self.assert_no_active_commit()
133
        result = self.vm.qmp('block-commit', device='drive0')
134
        self.assert_qmp(result, 'error/class', 'GenericError')
135
        self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing")
136

    
137
class TestRelativePaths(ImageCommitTestCase):
138
    image_len = 1 * 1024 * 1024
139
    test_len = 1 * 1024 * 256
140

    
141
    dir1 = "dir1"
142
    dir2 = "dir2/"
143
    dir3 = "dir2/dir3/"
144

    
145
    test_img = os.path.join(iotests.test_dir, dir3, 'test.img')
146
    mid_img = "../mid.img"
147
    backing_img = "../dir1/backing.img"
148

    
149
    backing_img_abs = os.path.join(iotests.test_dir, dir1, 'backing.img')
150
    mid_img_abs = os.path.join(iotests.test_dir, dir2, 'mid.img')
151

    
152
    def setUp(self):
153
        try:
154
            os.mkdir(os.path.join(iotests.test_dir, self.dir1))
155
            os.mkdir(os.path.join(iotests.test_dir, self.dir2))
156
            os.mkdir(os.path.join(iotests.test_dir, self.dir3))
157
        except OSError as exception:
158
            if exception.errno != errno.EEXIST:
159
                raise
160
        iotests.create_image(self.backing_img_abs, TestRelativePaths.image_len)
161
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.backing_img_abs, self.mid_img_abs)
162
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.mid_img_abs, self.test_img)
163
        qemu_img('rebase', '-u', '-b', self.backing_img, self.mid_img_abs)
164
        qemu_img('rebase', '-u', '-b', self.mid_img, self.test_img)
165
        qemu_io('-c', 'write -P 0xab 0 524288', self.backing_img_abs)
166
        qemu_io('-c', 'write -P 0xef 524288 524288', self.mid_img_abs)
167
        self.vm = iotests.VM().add_drive(self.test_img)
168
        self.vm.launch()
169

    
170
    def tearDown(self):
171
        self.vm.shutdown()
172
        os.remove(self.test_img)
173
        os.remove(self.mid_img_abs)
174
        os.remove(self.backing_img_abs)
175
        try:
176
            os.rmdir(os.path.join(iotests.test_dir, self.dir1))
177
            os.rmdir(os.path.join(iotests.test_dir, self.dir3))
178
            os.rmdir(os.path.join(iotests.test_dir, self.dir2))
179
        except OSError as exception:
180
            if exception.errno != errno.EEXIST and exception.errno != errno.ENOTEMPTY:
181
                raise
182

    
183
    def test_commit(self):
184
        self.assert_no_active_commit()
185
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img)
186
        self.assert_qmp(result, 'return', {})
187

    
188
        completed = False
189
        while not completed:
190
            for event in self.vm.get_qmp_events(wait=True):
191
                if event['event'] == 'BLOCK_JOB_COMPLETED':
192
                    self.assert_qmp(event, 'data/type', 'commit')
193
                    self.assert_qmp(event, 'data/device', 'drive0')
194
                    self.assert_qmp(event, 'data/offset', self.image_len)
195
                    self.assert_qmp(event, 'data/len', self.image_len)
196
                    completed = True
197

    
198
        self.assert_no_active_commit()
199
        self.vm.shutdown()
200

    
201
        self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed"))
202
        self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed"))
203

    
204
    def test_device_not_found(self):
205
        result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % self.mid_img)
206
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
207

    
208
    def test_top_same_base(self):
209
        self.assert_no_active_commit()
210
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='%s' % self.mid_img)
211
        self.assert_qmp(result, 'error/class', 'GenericError')
212
        self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img)
213

    
214
    def test_top_invalid(self):
215
        self.assert_no_active_commit()
216
        result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % self.backing_img)
217
        self.assert_qmp(result, 'error/class', 'GenericError')
218
        self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')
219

    
220
    def test_base_invalid(self):
221
        self.assert_no_active_commit()
222
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='badfile')
223
        self.assert_qmp(result, 'error/class', 'GenericError')
224
        self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found')
225

    
226
    def test_top_is_active(self):
227
        self.assert_no_active_commit()
228
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.test_img, base='%s' % self.backing_img)
229
        self.assert_qmp(result, 'error/class', 'GenericError')
230
        self.assert_qmp(result, 'error/desc', 'Top image as the active layer is currently unsupported')
231

    
232
    def test_top_and_base_reversed(self):
233
        self.assert_no_active_commit()
234
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.backing_img, base='%s' % self.mid_img)
235
        self.assert_qmp(result, 'error/class', 'GenericError')
236
        self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img)
237

    
238

    
239
class TestSetSpeed(ImageCommitTestCase):
240
    image_len = 80 * 1024 * 1024 # MB
241

    
242
    def setUp(self):
243
        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
244
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
245
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
246
        self.vm = iotests.VM().add_drive(test_img)
247
        self.vm.launch()
248

    
249
    def tearDown(self):
250
        self.vm.shutdown()
251
        os.remove(test_img)
252
        os.remove(mid_img)
253
        os.remove(backing_img)
254

    
255
    def test_set_speed(self):
256
        self.assert_no_active_commit()
257

    
258
        result = self.vm.qmp('block-commit', device='drive0', top=mid_img, speed=1024 * 1024)
259
        self.assert_qmp(result, 'return', {})
260

    
261
        # Ensure the speed we set was accepted
262
        result = self.vm.qmp('query-block-jobs')
263
        self.assert_qmp(result, 'return[0]/device', 'drive0')
264
        self.assert_qmp(result, 'return[0]/speed', 1024 * 1024)
265

    
266
        self.cancel_and_wait()
267

    
268

    
269
if __name__ == '__main__':
270
    iotests.main(supported_fmts=['qcow2', 'qed'])