2014-02-06 19:12:12 +08:00
|
|
|
# Copyright (C) 2013, 2014 Red Hat, Inc.
|
2013-03-18 05:06:52 +08:00
|
|
|
#
|
2018-04-04 21:35:41 +08:00
|
|
|
# This work is licensed under the GNU GPLv2 or later.
|
2018-03-21 03:00:02 +08:00
|
|
|
# See the COPYING file in the top-level directory.
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
import os
|
2018-02-23 03:57:10 +08:00
|
|
|
import sys
|
|
|
|
|
|
|
|
import libvirt
|
2020-09-19 04:26:28 +08:00
|
|
|
import pytest
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
import virtinst
|
2015-09-22 23:34:15 +08:00
|
|
|
import virtinst.uri
|
2020-09-05 20:29:04 +08:00
|
|
|
from virtinst import cli
|
|
|
|
from virtinst import xmlutil
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2014-02-01 02:44:50 +08:00
|
|
|
|
2014-04-03 06:39:43 +08:00
|
|
|
# pylint: disable=protected-access
|
2013-04-12 04:32:00 +08:00
|
|
|
|
2020-07-18 04:02:45 +08:00
|
|
|
class _TestConfig(object):
|
2018-01-09 06:05:55 +08:00
|
|
|
"""
|
|
|
|
Class containing any bits passed in from setup.py
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.regenerate_output = False
|
2018-02-23 02:46:24 +08:00
|
|
|
self.debug = False
|
2020-07-18 03:59:11 +08:00
|
|
|
self.skip_checkprops = False
|
2019-03-24 23:22:50 +08:00
|
|
|
|
|
|
|
self.url_only = False
|
|
|
|
self.url_iso_only = False
|
|
|
|
self.url_skip_libosinfo = False
|
|
|
|
self.url_force_libosinfo = False
|
|
|
|
|
|
|
|
|
2020-07-18 04:02:45 +08:00
|
|
|
TESTCONFIG = _TestConfig()
|
2020-08-30 20:54:41 +08:00
|
|
|
TESTDIR = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
TOPDIR = os.path.dirname(TESTDIR)
|
|
|
|
DATADIR = os.path.join(TESTDIR, "data")
|
|
|
|
UITESTDIR = os.path.join(TESTDIR, "uitests")
|
|
|
|
UITESTDATADIR = os.path.join(UITESTDIR, "data")
|
2018-01-09 06:05:55 +08:00
|
|
|
|
|
|
|
|
2018-10-05 07:18:27 +08:00
|
|
|
def has_old_osinfo():
|
|
|
|
# Some tests rely on newer osinfo data. Check for a new condition
|
|
|
|
# here, and older tests will be skipped
|
2018-10-14 04:33:37 +08:00
|
|
|
osname = "centos7.0"
|
2018-10-05 07:18:27 +08:00
|
|
|
if not virtinst.OSDB.lookup_os(osname):
|
|
|
|
return True
|
2018-10-05 02:59:54 +08:00
|
|
|
return not virtinst.OSDB.lookup_os(osname).supports_chipset_q35()
|
2018-10-05 07:18:27 +08:00
|
|
|
|
|
|
|
|
2018-02-23 03:57:10 +08:00
|
|
|
class _URIs(object):
|
|
|
|
def __init__(self):
|
|
|
|
self._conn_cache = {}
|
|
|
|
self._testdriver_cache = None
|
|
|
|
self._testdriver_error = None
|
|
|
|
self._testdriver_default = None
|
|
|
|
|
2020-08-30 20:54:41 +08:00
|
|
|
_capspath = DATADIR + "/capabilities/"
|
2018-06-12 23:48:11 +08:00
|
|
|
def _domcaps(path):
|
|
|
|
return ",domcaps=" + _capspath + path
|
|
|
|
def _caps(path):
|
|
|
|
return ",caps=" + _capspath + path
|
|
|
|
|
|
|
|
_testtmpl = "__virtinst_test__test://%s,predictable"
|
2020-08-30 20:54:41 +08:00
|
|
|
_testdriverdir = DATADIR + "/testdriver/"
|
2020-09-04 23:13:29 +08:00
|
|
|
# We don't use actual test:///default, which saves state
|
|
|
|
# for the lifetime of the process which can cause weird
|
|
|
|
# trickling effects for the testsuite. We use our own
|
|
|
|
# test XML which roughly matches test:///default, and then
|
|
|
|
# fake the URI
|
|
|
|
self.test_default = _testtmpl % (_testdriverdir + "testdefault.xml") + ",fakeuri=test:///default"
|
|
|
|
|
2020-08-25 01:34:15 +08:00
|
|
|
self.test_full = _testtmpl % (_testdriverdir + "testdriver.xml")
|
|
|
|
self.test_suite = _testtmpl % (_testdriverdir + "testsuite.xml")
|
|
|
|
self.test_defaultpool_collision = _testtmpl % (
|
|
|
|
_testdriverdir + "defaultpool-collision.xml")
|
2020-08-25 01:35:54 +08:00
|
|
|
self.test_empty = _testtmpl % (_testdriverdir + "empty.xml")
|
2020-08-25 01:34:15 +08:00
|
|
|
|
2020-02-03 07:16:48 +08:00
|
|
|
def _m(fakeuri):
|
|
|
|
return self.test_full + ",fakeuri=%s" % fakeuri
|
|
|
|
self.test_remote = _m("test+tls://fakeuri.example.com/")
|
|
|
|
|
|
|
|
self.xen = _m("xen:///") + _caps("xen-rhel5.4.xml")
|
|
|
|
self.lxc = _m("lxc:///") + _caps("lxc.xml")
|
|
|
|
self.vz = _m("vz:///") + _caps("vz.xml")
|
2021-02-11 23:41:10 +08:00
|
|
|
self.bhyve = _m("bhyve:///") + _caps("bhyve.xml") + _domcaps("bhyve-domcaps.xml")
|
2020-02-03 07:16:48 +08:00
|
|
|
|
|
|
|
_uri_qemu = _m("qemu:///system")
|
|
|
|
_kvm_x86_caps = _caps("kvm-x86_64.xml") + _domcaps("kvm-x86_64-domcaps.xml")
|
|
|
|
self.kvm = _uri_qemu + _kvm_x86_caps
|
2020-08-27 06:01:02 +08:00
|
|
|
self.kvm_cpu_insecure = _uri_qemu + _caps("kvm-x86_64.xml") + _domcaps("kvm-x86_64-insecure-domcaps.xml")
|
2020-02-03 07:16:48 +08:00
|
|
|
self.kvm_remote = _m("qemu+tls://fakeuri.example.com/system") + _kvm_x86_caps
|
|
|
|
self.kvm_session = _m("qemu:///session") + _kvm_x86_caps
|
2018-06-12 23:48:11 +08:00
|
|
|
|
2020-02-03 07:16:48 +08:00
|
|
|
_uri_kvm = _uri_qemu + _kvm_x86_caps
|
2019-04-11 20:47:00 +08:00
|
|
|
_uri_kvm_rhel7 = _uri_qemu + _domcaps("kvm-x86_64-rhel7-domcaps.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
_uri_kvm_q35 = _uri_qemu + _domcaps("kvm-x86_64-domcaps-q35.xml")
|
2019-06-11 23:41:56 +08:00
|
|
|
_uri_kvm_amd_sev = _uri_qemu + _domcaps("kvm-x86_64-domcaps-amd-sev.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
_uri_kvm_aarch64 = _uri_qemu + _domcaps("kvm-aarch64-domcaps.xml")
|
2019-04-04 18:49:42 +08:00
|
|
|
_uri_qemu_riscv64 = _uri_qemu + _domcaps("qemu-riscv64-domcaps.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
|
|
|
|
self.kvm_nodomcaps = _uri_qemu + _caps("kvm-x86_64.xml")
|
2019-04-11 20:47:00 +08:00
|
|
|
self.kvm_rhel = _uri_kvm_rhel7 + _caps("kvm-x86_64-rhel7.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
self.kvm_q35 = _uri_kvm_q35 + _caps("kvm-x86_64.xml")
|
2019-06-11 23:41:56 +08:00
|
|
|
self.kvm_amd_sev = _uri_kvm_amd_sev + _caps("kvm-x86_64.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
|
2018-09-01 04:47:10 +08:00
|
|
|
self.kvm_armv7l_nodomcaps = _uri_qemu + _caps("kvm-armv7l.xml")
|
2020-02-03 18:58:04 +08:00
|
|
|
self.kvm_armv7l = self.kvm_armv7l_nodomcaps + _domcaps("kvm-armv7l-domcaps.xml")
|
|
|
|
self.kvm_aarch64 = _uri_kvm_aarch64 + _caps("kvm-aarch64.xml") + _domcaps("kvm-aarch64-domcaps.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
self.kvm_ppc64le = _uri_kvm + _caps("kvm-ppc64le.xml")
|
|
|
|
self.kvm_s390x = _uri_kvm + _caps("kvm-s390x.xml")
|
|
|
|
self.kvm_s390x_KVMIBM = _uri_kvm + _caps("kvm-s390x-KVMIBM.xml")
|
2019-04-04 18:49:42 +08:00
|
|
|
self.qemu_riscv64 = _uri_qemu_riscv64 + _caps("qemu-riscv64.xml")
|
2018-06-12 23:48:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-02-23 03:57:10 +08:00
|
|
|
def openconn(self, uri):
|
|
|
|
"""
|
|
|
|
Extra super caching to speed up the test suite. We basically
|
|
|
|
cache the first guest/pool/vol poll attempt for each URI, and save it
|
|
|
|
across multiple reopenings of that connection. We aren't caching
|
|
|
|
libvirt objects, just parsed XML objects. This works fine since
|
|
|
|
generally every test uses a fresh virConnect, or undoes the
|
|
|
|
persistent changes it makes.
|
|
|
|
"""
|
|
|
|
is_testdriver_xml = "/testdriver.xml" in uri
|
|
|
|
|
|
|
|
if not (is_testdriver_xml and self._testdriver_error):
|
|
|
|
try:
|
2020-01-27 06:12:09 +08:00
|
|
|
conn = cli.getConnection(uri)
|
2018-02-23 03:57:10 +08:00
|
|
|
except libvirt.libvirtError as e:
|
|
|
|
if not is_testdriver_xml:
|
|
|
|
raise
|
|
|
|
self._testdriver_error = (
|
|
|
|
"error opening testdriver.xml: %s\n"
|
|
|
|
"libvirt is probably too old" % str(e))
|
|
|
|
print(self._testdriver_error, file=sys.stderr)
|
|
|
|
|
|
|
|
if is_testdriver_xml and self._testdriver_error:
|
2020-09-19 04:26:28 +08:00
|
|
|
pytest.skip(self._testdriver_error)
|
2018-02-23 03:57:10 +08:00
|
|
|
|
|
|
|
uri = conn._open_uri
|
|
|
|
|
|
|
|
# For the basic test:///default URI, skip this caching, so we have
|
|
|
|
# an option to test the stock code
|
2018-06-12 23:48:11 +08:00
|
|
|
if uri == self.test_default:
|
2018-02-23 03:57:10 +08:00
|
|
|
return conn
|
|
|
|
|
|
|
|
if uri not in self._conn_cache:
|
2018-09-01 03:20:50 +08:00
|
|
|
conn.fetch_all_domains()
|
2018-02-23 03:57:10 +08:00
|
|
|
conn.fetch_all_pools()
|
|
|
|
conn.fetch_all_vols()
|
|
|
|
conn.fetch_all_nodedevs()
|
|
|
|
|
|
|
|
self._conn_cache[uri] = {}
|
|
|
|
for key, value in conn._fetch_cache.items():
|
|
|
|
self._conn_cache[uri][key] = value[:]
|
|
|
|
|
|
|
|
# Prime the internal connection cache
|
|
|
|
for key, value in self._conn_cache[uri].items():
|
|
|
|
conn._fetch_cache[key] = value[:]
|
|
|
|
|
|
|
|
def cb_cache_new_pool(poolobj):
|
|
|
|
# Used by clonetest.py nvram-newpool test
|
|
|
|
if poolobj.name() == "nvram-newpool":
|
|
|
|
from virtinst import StorageVolume
|
|
|
|
vol = StorageVolume(conn)
|
|
|
|
vol.pool = poolobj
|
|
|
|
vol.name = "clone-orig-vars.fd"
|
|
|
|
vol.capacity = 1024 * 1024
|
|
|
|
vol.install()
|
|
|
|
conn._cache_new_pool_raw(poolobj)
|
|
|
|
|
|
|
|
conn.cb_cache_new_pool = cb_cache_new_pool
|
2013-09-29 09:03:03 +08:00
|
|
|
|
2017-08-30 22:36:37 +08:00
|
|
|
return conn
|
|
|
|
|
2018-02-23 03:57:10 +08:00
|
|
|
def open_testdriver_cached(self):
|
|
|
|
"""
|
|
|
|
Open plain testdriver.xml and cache the instance. Tests that
|
|
|
|
use this are expected to clean up after themselves so driver
|
|
|
|
state doesn't become polluted.
|
|
|
|
"""
|
|
|
|
if not self._testdriver_cache:
|
2018-06-12 23:48:11 +08:00
|
|
|
self._testdriver_cache = self.openconn(self.test_full)
|
2018-02-23 03:57:10 +08:00
|
|
|
return self._testdriver_cache
|
|
|
|
|
|
|
|
def open_testdefault_cached(self):
|
|
|
|
if not self._testdriver_default:
|
2018-06-12 23:48:11 +08:00
|
|
|
self._testdriver_default = self.openconn(self.test_default)
|
2018-02-23 03:57:10 +08:00
|
|
|
return self._testdriver_default
|
|
|
|
|
2019-06-10 04:39:15 +08:00
|
|
|
def open_kvm(self):
|
|
|
|
return self.openconn(self.kvm)
|
2018-02-23 03:57:10 +08:00
|
|
|
def open_test_remote(self):
|
2018-06-12 23:48:11 +08:00
|
|
|
return self.openconn(self.test_remote)
|
2018-02-23 03:57:10 +08:00
|
|
|
|
|
|
|
URIs = _URIs()
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-09-10 05:14:16 +08:00
|
|
|
def test_create(testconn, xml, define_func="defineXML"):
|
2015-09-22 23:34:15 +08:00
|
|
|
xml = virtinst.uri.sanitize_xml_for_test_define(xml)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-06-15 02:58:52 +08:00
|
|
|
try:
|
2013-09-10 05:14:16 +08:00
|
|
|
func = getattr(testconn, define_func)
|
|
|
|
obj = func(xml)
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2020-09-16 00:33:31 +08:00
|
|
|
# pylint: disable=raise-missing-from
|
2013-06-15 02:58:52 +08:00
|
|
|
raise RuntimeError(str(e) + "\n" + xml)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
try:
|
2013-09-10 05:14:16 +08:00
|
|
|
obj.create()
|
|
|
|
obj.destroy()
|
|
|
|
obj.undefine()
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2013-03-18 05:06:52 +08:00
|
|
|
try:
|
2013-09-10 05:14:16 +08:00
|
|
|
obj.destroy()
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2013-03-18 05:06:52 +08:00
|
|
|
pass
|
|
|
|
try:
|
2013-09-10 05:14:16 +08:00
|
|
|
obj.undefine()
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2013-03-18 05:06:52 +08:00
|
|
|
pass
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def diff_compare(actual_out, filename=None, expect_out=None):
|
|
|
|
"""Compare passed string output to contents of filename"""
|
|
|
|
if not expect_out:
|
2020-07-18 04:02:45 +08:00
|
|
|
if not os.path.exists(filename) or TESTCONFIG.regenerate_output:
|
2017-05-06 02:19:54 +08:00
|
|
|
open(filename, "w").write(actual_out)
|
2018-06-12 23:37:02 +08:00
|
|
|
expect_out = open(filename).read()
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2020-09-05 20:29:04 +08:00
|
|
|
diff = xmlutil.diff(expect_out, actual_out,
|
|
|
|
filename or '', "Generated output")
|
2013-03-18 05:06:52 +08:00
|
|
|
if diff:
|
|
|
|
raise AssertionError("Conversion outputs did not match.\n%s" % diff)
|
2019-06-08 21:11:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
def run_without_testsuite_hacks(cb):
|
|
|
|
"""
|
|
|
|
Decorator for unsetting the test suite env variable
|
|
|
|
"""
|
|
|
|
def wrapper_cb(*args, **kwargs):
|
|
|
|
origval = os.environ.pop("VIRTINST_TEST_SUITE", None)
|
|
|
|
try:
|
|
|
|
return cb(*args, **kwargs)
|
|
|
|
finally:
|
|
|
|
if origval:
|
|
|
|
os.environ["VIRTINST_TEST_SUITE"] = origval
|
|
|
|
return wrapper_cb
|