xref: /qemu/tests/qemu-iotests/118 (revision dfc828941c0f1771c5861fce11a428c8c64a206d)
1adfe2030SMax Reitz#!/usr/bin/env python
2adfe2030SMax Reitz#
3adfe2030SMax Reitz# Test case for the QMP 'change' command and all other associated
4adfe2030SMax Reitz# commands
5adfe2030SMax Reitz#
6adfe2030SMax Reitz# Copyright (C) 2015 Red Hat, Inc.
7adfe2030SMax Reitz#
8adfe2030SMax Reitz# This program is free software; you can redistribute it and/or modify
9adfe2030SMax Reitz# it under the terms of the GNU General Public License as published by
10adfe2030SMax Reitz# the Free Software Foundation; either version 2 of the License, or
11adfe2030SMax Reitz# (at your option) any later version.
12adfe2030SMax Reitz#
13adfe2030SMax Reitz# This program is distributed in the hope that it will be useful,
14adfe2030SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of
15adfe2030SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16adfe2030SMax Reitz# GNU General Public License for more details.
17adfe2030SMax Reitz#
18adfe2030SMax Reitz# You should have received a copy of the GNU General Public License
19adfe2030SMax Reitz# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20adfe2030SMax Reitz#
21adfe2030SMax Reitz
22adfe2030SMax Reitzimport os
23adfe2030SMax Reitzimport stat
24adfe2030SMax Reitzimport time
25adfe2030SMax Reitzimport iotests
26adfe2030SMax Reitzfrom iotests import qemu_img
27adfe2030SMax Reitz
28adfe2030SMax Reitzold_img = os.path.join(iotests.test_dir, 'test0.img')
29adfe2030SMax Reitznew_img = os.path.join(iotests.test_dir, 'test1.img')
30adfe2030SMax Reitz
311d701e0eSMax Reitzdef interface_to_device_name(interface):
321d701e0eSMax Reitz    if interface == 'ide':
331d701e0eSMax Reitz        return 'ide-cd'
341d701e0eSMax Reitz    elif interface == 'floppy':
351d701e0eSMax Reitz        return 'floppy'
36dfa26a11SKevin Wolf    elif interface == 'scsi':
37dfa26a11SKevin Wolf        return 'scsi-cd'
381d701e0eSMax Reitz    else:
391d701e0eSMax Reitz        return None
401d701e0eSMax Reitz
41adfe2030SMax Reitzclass ChangeBaseClass(iotests.QMPTestCase):
42adfe2030SMax Reitz    has_opened = False
43adfe2030SMax Reitz    has_closed = False
44adfe2030SMax Reitz
45adfe2030SMax Reitz    def process_events(self):
46adfe2030SMax Reitz        for event in self.vm.get_qmp_events(wait=False):
47adfe2030SMax Reitz            if (event['event'] == 'DEVICE_TRAY_MOVED' and
48adfe2030SMax Reitz                event['data']['device'] == 'drive0'):
49adfe2030SMax Reitz                if event['data']['tray-open'] == False:
50adfe2030SMax Reitz                    self.has_closed = True
51adfe2030SMax Reitz                else:
52adfe2030SMax Reitz                    self.has_opened = True
53adfe2030SMax Reitz
54adfe2030SMax Reitz    def wait_for_open(self):
55abb3e55bSMax Reitz        if not self.has_real_tray:
56abb3e55bSMax Reitz            return
57abb3e55bSMax Reitz
58d8336c6bSKevin Wolf        with iotests.Timeout(3, 'Timeout while waiting for the tray to open'):
59d8336c6bSKevin Wolf            while not self.has_opened:
60adfe2030SMax Reitz                self.process_events()
61adfe2030SMax Reitz
62adfe2030SMax Reitz    def wait_for_close(self):
63abb3e55bSMax Reitz        if not self.has_real_tray:
64abb3e55bSMax Reitz            return
65abb3e55bSMax Reitz
66d8336c6bSKevin Wolf        with iotests.Timeout(3, 'Timeout while waiting for the tray to close'):
67d8336c6bSKevin Wolf            while not self.has_closed:
68adfe2030SMax Reitz                self.process_events()
69adfe2030SMax Reitz
70adfe2030SMax Reitzclass GeneralChangeTestsBaseClass(ChangeBaseClass):
71486b88bdSKevin Wolf
721d701e0eSMax Reitz    device_name = 'qdev0'
73486b88bdSKevin Wolf
74adfe2030SMax Reitz    def test_change(self):
75adfe2030SMax Reitz        result = self.vm.qmp('change', device='drive0', target=new_img,
76adfe2030SMax Reitz                                       arg=iotests.imgfmt)
77adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
78adfe2030SMax Reitz
79adfe2030SMax Reitz        self.wait_for_open()
80adfe2030SMax Reitz        self.wait_for_close()
81adfe2030SMax Reitz
82adfe2030SMax Reitz        result = self.vm.qmp('query-block')
83abb3e55bSMax Reitz        if self.has_real_tray:
84adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
85adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
86adfe2030SMax Reitz
87adfe2030SMax Reitz    def test_blockdev_change_medium(self):
88486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-change-medium',
89486b88bdSKevin Wolf                             id=self.device_name, filename=new_img,
90adfe2030SMax Reitz                             format=iotests.imgfmt)
91486b88bdSKevin Wolf
92adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
93adfe2030SMax Reitz
94adfe2030SMax Reitz        self.wait_for_open()
95adfe2030SMax Reitz        self.wait_for_close()
96adfe2030SMax Reitz
97adfe2030SMax Reitz        result = self.vm.qmp('query-block')
98abb3e55bSMax Reitz        if self.has_real_tray:
99adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
100adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
101adfe2030SMax Reitz
102adfe2030SMax Reitz    def test_eject(self):
103486b88bdSKevin Wolf        result = self.vm.qmp('eject', id=self.device_name, force=True)
104adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
105adfe2030SMax Reitz
106adfe2030SMax Reitz        self.wait_for_open()
107adfe2030SMax Reitz
108adfe2030SMax Reitz        result = self.vm.qmp('query-block')
109abb3e55bSMax Reitz        if self.has_real_tray:
110adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
111adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
112adfe2030SMax Reitz
113adfe2030SMax Reitz    def test_tray_eject_change(self):
114486b88bdSKevin Wolf        result = self.vm.qmp('eject', id=self.device_name, force=True)
115adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
116adfe2030SMax Reitz
117adfe2030SMax Reitz        self.wait_for_open()
118adfe2030SMax Reitz
119adfe2030SMax Reitz        result = self.vm.qmp('query-block')
120abb3e55bSMax Reitz        if self.has_real_tray:
121adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
122adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
123adfe2030SMax Reitz
124486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
125486b88bdSKevin Wolf                             filename=new_img, format=iotests.imgfmt)
126adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
127adfe2030SMax Reitz
128adfe2030SMax Reitz        self.wait_for_close()
129adfe2030SMax Reitz
130adfe2030SMax Reitz        result = self.vm.qmp('query-block')
131abb3e55bSMax Reitz        if self.has_real_tray:
132adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
133adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
134adfe2030SMax Reitz
135adfe2030SMax Reitz    def test_tray_open_close(self):
136486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-open-tray',
137486b88bdSKevin Wolf                             id=self.device_name, force=True)
138adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
139adfe2030SMax Reitz
140adfe2030SMax Reitz        self.wait_for_open()
141adfe2030SMax Reitz
142adfe2030SMax Reitz        result = self.vm.qmp('query-block')
143abb3e55bSMax Reitz        if self.has_real_tray:
144adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
145adfe2030SMax Reitz        if self.was_empty == True:
146adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
147adfe2030SMax Reitz        else:
148adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
149adfe2030SMax Reitz
150486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
151adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
152adfe2030SMax Reitz
153adfe2030SMax Reitz        if self.has_real_tray or not self.was_empty:
154adfe2030SMax Reitz            self.wait_for_close()
155adfe2030SMax Reitz
156adfe2030SMax Reitz        result = self.vm.qmp('query-block')
157abb3e55bSMax Reitz        if self.has_real_tray:
158adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
159adfe2030SMax Reitz        if self.was_empty == True:
160adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
161adfe2030SMax Reitz        else:
162adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
163adfe2030SMax Reitz
164adfe2030SMax Reitz    def test_tray_eject_close(self):
1651d701e0eSMax Reitz        result = self.vm.qmp('eject', id=self.device_name, force=True)
166adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
167adfe2030SMax Reitz
168adfe2030SMax Reitz        self.wait_for_open()
169adfe2030SMax Reitz
170adfe2030SMax Reitz        result = self.vm.qmp('query-block')
171abb3e55bSMax Reitz        if self.has_real_tray:
172adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
173adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
174adfe2030SMax Reitz
175486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
176adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
177adfe2030SMax Reitz
178adfe2030SMax Reitz        self.wait_for_close()
179adfe2030SMax Reitz
180adfe2030SMax Reitz        result = self.vm.qmp('query-block')
181adfe2030SMax Reitz        if self.has_real_tray:
182adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
183adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
184adfe2030SMax Reitz
185adfe2030SMax Reitz    def test_tray_open_change(self):
1861d701e0eSMax Reitz        result = self.vm.qmp('blockdev-open-tray', id=self.device_name,
1871d701e0eSMax Reitz                                                   force=True)
188adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
189adfe2030SMax Reitz
190adfe2030SMax Reitz        self.wait_for_open()
191adfe2030SMax Reitz
192adfe2030SMax Reitz        result = self.vm.qmp('query-block')
193abb3e55bSMax Reitz        if self.has_real_tray:
194adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
195adfe2030SMax Reitz        if self.was_empty == True:
196adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
197adfe2030SMax Reitz        else:
198adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
199adfe2030SMax Reitz
2001d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
201adfe2030SMax Reitz                                                       filename=new_img,
202adfe2030SMax Reitz                                                       format=iotests.imgfmt)
203adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
204adfe2030SMax Reitz
205adfe2030SMax Reitz        self.wait_for_close()
206adfe2030SMax Reitz
207adfe2030SMax Reitz        result = self.vm.qmp('query-block')
208abb3e55bSMax Reitz        if self.has_real_tray:
209adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
210adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
211adfe2030SMax Reitz
21268174160SKevin Wolf    def test_cycle(self, read_only_node=False):
213adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
2140153d2f5SKevin Wolf                             node_name='new',
2150153d2f5SKevin Wolf                             driver=iotests.imgfmt,
21668174160SKevin Wolf                             read_only=read_only_node,
2170153d2f5SKevin Wolf                             file={'filename': new_img,
2180153d2f5SKevin Wolf                                    'driver': 'file'})
219adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
220adfe2030SMax Reitz
221486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-open-tray',
222486b88bdSKevin Wolf                             id=self.device_name, force=True)
223adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
224adfe2030SMax Reitz
225adfe2030SMax Reitz        self.wait_for_open()
226adfe2030SMax Reitz
227adfe2030SMax Reitz        result = self.vm.qmp('query-block')
228abb3e55bSMax Reitz        if self.has_real_tray:
229adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
230adfe2030SMax Reitz        if self.was_empty == True:
231adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
232adfe2030SMax Reitz        else:
233adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
234adfe2030SMax Reitz
23534ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium',
236486b88bdSKevin Wolf                             id=self.device_name)
237adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
238adfe2030SMax Reitz
239adfe2030SMax Reitz        result = self.vm.qmp('query-block')
240abb3e55bSMax Reitz        if self.has_real_tray:
241adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
242adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
243adfe2030SMax Reitz
24434ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium',
245486b88bdSKevin Wolf                             id=self.device_name, node_name='new')
246adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
247adfe2030SMax Reitz
248adfe2030SMax Reitz        result = self.vm.qmp('query-block')
249abb3e55bSMax Reitz        if self.has_real_tray:
250adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
251adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
252adfe2030SMax Reitz
253486b88bdSKevin Wolf        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
254adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
255adfe2030SMax Reitz
256adfe2030SMax Reitz        self.wait_for_close()
257adfe2030SMax Reitz
258adfe2030SMax Reitz        result = self.vm.qmp('query-block')
259abb3e55bSMax Reitz        if self.has_real_tray:
260adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
261adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
262adfe2030SMax Reitz
26368174160SKevin Wolf    def test_cycle_read_only_media(self):
26468174160SKevin Wolf        self.test_cycle(True)
26568174160SKevin Wolf
266adfe2030SMax Reitz    def test_close_on_closed(self):
2671d701e0eSMax Reitz        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
268adfe2030SMax Reitz        # Should be a no-op
269adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
270fa1cfb40SKevin Wolf        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
271adfe2030SMax Reitz
272adfe2030SMax Reitz    def test_remove_on_closed(self):
273abb3e55bSMax Reitz        if not self.has_real_tray:
274adfe2030SMax Reitz            return
275adfe2030SMax Reitz
27634ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
277adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
278adfe2030SMax Reitz
279adfe2030SMax Reitz    def test_insert_on_closed(self):
280abb3e55bSMax Reitz        if not self.has_real_tray:
281adfe2030SMax Reitz            return
282adfe2030SMax Reitz
283adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
2840153d2f5SKevin Wolf                             node_name='new',
2850153d2f5SKevin Wolf                             driver=iotests.imgfmt,
2860153d2f5SKevin Wolf                             file={'filename': new_img,
2870153d2f5SKevin Wolf                                   'driver': 'file'})
288adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
289adfe2030SMax Reitz
29034ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
291adfe2030SMax Reitz                                                       node_name='new')
292adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
293adfe2030SMax Reitz
294adfe2030SMax Reitzclass TestInitiallyFilled(GeneralChangeTestsBaseClass):
295adfe2030SMax Reitz    was_empty = False
296adfe2030SMax Reitz
297*dfc82894SKevin Wolf    def setUp(self):
298adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
299adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
300486b88bdSKevin Wolf        self.vm = iotests.VM()
301*dfc82894SKevin Wolf        self.vm.add_drive(old_img, 'media=%s' % self.media, 'none')
302*dfc82894SKevin Wolf        if self.interface == 'scsi':
303dfa26a11SKevin Wolf            self.vm.add_device('virtio-scsi-pci')
3041d701e0eSMax Reitz        self.vm.add_device('%s,drive=drive0,id=%s' %
305*dfc82894SKevin Wolf                           (interface_to_device_name(self.interface),
3061d701e0eSMax Reitz                            self.device_name))
307adfe2030SMax Reitz        self.vm.launch()
308adfe2030SMax Reitz
309adfe2030SMax Reitz    def tearDown(self):
310adfe2030SMax Reitz        self.vm.shutdown()
311adfe2030SMax Reitz        os.remove(old_img)
312adfe2030SMax Reitz        os.remove(new_img)
313adfe2030SMax Reitz
314adfe2030SMax Reitz    def test_insert_on_filled(self):
315adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
3160153d2f5SKevin Wolf                             node_name='new',
3170153d2f5SKevin Wolf                             driver=iotests.imgfmt,
3180153d2f5SKevin Wolf                             file={'filename': new_img,
3190153d2f5SKevin Wolf                                   'driver': 'file'})
320adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
321adfe2030SMax Reitz
3221d701e0eSMax Reitz        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
323adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
324adfe2030SMax Reitz
325adfe2030SMax Reitz        self.wait_for_open()
326adfe2030SMax Reitz
32734ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
328adfe2030SMax Reitz                                                       node_name='new')
329adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
330adfe2030SMax Reitz
331adfe2030SMax Reitzclass TestInitiallyEmpty(GeneralChangeTestsBaseClass):
332adfe2030SMax Reitz    was_empty = True
333adfe2030SMax Reitz
334*dfc82894SKevin Wolf    def setUp(self):
335adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
336*dfc82894SKevin Wolf        self.vm = iotests.VM().add_drive(None, 'media=%s' % self.media, 'none')
337*dfc82894SKevin Wolf        if self.interface == 'scsi':
338dfa26a11SKevin Wolf            self.vm.add_device('virtio-scsi-pci')
3391d701e0eSMax Reitz        self.vm.add_device('%s,drive=drive0,id=%s' %
340*dfc82894SKevin Wolf                           (interface_to_device_name(self.interface),
3411d701e0eSMax Reitz                            self.device_name))
342adfe2030SMax Reitz        self.vm.launch()
343adfe2030SMax Reitz
344adfe2030SMax Reitz    def tearDown(self):
345adfe2030SMax Reitz        self.vm.shutdown()
346adfe2030SMax Reitz        os.remove(new_img)
347adfe2030SMax Reitz
348adfe2030SMax Reitz    def test_remove_on_empty(self):
3491d701e0eSMax Reitz        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
350adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
351adfe2030SMax Reitz
352adfe2030SMax Reitz        self.wait_for_open()
353adfe2030SMax Reitz
35434ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
355adfe2030SMax Reitz        # Should be a no-op
356adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
357adfe2030SMax Reitz
358*dfc82894SKevin Wolf# Do this in a function to avoid leaking variables like case into the global
359*dfc82894SKevin Wolf# name space (otherwise tests would be run for the abstract base classes)
360*dfc82894SKevin Wolfdef create_basic_test_classes():
361*dfc82894SKevin Wolf    for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True),
362*dfc82894SKevin Wolf                                               ('cdrom', 'scsi', True),
363*dfc82894SKevin Wolf                                               ('disk', 'floppy', False) ]:
364adfe2030SMax Reitz
365*dfc82894SKevin Wolf        for case in [ TestInitiallyFilled, TestInitiallyEmpty ]:
366adfe2030SMax Reitz
367*dfc82894SKevin Wolf            attr = { 'media': media,
368*dfc82894SKevin Wolf                     'interface': interface,
369*dfc82894SKevin Wolf                     'has_real_tray': has_real_tray }
370adfe2030SMax Reitz
371*dfc82894SKevin Wolf            name = '%s_%s_%s' % (case.__name__, media, interface)
372*dfc82894SKevin Wolf            globals()[name] = type(name, (case, ), attr)
373adfe2030SMax Reitz
374*dfc82894SKevin Wolfcreate_basic_test_classes()
375adfe2030SMax Reitz
376adfe2030SMax Reitzclass TestChangeReadOnly(ChangeBaseClass):
3771d701e0eSMax Reitz    device_name = 'qdev0'
3781d701e0eSMax Reitz
379adfe2030SMax Reitz    def setUp(self):
380adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
381adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
382adfe2030SMax Reitz        self.vm = iotests.VM()
383adfe2030SMax Reitz
384adfe2030SMax Reitz    def tearDown(self):
385adfe2030SMax Reitz        self.vm.shutdown()
3864803c5cdSEduardo Habkost        os.chmod(old_img, 0o666)
3874803c5cdSEduardo Habkost        os.chmod(new_img, 0o666)
388adfe2030SMax Reitz        os.remove(old_img)
389adfe2030SMax Reitz        os.remove(new_img)
390adfe2030SMax Reitz
391adfe2030SMax Reitz    def test_ro_ro_retain(self):
3924803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
3934803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
3941d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
3951d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
396adfe2030SMax Reitz        self.vm.launch()
397adfe2030SMax Reitz
398adfe2030SMax Reitz        result = self.vm.qmp('query-block')
399adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
400adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
401adfe2030SMax Reitz
4021d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
403adfe2030SMax Reitz                                                       filename=new_img,
404adfe2030SMax Reitz                                                       format=iotests.imgfmt,
405adfe2030SMax Reitz                                                       read_only_mode='retain')
406adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
407adfe2030SMax Reitz
408adfe2030SMax Reitz        result = self.vm.qmp('query-block')
409adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
410adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
411adfe2030SMax Reitz
412adfe2030SMax Reitz    def test_ro_rw_retain(self):
4134803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
4141d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
4151d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
416adfe2030SMax Reitz        self.vm.launch()
417adfe2030SMax Reitz
418adfe2030SMax Reitz        result = self.vm.qmp('query-block')
419adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
420adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
421adfe2030SMax Reitz
4221d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
423adfe2030SMax Reitz                                                       filename=new_img,
424adfe2030SMax Reitz                                                       format=iotests.imgfmt,
425adfe2030SMax Reitz                                                       read_only_mode='retain')
426adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
427adfe2030SMax Reitz
428adfe2030SMax Reitz        result = self.vm.qmp('query-block')
429adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
430adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
431adfe2030SMax Reitz
432adfe2030SMax Reitz    def test_rw_ro_retain(self):
4334803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
4341d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4351d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
436adfe2030SMax Reitz        self.vm.launch()
437adfe2030SMax Reitz
438adfe2030SMax Reitz        result = self.vm.qmp('query-block')
439adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
440adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
441adfe2030SMax Reitz
4421d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
443adfe2030SMax Reitz                                                       filename=new_img,
444adfe2030SMax Reitz                                                       format=iotests.imgfmt,
445adfe2030SMax Reitz                                                       read_only_mode='retain')
446adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
447adfe2030SMax Reitz
448fa1cfb40SKevin Wolf        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
449adfe2030SMax Reitz
450adfe2030SMax Reitz        result = self.vm.qmp('query-block')
451adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
452adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
453adfe2030SMax Reitz
454adfe2030SMax Reitz    def test_ro_rw(self):
4554803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
4561d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
4571d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
458adfe2030SMax Reitz        self.vm.launch()
459adfe2030SMax Reitz
460adfe2030SMax Reitz        result = self.vm.qmp('query-block')
461adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
462adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
463adfe2030SMax Reitz
464adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
4651d701e0eSMax Reitz                             id=self.device_name,
466adfe2030SMax Reitz                             filename=new_img,
467adfe2030SMax Reitz                             format=iotests.imgfmt,
468adfe2030SMax Reitz                             read_only_mode='read-write')
469adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
470adfe2030SMax Reitz
471adfe2030SMax Reitz        result = self.vm.qmp('query-block')
472adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
473adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
474adfe2030SMax Reitz
475adfe2030SMax Reitz    def test_rw_ro(self):
4764803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
4771d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4781d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
479adfe2030SMax Reitz        self.vm.launch()
480adfe2030SMax Reitz
481adfe2030SMax Reitz        result = self.vm.qmp('query-block')
482adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
483adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
484adfe2030SMax Reitz
485adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
4861d701e0eSMax Reitz                             id=self.device_name,
487adfe2030SMax Reitz                             filename=new_img,
488adfe2030SMax Reitz                             format=iotests.imgfmt,
489adfe2030SMax Reitz                             read_only_mode='read-only')
490adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
491adfe2030SMax Reitz
492adfe2030SMax Reitz        result = self.vm.qmp('query-block')
493adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
494adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
495adfe2030SMax Reitz
496adfe2030SMax Reitz    def test_make_rw_ro(self):
4971d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4981d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
499adfe2030SMax Reitz        self.vm.launch()
500adfe2030SMax Reitz
501adfe2030SMax Reitz        result = self.vm.qmp('query-block')
502adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
503adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
504adfe2030SMax Reitz
505adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
5061d701e0eSMax Reitz                             id=self.device_name,
507adfe2030SMax Reitz                             filename=new_img,
508adfe2030SMax Reitz                             format=iotests.imgfmt,
509adfe2030SMax Reitz                             read_only_mode='read-only')
510adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
511adfe2030SMax Reitz
512adfe2030SMax Reitz        result = self.vm.qmp('query-block')
513adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
514adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
515adfe2030SMax Reitz
516adfe2030SMax Reitz    def test_make_ro_rw(self):
5174803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
5181d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
5191d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
520adfe2030SMax Reitz        self.vm.launch()
521adfe2030SMax Reitz
522adfe2030SMax Reitz        result = self.vm.qmp('query-block')
523adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
524adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
525adfe2030SMax Reitz
526adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
5271d701e0eSMax Reitz                             id=self.device_name,
528adfe2030SMax Reitz                             filename=new_img,
529adfe2030SMax Reitz                             format=iotests.imgfmt,
530adfe2030SMax Reitz                             read_only_mode='read-write')
531adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
532adfe2030SMax Reitz
533adfe2030SMax Reitz        result = self.vm.qmp('query-block')
534adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
535adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
536adfe2030SMax Reitz
537adfe2030SMax Reitz    def test_make_rw_ro_by_retain(self):
5384803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
5391d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
5401d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
541adfe2030SMax Reitz        self.vm.launch()
542adfe2030SMax Reitz
543adfe2030SMax Reitz        result = self.vm.qmp('query-block')
544adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
545adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
546adfe2030SMax Reitz
5471d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
548adfe2030SMax Reitz                                                       filename=new_img,
549adfe2030SMax Reitz                                                       format=iotests.imgfmt,
550adfe2030SMax Reitz                                                       read_only_mode='retain')
551adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
552adfe2030SMax Reitz
553adfe2030SMax Reitz        result = self.vm.qmp('query-block')
554adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
555adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
556adfe2030SMax Reitz
557adfe2030SMax Reitz    def test_make_ro_rw_by_retain(self):
5584803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
5591d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
5601d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
561adfe2030SMax Reitz        self.vm.launch()
562adfe2030SMax Reitz
563adfe2030SMax Reitz        result = self.vm.qmp('query-block')
564adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
565adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
566adfe2030SMax Reitz
5671d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
568adfe2030SMax Reitz                                                       filename=new_img,
569adfe2030SMax Reitz                                                       format=iotests.imgfmt,
570adfe2030SMax Reitz                                                       read_only_mode='retain')
571adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
572adfe2030SMax Reitz
573adfe2030SMax Reitz        result = self.vm.qmp('query-block')
574adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
575adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
576adfe2030SMax Reitz
577adfe2030SMax Reitz    def test_rw_ro_cycle(self):
5784803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
5791d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
5801d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
581adfe2030SMax Reitz        self.vm.launch()
582adfe2030SMax Reitz
583adfe2030SMax Reitz        result = self.vm.qmp('query-block')
584adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
585adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
586adfe2030SMax Reitz
587adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
5880153d2f5SKevin Wolf                             node_name='new',
5890153d2f5SKevin Wolf                             driver=iotests.imgfmt,
5900153d2f5SKevin Wolf                             read_only=True,
5910153d2f5SKevin Wolf                             file={'filename': new_img,
5920153d2f5SKevin Wolf                                    'driver': 'file'})
593adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
594adfe2030SMax Reitz
595adfe2030SMax Reitz        result = self.vm.qmp('query-block')
596adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
597adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
598adfe2030SMax Reitz
59934ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
600adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
601adfe2030SMax Reitz
602adfe2030SMax Reitz        result = self.vm.qmp('query-block')
603adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
604adfe2030SMax Reitz
60534ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
606adfe2030SMax Reitz                                                       node_name='new')
607adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
608adfe2030SMax Reitz
609adfe2030SMax Reitz        result = self.vm.qmp('query-block')
610adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
611adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
612adfe2030SMax Reitz
613adfe2030SMax Reitz        result = self.vm.qmp('query-block')
614adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
615adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
616adfe2030SMax Reitz
617adfe2030SMax ReitzGeneralChangeTestsBaseClass = None
618adfe2030SMax ReitzTestInitiallyFilled = None
619adfe2030SMax ReitzTestInitiallyEmpty = None
620adfe2030SMax Reitz
621adfe2030SMax Reitz
622adfe2030SMax Reitzclass TestBlockJobsAfterCycle(ChangeBaseClass):
6231d701e0eSMax Reitz    device_name = 'qdev0'
6241d701e0eSMax Reitz
625adfe2030SMax Reitz    def setUp(self):
6261d701e0eSMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
627adfe2030SMax Reitz
628adfe2030SMax Reitz        self.vm = iotests.VM()
629e4fd2e9dSKevin Wolf        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
6301d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
631adfe2030SMax Reitz        self.vm.launch()
632adfe2030SMax Reitz
633adfe2030SMax Reitz        result = self.vm.qmp('query-block')
634adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
635adfe2030SMax Reitz
636adfe2030SMax Reitz        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
637adfe2030SMax Reitz        # is not necessary
63834ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
639adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
640adfe2030SMax Reitz
641adfe2030SMax Reitz        result = self.vm.qmp('query-block')
642adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
643adfe2030SMax Reitz
644adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
6450153d2f5SKevin Wolf                             node_name='node0',
6460153d2f5SKevin Wolf                             driver=iotests.imgfmt,
6470153d2f5SKevin Wolf                             file={'filename': old_img,
6480153d2f5SKevin Wolf                                   'driver': 'file'})
649adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
650adfe2030SMax Reitz
65134ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
652adfe2030SMax Reitz                                                       node_name='node0')
653adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
654adfe2030SMax Reitz
655adfe2030SMax Reitz        result = self.vm.qmp('query-block')
656adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
657adfe2030SMax Reitz
658adfe2030SMax Reitz    def tearDown(self):
659adfe2030SMax Reitz        self.vm.shutdown()
660adfe2030SMax Reitz        os.remove(old_img)
661adfe2030SMax Reitz        try:
662adfe2030SMax Reitz            os.remove(new_img)
663adfe2030SMax Reitz        except OSError:
664adfe2030SMax Reitz            pass
665adfe2030SMax Reitz
666adfe2030SMax Reitz    def test_snapshot_and_commit(self):
667adfe2030SMax Reitz        # We need backing file support
668adfe2030SMax Reitz        if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
669adfe2030SMax Reitz            return
670adfe2030SMax Reitz
671adfe2030SMax Reitz        result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
672adfe2030SMax Reitz                                                       snapshot_file=new_img,
673adfe2030SMax Reitz                                                       format=iotests.imgfmt)
674adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
675adfe2030SMax Reitz
676adfe2030SMax Reitz        result = self.vm.qmp('query-block')
677adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
678adfe2030SMax Reitz        self.assert_qmp(result,
679adfe2030SMax Reitz                        'return[0]/inserted/image/backing-image/filename',
680adfe2030SMax Reitz                        old_img)
681adfe2030SMax Reitz
682adfe2030SMax Reitz        result = self.vm.qmp('block-commit', device='drive0')
683adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
684adfe2030SMax Reitz
685adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_READY')
686adfe2030SMax Reitz
687adfe2030SMax Reitz        result = self.vm.qmp('query-block-jobs')
688adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/device', 'drive0')
689adfe2030SMax Reitz
690adfe2030SMax Reitz        result = self.vm.qmp('block-job-complete', device='drive0')
691adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
692adfe2030SMax Reitz
693adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
694adfe2030SMax Reitz
695adfe2030SMax Reitz
696adfe2030SMax Reitzif __name__ == '__main__':
697adfe2030SMax Reitz    if iotests.qemu_default_machine != 'pc':
698adfe2030SMax Reitz        # We need floppy and IDE CD-ROM
699adfe2030SMax Reitz        iotests.notrun('not suitable for this machine type: %s' %
700adfe2030SMax Reitz                       iotests.qemu_default_machine)
701cc8c46b7SMax Reitz    # Need to support image creation
702cc8c46b7SMax Reitz    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
703cc8c46b7SMax Reitz                                 'vmdk', 'raw', 'vhdx', 'qed'])
704