#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/../common/pywrap", sys.argv)## Copyright (C) 2015 Red Hat, Inc.# SPDX-License-Identifier: LGPL-2.1-or-laterimport storagelibimport testlib@testlib.nondestructiveclass TestStoragePartitions(storagelib.StorageCase):def testPartitions(self):b = self.browserself.login_and_go("/storage")# A loopback device ends with a digit and partitions have# names like "/dev/loop0p1". Check that the storage stack has# no difficulties with that.## We are especially careful to use a device name that doesn't# end in all zeros, because that would be too easy and# wouldn't trigger this bug:## https://github.com/storaged-project/storaged/issues/97dev = self.add_loopback_disk(10, "loop12")self.click_card_row("Storage", name=dev)self.click_card_dropdown("Block device", "Create partition table")self.dialog({"type": "gpt"})b.wait_text(self.card_row_col("GPT partitions", 1, 1), "Free space")self.click_dropdown(self.card_row("GPT partitions", 1), "Create partition")self.dialog({"type": "ext4","mount_point": f"{self.mnt_dir}/foo"})b.wait_text(self.card_row_col("GPT partitions", 1, 3), f"{self.mnt_dir}/foo")self.click_card_row("GPT partitions", 1)self.click_card_dropdown("Partition", "Delete")self.confirm()b.wait_text(self.card_row_col("GPT partitions", 1, 1), "Free space")self.machine.execute(f"until ! findmnt -n {self.mnt_dir}/foo; do sleep 0.1; done")def testSizeSlider(self):m = self.machineb = self.browserself.login_and_go("/storage")disk = self.add_ram_disk()self.click_card_row("Storage", name=disk)self.click_card_dropdown("Solid State Drive", "Create partition table")self.dialog({"type": "gpt"})b.wait_text(self.card_row_col("GPT partitions", 1, 1), "Free space")self.click_dropdown(self.card_row("GPT partitions", 1), "Create partition")self.dialog_wait_open()self.dialog_set_val("type", "empty")slider = self.dialog_field("size") + " .pf-v6-c-slider .pf-v6-c-slider__rail"# Move the slider one pixel past the middle, this should give a fractional size.# See https://github.com/cockpit-project/cockpit/pull/10968 for more about this.width = b.call_js_func('(function (sel) { return ph_find(sel).offsetWidth; })', slider)about_half_way = width / 2 + 1b.mouse(slider, "click", about_half_way, 0)self.dialog_wait_val("size", 27.3)b.focus(slider + " + .pf-v6-c-slider__thumb")b.key("ArrowLeft", 5)self.dialog_wait_val("size", 26.2)# Check that changing units doesn't affect the text inputunit = "1000000000"b.select_from_dropdown(".size-unit > select", unit)self.dialog_wait_val("size", 26.2, unit)# Switch the dialog into the mode where it stores separate text and unit# instead of a numeric value.b.set_input_text(".size-text > input", "26.200001")b.select_from_dropdown(".size-unit > select", "1000000000") # GB# Apply the dialog. This will convert from text+unit back to a# correctly rounded numeric value (which is too large).self.dialog_apply()self.dialog_wait_error("size", "Size is too large")# The text in the input field must not have changedb.wait_val(".size-text > input", "26.200001")# Change unit back to MB. (This must round again, which it# didn't always do.)b.select_from_dropdown(".size-unit > select", "1000000") # MBself.dialog_apply()self.dialog_wait_close()testlib.wait(lambda: m.execute(f"lsblk -no SIZE {disk}1").strip() == "25M")def testResize(self):m = self.machineb = self.browserself.login_and_go("/storage")disk = self.add_ram_disk(100)self.click_card_row("Storage", name=disk)self.click_card_dropdown("Solid State Drive", "Create partition table")self.dialog({"type": "gpt"})b.wait_text(self.card_row_col("GPT partitions", 1, 1), "Free space")# Make two partitions that cover the whole disk.self.click_dropdown(self.card_row("GPT partitions", 1), "Create partition")self.dialog({"type": "ext4","mount_point": f"{self.mnt_dir}/foo1","size": 80},secondary=True)self.click_dropdown(self.card_row("GPT partitions", 2), "Create partition")self.dialog({"type": "ext4","mount_point": f"{self.mnt_dir}/foo2","size": 23},secondary=True)b.wait_text(self.card_row_col("GPT partitions", 1, 4), "79.7 MB")b.wait_text(self.card_row_col("GPT partitions", 2, 4), "23.1 MB")# Shrink the firstself.click_card_row("GPT partitions", 1)b.click(self.card_button("Partition", "Shrink"))self.dialog({"size": 50})b.wait_in_text(self.card_desc("Partition", "Size"), "50.3 MB")# Grow it back externally, Cockpit should complain. Shrink it# again with Cockpit.m.execute(f"parted -s {disk} resizepart 1 80.7MB")b.click(self.card_button("Partition", "Shrink partition"))b.wait_in_text(self.card_desc("Partition", "Size"), "50.3 MB")# Grow it back externally again. Grow the filesystem with# Cockpit.m.execute(f"parted -s {disk} resizepart 1 80.7MB")b.click(self.card_button("Partition", "Grow content"))b.wait_in_text(self.card_desc("Partition", "Size"), "79.7 MB")b.wait_visible(self.card_button("Partition", "Grow") + ":disabled")# Delete second partition and grow the first to take all the# space.b.click(self.card_parent_link())self.click_card_row("GPT partitions", 2)self.click_card_dropdown("Partition", "Delete")self.confirm()self.click_card_row("GPT partitions", location=f"{self.mnt_dir}/foo1 (not mounted)")b.click(self.card_button("Partition", "Grow"))self.dialog({"size": 103})b.wait_visible(self.card_button("Partition", "Grow") + ":disabled")b.wait_in_text(self.card_desc("Partition", "Size"), "103 MB")def testType(self):b = self.browserself.login_and_go("/storage")disk = self.add_ram_disk(100)self.click_card_row("Storage", name=disk)# GPTself.click_card_dropdown("Solid State Drive", "Create partition table")self.dialog({"type": "gpt"})b.wait_text(self.card_row_col("GPT partitions", 1, 1), "Free space")self.click_dropdown(self.card_row("GPT partitions", 1), "Create partition")self.dialog({"type": "empty"})self.click_card_row("GPT partitions", 1)b.wait_text(self.card_desc("Partition", "Type"), "Linux filesystem data")b.click(self.card_desc_action("Partition", "Type"))self.dialog({"type": "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"})b.wait_text(self.card_desc("Partition", "Type"), "EFI system partition")b.click(self.card_desc_action("Partition", "Type"))self.dialog_wait_open()self.dialog_set_val("type", "custom")self.dialog_set_val("custom", "bla bla")self.dialog_apply()self.dialog_wait_error("custom", "Type can only contain the characters 0 to 9, A to F, and \"-\".")self.dialog_set_val("custom", "7D0359A3-02B3-4F0A865C-654403E70625")self.dialog_apply()self.dialog_wait_error("custom", "Type must be of the form NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN.")self.dialog_set_val("custom", "7D0359A3-02B3-4F0A-865C-654403E70625")self.dialog_apply()self.dialog_wait_close()b.wait_text(self.card_desc("Partition", "Type"), "7d0359a3-02b3-4f0a-865c-654403e70625")# DOSb.click(self.card_parent_link())self.click_card_dropdown("Solid State Drive", "Create partition table")self.dialog({"type": "dos"})b.wait_text(self.card_row_col("DOS partitions", 1, 1), "Free space")self.click_dropdown(self.card_row("DOS partitions", 1), "Create partition")self.dialog({"size": 100, "type": "empty"})self.click_card_row("DOS partitions", 1)b.wait_text(self.card_desc("Partition", "Type"), "Linux filesystem data")b.click(self.card_desc_action("Partition", "Type"))self.dialog({"type": "ef"})b.wait_text(self.card_desc("Partition", "Type"), "EFI system partition")b.click(self.card_desc_action("Partition", "Type"))self.dialog_wait_open()self.dialog_set_val("type", "custom")self.dialog_set_val("custom", "bla bla")self.dialog_apply()self.dialog_wait_error("custom", "Type must contain exactly two hexadecimal characters (0 to 9, A to F).")self.dialog_set_val("custom", "C7")self.dialog_apply()self.dialog_wait_close()b.wait_text(self.card_desc("Partition", "Type"), "c7")if __name__ == '__main__':testlib.test_main()