uitests: finish createvm.py coverage

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2020-08-28 20:30:03 -04:00
parent 5442b6a890
commit 30e021bd3d
3 changed files with 262 additions and 66 deletions

View File

@ -45,13 +45,53 @@ class NewVM(uiutils.UITestCase):
"""
Test the wizard's multiple connection handling
"""
# Add an extra connection for test:///default
self.app.root.find("File", "menu").click()
self.app.root.find("Add Connection...", "menu item").click()
win = self.app.root.find_fuzzy("Add Connection", "dialog")
win.combo_select("Hypervisor", "Custom URI")
win.find("uri-entry", "text").set_text("test:///default")
win.find("Connect", "push button").click()
manager = self.app.topwin
def _add_conn(uri):
manager.find("File", "menu").click()
manager.find("Add Connection...", "menu item").click()
win = self.app.root.find_fuzzy("Add Connection", "dialog")
win.combo_select("Hypervisor", "Custom URI")
win.find("uri-entry", "text").set_text(uri)
win.find("Connect", "push button").click()
def _stop_conn(txt):
c = manager.find(txt, "table cell")
c.click()
c.click(button=3)
self.app.root.find("conn-disconnect", "menu item").click()
uiutils.check(lambda: "Not Connected" in c.text)
# Check the dialog shows 'no connection' error
_stop_conn("test testdriver.xml")
newvm = self._open_create_wizard()
newvm.find_fuzzy("No active connection to install on")
newvm.keyCombo("<alt>F4")
uiutils.check(lambda: manager.active)
# Check the xen PV only startup warning
def _capsopt(fname):
capsdir = tests.utils.DATADIR + "/capabilities/"
return ",caps=" + capsdir + fname
# Test empty qemu connection
_add_conn(tests.utils.URIs.kvm + _capsopt("test-empty.xml"))
newvm = self._open_create_wizard()
newvm.find(".*No hypervisor options were found.*KVM kernel modules.*")
newvm.click_title()
newvm.keyCombo("<alt>F4")
_stop_conn("QEMU/KVM")
_add_conn(tests.utils.URIs.kvm_session +
_capsopt("test-qemu-no-kvm.xml"))
newvm = self._open_create_wizard()
newvm.find(".*KVM is not available.*")
newvm.click_title()
newvm.keyCombo("<alt>F4")
_add_conn(tests.utils.URIs.lxc)
_add_conn(tests.utils.URIs.test_full)
_add_conn(tests.utils.URIs.test_default)
# Open the new VM wizard, select a connection
newvm = self._open_create_wizard()
@ -64,15 +104,26 @@ class NewVM(uiutils.UITestCase):
cdrom.click_combo_entry()
cdrom.find_fuzzy(r"\(/dev/sr1\)")
entry.click()
# Launch this so we can verify storage browser is reset too
newvm.find_fuzzy("install-iso-browse", "button").click()
self._select_storagebrowser_volume("default-pool", "iso-vol")
newvm.find_fuzzy("Automatically detect", "check").click()
newvm.find("oslist-entry").set_text("generic")
newvm.find("oslist-popover").find_fuzzy("generic").click()
self.forward(newvm)
# Back up, select test:///default, verify media-combo is now empty
self.back(newvm)
back = newvm.find_fuzzy("Back", "button")
uiutils.check(lambda: not back.sensitive)
newvm.click_title()
newvm.keyCombo("<alt>F4")
newvm = self._open_create_wizard()
newvm.combo_select("create-conn", ".*test default.*")
self.forward(newvm)
cdrom.click_combo_entry()
cdrom.print_nodes()
uiutils.check(lambda: "/dev/sr1" not in cdrom.fmt_nodes())
newvm.find_fuzzy("install-iso-browse", "button").click()
browsewin = self.app.root.find("vmm-storage-browser")
uiutils.check(lambda: "disk-pool" not in browsewin.fmt_nodes())
def testNewVMManualDefault(self):
"""
@ -115,6 +166,15 @@ class NewVM(uiutils.UITestCase):
self.sleep(.5)
self.forward(newvm)
self.sleep(.5)
# Empty triggers a specific codepath
newvm.find_fuzzy("Name", "text").set_text("")
# Name collision failure
newvm.find_fuzzy("Name", "text").set_text("test-many-devices")
newvm.find_fuzzy("Finish", "button").click()
self._click_alert_button("in use", "OK")
newvm.find_fuzzy("Name", "text").set_text("vm1")
newvm.find_fuzzy("Finish", "button").click()
# Delete it from the VM window
@ -129,8 +189,48 @@ class NewVM(uiutils.UITestCase):
# Verify delete dialog and VM dialog are now gone
uiutils.check(lambda: vmwindow.showing is False)
def testNewVMStorage(self):
"""
Test some storage specific paths
"""
newvm = self._open_create_wizard()
def testNewVMCDROM(self):
newvm.find_fuzzy("Manual", "radio").click()
self.forward(newvm)
newvm.find("oslist-entry").set_text("generic")
newvm.find("oslist-popover").find_fuzzy("generic").click()
self.forward(newvm)
self.forward(newvm)
# Trigger size validation failure
sizetext = newvm.find(None, "spin button", "GiB")
sizetext.set_text("10000000")
self.forward(newvm, check=False)
self._click_alert_button("Storage parameter error", "OK")
sizetext.set_text("1")
# Use the storage browser to select a local file
storagetext = newvm.find("storage-entry")
newvm.find_fuzzy("Select or create", "radio").click()
newvm.find("storage-browse").click()
browse = self.app.root.find("vmm-storage-browser")
browse.find("Browse Local", "push button").click()
chooser = self.app.root.find(
"Locate existing storage", "file chooser")
fname = "COPYING"
chooser.find(fname, "table cell").click()
chooser.find("Open", "push button").click()
uiutils.check(lambda: newvm.active)
uiutils.check(lambda: "COPYING" in storagetext.text)
# Start the install
self.forward(newvm)
newvm.find("Finish", "push button").click()
self.app.root.find_fuzzy("vm1 on", "frame")
uiutils.check(lambda: not newvm.showing)
def testNewVMCDROMRegular(self):
"""
Create a new CDROM VM, choosing distro win8, and do some basic
'Customize before install' before exiting
@ -145,9 +245,16 @@ class NewVM(uiutils.UITestCase):
combo.click_combo_entry()
combo.find(r"No media detected \(/dev/sr1\)")
combo.find(r"Fedora12_media \(/dev/sr0\)").click()
# test entry activation too
# Catch validation error
entry = newvm.find("media-entry")
entry.click()
entry.set_text("")
self.forward(newvm, check=False)
self._click_alert_button("media selection is required", "OK")
# test entry activation too
entry.click()
entry.set_text("/dev/sr0")
self.pressKey("Enter")
@ -246,6 +353,24 @@ class NewVM(uiutils.UITestCase):
vmwindow.find_fuzzy("Quit", "menu item").click()
uiutils.check(lambda: self.app.is_running())
def testNewVMCDROMDetect(self):
"""
CDROM with detection
"""
cdrom = tests.utils.DATADIR + "/cli/fake-win7.iso"
newvm = self._open_create_wizard()
newvm.find_fuzzy("Local install media", "radio").click()
self.forward(newvm)
newvm.find("media-entry").click()
newvm.find("media-entry").set_text(cdrom)
# Use forward to trigger detection
self.forward(newvm)
self.forward(newvm)
self.forward(newvm)
newvm.find("Finish", "push button").click()
self.app.root.find_fuzzy("win7 on", "frame")
uiutils.check(lambda: not newvm.showing)
def testNewVMURL(self):
"""
@ -260,9 +385,15 @@ class NewVM(uiutils.UITestCase):
osentry = newvm.find("oslist-entry")
uiutils.check(lambda: osentry.text.startswith("Waiting"))
newvm.find("install-url-entry").set_text("")
self.forward(newvm, check=False)
self._click_alert_button("tree is required", "OK")
url = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/10/Fedora/x86_64/os/"
oslabel = "Fedora 10"
newvm.find("install-url-entry").set_text(url)
newvm.find("install-url-entry").click()
self.pressKey("Enter")
newvm.find("install-urlopts-expander").click_expander()
newvm.find("install-urlopts-entry").set_text("foo=bar")
@ -303,9 +434,18 @@ class NewVM(uiutils.UITestCase):
"Creating Virtual Machine", "frame")
uiutils.check(lambda: not progress.showing, timeout=120)
self.app.root.find_fuzzy("fedora10 on", "frame")
details = self.app.root.find_fuzzy("fedora10 on", "frame")
uiutils.check(lambda: not newvm.showing)
# Re-run the newvm wizard, check that URL was remembered
details.keyCombo("<alt>F4")
newvm = self._open_create_wizard()
newvm.find_fuzzy("Network Install", "radio").click()
self.forward(newvm)
urlcombo = newvm.find("install-url-combo")
uiutils.check(lambda: urlcombo.showing)
uiutils.check(lambda: url in urlcombo.fmt_nodes())
def testNewKVMQ35Tweaks(self):
"""
New VM that should default to Q35, but tweak things a bunch
@ -700,11 +840,16 @@ class NewVM(uiutils.UITestCase):
newvm = self._open_create_wizard()
newvm.find_fuzzy("Container", "radio").click()
newvm.find_fuzzy("Virtual machine", "radio").click()
newvm.find_fuzzy("Container", "radio").click()
self.forward(newvm)
# Set directory path
newvm.find_fuzzy(None,
"text", "container template").set_text("centos-6-x86_64")
templatetext = newvm.find_fuzzy(None, "text", "container template")
templatetext.set_text("")
self.forward(newvm, check=False)
self._click_alert_button("template name is required", "OK")
templatetext.set_text("centos-6-x86_64")
self.forward(newvm)
self.forward(newvm)
newvm.find_fuzzy("Finish", "button").click()
@ -728,11 +873,42 @@ class NewVM(uiutils.UITestCase):
import tempfile
tmpdir = tempfile.TemporaryDirectory()
newvm.find_fuzzy("Create OS directory", "check box").click()
uritext = newvm.find("install-oscontainer-source-uri")
uritext.text = ""
self.forward(newvm, check=False)
self._click_alert_button("Source URL is required", "OK")
uritext.text = "docker://alpine"
rootdir = newvm.find_fuzzy(None, "text", "root directory")
uiutils.check(lambda: ".local/share/libvirt" in rootdir.text)
rootdir.set_text("/dev/null")
self.forward(newvm, check=False)
self._click_alert_button("not directory", "OK")
rootdir.set_text("/root")
self.forward(newvm, check=False)
self._click_alert_button("No write permissions", "OK")
rootdir.set_text("/tmp")
self.forward(newvm, check=False)
self._click_alert_button("directory is not empty", "No")
rootdir.set_text(tmpdir.name)
newvm.find("install-oscontainer-source-uri").set_text("docker://alpine")
newvm.find("install-oscontainer-root-passwd").set_text("foobar")
# Invalid credentials to trigger failure
newvm.find("Credentials", "toggle button").click_expander()
newvm.find("bootstrap-registry-user").set_text("foo")
self.forward(newvm, check=None)
self._click_alert_button("Please specify password", "OK")
newvm.find("bootstrap-registry-password").set_text("bar")
self.forward(newvm)
self.forward(newvm)
newvm.find_fuzzy("Finish", "button").click()
self._click_alert_button("virt-bootstrap did not complete", "Close")
self.back(newvm)
self.back(newvm)
newvm.find("bootstrap-registry-user").set_text("")
newvm.find("bootstrap-registry-password").set_text("")
self.forward(newvm)
self.forward(newvm)
newvm.find_fuzzy("Finish", "button").click()
@ -784,7 +960,13 @@ class NewVM(uiutils.UITestCase):
return _newvm
newvm = dofail()
pathlabel = newvm.find(".*test/bad.qcow2")
generatedpath = pathlabel.text
# Changing VM name should not generate a new path
newvm.find_fuzzy("Name", "text").set_text("test/badfoo")
uiutils.check(lambda: pathlabel.text == generatedpath)
newvm.find_fuzzy("Finish", "button").click()
self._click_alert_button("Unable to complete install", "Close")
# Closing dialog should trigger storage cleanup path
newvm.find_fuzzy("Cancel", "button").click()
uiutils.check(lambda: not newvm.visible)
@ -793,6 +975,7 @@ class NewVM(uiutils.UITestCase):
newvm = dofail()
self.back(newvm)
newvm.find_fuzzy("Select or create", "radio").click()
newvm.find("storage-entry").set_text("/dev/default-pool/somenewvol1")
self.forward(newvm)
newvm.find_fuzzy("Name", "text").set_text("test-foo")
@ -919,14 +1102,6 @@ class NewVM(uiutils.UITestCase):
self.forward(newvm)
importtext = newvm.find("import-entry")
# Click forward, hitting missing OS error
self.forward(newvm, check=False)
self._click_alert_button("select an OS", "OK")
# Set OS
newvm.find("oslist-entry").set_text("generic")
newvm.find("oslist-popover").find_fuzzy("generic").click()
# Click forward, hitting missing Import path error
self.forward(newvm, check=False)
self._click_alert_button("import is required", "OK")
@ -935,9 +1110,17 @@ class NewVM(uiutils.UITestCase):
importtext.set_text("/dev/default-pool/idontexist")
self.forward(newvm, check=False)
self._click_alert_button("import path must point", "OK")
importtext.set_text("/dev/default-pool/default-vol")
# Click forward, hitting missing OS error
self.forward(newvm, check=False)
self._click_alert_button("select an OS", "OK")
# Set OS
newvm.find("oslist-entry").set_text("generic")
newvm.find("oslist-popover").find_fuzzy("generic").click()
# Click forward, but Import path is in use, and exit
importtext.set_text("/dev/default-pool/default-vol")
self.forward(newvm, check=False)
self._click_alert_button("in use", "No")

