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 Test the wizard's multiple connection handling
""" """
# Add an extra connection for test:///default manager = self.app.topwin
self.app.root.find("File", "menu").click()
self.app.root.find("Add Connection...", "menu item").click() def _add_conn(uri):
win = self.app.root.find_fuzzy("Add Connection", "dialog") manager.find("File", "menu").click()
win.combo_select("Hypervisor", "Custom URI") manager.find("Add Connection...", "menu item").click()
win.find("uri-entry", "text").set_text("test:///default") win = self.app.root.find_fuzzy("Add Connection", "dialog")
win.find("Connect", "push button").click() 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 # Open the new VM wizard, select a connection
newvm = self._open_create_wizard() newvm = self._open_create_wizard()
@ -64,15 +104,26 @@ class NewVM(uiutils.UITestCase):
cdrom.click_combo_entry() cdrom.click_combo_entry()
cdrom.find_fuzzy(r"\(/dev/sr1\)") cdrom.find_fuzzy(r"\(/dev/sr1\)")
entry.click() 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 # Back up, select test:///default, verify media-combo is now empty
self.back(newvm) newvm.click_title()
back = newvm.find_fuzzy("Back", "button") newvm.keyCombo("<alt>F4")
uiutils.check(lambda: not back.sensitive) newvm = self._open_create_wizard()
newvm.combo_select("create-conn", ".*test default.*") newvm.combo_select("create-conn", ".*test default.*")
self.forward(newvm) self.forward(newvm)
cdrom.click_combo_entry() cdrom.click_combo_entry()
cdrom.print_nodes()
uiutils.check(lambda: "/dev/sr1" not in cdrom.fmt_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): def testNewVMManualDefault(self):
""" """
@ -115,6 +166,15 @@ class NewVM(uiutils.UITestCase):
self.sleep(.5) self.sleep(.5)
self.forward(newvm) self.forward(newvm)
self.sleep(.5) 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() newvm.find_fuzzy("Finish", "button").click()
# Delete it from the VM window # Delete it from the VM window
@ -129,8 +189,48 @@ class NewVM(uiutils.UITestCase):
# Verify delete dialog and VM dialog are now gone # Verify delete dialog and VM dialog are now gone
uiutils.check(lambda: vmwindow.showing is False) 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 Create a new CDROM VM, choosing distro win8, and do some basic
'Customize before install' before exiting 'Customize before install' before exiting
@ -145,9 +245,16 @@ class NewVM(uiutils.UITestCase):
combo.click_combo_entry() combo.click_combo_entry()
combo.find(r"No media detected \(/dev/sr1\)") combo.find(r"No media detected \(/dev/sr1\)")
combo.find(r"Fedora12_media \(/dev/sr0\)").click() combo.find(r"Fedora12_media \(/dev/sr0\)").click()
# test entry activation too
# Catch validation error
entry = newvm.find("media-entry") entry = newvm.find("media-entry")
entry.click() 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") entry.set_text("/dev/sr0")
self.pressKey("Enter") self.pressKey("Enter")
@ -246,6 +353,24 @@ class NewVM(uiutils.UITestCase):
vmwindow.find_fuzzy("Quit", "menu item").click() vmwindow.find_fuzzy("Quit", "menu item").click()
uiutils.check(lambda: self.app.is_running()) 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): def testNewVMURL(self):
""" """
@ -260,9 +385,15 @@ class NewVM(uiutils.UITestCase):
osentry = newvm.find("oslist-entry") osentry = newvm.find("oslist-entry")
uiutils.check(lambda: osentry.text.startswith("Waiting")) 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/" url = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/10/Fedora/x86_64/os/"
oslabel = "Fedora 10" oslabel = "Fedora 10"
newvm.find("install-url-entry").set_text(url) 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-expander").click_expander()
newvm.find("install-urlopts-entry").set_text("foo=bar") newvm.find("install-urlopts-entry").set_text("foo=bar")
@ -303,9 +434,18 @@ class NewVM(uiutils.UITestCase):
"Creating Virtual Machine", "frame") "Creating Virtual Machine", "frame")
uiutils.check(lambda: not progress.showing, timeout=120) 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) 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): def testNewKVMQ35Tweaks(self):
""" """
New VM that should default to Q35, but tweak things a bunch 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 = self._open_create_wizard()
newvm.find_fuzzy("Container", "radio").click() newvm.find_fuzzy("Container", "radio").click()
newvm.find_fuzzy("Virtual machine", "radio").click()
newvm.find_fuzzy("Container", "radio").click()
self.forward(newvm) self.forward(newvm)
# Set directory path # Set directory path
newvm.find_fuzzy(None, templatetext = newvm.find_fuzzy(None, "text", "container template")
"text", "container template").set_text("centos-6-x86_64") 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)
self.forward(newvm) self.forward(newvm)
newvm.find_fuzzy("Finish", "button").click() newvm.find_fuzzy("Finish", "button").click()
@ -728,11 +873,42 @@ class NewVM(uiutils.UITestCase):
import tempfile import tempfile
tmpdir = tempfile.TemporaryDirectory() tmpdir = tempfile.TemporaryDirectory()
newvm.find_fuzzy("Create OS directory", "check box").click() 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") rootdir = newvm.find_fuzzy(None, "text", "root directory")
uiutils.check(lambda: ".local/share/libvirt" in rootdir.text) 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) rootdir.set_text(tmpdir.name)
newvm.find("install-oscontainer-source-uri").set_text("docker://alpine")
newvm.find("install-oscontainer-root-passwd").set_text("foobar") 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)
self.forward(newvm) self.forward(newvm)
newvm.find_fuzzy("Finish", "button").click() newvm.find_fuzzy("Finish", "button").click()
@ -784,7 +960,13 @@ class NewVM(uiutils.UITestCase):
return _newvm return _newvm
newvm = dofail() 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 # Closing dialog should trigger storage cleanup path
newvm.find_fuzzy("Cancel", "button").click() newvm.find_fuzzy("Cancel", "button").click()
uiutils.check(lambda: not newvm.visible) uiutils.check(lambda: not newvm.visible)
@ -793,6 +975,7 @@ class NewVM(uiutils.UITestCase):
newvm = dofail() newvm = dofail()
self.back(newvm) self.back(newvm)
newvm.find_fuzzy("Select or create", "radio").click() newvm.find_fuzzy("Select or create", "radio").click()
newvm.find("storage-entry").set_text("/dev/default-pool/somenewvol1") newvm.find("storage-entry").set_text("/dev/default-pool/somenewvol1")
self.forward(newvm) self.forward(newvm)
newvm.find_fuzzy("Name", "text").set_text("test-foo") newvm.find_fuzzy("Name", "text").set_text("test-foo")
@ -919,14 +1102,6 @@ class NewVM(uiutils.UITestCase):
self.forward(newvm) self.forward(newvm)
importtext = newvm.find("import-entry") 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 # Click forward, hitting missing Import path error
self.forward(newvm, check=False) self.forward(newvm, check=False)
self._click_alert_button("import is required", "OK") self._click_alert_button("import is required", "OK")
@ -935,9 +1110,17 @@ class NewVM(uiutils.UITestCase):
importtext.set_text("/dev/default-pool/idontexist") importtext.set_text("/dev/default-pool/idontexist")
self.forward(newvm, check=False) self.forward(newvm, check=False)
self._click_alert_button("import path must point", "OK") 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 # Click forward, but Import path is in use, and exit
importtext.set_text("/dev/default-pool/default-vol")
self.forward(newvm, check=False) self.forward(newvm, check=False)
self._click_alert_button("in use", "No") self._click_alert_button("in use", "No")

View File

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

View File

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