Statistics
| Branch: | Revision:

root / tests / qemu-iotests / 030 @ 58c8cce2

History | View | Annotate | Download (8.6 kB)

1
#!/usr/bin/env python
2
#
3
# Tests for image streaming.
4
#
5
# Copyright (C) 2012 IBM Corp.
6
#
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.
11
#
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.
16
#
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/>.
19
#
20

    
21
import os
22
import iotests
23
from iotests import qemu_img, qemu_io
24
import struct
25

    
26
backing_img = os.path.join(iotests.test_dir, 'backing.img')
27
mid_img = os.path.join(iotests.test_dir, 'mid.img')
28
test_img = os.path.join(iotests.test_dir, 'test.img')
29

    
30
class ImageStreamingTestCase(iotests.QMPTestCase):
31
    '''Abstract base class for image streaming test cases'''
32

    
33
    def assert_no_active_streams(self):
34
        result = self.vm.qmp('query-block-jobs')
35
        self.assert_qmp(result, 'return', [])
36

    
37
    def cancel_and_wait(self, drive='drive0'):
38
        '''Cancel a block job and wait for it to finish'''
39
        result = self.vm.qmp('block-job-cancel', device=drive)
40
        self.assert_qmp(result, 'return', {})
41

    
42
        cancelled = False
43
        while not cancelled:
44
            for event in self.vm.get_qmp_events(wait=True):
45
                if event['event'] == 'BLOCK_JOB_CANCELLED':
46
                    self.assert_qmp(event, 'data/type', 'stream')
47
                    self.assert_qmp(event, 'data/device', drive)
48
                    cancelled = True
49

    
50
        self.assert_no_active_streams()
51

    
52
    def create_image(self, name, size):
53
        file = open(name, 'w')
54
        i = 0
55
        while i < size:
56
            sector = struct.pack('>l504xl', i / 512, i / 512)
57
            file.write(sector)
58
            i = i + 512
59
        file.close()
60

    
61

    
62
class TestSingleDrive(ImageStreamingTestCase):
63
    image_len = 1 * 1024 * 1024 # MB
64

    
65
    def setUp(self):
66
        self.create_image(backing_img, TestSingleDrive.image_len)
67
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
68
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
69
        self.vm = iotests.VM().add_drive(test_img)
70
        self.vm.launch()
71

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

    
78
    def test_stream(self):
79
        self.assert_no_active_streams()
80

    
81
        result = self.vm.qmp('block-stream', device='drive0')
82
        self.assert_qmp(result, 'return', {})
83

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

    
94
        self.assert_no_active_streams()
95
        self.vm.shutdown()
96

    
97
        self.assertEqual(qemu_io('-c', 'map', backing_img),
98
                         qemu_io('-c', 'map', test_img),
99
                         'image file map does not match backing file after streaming')
100

    
101
    def test_stream_partial(self):
102
        self.assert_no_active_streams()
103

    
104
        result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
105
        self.assert_qmp(result, 'return', {})
106

    
107
        completed = False
108
        while not completed:
109
            for event in self.vm.get_qmp_events(wait=True):
110
                if event['event'] == 'BLOCK_JOB_COMPLETED':
111
                    self.assert_qmp(event, 'data/type', 'stream')
112
                    self.assert_qmp(event, 'data/device', 'drive0')
113
                    self.assert_qmp(event, 'data/offset', self.image_len)
114
                    self.assert_qmp(event, 'data/len', self.image_len)
115
                    completed = True
116

    
117
        self.assert_no_active_streams()
118
        self.vm.shutdown()
119

    
120
        self.assertEqual(qemu_io('-c', 'map', mid_img),
121
                         qemu_io('-c', 'map', test_img),
122
                         'image file map does not match backing file after streaming')
123

    
124
    def test_device_not_found(self):
125
        result = self.vm.qmp('block-stream', device='nonexistent')