View File

@ -911,6 +911,11 @@ bar</property>
</child>
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="install-url-combo-atkobject">
<property name="AtkObject::accessible-name">install-url-combo</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
@ -1505,11 +1510,12 @@ connections is not yet supported.&lt;/small&gt;</property>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">10</property>
<property name="label" translatable="yes">Username:</property>
</object>
<packing>
@ -1521,7 +1527,6 @@ connections is not yet supported.&lt;/small&gt;</property>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">10</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
@ -1533,6 +1538,11 @@ connections is not yet supported.&lt;/small&gt;</property>
<object class="GtkEntry" id="install-oscontainer-source-user">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="install-oscontainer-source-user-atkobject">
<property name="AtkObject::accessible-name">bootstrap-registry-user</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
@ -1546,6 +1556,11 @@ connections is not yet supported.&lt;/small&gt;</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="input_purpose">password</property>
<child internal-child="accessible">
<object class="AtkObject" id="install-oscontainer-source-passwd-atkobject">
<property name="AtkObject::accessible-name">bootstrap-registry-password</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>

View File

@ -280,7 +280,7 @@ class vmmCreateVM(vmmGObjectUI):
if self._storage_browser:
self._storage_browser.cleanup()
self._storage_browser = None
if self._netlist:
if self._netlist: # pragma: no cover
self._netlist.cleanup()
self._netlist = None
if self._mediacombo:
@ -411,9 +411,7 @@ class vmmCreateVM(vmmGObjectUI):
def _populate_media_model(media_model, urls):
media_model.clear()
if urls is None:
return
for url in urls:
for url in (urls or []):
media_model.append([url])
# Install local
@ -518,7 +516,7 @@ class vmmCreateVM(vmmGObjectUI):
if not can_remote_url:
tree_tt = _("Libvirt version does not "
"support remote URL installs.")
if not is_storage_capable:
if not is_storage_capable: # pragma: no cover
local_tt = _("Connection does not support storage management.")
import_tt = local_tt
@ -540,7 +538,7 @@ class vmmCreateVM(vmmGObjectUI):
if not (is_container_only or
[w for w in virt_methods if w.get_sensitive()]):
return self._show_startup_error(
return self._show_startup_error( # pragma: no cover
_("No install methods available for this connection."),
hideinstall=False)
@ -790,7 +788,7 @@ class vmmCreateVM(vmmGObjectUI):
prios = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le",
"s390x"]
if self.conn.caps.host.cpu.arch not in prios:
prios = []
prios = [] # pragma: no cover
for p in prios[:]:
if p not in archs:
prios.remove(p)
@ -862,7 +860,7 @@ class vmmCreateVM(vmmGObjectUI):
for p in prios[:]:
if p not in machines:
prios.remove(p)
prios.remove(p) # pragma: no cover
else:
machines.remove(p)
if prios:
@ -907,7 +905,7 @@ class vmmCreateVM(vmmGObjectUI):
no_conns = (len(model) == 0)
if default < 0 and not no_conns:
default = 0
default = 0 # pragma: no cover
activeuri = ""
activedesc = ""
@ -1207,7 +1205,7 @@ class vmmCreateVM(vmmGObjectUI):
def _detect_os_toggled_cb(self, src):
if not src.is_visible():
return
return # pragma: no cover
# We are only here if the user explicitly changed detection UI
dodetect = src.get_active()
@ -1450,7 +1448,7 @@ class vmmCreateVM(vmmGObjectUI):
return self._validate_storage_page()
elif pagenum == PAGE_FINISH:
return self._validate_final_page()
except Exception as e:
except Exception as e: # pragma: no cover
self.err.show_err(_("Uncaught error validating install "
"parameters: %s") % str(e))
return
@ -1472,7 +1470,7 @@ class vmmCreateVM(vmmGObjectUI):
# Validate destination path
if not os.path.exists(fs):
return
return # pragma: no cover
if not os.path.isdir(fs):
msg = _("Destination path is not directory: %s") % fs
@ -1502,11 +1500,6 @@ class vmmCreateVM(vmmGObjectUI):
template = None
osobj = self._os_list.get_selected_os()
if not self._is_container_install() and not osobj:
msg = _("You must select an OS.")
msg += "\n\n" + self._os_list.eol_text
return self.err.val_err(msg)
if instmethod == INSTALL_PAGE_ISO:
media = self._get_config_local_media()
if not media:
@ -1559,6 +1552,11 @@ class vmmCreateVM(vmmGObjectUI):
if not template:
return self.err.val_err(_("A template name is required."))
if not self._is_container_install() and not osobj:
msg = _("You must select an OS.")
msg += "\n\n" + self._os_list.eol_text
return self.err.val_err(msg)
# Build the installer and Guest instance
try:
if init:
@ -1592,7 +1590,7 @@ class vmmCreateVM(vmmGObjectUI):
name = virtinst.Guest.generate_name(guest)
virtinst.Guest.validate_name(self._gdata.conn, name)
self._gdata.name = name
except Exception as e:
except Exception as e: # pragma: no cover
return self.err.val_err(_("Error setting default name."), e)
self.widget("create-vm-name").set_text(self._gdata.name)
@ -1710,10 +1708,8 @@ class vmmCreateVM(vmmGObjectUI):
if self._is_default_storage():
log.debug("User changed VM name and using default "
"storage, re-validating with new default storage path.")
# User changed the name and we are using default storage
# which depends on the VM name. Revalidate things
if not self._validate_storage_page():
return False
return False # pragma: no cover
macaddr = virtinst.DeviceInterface.generate_mac(
self.conn.get_backend())
@ -1742,9 +1738,9 @@ class vmmCreateVM(vmmGObjectUI):
cdrom, location = self._get_config_detectable_media()
if self._detect_os_in_progress:
return
return # pragma: no cover
if not is_install_page:
return
return # pragma: no cover
if not cdrom and not location:
return
if not self._is_os_detect_active():
@ -1832,7 +1828,7 @@ class vmmCreateVM(vmmGObjectUI):
return
distro = thread_results.get_distro()
except Exception:
except Exception: # pragma: no cover
distro = None
log.exception("Error in distro detect timeout")
@ -1847,7 +1843,7 @@ class vmmCreateVM(vmmGObjectUI):
if not self._is_os_detect_active():
# If the user changed the OS detect checkbox in the meantime,
# don't update the UI
return
return # pragma: no cover
if distro:
self._os_list.select_os(virtinst.OSDB.lookup_os(distro))
@ -1867,7 +1863,7 @@ class vmmCreateVM(vmmGObjectUI):
# Validate the final page
page = self.widget("create-pages").get_current_page()
if self._validate(page) is not True:
return False
return
log.debug("Starting create finish() sequence")
self._gdata.failed_guest = None
@ -1888,7 +1884,7 @@ class vmmCreateVM(vmmGObjectUI):
log.debug("User requested 'customize', launching dialog")
self._show_customize_dialog(guest, installer)
except Exception as e:
except Exception as e: # pragma: no cover
self.reset_finish_cursor()
self.err.show_err(_("Error starting installation: %s") % str(e))
return
@ -1908,7 +1904,7 @@ class vmmCreateVM(vmmGObjectUI):
def customize_finished_cb(src, vdomain):
if not self.is_visible():
return
return # pragma: no cover
log.debug("User finished customize dialog, starting install")
self._gdata.failed_guest = None
self._start_install(vdomain.get_backend(), installer)
@ -2000,7 +1996,7 @@ class vmmCreateVM(vmmGObjectUI):
pool = disk.get_parent_pool()
if not pool:
continue
continue # pragma: no cover
poolname = pool.name()
if poolname not in refresh_pools:
@ -2024,7 +2020,7 @@ class vmmCreateVM(vmmGObjectUI):
time.sleep(.1)
if not foundvm:
raise RuntimeError(
raise RuntimeError( # pragma: no cover
_("VM '%s' didn't show up after expected time.") % guest.name)
vm = foundvm
@ -2032,7 +2028,7 @@ class vmmCreateVM(vmmGObjectUI):
# Domain is already shutdown, but no error was raised.
# Probably means guest had no 'install' phase, as in
# for live cds. Try to restart the domain.
vm.startup()
vm.startup() # pragma: no cover
elif installer.has_install_phase():
# Register a status listener, which will restart the
# guest after the install has finished
@ -2047,7 +2043,7 @@ class vmmCreateVM(vmmGObjectUI):
try:
pool = self.conn.get_pool(poolname)
self.idle_add(pool.refresh)
except Exception:
except Exception: # pragma: no cover
log.debug("Error looking up pool=%s for refresh after "
"VM creation.", poolname, exc_info=True)
@ -2057,25 +2053,27 @@ class vmmCreateVM(vmmGObjectUI):
Watch the domain that we are installing, waiting for the state
to change, so we can restart it as needed
"""
if vm.is_crashed():
if vm.is_crashed(): # pragma: no cover
log.debug("VM crashed, cancelling install plans.")
return True
if not vm.is_shutoff():
return
return # pragma: no cover
if vm.get_install_abort():
log.debug("User manually shutdown VM, not restarting "
"guest after install.")
return True
try:
# Hitting this from the test suite is hard because we can't force
# the test driver VM to stop behind virt-manager's back
try: # pragma: no cover
log.debug("Install should be completed, starting VM.")
vm.startup()
except Exception as e:
self.err.show_err(_("Error continue install: %s") % str(e))
except Exception as e: # pragma: no cover
self.err.show_err(_("Error continuing install: %s") % str(e))
return True
return True # pragma: no cover
def _create_directory_tree(self, asyncjob, meter, bootstrap_args):