xref: /qemu/tests/qemu-iotests/030 (revision 0c817347)
137ce63ebSStefan Hajnoczi#!/usr/bin/env python
237ce63ebSStefan Hajnoczi#
337ce63ebSStefan Hajnoczi# Tests for image streaming.
437ce63ebSStefan Hajnoczi#
537ce63ebSStefan Hajnoczi# Copyright (C) 2012 IBM Corp.
637ce63ebSStefan Hajnoczi#
737ce63ebSStefan Hajnoczi# This program is free software; you can redistribute it and/or modify
837ce63ebSStefan Hajnoczi# it under the terms of the GNU General Public License as published by
937ce63ebSStefan Hajnoczi# the Free Software Foundation; either version 2 of the License, or
1037ce63ebSStefan Hajnoczi# (at your option) any later version.
1137ce63ebSStefan Hajnoczi#
1237ce63ebSStefan Hajnoczi# This program is distributed in the hope that it will be useful,
1337ce63ebSStefan Hajnoczi# but WITHOUT ANY WARRANTY; without even the implied warranty of
1437ce63ebSStefan Hajnoczi# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1537ce63ebSStefan Hajnoczi# GNU General Public License for more details.
1637ce63ebSStefan Hajnoczi#
1737ce63ebSStefan Hajnoczi# You should have received a copy of the GNU General Public License
1837ce63ebSStefan Hajnoczi# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1937ce63ebSStefan Hajnoczi#
2037ce63ebSStefan Hajnoczi
21*0c817347SPaolo Bonziniimport time
2237ce63ebSStefan Hajnocziimport os
2337ce63ebSStefan Hajnocziimport iotests
2437ce63ebSStefan Hajnoczifrom iotests import qemu_img, qemu_io
25ab68cdfaSPaolo Bonziniimport struct
2637ce63ebSStefan Hajnoczi
2737ce63ebSStefan Hajnoczibacking_img = os.path.join(iotests.test_dir, 'backing.img')
286e343609SPaolo Bonzinimid_img = os.path.join(iotests.test_dir, 'mid.img')
2937ce63ebSStefan Hajnoczitest_img = os.path.join(iotests.test_dir, 'test.img')
3037ce63ebSStefan Hajnoczi
3137ce63ebSStefan Hajnocziclass ImageStreamingTestCase(iotests.QMPTestCase):
3237ce63ebSStefan Hajnoczi    '''Abstract base class for image streaming test cases'''
3337ce63ebSStefan Hajnoczi
3437ce63ebSStefan Hajnoczi    def assert_no_active_streams(self):
3537ce63ebSStefan Hajnoczi        result = self.vm.qmp('query-block-jobs')
3637ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'return', [])
3737ce63ebSStefan Hajnoczi
38e425306aSStefan Hajnoczi    def cancel_and_wait(self, drive='drive0'):
39e425306aSStefan Hajnoczi        '''Cancel a block job and wait for it to finish'''
40e425306aSStefan Hajnoczi        result = self.vm.qmp('block-job-cancel', device=drive)
41e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
42e425306aSStefan Hajnoczi
43e425306aSStefan Hajnoczi        cancelled = False
44e425306aSStefan Hajnoczi        while not cancelled:
45e425306aSStefan Hajnoczi            for event in self.vm.get_qmp_events(wait=True):
46e425306aSStefan Hajnoczi                if event['event'] == 'BLOCK_JOB_CANCELLED':
47e425306aSStefan Hajnoczi                    self.assert_qmp(event, 'data/type', 'stream')
48e425306aSStefan Hajnoczi                    self.assert_qmp(event, 'data/device', drive)
49e425306aSStefan Hajnoczi                    cancelled = True
50e425306aSStefan Hajnoczi
51e425306aSStefan Hajnoczi        self.assert_no_active_streams()
52e425306aSStefan Hajnoczi
53ab68cdfaSPaolo Bonzini    def create_image(self, name, size):
54ab68cdfaSPaolo Bonzini        file = open(name, 'w')
55ab68cdfaSPaolo Bonzini        i = 0
56ab68cdfaSPaolo Bonzini        while i < size:
57ab68cdfaSPaolo Bonzini            sector = struct.pack('>l504xl', i / 512, i / 512)
58ab68cdfaSPaolo Bonzini            file.write(sector)
59ab68cdfaSPaolo Bonzini            i = i + 512
60ab68cdfaSPaolo Bonzini        file.close()
61ab68cdfaSPaolo Bonzini
62ab68cdfaSPaolo Bonzini
6337ce63ebSStefan Hajnocziclass TestSingleDrive(ImageStreamingTestCase):
6437ce63ebSStefan Hajnoczi    image_len = 1 * 1024 * 1024 # MB
6537ce63ebSStefan Hajnoczi
6637ce63ebSStefan Hajnoczi    def setUp(self):
67ab68cdfaSPaolo Bonzini        self.create_image(backing_img, TestSingleDrive.image_len)
686e343609SPaolo Bonzini        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
696e343609SPaolo Bonzini        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
7037ce63ebSStefan Hajnoczi        self.vm = iotests.VM().add_drive(test_img)
7137ce63ebSStefan Hajnoczi        self.vm.launch()
7237ce63ebSStefan Hajnoczi
7337ce63ebSStefan Hajnoczi    def tearDown(self):
7437ce63ebSStefan Hajnoczi        self.vm.shutdown()
7537ce63ebSStefan Hajnoczi        os.remove(test_img)
766e343609SPaolo Bonzini        os.remove(mid_img)
7737ce63ebSStefan Hajnoczi        os.remove(backing_img)
7837ce63ebSStefan Hajnoczi
7937ce63ebSStefan Hajnoczi    def test_stream(self):
8037ce63ebSStefan Hajnoczi        self.assert_no_active_streams()
8137ce63ebSStefan Hajnoczi
82db58f9c0SStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
8337ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
8437ce63ebSStefan Hajnoczi
8537ce63ebSStefan Hajnoczi        completed = False
8637ce63ebSStefan Hajnoczi        while not completed:
8737ce63ebSStefan Hajnoczi            for event in self.vm.get_qmp_events(wait=True):
8837ce63ebSStefan Hajnoczi                if event['event'] == 'BLOCK_JOB_COMPLETED':
8937ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/type', 'stream')
9037ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/device', 'drive0')
9137ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/offset', self.image_len)
9237ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/len', self.image_len)
9337ce63ebSStefan Hajnoczi                    completed = True
9437ce63ebSStefan Hajnoczi
9537ce63ebSStefan Hajnoczi        self.assert_no_active_streams()
96863a5d04SPaolo Bonzini        self.vm.shutdown()
9737ce63ebSStefan Hajnoczi
98efcc7a23SPaolo Bonzini        self.assertEqual(qemu_io('-c', 'map', backing_img),
99efcc7a23SPaolo Bonzini                         qemu_io('-c', 'map', test_img),
100efcc7a23SPaolo Bonzini                         'image file map does not match backing file after streaming')
10137ce63ebSStefan Hajnoczi
102*0c817347SPaolo Bonzini    def test_stream_pause(self):
103*0c817347SPaolo Bonzini        self.assert_no_active_streams()
104*0c817347SPaolo Bonzini
105*0c817347SPaolo Bonzini        result = self.vm.qmp('block-stream', device='drive0')
106*0c817347SPaolo Bonzini        self.assert_qmp(result, 'return', {})
107*0c817347SPaolo Bonzini
108*0c817347SPaolo Bonzini        result = self.vm.qmp('block-job-pause', device='drive0')
109*0c817347SPaolo Bonzini        self.assert_qmp(result, 'return', {})
110*0c817347SPaolo Bonzini
111*0c817347SPaolo Bonzini        time.sleep(1)
112*0c817347SPaolo Bonzini        result = self.vm.qmp('query-block-jobs')
113*0c817347SPaolo Bonzini        offset = self.dictpath(result, 'return[0]/offset')
114*0c817347SPaolo Bonzini
115*0c817347SPaolo Bonzini        time.sleep(1)
116*0c817347SPaolo Bonzini        result = self.vm.qmp('query-block-jobs')
117*0c817347SPaolo Bonzini        self.assert_qmp(result, 'return[0]/offset', offset)
118*0c817347SPaolo Bonzini
119*0c817347SPaolo Bonzini        result = self.vm.qmp('block-job-resume', device='drive0')
120*0c817347SPaolo Bonzini        self.assert_qmp(result, 'return', {})
121*0c817347SPaolo Bonzini
122*0c817347SPaolo Bonzini        completed = False
123*0c817347SPaolo Bonzini        while not completed:
124*0c817347SPaolo Bonzini            for event in self.vm.get_qmp_events(wait=True):
125*0c817347SPaolo Bonzini                if event['event'] == 'BLOCK_JOB_COMPLETED':
126*0c817347SPaolo Bonzini                    self.assert_qmp(event, 'data/type', 'stream')
127*0c817347SPaolo Bonzini                    self.assert_qmp(event, 'data/device', 'drive0')
128*0c817347SPaolo Bonzini                    self.assert_qmp(event, 'data/offset', self.image_len)
129*0c817347SPaolo Bonzini                    self.assert_qmp(event, 'data/len', self.image_len)
130*0c817347SPaolo Bonzini                    completed = True
131*0c817347SPaolo Bonzini
132*0c817347SPaolo Bonzini        self.assert_no_active_streams()
133*0c817347SPaolo Bonzini        self.vm.shutdown()
134*0c817347SPaolo Bonzini
135*0c817347SPaolo Bonzini        self.assertEqual(qemu_io('-c', 'map', backing_img),
136*0c817347SPaolo Bonzini                         qemu_io('-c', 'map', test_img),
137*0c817347SPaolo Bonzini                         'image file map does not match backing file after streaming')
138*0c817347SPaolo Bonzini
1396e343609SPaolo Bonzini    def test_stream_partial(self):
1406e343609SPaolo Bonzini        self.assert_no_active_streams()
1416e343609SPaolo Bonzini
1426e343609SPaolo Bonzini        result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
1436e343609SPaolo Bonzini        self.assert_qmp(result, 'return', {})
1446e343609SPaolo Bonzini
1456e343609SPaolo Bonzini        completed = False
1466e343609SPaolo Bonzini        while not completed:
1476e343609SPaolo Bonzini            for event in self.vm.get_qmp_events(wait=True):
1486e343609SPaolo Bonzini                if event['event'] == 'BLOCK_JOB_COMPLETED':
1496e343609SPaolo Bonzini                    self.assert_qmp(event, 'data/type', 'stream')
1506e343609SPaolo Bonzini                    self.assert_qmp(event, 'data/device', 'drive0')
1516e343609SPaolo Bonzini                    self.assert_qmp(event, 'data/offset', self.image_len)
1526e343609SPaolo Bonzini                    self.assert_qmp(event, 'data/len', self.image_len)
1536e343609SPaolo Bonzini                    completed = True
1546e343609SPaolo Bonzini
1556e343609SPaolo Bonzini        self.assert_no_active_streams()
1566e343609SPaolo Bonzini        self.vm.shutdown()
1576e343609SPaolo Bonzini
1586e343609SPaolo Bonzini        self.assertEqual(qemu_io('-c', 'map', mid_img),
1596e343609SPaolo Bonzini                         qemu_io('-c', 'map', test_img),
1606e343609SPaolo Bonzini                         'image file map does not match backing file after streaming')
1616e343609SPaolo Bonzini
16237ce63ebSStefan Hajnoczi    def test_device_not_found(self):
163db58f9c0SStefan Hajnoczi        result = self.vm.qmp('block-stream', device='nonexistent')
16437ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
16537ce63ebSStefan Hajnoczi
166774a8850SStefan Hajnoczi
167774a8850SStefan Hajnocziclass TestSmallerBackingFile(ImageStreamingTestCase):
168774a8850SStefan Hajnoczi    backing_len = 1 * 1024 * 1024 # MB
169774a8850SStefan Hajnoczi    image_len = 2 * backing_len
170774a8850SStefan Hajnoczi
171774a8850SStefan Hajnoczi    def setUp(self):
172774a8850SStefan Hajnoczi        self.create_image(backing_img, self.backing_len)
173774a8850SStefan Hajnoczi        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len))
174774a8850SStefan Hajnoczi        self.vm = iotests.VM().add_drive(test_img)
175774a8850SStefan Hajnoczi        self.vm.launch()
176774a8850SStefan Hajnoczi
177774a8850SStefan Hajnoczi    # If this hangs, then you are missing a fix to complete streaming when the
178774a8850SStefan Hajnoczi    # end of the backing file is reached.
179774a8850SStefan Hajnoczi    def test_stream(self):
180774a8850SStefan Hajnoczi        self.assert_no_active_streams()
181774a8850SStefan Hajnoczi
182774a8850SStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
183774a8850SStefan Hajnoczi        self.assert_qmp(result, 'return', {})
184774a8850SStefan Hajnoczi
185774a8850SStefan Hajnoczi        completed = False
186774a8850SStefan Hajnoczi        while not completed:
187774a8850SStefan Hajnoczi            for event in self.vm.get_qmp_events(wait=True):
188774a8850SStefan Hajnoczi                if event['event'] == 'BLOCK_JOB_COMPLETED':
189774a8850SStefan Hajnoczi                    self.assert_qmp(event, 'data/type', 'stream')
190774a8850SStefan Hajnoczi                    self.assert_qmp(event, 'data/device', 'drive0')
191774a8850SStefan Hajnoczi                    self.assert_qmp(event, 'data/offset', self.image_len)
192774a8850SStefan Hajnoczi                    self.assert_qmp(event, 'data/len', self.image_len)
193774a8850SStefan Hajnoczi                    completed = True
194774a8850SStefan Hajnoczi
195774a8850SStefan Hajnoczi        self.assert_no_active_streams()
196774a8850SStefan Hajnoczi        self.vm.shutdown()
197774a8850SStefan Hajnoczi
198774a8850SStefan Hajnoczi
19937ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase):
20037ce63ebSStefan Hajnoczi    image_len = 8 * 1024 * 1024 * 1024 # GB
20137ce63ebSStefan Hajnoczi
20237ce63ebSStefan Hajnoczi    def setUp(self):
20337ce63ebSStefan Hajnoczi        qemu_img('create', backing_img, str(TestStreamStop.image_len))
20437ce63ebSStefan Hajnoczi        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
20537ce63ebSStefan Hajnoczi        self.vm = iotests.VM().add_drive(test_img)
20637ce63ebSStefan Hajnoczi        self.vm.launch()
20737ce63ebSStefan Hajnoczi
20837ce63ebSStefan Hajnoczi    def tearDown(self):
20937ce63ebSStefan Hajnoczi        self.vm.shutdown()
21037ce63ebSStefan Hajnoczi        os.remove(test_img)
21137ce63ebSStefan Hajnoczi        os.remove(backing_img)
21237ce63ebSStefan Hajnoczi
21337ce63ebSStefan Hajnoczi    def test_stream_stop(self):
21437ce63ebSStefan Hajnoczi        self.assert_no_active_streams()
21537ce63ebSStefan Hajnoczi
216db58f9c0SStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
21737ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
21837ce63ebSStefan Hajnoczi
2190fd05e8dSPaolo Bonzini        time.sleep(0.1)
22037ce63ebSStefan Hajnoczi        events = self.vm.get_qmp_events(wait=False)
22137ce63ebSStefan Hajnoczi        self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
22237ce63ebSStefan Hajnoczi
223e425306aSStefan Hajnoczi        self.cancel_and_wait()
22437ce63ebSStefan Hajnoczi
22537ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase):
22637ce63ebSStefan Hajnoczi    image_len = 80 * 1024 * 1024 # MB
22737ce63ebSStefan Hajnoczi
22837ce63ebSStefan Hajnoczi    def setUp(self):
22937ce63ebSStefan Hajnoczi        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
23037ce63ebSStefan Hajnoczi        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
23137ce63ebSStefan Hajnoczi        self.vm = iotests.VM().add_drive(test_img)
23237ce63ebSStefan Hajnoczi        self.vm.launch()
23337ce63ebSStefan Hajnoczi
23437ce63ebSStefan Hajnoczi    def tearDown(self):
23537ce63ebSStefan Hajnoczi        self.vm.shutdown()
23637ce63ebSStefan Hajnoczi        os.remove(test_img)
23737ce63ebSStefan Hajnoczi        os.remove(backing_img)
23837ce63ebSStefan Hajnoczi
239e425306aSStefan Hajnoczi    # This is a short performance test which is not run by default.
240e425306aSStefan Hajnoczi    # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
241e425306aSStefan Hajnoczi    def perf_test_throughput(self):
24237ce63ebSStefan Hajnoczi        self.assert_no_active_streams()
24337ce63ebSStefan Hajnoczi
244db58f9c0SStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
24537ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
24637ce63ebSStefan Hajnoczi
247e425306aSStefan Hajnoczi        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
24837ce63ebSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
24937ce63ebSStefan Hajnoczi
25037ce63ebSStefan Hajnoczi        completed = False
25137ce63ebSStefan Hajnoczi        while not completed:
25237ce63ebSStefan Hajnoczi            for event in self.vm.get_qmp_events(wait=True):
25337ce63ebSStefan Hajnoczi                if event['event'] == 'BLOCK_JOB_COMPLETED':
25437ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/type', 'stream')
25537ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/device', 'drive0')
25637ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/offset', self.image_len)
25737ce63ebSStefan Hajnoczi                    self.assert_qmp(event, 'data/len', self.image_len)
25837ce63ebSStefan Hajnoczi                    completed = True
25937ce63ebSStefan Hajnoczi
26037ce63ebSStefan Hajnoczi        self.assert_no_active_streams()
26137ce63ebSStefan Hajnoczi
262e425306aSStefan Hajnoczi    def test_set_speed(self):
263e425306aSStefan Hajnoczi        self.assert_no_active_streams()
264e425306aSStefan Hajnoczi
265e425306aSStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
266e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
267e425306aSStefan Hajnoczi
268e425306aSStefan Hajnoczi        # Default speed is 0
269e425306aSStefan Hajnoczi        result = self.vm.qmp('query-block-jobs')
270e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/device', 'drive0')
271e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/speed', 0)
272e425306aSStefan Hajnoczi
273e425306aSStefan Hajnoczi        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
274e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
275e425306aSStefan Hajnoczi
276e425306aSStefan Hajnoczi        # Ensure the speed we set was accepted
277e425306aSStefan Hajnoczi        result = self.vm.qmp('query-block-jobs')
278e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/device', 'drive0')
279e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
280e425306aSStefan Hajnoczi
281e425306aSStefan Hajnoczi        self.cancel_and_wait()
282e425306aSStefan Hajnoczi
283e425306aSStefan Hajnoczi        # Check setting speed in block-stream works
284e425306aSStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
285e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
286e425306aSStefan Hajnoczi
287e425306aSStefan Hajnoczi        result = self.vm.qmp('query-block-jobs')
288e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/device', 'drive0')
289e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
290e425306aSStefan Hajnoczi
291e425306aSStefan Hajnoczi        self.cancel_and_wait()
292e425306aSStefan Hajnoczi
293e425306aSStefan Hajnoczi    def test_set_speed_invalid(self):
294e425306aSStefan Hajnoczi        self.assert_no_active_streams()
295e425306aSStefan Hajnoczi
296e425306aSStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0', speed=-1)
29758c8cce2SKevin Wolf        self.assert_qmp(result, 'error/class', 'GenericError')
298e425306aSStefan Hajnoczi
299e425306aSStefan Hajnoczi        self.assert_no_active_streams()
300e425306aSStefan Hajnoczi
301e425306aSStefan Hajnoczi        result = self.vm.qmp('block-stream', device='drive0')
302e425306aSStefan Hajnoczi        self.assert_qmp(result, 'return', {})
303e425306aSStefan Hajnoczi
304e425306aSStefan Hajnoczi        result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
30558c8cce2SKevin Wolf        self.assert_qmp(result, 'error/class', 'GenericError')
306e425306aSStefan Hajnoczi
307e425306aSStefan Hajnoczi        self.cancel_and_wait()
308e425306aSStefan Hajnoczi
30937ce63ebSStefan Hajnocziif __name__ == '__main__':
31037ce63ebSStefan Hajnoczi    iotests.main(supported_fmts=['qcow2', 'qed'])
311