126
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
127

    
128
class TestStreamStop(ImageStreamingTestCase):
129
    image_len = 8 * 1024 * 1024 * 1024 # GB
130

    
131
    def setUp(self):
132
        qemu_img('create', backing_img, str(TestStreamStop.image_len))
133
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
134
        self.vm = iotests.VM().add_drive(test_img)
135
        self.vm.launch()
136

    
137
    def tearDown(self):
138
        self.vm.shutdown()
139
        os.remove(test_img)
140
        os.remove(backing_img)
141

    
142
    def test_stream_stop(self):
143
        import time
144

    
145
        self.assert_no_active_streams()
146

    
147
        result = self.vm.qmp('block-stream', device='drive0')
148
        self.assert_qmp(result, 'return', {})
149

    
150
        time.sleep(0.1)
151
        events = self.vm.get_qmp_events(wait=False)
152
        self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
153

    
154
        self.cancel_and_wait()
155

    
156
class TestSetSpeed(ImageStreamingTestCase):
157
    image_len = 80 * 1024 * 1024 # MB
158

    
159
    def setUp(self):
160
        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
161
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
162
        self.vm = iotests.VM().add_drive(test_img)
163
        self.vm.launch()
164

    
165
    def tearDown(self):
166
        self.vm.shutdown()
167
        os.remove(test_img)
168
        os.remove(backing_img)
169

    
170
    # This is a short performance test which is not run by default.
171
    # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
172
    def perf_test_throughput(self):
173
        self.assert_no_active_streams()
174

    
175
        result = self.vm.qmp('block-stream', device='drive0')
176
        self.assert_qmp(result, 'return', {})
177

    
178
        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
179
        self.assert_qmp(result, 'return', {})
180

    
181
        completed = False
182
        while not completed:
183
            for event in self.vm.get_qmp_events(wait=True):
184
                if event['event'] == 'BLOCK_JOB_COMPLETED':
185
                    self.assert_qmp(event, 'data/type', 'stream')
186
                    self.assert_qmp(event, 'data/device', 'drive0')
187
                    self.assert_qmp(event, 'data/offset', self.image_len)
188
                    self.assert_qmp(event, 'data/len', self.image_len)
189
                    completed = True
190

    
191
        self.assert_no_active_streams()
192

    
193
    def test_set_speed(self):
194
        self.assert_no_active_streams()
195

    
196
        result = self.vm.qmp('block-stream', device='drive0')
197
        self.assert_qmp(result, 'return', {})
198

    
199
        # Default speed is 0
200
        result = self.vm.qmp('query-block-jobs')
201
        self.assert_qmp(result, 'return[0]/device', 'drive0')
202
        self.assert_qmp(result, 'return[0]/speed', 0)
203

    
204
        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
205
        self.assert_qmp(result, 'return', {})
206

    
207
        # Ensure the speed we set was accepted
208
        result = self.vm.qmp('query-block-jobs')
209
        self.assert_qmp(result, 'return[0]/device', 'drive0')
210
        self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
211

    
212
        self.cancel_and_wait()
213

    
214
        # Check setting speed in block-stream works
215
        result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
216
        self.assert_qmp(result, 'return', {})
217

    
218
        result = self.vm.qmp('query-block-jobs')
219
        self.assert_qmp(result, 'return[0]/device', 'drive0')
220
        self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
221

    
222
        self.cancel_and_wait()
223

    
224
    def test_set_speed_invalid(self):
225
        self.assert_no_active_streams()
226

    
227
        result = self.vm.qmp('block-stream', device='drive0', speed=-1)
228
        self.assert_qmp(result, 'error/class', 'GenericError')
229

    
230
        self.assert_no_active_streams()
231

    
232
        result = self.vm.qmp('block-stream', device='drive0')
233
        self.assert_qmp(result, 'return', {})
234

    
235
        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
236
        self.assert_qmp(result, 'error/class', 'GenericError')
237

    
238
        self.cancel_and_wait()
239

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