xref: /openbmc/qemu/tests/qemu-iotests/118 (revision 6c9ae1ce82b65faa3f266fd103729878cf11e07e)
1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3
29dd003a9SVladimir Sementsov-Ogievskiy# group: rw
3adfe2030SMax Reitz#
4014bb4b0SMax Reitz# Test case for media change monitor 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
4519462c4bSKevin Wolf    device_name = 'qdev0'
4619462c4bSKevin Wolf    use_drive = False
4719462c4bSKevin Wolf
48adfe2030SMax Reitz    def process_events(self):
49adfe2030SMax Reitz        for event in self.vm.get_qmp_events(wait=False):
50adfe2030SMax Reitz            if (event['event'] == 'DEVICE_TRAY_MOVED' and
5119462c4bSKevin Wolf                (event['data']['device'] == 'drive0' or
5219462c4bSKevin Wolf                 event['data']['id'] == self.device_name)):
53adfe2030SMax Reitz                if event['data']['tray-open'] == False:
54adfe2030SMax Reitz                    self.has_closed = True
55adfe2030SMax Reitz                else:
56adfe2030SMax Reitz                    self.has_opened = True
57adfe2030SMax Reitz
58adfe2030SMax Reitz    def wait_for_open(self):
59abb3e55bSMax Reitz        if not self.has_real_tray:
60abb3e55bSMax Reitz            return
61abb3e55bSMax Reitz
62d8336c6bSKevin Wolf        with iotests.Timeout(3, 'Timeout while waiting for the tray to open'):
63d8336c6bSKevin Wolf            while not self.has_opened:
64adfe2030SMax Reitz                self.process_events()
65adfe2030SMax Reitz
66adfe2030SMax Reitz    def wait_for_close(self):
67abb3e55bSMax Reitz        if not self.has_real_tray:
68abb3e55bSMax Reitz            return
69abb3e55bSMax Reitz
70d8336c6bSKevin Wolf        with iotests.Timeout(3, 'Timeout while waiting for the tray to close'):
71d8336c6bSKevin Wolf            while not self.has_closed:
72adfe2030SMax Reitz                self.process_events()
73adfe2030SMax Reitz
74adfe2030SMax Reitzclass GeneralChangeTestsBaseClass(ChangeBaseClass):
75486b88bdSKevin Wolf
76adfe2030SMax Reitz    def test_blockdev_change_medium(self):
77b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium',
78486b88bdSKevin Wolf                    id=self.device_name, filename=new_img,
79adfe2030SMax Reitz                    format=iotests.imgfmt)
80486b88bdSKevin Wolf
81adfe2030SMax Reitz        self.wait_for_open()
82adfe2030SMax Reitz        self.wait_for_close()
83adfe2030SMax Reitz
84adfe2030SMax Reitz        result = self.vm.qmp('query-block')
85abb3e55bSMax Reitz        if self.has_real_tray:
86adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
87adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
88adfe2030SMax Reitz
89adfe2030SMax Reitz    def test_eject(self):
90b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('eject', id=self.device_name, force=True)
91adfe2030SMax Reitz
92adfe2030SMax Reitz        self.wait_for_open()
93adfe2030SMax Reitz
94adfe2030SMax Reitz        result = self.vm.qmp('query-block')
95abb3e55bSMax Reitz        if self.has_real_tray:
96adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
97adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
98adfe2030SMax Reitz
99adfe2030SMax Reitz    def test_tray_eject_change(self):
100b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('eject', id=self.device_name, force=True)
101adfe2030SMax Reitz
102adfe2030SMax Reitz        self.wait_for_open()
103adfe2030SMax Reitz
104adfe2030SMax Reitz        result = self.vm.qmp('query-block')
105abb3e55bSMax Reitz        if self.has_real_tray:
106adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
107adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
108adfe2030SMax Reitz
109b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium', id=self.device_name,
110486b88bdSKevin Wolf                    filename=new_img, format=iotests.imgfmt)
111adfe2030SMax Reitz
112adfe2030SMax Reitz        self.wait_for_close()
113adfe2030SMax Reitz
114adfe2030SMax Reitz        result = self.vm.qmp('query-block')
115abb3e55bSMax Reitz        if self.has_real_tray:
116adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
117adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
118adfe2030SMax Reitz
119adfe2030SMax Reitz    def test_tray_open_close(self):
120b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-open-tray',
121486b88bdSKevin Wolf                    id=self.device_name, force=True)
122adfe2030SMax Reitz
123adfe2030SMax Reitz        self.wait_for_open()
124adfe2030SMax Reitz
125adfe2030SMax Reitz        result = self.vm.qmp('query-block')
126abb3e55bSMax Reitz        if self.has_real_tray:
127adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
128adfe2030SMax Reitz        if self.was_empty == True:
129adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
130adfe2030SMax Reitz        else:
131adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
132adfe2030SMax Reitz
133b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-close-tray', id=self.device_name)
134adfe2030SMax Reitz
135adfe2030SMax Reitz        if self.has_real_tray or not self.was_empty:
136adfe2030SMax Reitz            self.wait_for_close()
137adfe2030SMax Reitz
138adfe2030SMax Reitz        result = self.vm.qmp('query-block')
139abb3e55bSMax Reitz        if self.has_real_tray:
140adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
141adfe2030SMax Reitz        if self.was_empty == True:
142adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
143adfe2030SMax Reitz        else:
144adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
145adfe2030SMax Reitz
146adfe2030SMax Reitz    def test_tray_eject_close(self):
147b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('eject', id=self.device_name, force=True)
148adfe2030SMax Reitz
149adfe2030SMax Reitz        self.wait_for_open()
150adfe2030SMax Reitz
151adfe2030SMax Reitz        result = self.vm.qmp('query-block')
152abb3e55bSMax Reitz        if self.has_real_tray:
153adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
154adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
155adfe2030SMax Reitz
156b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-close-tray', id=self.device_name)
157adfe2030SMax Reitz
158adfe2030SMax Reitz        self.wait_for_close()
159adfe2030SMax Reitz
160adfe2030SMax Reitz        result = self.vm.qmp('query-block')
161adfe2030SMax Reitz        if self.has_real_tray:
162adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
163adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
164adfe2030SMax Reitz
165adfe2030SMax Reitz    def test_tray_open_change(self):
166b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-open-tray', id=self.device_name,
1671d701e0eSMax Reitz                                          force=True)
168adfe2030SMax Reitz
169adfe2030SMax Reitz        self.wait_for_open()
170adfe2030SMax Reitz
171adfe2030SMax Reitz        result = self.vm.qmp('query-block')
172abb3e55bSMax Reitz        if self.has_real_tray:
173adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
174adfe2030SMax Reitz        if self.was_empty == True:
175adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
176adfe2030SMax Reitz        else:
177adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
178adfe2030SMax Reitz
179b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium', id=self.device_name,
180adfe2030SMax Reitz                                              filename=new_img,
181adfe2030SMax Reitz                                              format=iotests.imgfmt)
182adfe2030SMax Reitz
183adfe2030SMax Reitz        self.wait_for_close()
184adfe2030SMax Reitz
185adfe2030SMax Reitz        result = self.vm.qmp('query-block')
186abb3e55bSMax Reitz        if self.has_real_tray:
187adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
188adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
189adfe2030SMax Reitz
19068174160SKevin Wolf    def test_cycle(self, read_only_node=False):
191b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-add',
1920153d2f5SKevin Wolf                    node_name='new',
1930153d2f5SKevin Wolf                    driver=iotests.imgfmt,
19468174160SKevin Wolf                    read_only=read_only_node,
1950153d2f5SKevin Wolf                    file={'filename': new_img,
1960153d2f5SKevin Wolf                           'driver': 'file'})
197adfe2030SMax Reitz
198b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-open-tray',
199486b88bdSKevin Wolf                    id=self.device_name, force=True)
200adfe2030SMax Reitz
201adfe2030SMax Reitz        self.wait_for_open()
202adfe2030SMax Reitz
203adfe2030SMax Reitz        result = self.vm.qmp('query-block')
204abb3e55bSMax Reitz        if self.has_real_tray:
205adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
206adfe2030SMax Reitz        if self.was_empty == True:
207adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
208adfe2030SMax Reitz        else:
209adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
210adfe2030SMax Reitz
211b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-remove-medium',
212486b88bdSKevin Wolf                    id=self.device_name)
213adfe2030SMax Reitz
214adfe2030SMax Reitz        result = self.vm.qmp('query-block')
215abb3e55bSMax Reitz        if self.has_real_tray:
216adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
217adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
218adfe2030SMax Reitz
219b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-insert-medium',
220486b88bdSKevin Wolf                    id=self.device_name, node_name='new')
221adfe2030SMax Reitz
222adfe2030SMax Reitz        result = self.vm.qmp('query-block')
223abb3e55bSMax Reitz        if self.has_real_tray:
224adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
225adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
226adfe2030SMax Reitz
227b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-close-tray', id=self.device_name)
228adfe2030SMax Reitz
229adfe2030SMax Reitz        self.wait_for_close()
230adfe2030SMax Reitz
231adfe2030SMax Reitz        result = self.vm.qmp('query-block')
232abb3e55bSMax Reitz        if self.has_real_tray:
233adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
234adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
235adfe2030SMax Reitz
23668174160SKevin Wolf    def test_cycle_read_only_media(self):
23768174160SKevin Wolf        self.test_cycle(True)
23868174160SKevin Wolf
239adfe2030SMax Reitz    def test_close_on_closed(self):
240adfe2030SMax Reitz        # Should be a no-op
241b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-close-tray', id=self.device_name)
242fa1cfb40SKevin Wolf        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
243adfe2030SMax Reitz
244adfe2030SMax Reitz    def test_remove_on_closed(self):
245abb3e55bSMax Reitz        if not self.has_real_tray:
246adfe2030SMax Reitz            return
247adfe2030SMax Reitz
24834ce1111SMax Reitz        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
249adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
250adfe2030SMax Reitz
251adfe2030SMax Reitz    def test_insert_on_closed(self):
252abb3e55bSMax Reitz        if not self.has_real_tray:
253adfe2030SMax Reitz            return
254adfe2030SMax Reitz
255b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-add',
2560153d2f5SKevin Wolf                    node_name='new',
2570153d2f5SKevin Wolf                    driver=iotests.imgfmt,
2580153d2f5SKevin Wolf                    file={'filename': new_img,
2590153d2f5SKevin Wolf                          'driver': 'file'})
260adfe2030SMax Reitz
26134ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
262adfe2030SMax Reitz                                                       node_name='new')
263adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
264adfe2030SMax Reitz
265adfe2030SMax Reitzclass TestInitiallyFilled(GeneralChangeTestsBaseClass):
266adfe2030SMax Reitz    was_empty = False
267adfe2030SMax Reitz
268dfc82894SKevin Wolf    def setUp(self):
269adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
270adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
271486b88bdSKevin Wolf        self.vm = iotests.VM()
27219462c4bSKevin Wolf        if self.use_drive:
273dfc82894SKevin Wolf            self.vm.add_drive(old_img, 'media=%s' % self.media, 'none')
27419462c4bSKevin Wolf        else:
27519462c4bSKevin Wolf            self.vm.add_blockdev([ 'node-name=drive0',
27619462c4bSKevin Wolf                                   'driver=%s' % iotests.imgfmt,
27719462c4bSKevin Wolf                                   'file.driver=file',
27819462c4bSKevin Wolf                                   'file.filename=%s' % old_img ])
279dfc82894SKevin Wolf        if self.interface == 'scsi':
280*3be57622SKevin Wolf            self.vm.add_object('iothread,id=iothread0')
281*3be57622SKevin Wolf            self.vm.add_device('virtio-scsi-pci,iothread=iothread0')
2821d701e0eSMax Reitz        self.vm.add_device('%s,drive=drive0,id=%s' %
283dfc82894SKevin Wolf                           (interface_to_device_name(self.interface),
2841d701e0eSMax Reitz                            self.device_name))
285adfe2030SMax Reitz        self.vm.launch()
286adfe2030SMax Reitz
287adfe2030SMax Reitz    def tearDown(self):
288adfe2030SMax Reitz        self.vm.shutdown()
289adfe2030SMax Reitz        os.remove(old_img)
290adfe2030SMax Reitz        os.remove(new_img)
291adfe2030SMax Reitz
292adfe2030SMax Reitz    def test_insert_on_filled(self):
293b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-add',
2940153d2f5SKevin Wolf                    node_name='new',
2950153d2f5SKevin Wolf                    driver=iotests.imgfmt,
2960153d2f5SKevin Wolf                    file={'filename': new_img,
2970153d2f5SKevin Wolf                          'driver': 'file'})
298adfe2030SMax Reitz
299b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-open-tray', id=self.device_name)
300adfe2030SMax Reitz
301adfe2030SMax Reitz        self.wait_for_open()
302adfe2030SMax Reitz
30334ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
304adfe2030SMax Reitz                                                       node_name='new')
305adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
306adfe2030SMax Reitz
307adfe2030SMax Reitzclass TestInitiallyEmpty(GeneralChangeTestsBaseClass):
308adfe2030SMax Reitz    was_empty = True
309adfe2030SMax Reitz
310dfc82894SKevin Wolf    def setUp(self):
311adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
31219462c4bSKevin Wolf        self.vm = iotests.VM()
31319462c4bSKevin Wolf        if self.use_drive:
31419462c4bSKevin Wolf            self.vm.add_drive(None, 'media=%s' % self.media, 'none')
315dfc82894SKevin Wolf        if self.interface == 'scsi':
316*3be57622SKevin Wolf            self.vm.add_object('iothread,id=iothread0')
317*3be57622SKevin Wolf            self.vm.add_device('virtio-scsi-pci,iothread=iothread0')
31819462c4bSKevin Wolf        self.vm.add_device('%s,%sid=%s' %
319dfc82894SKevin Wolf                           (interface_to_device_name(self.interface),
32019462c4bSKevin Wolf                            'drive=drive0,' if self.use_drive else '',
3211d701e0eSMax Reitz                            self.device_name))
322adfe2030SMax Reitz        self.vm.launch()
323adfe2030SMax Reitz
324adfe2030SMax Reitz    def tearDown(self):
325adfe2030SMax Reitz        self.vm.shutdown()
326adfe2030SMax Reitz        os.remove(new_img)
327adfe2030SMax Reitz
328adfe2030SMax Reitz    def test_remove_on_empty(self):
329b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-open-tray', id=self.device_name)
330adfe2030SMax Reitz
331adfe2030SMax Reitz        self.wait_for_open()
332adfe2030SMax Reitz
333adfe2030SMax Reitz        # Should be a no-op
334b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
335adfe2030SMax Reitz
336dfc82894SKevin Wolf# Do this in a function to avoid leaking variables like case into the global
337dfc82894SKevin Wolf# name space (otherwise tests would be run for the abstract base classes)
338dfc82894SKevin Wolfdef create_basic_test_classes():
339dfc82894SKevin Wolf    for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True),
340dfc82894SKevin Wolf                                               ('cdrom', 'scsi', True),
341dfc82894SKevin Wolf                                               ('disk', 'floppy', False) ]:
342adfe2030SMax Reitz
343dfc82894SKevin Wolf        for case in [ TestInitiallyFilled, TestInitiallyEmpty ]:
34419462c4bSKevin Wolf            for use_drive in [ True, False ]:
345dfc82894SKevin Wolf                attr = { 'media': media,
346dfc82894SKevin Wolf                         'interface': interface,
34719462c4bSKevin Wolf                         'has_real_tray': has_real_tray,
34819462c4bSKevin Wolf                         'use_drive': use_drive }
349adfe2030SMax Reitz
35019462c4bSKevin Wolf                name = '%s_%s_%s_%s' % (case.__name__, media, interface,
35119462c4bSKevin Wolf                                        'drive' if use_drive else 'blockdev')
352dfc82894SKevin Wolf                globals()[name] = type(name, (case, ), attr)
353adfe2030SMax Reitz
354dfc82894SKevin Wolfcreate_basic_test_classes()
355adfe2030SMax Reitz
356adfe2030SMax Reitzclass TestChangeReadOnly(ChangeBaseClass):
3571d701e0eSMax Reitz    device_name = 'qdev0'
3581d701e0eSMax Reitz
359adfe2030SMax Reitz    def setUp(self):
360adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
361adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
362adfe2030SMax Reitz        self.vm = iotests.VM()
363adfe2030SMax Reitz
364adfe2030SMax Reitz    def tearDown(self):
365adfe2030SMax Reitz        self.vm.shutdown()
3664803c5cdSEduardo Habkost        os.chmod(old_img, 0o666)
3674803c5cdSEduardo Habkost        os.chmod(new_img, 0o666)
368adfe2030SMax Reitz        os.remove(old_img)
369adfe2030SMax Reitz        os.remove(new_img)
370adfe2030SMax Reitz
371adfe2030SMax Reitz    def test_ro_ro_retain(self):
3724803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
3734803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
3741d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
3751d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
376adfe2030SMax Reitz        self.vm.launch()
377adfe2030SMax Reitz
378adfe2030SMax Reitz        result = self.vm.qmp('query-block')
379adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
380adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
381adfe2030SMax Reitz
382b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium', id=self.device_name,
383adfe2030SMax Reitz                                              filename=new_img,
384adfe2030SMax Reitz                                              format=iotests.imgfmt,
385adfe2030SMax Reitz                                              read_only_mode='retain')
386adfe2030SMax Reitz
387adfe2030SMax Reitz        result = self.vm.qmp('query-block')
388adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
389adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
390adfe2030SMax Reitz
391adfe2030SMax Reitz    def test_ro_rw_retain(self):
3924803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
3931d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
3941d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
395adfe2030SMax Reitz        self.vm.launch()
396adfe2030SMax Reitz
397adfe2030SMax Reitz        result = self.vm.qmp('query-block')
398adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
399adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
400adfe2030SMax Reitz
401b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium', id=self.device_name,
402adfe2030SMax Reitz                                              filename=new_img,
403adfe2030SMax Reitz                                              format=iotests.imgfmt,
404adfe2030SMax Reitz                                              read_only_mode='retain')
405adfe2030SMax Reitz
406adfe2030SMax Reitz        result = self.vm.qmp('query-block')
407adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
408adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
409adfe2030SMax Reitz
410d926f4ddSKevin Wolf    @iotests.skip_if_user_is_root
411adfe2030SMax Reitz    def test_rw_ro_retain(self):
4124803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
4131d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4141d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
415adfe2030SMax Reitz        self.vm.launch()
416adfe2030SMax Reitz
417adfe2030SMax Reitz        result = self.vm.qmp('query-block')
418adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
419adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
420adfe2030SMax Reitz
4211d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
422adfe2030SMax Reitz                                                       filename=new_img,
423adfe2030SMax Reitz                                                       format=iotests.imgfmt,
424adfe2030SMax Reitz                                                       read_only_mode='retain')
425adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
426adfe2030SMax Reitz
427fa1cfb40SKevin Wolf        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
428adfe2030SMax Reitz
429adfe2030SMax Reitz        result = self.vm.qmp('query-block')
430adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
431adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
432adfe2030SMax Reitz
433adfe2030SMax Reitz    def test_ro_rw(self):
4344803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
4351d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
4361d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
437adfe2030SMax Reitz        self.vm.launch()
438adfe2030SMax Reitz
439adfe2030SMax Reitz        result = self.vm.qmp('query-block')
440adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
441adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
442adfe2030SMax Reitz
443b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium',
4441d701e0eSMax Reitz                    id=self.device_name,
445adfe2030SMax Reitz                    filename=new_img,
446adfe2030SMax Reitz                    format=iotests.imgfmt,
447adfe2030SMax Reitz                    read_only_mode='read-write')
448adfe2030SMax Reitz
449adfe2030SMax Reitz        result = self.vm.qmp('query-block')
450adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
451adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
452adfe2030SMax Reitz
453adfe2030SMax Reitz    def test_rw_ro(self):
4544803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
4551d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4561d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
457adfe2030SMax Reitz        self.vm.launch()
458adfe2030SMax Reitz
459adfe2030SMax Reitz        result = self.vm.qmp('query-block')
460adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
461adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
462adfe2030SMax Reitz
463b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium',
4641d701e0eSMax Reitz                    id=self.device_name,
465adfe2030SMax Reitz                    filename=new_img,
466adfe2030SMax Reitz                    format=iotests.imgfmt,
467adfe2030SMax Reitz                    read_only_mode='read-only')
468adfe2030SMax Reitz
469adfe2030SMax Reitz        result = self.vm.qmp('query-block')
470adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
471adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
472adfe2030SMax Reitz
473adfe2030SMax Reitz    def test_make_rw_ro(self):
4741d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4751d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
476adfe2030SMax Reitz        self.vm.launch()
477adfe2030SMax Reitz
478adfe2030SMax Reitz        result = self.vm.qmp('query-block')
479adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
480adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
481adfe2030SMax Reitz
482b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium',
4831d701e0eSMax Reitz                    id=self.device_name,
484adfe2030SMax Reitz                    filename=new_img,
485adfe2030SMax Reitz                    format=iotests.imgfmt,
486adfe2030SMax Reitz                    read_only_mode='read-only')
487adfe2030SMax Reitz
488adfe2030SMax Reitz        result = self.vm.qmp('query-block')
489adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
490adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
491adfe2030SMax Reitz
492d926f4ddSKevin Wolf    @iotests.skip_if_user_is_root
493adfe2030SMax Reitz    def test_make_ro_rw(self):
4944803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
4951d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
4961d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
497adfe2030SMax Reitz        self.vm.launch()
498adfe2030SMax Reitz
499adfe2030SMax Reitz        result = self.vm.qmp('query-block')
500adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
501adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
502adfe2030SMax Reitz
503adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
5041d701e0eSMax Reitz                             id=self.device_name,
505adfe2030SMax Reitz                             filename=new_img,
506adfe2030SMax Reitz                             format=iotests.imgfmt,
507adfe2030SMax Reitz                             read_only_mode='read-write')
508adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
509adfe2030SMax Reitz
510adfe2030SMax Reitz        result = self.vm.qmp('query-block')
511adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
512adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
513adfe2030SMax Reitz
514adfe2030SMax Reitz    def test_make_rw_ro_by_retain(self):
5154803c5cdSEduardo Habkost        os.chmod(old_img, 0o444)
5161d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
5171d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
518adfe2030SMax Reitz        self.vm.launch()
519adfe2030SMax Reitz
520adfe2030SMax Reitz        result = self.vm.qmp('query-block')
521adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
522adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
523adfe2030SMax Reitz
524b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-change-medium', id=self.device_name,
525adfe2030SMax Reitz                                              filename=new_img,
526adfe2030SMax Reitz                                              format=iotests.imgfmt,
527adfe2030SMax Reitz                                              read_only_mode='retain')
528adfe2030SMax Reitz
529adfe2030SMax Reitz        result = self.vm.qmp('query-block')
530adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
531adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
532adfe2030SMax Reitz
533d926f4ddSKevin Wolf    @iotests.skip_if_user_is_root
534adfe2030SMax Reitz    def test_make_ro_rw_by_retain(self):
5354803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
5361d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
5371d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
538adfe2030SMax Reitz        self.vm.launch()
539adfe2030SMax Reitz
540adfe2030SMax Reitz        result = self.vm.qmp('query-block')
541adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
542adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
543adfe2030SMax Reitz
5441d701e0eSMax Reitz        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
545adfe2030SMax Reitz                                                       filename=new_img,
546adfe2030SMax Reitz                                                       format=iotests.imgfmt,
547adfe2030SMax Reitz                                                       read_only_mode='retain')
548adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
549adfe2030SMax Reitz
550adfe2030SMax Reitz        result = self.vm.qmp('query-block')
551adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
552adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
553adfe2030SMax Reitz
554adfe2030SMax Reitz    def test_rw_ro_cycle(self):
5554803c5cdSEduardo Habkost        os.chmod(new_img, 0o444)
5561d701e0eSMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'none')
5571d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
558adfe2030SMax Reitz        self.vm.launch()
559adfe2030SMax Reitz
560adfe2030SMax Reitz        result = self.vm.qmp('query-block')
561adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
562adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
563adfe2030SMax Reitz
564b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-add',
5650153d2f5SKevin Wolf                    node_name='new',
5660153d2f5SKevin Wolf                    driver=iotests.imgfmt,
5670153d2f5SKevin Wolf                    read_only=True,
5680153d2f5SKevin Wolf                    file={'filename': new_img,
5690153d2f5SKevin Wolf                           'driver': 'file'})
570adfe2030SMax Reitz
571adfe2030SMax Reitz        result = self.vm.qmp('query-block')
572adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
573adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
574adfe2030SMax Reitz
575b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
576adfe2030SMax Reitz
577adfe2030SMax Reitz        result = self.vm.qmp('query-block')
578adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
579adfe2030SMax Reitz
580b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
581adfe2030SMax Reitz                                              node_name='new')
582adfe2030SMax Reitz
583adfe2030SMax Reitz        result = self.vm.qmp('query-block')
584adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
585adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
586adfe2030SMax Reitz
587adfe2030SMax Reitz        result = self.vm.qmp('query-block')
588adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
589adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
590adfe2030SMax Reitz
591adfe2030SMax ReitzGeneralChangeTestsBaseClass = None
592adfe2030SMax ReitzTestInitiallyFilled = None
593adfe2030SMax ReitzTestInitiallyEmpty = None
594adfe2030SMax Reitz
595adfe2030SMax Reitz
596adfe2030SMax Reitzclass TestBlockJobsAfterCycle(ChangeBaseClass):
5971d701e0eSMax Reitz    device_name = 'qdev0'
5981d701e0eSMax Reitz
599adfe2030SMax Reitz    def setUp(self):
6001d701e0eSMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
601adfe2030SMax Reitz
602adfe2030SMax Reitz        self.vm = iotests.VM()
603e4fd2e9dSKevin Wolf        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
6041d701e0eSMax Reitz        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
605adfe2030SMax Reitz        self.vm.launch()
606adfe2030SMax Reitz
607adfe2030SMax Reitz        result = self.vm.qmp('query-block')
608adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
609adfe2030SMax Reitz
610adfe2030SMax Reitz        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
611adfe2030SMax Reitz        # is not necessary
612b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
613adfe2030SMax Reitz
614adfe2030SMax Reitz        result = self.vm.qmp('query-block')
615adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
616adfe2030SMax Reitz
617b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-add',
6180153d2f5SKevin Wolf                    node_name='node0',
6190153d2f5SKevin Wolf                    driver=iotests.imgfmt,
6200153d2f5SKevin Wolf                    file={'filename': old_img,
6210153d2f5SKevin Wolf                          'driver': 'file'})
622adfe2030SMax Reitz
623b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
624adfe2030SMax Reitz                                              node_name='node0')
625adfe2030SMax Reitz
626adfe2030SMax Reitz        result = self.vm.qmp('query-block')
627adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
628adfe2030SMax Reitz
629adfe2030SMax Reitz    def tearDown(self):
630adfe2030SMax Reitz        self.vm.shutdown()
631adfe2030SMax Reitz        os.remove(old_img)
632adfe2030SMax Reitz        try:
633adfe2030SMax Reitz            os.remove(new_img)
634adfe2030SMax Reitz        except OSError:
635adfe2030SMax Reitz            pass
636adfe2030SMax Reitz
637adfe2030SMax Reitz    # We need backing file support
638ff3caf5aSMax Reitz    @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw',
639ff3caf5aSMax Reitz                               'vhdx'))
640ff3caf5aSMax Reitz    def test_snapshot_and_commit(self):
641b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('blockdev-snapshot-sync', device='drive0',
642adfe2030SMax Reitz                                              snapshot_file=new_img,
643adfe2030SMax Reitz                                              format=iotests.imgfmt)
644adfe2030SMax Reitz
645adfe2030SMax Reitz        result = self.vm.qmp('query-block')
646adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
647adfe2030SMax Reitz        self.assert_qmp(result,
648adfe2030SMax Reitz                        'return[0]/inserted/image/backing-image/filename',
649adfe2030SMax Reitz                        old_img)
650adfe2030SMax Reitz
651b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('block-commit', device='drive0')
652adfe2030SMax Reitz
653adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_READY')
654adfe2030SMax Reitz
655adfe2030SMax Reitz        result = self.vm.qmp('query-block-jobs')
656adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/device', 'drive0')
657adfe2030SMax Reitz
658b6aed193SVladimir Sementsov-Ogievskiy        self.vm.cmd('block-job-complete', device='drive0')
659adfe2030SMax Reitz
660adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
661adfe2030SMax Reitz
662adfe2030SMax Reitz
663adfe2030SMax Reitzif __name__ == '__main__':
664adfe2030SMax Reitz    if iotests.qemu_default_machine != 'pc':
665adfe2030SMax Reitz        # We need floppy and IDE CD-ROM
666adfe2030SMax Reitz        iotests.notrun('not suitable for this machine type: %s' %
667adfe2030SMax Reitz                       iotests.qemu_default_machine)
668cc8c46b7SMax Reitz    # Need to support image creation
669cc8c46b7SMax Reitz    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
670103cbc77SMax Reitz                                 'vmdk', 'raw', 'vhdx', 'qed'],
671103cbc77SMax Reitz                 supported_protocols=['file'])
672