# This work is licensed under the GNU GPLv2 or later. # See the COPYING file in the top-level directory. import os import tests.utils from . import lib class _CloneRow: """ Helper class for interacting with the clone row """ def __init__(self, *args): self.chkcell = args[2] self.txtcell = args[5] self.is_cloneable = self.chkcell.showing self.is_share_requested = ( not self.is_cloneable or not self.chkcell.checked) self.is_clone_requested = not self.is_share_requested def check_in_text(self, substr): lib.utils.check(lambda: substr in self.txtcell.text) def select(self): self.txtcell.click() def _get_all_rows(win): slist = win.find("storage-list") def pred(node): return node.roleName == "table cell" cells = slist.findChildren(pred, isLambda=True) idx = 0 rows = [] cellcount = 6 while idx < len(cells): rows.append(_CloneRow(*cells[idx:idx + cellcount])) idx += cellcount # Skip the next row which is always a separator idx += cellcount return rows ############################################## # UI tests for virt-manager's CloneVM wizard # ############################################## def testCloneSimple(app): # Disable predictable so UUID generation doesn't collide uri = tests.utils.URIs.test_full.replace(",predictable", "") app.uri = uri # Clone 'test-clone-simple' which is the most basic case # Cancel, and reopen win = app.manager_open_clone("test-clone-simple") win.find("Cancel", "push button").click() lib.utils.check(lambda: not win.showing) # Do default clone win = app.manager_open_clone("test-clone-simple") rows = _get_all_rows(win) assert len(rows) == 1 assert rows[0].is_clone_requested rows[0].check_in_text("test-clone-simple.img") win.find("Clone", "push button").click() lib.utils.check(lambda: not win.showing) # Check path was generated correctly win = app.manager_open_clone("test-clone-simple-clone") rows = _get_all_rows(win) assert len(rows) == 1 assert rows[0].is_clone_requested rows[0].check_in_text("test-clone-simple-clone.img") # Share storage and deal with warnings rows[0].chkcell.click() rows[0].check_in_text("Share disk with") # Do 'cancel' first win.find("Clone", "push button").click() app.click_alert_button("cause data to be overwritten", "Cancel") lib.utils.check(lambda: win.active) win.find("Clone", "push button").click() app.click_alert_button("cause data to be overwritten", "OK") lib.utils.check(lambda: not win.active) # Verify the new VM shared storage win = app.manager_open_clone("test-clone-simple-clone1") rows = _get_all_rows(win) assert len(rows) == 1 rows[0].check_in_text("test-clone-simple-clone.img") def testCloneMulti(app): # Clone 'test-clone', check some results, make sure clone works manager = app.topwin manager.window_maximize() # Shutdown this VM to prep for later manager.find("test-many-devices").click() sbutton = manager.find("Shut Down", "push button") sbutton.click() lib.utils.check(lambda: not sbutton.sensitive) # Do a basic clone win = app.manager_open_clone("test-clone") win.find("Clone", "push button").click() lib.utils.check(lambda: not win.showing) manager.find("test-clone1", "table cell") # Check test-many-devices which will not work, but confirm # it errors gracefully win = app.manager_open_clone("test-many-devices") win.find("Clone", "push button").click() app.click_alert_button("relative.sock", "Cancel") # Ensure disconnecting will close the dialog manager.grab_focus() app.manager_conn_disconnect("test testdriver.xml") lib.utils.check(lambda: not win.showing) def testCloneStorageChange(app): # Disable predictable so UUID generation doesn't collide uri = tests.utils.URIs.test_full.replace(",predictable", "") app.uri = uri # Trigger some error handling scenarios win = app.manager_open_clone("test-clone-simple") newname = "test-aaabbb" win.find("Name:", "text").set_text(newname) win.find("Clone", "push button").click() lib.utils.check(lambda: not win.showing) win = app.manager_open_clone(newname) row = _get_all_rows(win)[0] row.check_in_text(newname) oldnewname = newname newname = "test-aaazzzzbbb" win.find("Name:", "text").set_text(newname) row.select() win.find("Details", "push button").click() stgwin = app.root.find("Change storage path", "dialog") pathtxt = stgwin.find(None, "text", "New Path:") lib.utils.check(lambda: newname in pathtxt.text) stgwin.find("Browse", "push button").click() app.select_storagebrowser_volume("default-pool", "iso-vol") lib.utils.check(lambda: "iso-vol" in pathtxt.text) stgwin.find("OK").click() app.click_alert_button("overwrite the existing", "No") lib.utils.check(lambda: stgwin.showing) stgwin.find("OK").click() app.click_alert_button("overwrite the existing", "Yes") lib.utils.check(lambda: not stgwin.showing) # Can't clone onto existing storage volume win.find("Clone", "push button").click() app.click_alert_button(".*Clone onto existing.*", "Close") # Reopen dialog and request to share it win.find("Details", "push button").click() stgwin = app.root.find("Change storage path", "dialog") chkbox = stgwin.find("Create a new", "check") lib.utils.check(lambda: chkbox.checked) chkbox.click() # Cancel and reopen, confirm changes didn't stick stgwin.find("Cancel").click() lib.utils.check(lambda: not stgwin.showing) win.find("Details", "push button").click() stgwin = app.root.find("Change storage path", "dialog") chkbox = stgwin.find("Create a new", "check") lib.utils.check(lambda: chkbox.checked) # Requesting sharing again and exit chkbox.click() stgwin.find("OK").click() lib.utils.check(lambda: not stgwin.active) # Finish install, verify storage was shared win.find("Clone", "push button").click() app.click_alert_button("cause data to be overwritten", "OK") lib.utils.check(lambda: not win.active) win = app.manager_open_clone(newname) row = _get_all_rows(win)[0].check_in_text(oldnewname) def testCloneError(app): # Trigger some error handling scenarios win = app.manager_open_clone("test-clone-full") win.find("Clone", "push button").click() app.click_alert_button("not enough free space", "Close") win.window_close() win = app.manager_open_clone("test-clone-simple") badname = "test/foo" win.find("Name:", "text").set_text(badname) rows = _get_all_rows(win) rows[0].chkcell.click() rows[0].check_in_text("Share disk with") win.find("Clone", "push button").click() win.find("Clone", "push button").click() app.click_alert_button("cause data to be overwritten", "OK") app.click_alert_button(badname, "Close") lib.utils.check(lambda: win.active) def testCloneNonmanaged(app): # Verify unmanaged clone actual works import tempfile tmpsrc = tempfile.NamedTemporaryFile() tmpdst = tempfile.NamedTemporaryFile() open(tmpsrc.name, "w").write(__file__) app.open(xmleditor_enabled=True) manager = app.topwin win = app.manager_open_details("test-clone-simple") win.find("IDE Disk 1", "table cell").click() win.find("XML", "page tab").click() xmleditor = win.find("XML editor") origpath = "/dev/default-pool/test-clone-simple.img" newpath = tmpsrc.name xmleditor.set_text(xmleditor.text.replace(origpath, newpath)) win.find("config-apply").click() win.find("Details", "page tab").click() disksrc = win.find("disk-source-path") lib.utils.check(lambda: disksrc.text == newpath) win.window_close() lib.utils.check(lambda: manager.active) win = app.manager_open_clone("test-clone-simple") row = _get_all_rows(win)[0] row.check_in_text(tmpsrc.name) row.select() win.find("Details", "push button").click() stgwin = app.root.find("Change storage path", "dialog") pathtxt = stgwin.find(None, "text", "New Path:") os.unlink(tmpdst.name) pathtxt.set_text(tmpdst.name) stgwin.find("OK").click() win.find("Clone", "push button").click() lib.utils.check(lambda: not win.active) lib.utils.check(lambda: os.path.exists(tmpdst.name)) assert open(tmpsrc.name).read() == open(tmpdst.name).read()