2014-02-06 15:12:12 +04:00
# Copyright (C) 2013, 2014 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-03-18 01:06:52 +04:00
import os
2018-02-22 22:57:10 +03:00
import sys
import libvirt
2020-09-18 23:26:28 +03:00
import pytest
2013-03-18 01:06:52 +04:00
import virtinst
2015-09-22 18:34:15 +03:00
import virtinst . uri
2020-09-05 15:29:04 +03:00
from virtinst import cli
from virtinst import xmlutil
2013-03-18 01:06:52 +04:00
2014-01-31 22:44:50 +04:00
2014-04-03 02:39:43 +04:00
# pylint: disable=protected-access
2013-04-12 00:32:00 +04:00
2020-07-17 23:02:45 +03:00
class _TestConfig ( object ) :
2018-01-09 01:05:55 +03:00
"""
Class containing any bits passed in from setup . py
"""
def __init__ ( self ) :
self . regenerate_output = False
2018-02-22 21:46:24 +03:00
self . debug = False
2020-07-17 22:59:11 +03:00
self . skip_checkprops = False
2019-03-24 18:22:50 +03:00
self . url_only = False
self . url_iso_only = False
self . url_skip_libosinfo = False
self . url_force_libosinfo = False
2020-07-17 23:02:45 +03:00
TESTCONFIG = _TestConfig ( )
2020-08-30 15:54:41 +03: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 01:05:55 +03:00
2018-10-05 02:18:27 +03: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-13 23:33:37 +03:00
osname = " centos7.0 "
2018-10-05 02:18:27 +03:00
if not virtinst . OSDB . lookup_os ( osname ) :
return True
2018-10-04 21:59:54 +03:00
return not virtinst . OSDB . lookup_os ( osname ) . supports_chipset_q35 ( )
2018-10-05 02:18:27 +03:00
2018-02-22 22:57:10 +03: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 15:54:41 +03:00
_capspath = DATADIR + " /capabilities/ "
2018-06-12 18:48:11 +03:00
def _domcaps ( path ) :
return " ,domcaps= " + _capspath + path
def _caps ( path ) :
return " ,caps= " + _capspath + path
_testtmpl = " __virtinst_test__test:// %s ,predictable "
2020-08-30 15:54:41 +03:00
_testdriverdir = DATADIR + " /testdriver/ "
2020-09-04 18:13:29 +03: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-24 20:34:15 +03: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-24 20:35:54 +03:00
self . test_empty = _testtmpl % ( _testdriverdir + " empty.xml " )
2020-08-24 20:34:15 +03:00
2020-02-03 02:16:48 +03: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 18:41:10 +03:00
self . bhyve = _m ( " bhyve:/// " ) + _caps ( " bhyve.xml " ) + _domcaps ( " bhyve-domcaps.xml " )
2020-02-03 02:16:48 +03:00
_uri_qemu = _m ( " qemu:///system " )
2018-06-12 18:48:11 +03:00
2022-01-24 21:37:40 +03:00
# KVM x86 URIs
2022-02-16 19:21:18 +03:00
_kvm_x86_caps = _caps ( " kvm-x86_64.xml " ) + _domcaps ( " kvm-x86_64-domcaps-latest.xml " )
2022-01-24 21:37:40 +03:00
self . kvm_x86_session = _m ( " qemu:///session " ) + _kvm_x86_caps
self . kvm_x86 = _uri_qemu + _kvm_x86_caps
self . kvm_x86_remote = _m ( " qemu+tls://fakeuri.example.com/system " ) + _kvm_x86_caps
self . kvm_x86_nodomcaps = _uri_qemu + _caps ( " kvm-x86_64.xml " )
2022-02-16 19:21:18 +03:00
self . kvm_x86_cpu_insecure = self . kvm_x86_nodomcaps + _domcaps ( " kvm-x86_64-domcaps-insecure.xml " )
self . kvm_x86_oldfirmware = self . kvm_x86_nodomcaps + _domcaps ( " kvm-x86_64-domcaps-oldfirmware.xml " )
2022-01-24 21:37:40 +03:00
self . kvm_amd_sev = self . kvm_x86_nodomcaps + _domcaps ( " kvm-x86_64-domcaps-amd-sev.xml " )
# Non-x86 arch URIs
2018-08-31 23:47:10 +03:00
self . kvm_armv7l_nodomcaps = _uri_qemu + _caps ( " kvm-armv7l.xml " )
2020-02-03 13:58:04 +03:00
self . kvm_armv7l = self . kvm_armv7l_nodomcaps + _domcaps ( " kvm-armv7l-domcaps.xml " )
2022-01-24 21:37:40 +03:00
self . kvm_aarch64 = _uri_qemu + _caps ( " kvm-aarch64.xml " ) + _domcaps ( " kvm-aarch64-domcaps.xml " )
2022-02-17 22:45:15 +03:00
self . kvm_ppc64le = _uri_qemu + _caps ( " kvm-ppc64le.xml " ) + _domcaps ( " kvm-ppc64le-domcaps.xml " )
self . kvm_s390x = _uri_qemu + _caps ( " kvm-s390x.xml " ) + _domcaps ( " kvm-s390x-domcaps.xml " )
2022-01-24 21:37:40 +03:00
self . qemu_riscv64 = _uri_qemu + _caps ( " qemu-riscv64.xml " ) + _domcaps ( " qemu-riscv64-domcaps.xml " )
2024-03-04 09:27:57 +03:00
self . kvm_loongarch64 = _uri_qemu + _caps ( " kvm-loongarch64.xml " ) + _domcaps ( " kvm-loongarch64-domcaps.xml " )
2018-06-12 18:48:11 +03:00
2024-02-05 22:38:50 +03:00
# hvf
self . hvf_x86 = _uri_qemu + _caps ( " hvf-x86_64.xml " ) + _domcaps ( " hvf-x86_64-domcaps.xml " )
2018-06-12 18:48:11 +03:00
2018-02-22 22:57:10 +03: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 01:12:09 +03:00
conn = cli . getConnection ( uri )
2018-02-22 22:57:10 +03: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-18 23:26:28 +03:00
pytest . skip ( self . _testdriver_error )
2018-02-22 22:57:10 +03: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 18:48:11 +03:00
if uri == self . test_default :
2018-02-22 22:57:10 +03:00
return conn
if uri not in self . _conn_cache :
2018-08-31 22:20:50 +03:00
conn . fetch_all_domains ( )
2018-02-22 22:57:10 +03: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 05:03:03 +04:00
2017-08-30 17:36:37 +03:00
return conn
2018-02-22 22:57:10 +03: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 18:48:11 +03:00
self . _testdriver_cache = self . openconn ( self . test_full )
2018-02-22 22:57:10 +03:00
return self . _testdriver_cache
def open_testdefault_cached ( self ) :
if not self . _testdriver_default :
2018-06-12 18:48:11 +03:00
self . _testdriver_default = self . openconn ( self . test_default )
2018-02-22 22:57:10 +03:00
return self . _testdriver_default
2019-06-09 23:39:15 +03:00
def open_kvm ( self ) :
2022-01-24 21:37:40 +03:00
return self . openconn ( self . kvm_x86 )
2018-02-22 22:57:10 +03:00
def open_test_remote ( self ) :
2018-06-12 18:48:11 +03:00
return self . openconn ( self . test_remote )
2018-02-22 22:57:10 +03:00
URIs = _URIs ( )
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-09-10 01:14:16 +04:00
def test_create ( testconn , xml , define_func = " defineXML " ) :
2015-09-22 18:34:15 +03:00
xml = virtinst . uri . sanitize_xml_for_test_define ( xml )
2013-03-18 01:06:52 +04:00
2013-06-14 22:58:52 +04:00
try :
2013-09-10 01:14:16 +04:00
func = getattr ( testconn , define_func )
obj = func ( xml )
2017-05-05 19:47:21 +03:00
except Exception as e :
2020-09-15 19:33:31 +03:00
# pylint: disable=raise-missing-from
2013-06-14 22:58:52 +04:00
raise RuntimeError ( str ( e ) + " \n " + xml )
2013-03-18 01:06:52 +04:00
try :
2013-09-10 01:14:16 +04:00
obj . create ( )
obj . destroy ( )
obj . undefine ( )
2017-07-24 11:26:48 +03:00
except Exception :
2013-03-18 01:06:52 +04:00
try :
2013-09-10 01:14:16 +04:00
obj . destroy ( )
2017-07-24 11:26:48 +03:00
except Exception :
2013-03-18 01:06:52 +04:00
pass
try :
2013-09-10 01:14:16 +04:00
obj . undefine ( )
2017-07-24 11:26:48 +03:00
except Exception :
2013-03-18 01:06:52 +04:00
pass
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def diff_compare ( actual_out , filename = None , expect_out = None ) :
2022-08-03 17:33:12 +03:00
"""
Test suite helper for comparing two strings
If filename is passed , but the file doesn ' t exist, we write actual_out
to it . This makes it easy to populate output for new testcases
If the - - regenerate - output pytest flag was passed , we re - write every
specified filename .
@actual_out : Output we generated
@filename : filename where expected good test output is stored
@expect_out : expected string to compare against
"""
# Make sure all test output has trailing newline, simplifies diffing
if not actual_out . endswith ( " \n " ) :
actual_out + = " \n "
2013-03-18 01:06:52 +04:00
if not expect_out :
2020-07-17 23:02:45 +03:00
if not os . path . exists ( filename ) or TESTCONFIG . regenerate_output :
2017-05-05 21:19:54 +03:00
open ( filename , " w " ) . write ( actual_out )
2018-06-12 18:37:02 +03:00
expect_out = open ( filename ) . read ( )
2013-03-18 01:06:52 +04:00
2022-08-03 17:33:12 +03:00
if not expect_out . endswith ( " \n " ) :
expect_out + = " \n "
diff = xmlutil . diff ( expect_out , actual_out ,
2020-09-05 15:29:04 +03:00
filename or ' ' , " Generated output " )
2013-03-18 01:06:52 +04:00
if diff :
raise AssertionError ( " Conversion outputs did not match. \n %s " % diff )
2019-06-08 16:11:00 +03: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