#!/usr/bin/python3## Copyright (C) 2022 Red Hat, Inc.# SPDX-License-Identifier: LGPL-2.1-or-laterimport osfrom anacondalib import VirtInstallMachineCase, disk_images, pixel_tests_ignorefrom installer import Installerfrom storage import Storagefrom testlib import nondestructive, test_main # pylint: disable=import-errorfrom utils import check_cockpit_module_js_errorTEST_DIR = os.path.dirname(__file__)ROOT_DIR = os.path.dirname(TEST_DIR)BOTS_DIR = f'{ROOT_DIR}/bots'@nondestructiveclass TestStorageBasic(VirtInstallMachineCase):def testLocalStandardDisks(self):"""Description:Test that the installer can detect and select local standard disksExpected results:- The installer should detect the local standard disks- The installer should allow the user to select the disks- Without any disks selected, the installer should not allow the user to continue- When the selected disk[s] does not have enough space for the installation,the installer should not allow the user to continue- The disk selection should be preserved when moving back and forth between screens- Removing the second disk and rescanning should reflect only the remaining disk(rhbz#2456923)"""b = self.browseri = Installer(b, self.machine)s = Storage(b, self.machine)i.open()i.reach(i.steps.INSTALLATION_METHOD)# Check the auto-selected disk's detailss.check_disk_selected("vda", selected=True, size="16.1 GB")# Wait for the form to be ready before taking a screenshoti.check_next_disabled(False)b.assert_pixels("#app","storage-step-basic",ignore=pixel_tests_ignore,)# Unselect the only available disks.select_disks([("vda", False)])s.wait_no_disks()# Check the next buton is disabled if no disks are selectedi.check_next_disabled()# This attaches a disk to the running VM# However, since the storage module initialization is long completed# the newly added disk, will not be visible in the UI,# until the test clicks on the re-scan buttondev = "vdb"vdb_image = self.add_disk(2, target=dev)s.rescan_disks(["vda", dev])# Check the next button is disabled when not sufficient disk space is availables.select_disks([("vda", False), (dev, True)])i.check_next_disabled()# Check that the disk selection persists when moving next and backs.select_disks([("vda", True), (dev, False)])s.check_disk_selected("vda", True)s.check_disk_selected(dev, False)i.next()i.back()s.check_disk_selected("vda", True)s.check_disk_selected(dev, False)# Try unselecting both disks and expect and errors.select_disks([("vda", False), (dev, False)])s.wait_no_disks()# Check the next button is disabled if no disks are selectedi.check_next_disabled()# Pixel test the storage step when no disks are selectedb.assert_pixels("#app","storage-step-no-disks",ignore=pixel_tests_ignore,)# Check that disk selection is kept on Next and Backs.select_disks([(dev, True), ("vda", True)])i.next()i.back()for disk in ["vda", dev]:s.check_disk_selected(disk)# rhbz#2456923: unplug second disk while it remains in the installer's selection, then rescanself.rem_disk(vdb_image)s.rescan_disks(["vda"])s.check_disk_selected("vda", selected=True)s.check_disk_selected(dev, selected=False)i.check_next_disabled(False)def testScenarioSelection(self):"""Description:Test that the use-free-space scenario is conditionally availableand the user selection for scenario is kept when moving back and forthbetween screens"""b = self.browseri = Installer(b, self.machine)s = Storage(b, self.machine)i.open()i.reach(i.steps.INSTALLATION_METHOD)# Check the default modes.check_scenario_selected("erase-all")# Check that when an unpartitioned disk is selected the "Use free space" scenario is hiddens.wait_scenario_visible("use-free-space", False)# Check that when a partitioned disk is selected the "Use free space" scenario is visibles.partition_disk("/dev/vda", [("10GiB", "lvmpv")])s.rescan_disks()s.wait_scenario_visible("use-free-space")# Storage Configuration# The choice is preserved (stored in the backend).# The choice is available only if the partitioning was reset# (there is enough free space)s.set_scenario("use-free-space")i.next()i.back()s.check_scenario_selected("use-free-space")def testPartitioningObject(self):"""Description:Test which partitioning object ends up being the AppliedPartitioningwhen we go back and forward the storage steps"""b = self.browseri = Installer(b, self.machine)s = Storage(b, self.machine)# Read partitioning data before we do anythingcreated_partitioning = s.dbus_get_created_partitioning()# Go to Review stepi.open()i.reach(i.steps.REVIEW)# Read partitioning data after we went to Review stepnew_applied_partitioning = s.dbus_get_applied_partitioning()new_created_partitioning = s.dbus_get_created_partitioning()# A new AUTOMATIC partitioning object should be created each time the user enters the review pageself.assertEqual(len(created_partitioning) + 1, len(new_created_partitioning))# The applied partitioning object should be the last one createdself.assertEqual(new_applied_partitioning, new_created_partitioning[-1])created_partitioning = new_created_partitioning# Create a few partitioning objects and ensure that these will not mess up with the user's# configurationfor _ in range(10):s.dbus_create_partitioning("AUTOMATIC")# Go back to the Disk Configuration page and re-enter the review screen.# This should create again a new partitioning object and apply it# no matter how many partitioning objects were created beforei.reach_on_sidebar(i.steps.INSTALLATION_METHOD)i.reach(i.steps.REVIEW)new_applied_partitioning = s.dbus_get_applied_partitioning()new_created_partitioning = s.dbus_get_created_partitioning()self.assertEqual(len(created_partitioning) + 11, len(new_created_partitioning))self.assertEqual(new_applied_partitioning, new_created_partitioning[-1])# The applied partitioning should be reset also when going back to installation methodi.click_step_on_sidebar(i.steps.INSTALLATION_METHOD)new_applied_partitioning = s.dbus_get_applied_partitioning()self.assertEqual(new_applied_partitioning, "")def testCockpitJsErrorHandling(self):"""Description:Test that the installer can handle JS errors in the storage moduleand that it does not crash the installerSetup:- Generate a JS error in the storage moduleExpected results:- The installer should not crash- The installer should show a critical error dialog"""b = self.browserm = self.machinei = Installer(b, m)s = Storage(b, m)i.open()i.reach(i.steps.INSTALLATION_METHOD)s.enter_cockpit_storage()check_cockpit_module_js_error(b, "Storage")def _testDiskSelectionLVM_partition_disk(self):b = self.browserm = self.machines = Storage(b, m)s.partition_disk("/dev/vda", [("10GiB", "lvmpv")])s.partition_disk("/dev/vdb", [("10GiB", "lvmpv")])# Create VG on LUKS with the two available disksm.execute("""vgcreate -y vg /dev/vda1 /dev/vdb1lvcreate -y -n lv -l 100%FREE vgmkfs.ext4 -F /dev/vg/lvvgchange -a n vg""")@disk_images([("", 15), ("", 15)])def testDiskSelectionLVM(self):"""Description:Test that the user can't select one PV when VG group spans across multiple disksSetup:- Create a VG group on LVM with two disks- Create a LV on the VG groupExpected results:- The installer should not allow the user to select one of the disks and proceed with the installation"""b = self.browserm = self.machinei = Installer(b, m)s = Storage(b, m)i.open()i.reach(i.steps.INSTALLATION_METHOD)s.set_scenario("erase-all")i.reach(i.steps.STORAGE_CONFIGURATION)i.next(should_fail=True)b.wait_in_text("#anaconda-screen-storage-configuration-step-notification","Selected disks vda contain volume group 'vg' that also uses further unselected disks")if __name__ == '__main__':test_main()