Statistics
| Branch: | Revision:

root / tests / qemu-iotests / 030 @ 6e343609

History | View | Annotate | Download (8.4 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

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

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

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

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

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

    
49
        self.assert_no_active_streams()
50

    
51
class TestSingleDrive(ImageStreamingTestCase):
52
    image_len = 1 * 1024 * 1024 # MB
53

    
54
    def setUp(self):
55
        qemu_img('create', backing_img, str(TestSingleDrive.image_len))
56
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
57
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
58
        self.vm = iotests.VM().add_drive(test_img)
59
        self.vm.launch()
60

    
61
    def tearDown(self):
62
        self.vm.shutdown()
63
        os.remove(test_img)
64
        os.remove(mid_img)
65
        os.remove(backing_img)
66

    
67
    def test_stream(self):
68
        self.assert_no_active_streams()
69

    
70
        result = self.vm.qmp('block-stream', device='drive0')
71
        self.assert_qmp(result, 'return', {})
72

    
73
        completed = False
74
        while not completed:
75
            for event in self.vm.get_qmp_events(wait=True):
76
                if event['event'] == 'BLOCK_JOB_COMPLETED':
77
                    self.assert_qmp(event, 'data/type', 'stream')
78
                    self.assert_qmp(event, 'data/device', 'drive0')
79
                    self.assert_qmp(event, 'data/offset', self.image_len)
80
                    self.assert_qmp(event, 'data/len', self.image_len)
81
                    completed = True
82

    
83
        self.assert_no_active_streams()
84
        self.vm.shutdown()
85

    
86
        self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', test_img),
87
                         'image file not fully populated after streaming')
88

    
89
    def test_stream_partial(self):
90
        self.assert_no_active_streams()
91

    
92
        result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
93
        self.assert_qmp(result, 'return', {})
94

    
95
        completed = False
96
        while not completed:
97
            for event in self.vm.get_qmp_events(wait=True):
98
                if event['event'] == 'BLOCK_JOB_COMPLETED':
99
                    self.assert_qmp(event, 'data/type', 'stream')
100
                    self.assert_qmp(event, 'data/device', 'drive0')
101
                    self.assert_qmp(event, 'data/offset', self.image_len)
102
                    self.assert_qmp(event, 'data/len', self.image_len)
103
                    completed = True
104

    
105
        self.assert_no_active_streams()
106
        self.vm.shutdown()
107

    
108
        self.assertEqual(qemu_io('-c', 'map', mid_img),
109
                         qemu_io('-c', 'map', test_img),
110
                         'image file map does not match backing file after streaming')
111

    
112
    def test_device_not_found(self):
113
        result = self.vm.qmp('block-stream', device='nonexistent')
114
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
115

    
116
class TestStreamStop(ImageStreamingTestCase):
117
    image_len = 8 * 1024 * 1024 * 1024 # GB
118

    
119
    def setUp(self):
120
        qemu_img('create', backing_img, str(TestStreamStop.image_len))
121
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
122
        self.vm = iotests.VM().add_drive(test_img)
123
        self.vm.launch()
124

    
125
    def tearDown(self):
126
        self.vm.shutdown()
127
        os.remove(test_img)
128
        os.remove(backing_img)
129

    
130
    def test_stream_stop(self):
131
        import time
132

    
133
        self.assert_no_active_streams()
134

    
135
        result = self.vm.qmp('block-stream', device='drive0')
136
        self.assert_qmp(result, 'return', {})
137

    
138
        time.sleep(1)
139
        events = self.vm.get_qmp_events(wait=False)
140
        self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
141

    
142
        self.cancel_and_wait()
143

    
144
class TestSetSpeed(ImageStreamingTestCase):
145
    image_len = 80 * 1024 * 1024 # MB
146

    
147
    def setUp(self):
148
        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
149
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
150
        self.vm = iotests.VM().add_drive(test_img)
151
        self.vm.launch()
152

    
153
    def tearDown(self):
154
        self.vm.shutdown()
155
        os.remove(test_img)
156
        os.remove(backing_img)
157

    
158
    # This is a short performance test which is not run by default.
159
    # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
160
    def perf_test_throughput(self):
161
        self.assert_no_active_streams()
162

    
163
        result = self.vm.qmp('block-stream', device='drive0')
164
        self.assert_qmp(result, 'return', {})
165

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

    
169
        completed = False
170
        while not completed:
171
            for event in self.vm.get_qmp_events(wait=True):
172
                if event['event'] == 'BLOCK_JOB_COMPLETED':
173
                    self.assert_qmp(event, 'data/type', 'stream')
174
                    self.assert_qmp(event, 'data/device', 'drive0')
175
                    self.assert_qmp(event, 'data/offset', self.image_len)
176
                    self.assert_qmp(event, 'data/len', self.image_len)
177
                    completed = True
178

    
179
        self.assert_no_active_streams()
180

    
181
    def test_set_speed(self):
182
        self.assert_no_active_streams()
183

    
184
        result = self.vm.qmp('block-stream', device='drive0')
185
        self.assert_qmp(result, 'return', {})
186

    
187
        # Default speed is 0
188
        result = self.vm.qmp('query-block-jobs')
189
        self.assert_qmp(result, 'return[0]/device', 'drive0')
190
        self.assert_qmp(result, 'return[0]/speed', 0)
191

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

    
195
        # Ensure the speed we set was accepted
196
        result = self.vm.qmp('query-block-jobs')
197
        self.assert_qmp(result, 'return[0]/device', 'drive0')
198
        self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
199

    
200
        self.cancel_and_wait()
201

    
202
        # Check setting speed in block-stream works
203
        result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
204
        self.assert_qmp(result, 'return', {})
205

    
206
        result = self.vm.qmp('query-block-jobs')
207
        self.assert_qmp(result, 'return[0]/device', 'drive0')
208
        self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
209

    
210
        self.cancel_and_wait()
211

    
212
    def test_set_speed_invalid(self):
213
        self.assert_no_active_streams()
214

    
215
        result = self.vm.qmp('block-stream', device='drive0', speed=-1)
216
        self.assert_qmp(result, 'error/class', 'InvalidParameter')
217
        self.assert_qmp(result, 'error/data/name', 'speed')
218

    
219
        self.assert_no_active_streams()
220

    
221
        result = self.vm.qmp('block-stream', device='drive0')
222
        self.assert_qmp(result, 'return', {})
223

    
224
        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
225
        self.assert_qmp(result, 'error/class', 'InvalidParameter')
226
        self.assert_qmp(result, 'error/data/name', 'speed')
227

    
228
        self.cancel_and_wait()
229

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