2013-06-21 18:27:59 +04:00
/*
* Copyright ( C ) 2011 - 2013 Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*
*/
# include <config.h>
2016-02-16 18:24:35 +03:00
# include "qemu/qemu_alias.h"
2013-06-21 18:27:59 +04:00
# include "qemu/qemu_conf.h"
# include "qemu/qemu_hotplug.h"
2013-07-26 16:22:10 +04:00
# include "qemu/qemu_hotplugpriv.h"
2013-06-21 18:27:59 +04:00
# include "qemumonitortestutils.h"
# include "testutils.h"
# include "testutilsqemu.h"
# include "virerror.h"
# include "virstring.h"
# include "virthread.h"
# include "virfile.h"
# define VIR_FROM_THIS VIR_FROM_NONE
static virQEMUDriver driver ;
2013-07-02 12:16:30 +04:00
enum {
ATTACH ,
DETACH ,
UPDATE
} ;
2014-12-16 10:46:44 +03:00
# define QEMU_HOTPLUG_TEST_DOMAIN_ID 7
2013-06-21 18:27:59 +04:00
struct qemuHotplugTestData {
const char * domain_filename ;
const char * device_filename ;
bool fail ;
const char * const * mon ;
2013-07-02 12:16:30 +04:00
int action ;
bool keep ;
virDomainObjPtr vm ;
2013-07-26 16:22:10 +04:00
bool deviceDeletedEvent ;
2013-06-21 18:27:59 +04:00
} ;
static int
qemuHotplugCreateObjects ( virDomainXMLOptionPtr xmlopt ,
virDomainObjPtr * vm ,
2013-07-26 16:22:10 +04:00
const char * domxml ,
2015-09-09 17:03:15 +03:00
bool event , const char * testname )
2013-06-21 18:27:59 +04:00
{
int ret = - 1 ;
2013-07-02 12:16:30 +04:00
qemuDomainObjPrivatePtr priv = NULL ;
2013-06-21 18:27:59 +04:00
if ( ! ( * vm = virDomainObjNew ( xmlopt ) ) )
goto cleanup ;
2013-07-02 12:16:30 +04:00
priv = ( * vm ) - > privateData ;
if ( ! ( priv - > qemuCaps = virQEMUCapsNew ( ) ) )
goto cleanup ;
2013-07-26 17:28:33 +04:00
virQEMUCapsSet ( priv - > qemuCaps , QEMU_CAPS_VIRTIO_SCSI ) ;
2013-08-23 14:38:10 +04:00
virQEMUCapsSet ( priv - > qemuCaps , QEMU_CAPS_DEVICE_USB_STORAGE ) ;
2013-07-26 16:22:10 +04:00
if ( event )
virQEMUCapsSet ( priv - > qemuCaps , QEMU_CAPS_DEVICE_DEL_EVENT ) ;
2013-07-18 13:21:34 +04:00
2016-04-14 14:48:57 +03:00
if ( qemuTestCapsCacheInsert ( driver . qemuCapsCache , testname ,
priv - > qemuCaps ) < 0 )
2015-09-09 17:03:15 +03:00
goto cleanup ;
if ( ! ( ( * vm ) - > def = virDomainDefParseString ( domxml ,
driver . caps ,
driver . xmlopt ,
VIR_DOMAIN_DEF_PARSE_INACTIVE ) ) )
goto cleanup ;
2015-03-02 12:59:52 +03:00
if ( qemuDomainAssignAddresses ( ( * vm ) - > def , priv - > qemuCaps , * vm ) < 0 )
2013-07-18 13:21:34 +04:00
goto cleanup ;
if ( qemuAssignDeviceAliases ( ( * vm ) - > def , priv - > qemuCaps ) < 0 )
goto cleanup ;
2013-07-02 12:16:30 +04:00
2014-12-16 10:46:44 +03:00
( * vm ) - > def - > id = QEMU_HOTPLUG_TEST_DOMAIN_ID ;
2013-06-21 18:27:59 +04:00
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-06-21 18:27:59 +04:00
return ret ;
}
2013-07-02 12:16:30 +04:00
static int
testQemuHotplugAttach ( virDomainObjPtr vm ,
virDomainDeviceDefPtr dev )
{
int ret = - 1 ;
switch ( dev - > type ) {
2013-07-18 13:21:34 +04:00
case VIR_DOMAIN_DEVICE_DISK :
/* conn in only used for storage pool and secrets lookup so as long
* as we don ' t use any of them , passing NULL should be safe
*/
ret = qemuDomainAttachDeviceDiskLive ( NULL , & driver , vm , dev ) ;
break ;
2013-07-02 12:16:30 +04:00
case VIR_DOMAIN_DEVICE_CHR :
ret = qemuDomainAttachChrDevice ( & driver , vm , dev - > data . chr ) ;
break ;
default :
2015-04-23 20:38:00 +03:00
VIR_TEST_VERBOSE ( " device type '%s' cannot be attached \n " ,
virDomainDeviceTypeToString ( dev - > type ) ) ;
2013-07-02 12:16:30 +04:00
break ;
}
return ret ;
}
static int
testQemuHotplugDetach ( virDomainObjPtr vm ,
virDomainDeviceDefPtr dev )
{
int ret = - 1 ;
switch ( dev - > type ) {
2013-07-18 13:21:34 +04:00
case VIR_DOMAIN_DEVICE_DISK :
ret = qemuDomainDetachDeviceDiskLive ( & driver , vm , dev ) ;
break ;
2013-07-02 12:16:30 +04:00
case VIR_DOMAIN_DEVICE_CHR :
ret = qemuDomainDetachChrDevice ( & driver , vm , dev - > data . chr ) ;
break ;
default :
2015-04-23 20:38:00 +03:00
VIR_TEST_VERBOSE ( " device type '%s' cannot be detached \n " ,
virDomainDeviceTypeToString ( dev - > type ) ) ;
2013-07-02 12:16:30 +04:00
break ;
}
return ret ;
}
static int
testQemuHotplugUpdate ( virDomainObjPtr vm ,
virDomainDeviceDefPtr dev )
{
int ret = - 1 ;
/* XXX Ideally, we would call qemuDomainUpdateDeviceLive here. But that
* would require us to provide virConnectPtr and virDomainPtr ( they ' re used
* in case of updating a disk device . So for now , we will proceed with
* breaking the function into pieces . If we ever learn how to fake those
* required object , we can replace this code then . */
switch ( dev - > type ) {
case VIR_DOMAIN_DEVICE_GRAPHICS :
ret = qemuDomainChangeGraphics ( & driver , vm , dev - > data . graphics ) ;
break ;
default :
2015-04-23 20:38:00 +03:00
VIR_TEST_VERBOSE ( " device type '%s' cannot be updated \n " ,
virDomainDeviceTypeToString ( dev - > type ) ) ;
2013-07-02 12:16:30 +04:00
break ;
}
return ret ;
}
2013-07-18 18:46:13 +04:00
static int
testQemuHotplugCheckResult ( virDomainObjPtr vm ,
const char * expected ,
2015-12-10 16:12:13 +03:00
const char * expectedFile ,
2013-07-18 18:46:13 +04:00
bool fail )
{
char * actual ;
int ret ;
2014-12-16 10:46:44 +03:00
vm - > def - > id = - 1 ;
2016-02-04 00:40:35 +03:00
actual = virDomainDefFormat ( vm - > def , driver . caps ,
VIR_DOMAIN_DEF_FORMAT_SECURE ) ;
2013-07-18 18:46:13 +04:00
if ( ! actual )
return - 1 ;
2014-12-16 10:46:44 +03:00
vm - > def - > id = QEMU_HOTPLUG_TEST_DOMAIN_ID ;
2013-07-18 18:46:13 +04:00
if ( STREQ ( expected , actual ) ) {
2015-04-23 20:38:00 +03:00
if ( fail )
VIR_TEST_VERBOSE ( " domain XML should not match the expected result \n " ) ;
2013-07-18 18:46:13 +04:00
ret = 0 ;
} else {
if ( ! fail )
2015-12-10 16:12:13 +03:00
virtTestDifferenceFull ( stderr ,
expected , expectedFile ,
actual , NULL ) ;
2013-07-18 18:46:13 +04:00
ret = - 1 ;
}
VIR_FREE ( actual ) ;
return ret ;
}
2013-06-21 18:27:59 +04:00
static int
testQemuHotplug ( const void * data )
{
int ret = - 1 ;
struct qemuHotplugTestData * test = ( struct qemuHotplugTestData * ) data ;
char * domain_filename = NULL ;
char * device_filename = NULL ;
2013-07-18 18:46:13 +04:00
char * result_filename = NULL ;
char * domain_xml = NULL ;
2013-06-21 18:27:59 +04:00
char * device_xml = NULL ;
2013-07-18 18:46:13 +04:00
char * result_xml = NULL ;
2013-06-21 18:27:59 +04:00
const char * const * tmp ;
bool fail = test - > fail ;
2013-07-02 12:16:30 +04:00
bool keep = test - > keep ;
2014-03-19 18:46:07 +04:00
unsigned int device_parse_flags = 0 ;
2013-06-21 18:27:59 +04:00
virDomainObjPtr vm = NULL ;
virDomainDeviceDefPtr dev = NULL ;
virCapsPtr caps = NULL ;
qemuMonitorTestPtr test_mon = NULL ;
qemuDomainObjPrivatePtr priv = NULL ;
if ( virAsprintf ( & domain_filename , " %s/qemuxml2argvdata/qemuxml2argv-%s.xml " ,
abs_srcdir , test - > domain_filename ) < 0 | |
virAsprintf ( & device_filename , " %s/qemuhotplugtestdata/qemuhotplug-%s.xml " ,
2013-07-18 18:46:13 +04:00
abs_srcdir , test - > device_filename ) < 0 | |
virAsprintf ( & result_filename ,
" %s/qemuhotplugtestdata/qemuhotplug-%s+%s.xml " ,
abs_srcdir , test - > domain_filename ,
test - > device_filename ) < 0 )
goto cleanup ;
if ( virtTestLoadFile ( domain_filename , & domain_xml ) < 0 | |
virtTestLoadFile ( device_filename , & device_xml ) < 0 )
goto cleanup ;
if ( test - > action ! = UPDATE & &
virtTestLoadFile ( result_filename , & result_xml ) < 0 )
2013-06-21 18:27:59 +04:00
goto cleanup ;
if ( ! ( caps = virQEMUDriverGetCapabilities ( & driver , false ) ) )
goto cleanup ;
2013-07-02 12:16:30 +04:00
if ( test - > vm ) {
vm = test - > vm ;
} else {
2013-07-26 16:22:10 +04:00
if ( qemuHotplugCreateObjects ( driver . xmlopt , & vm , domain_xml ,
2015-09-09 17:03:15 +03:00
test - > deviceDeletedEvent ,
test - > domain_filename ) < 0 )
2013-07-02 12:16:30 +04:00
goto cleanup ;
}
2013-06-21 18:27:59 +04:00
2014-03-19 18:46:07 +04:00
if ( test - > action = = ATTACH )
2014-11-18 19:44:00 +03:00
device_parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE ;
2014-03-19 18:46:07 +04:00
2013-06-21 18:27:59 +04:00
if ( ! ( dev = virDomainDeviceDefParse ( device_xml , vm - > def ,
2014-03-19 18:46:07 +04:00
caps , driver . xmlopt ,
device_parse_flags ) ) )
2013-06-21 18:27:59 +04:00
goto cleanup ;
/* Now is the best time to feed the spoofed monitor with predefined
* replies . */
2013-09-19 15:56:30 +04:00
if ( ! ( test_mon = qemuMonitorTestNew ( true , driver . xmlopt , vm , & driver , NULL ) ) )
2013-06-21 18:27:59 +04:00
goto cleanup ;
tmp = test - > mon ;
while ( tmp & & * tmp ) {
const char * command_name ;
const char * response ;
if ( ! ( command_name = * tmp + + ) | |
! ( response = * tmp + + ) )
break ;
if ( qemuMonitorTestAddItem ( test_mon , command_name , response ) < 0 )
goto cleanup ;
}
2013-07-02 12:16:30 +04:00
priv = vm - > privateData ;
2013-06-21 18:27:59 +04:00
priv - > mon = qemuMonitorTestGetMonitor ( test_mon ) ;
priv - > monJSON = true ;
/* XXX We need to unlock the monitor here, as
* qemuDomainObjEnterMonitorInternal ( called from qemuDomainChangeGraphics )
* tries to lock it again */
virObjectUnlock ( priv - > mon ) ;
2013-07-02 12:16:30 +04:00
switch ( test - > action ) {
case ATTACH :
ret = testQemuHotplugAttach ( vm , dev ) ;
2013-07-18 13:21:34 +04:00
if ( ret = = 0 ) {
/* vm->def stolen dev->data.* so we just need to free the dev
* envelope */
VIR_FREE ( dev ) ;
}
2013-07-18 18:46:13 +04:00
if ( ret = = 0 | | fail )
2015-12-10 16:12:13 +03:00
ret = testQemuHotplugCheckResult ( vm , result_xml ,
result_filename , fail ) ;
2013-06-21 18:27:59 +04:00
break ;
2013-07-02 12:16:30 +04:00
case DETACH :
ret = testQemuHotplugDetach ( vm , dev ) ;
2013-07-18 18:46:13 +04:00
if ( ret = = 0 | | fail )
2015-12-10 16:12:13 +03:00
ret = testQemuHotplugCheckResult ( vm , domain_xml ,
domain_filename , fail ) ;
2013-06-21 18:27:59 +04:00
break ;
2013-07-02 12:16:30 +04:00
case UPDATE :
ret = testQemuHotplugUpdate ( vm , dev ) ;
2013-06-21 18:27:59 +04:00
}
2014-03-25 10:53:44 +04:00
cleanup :
2013-06-21 18:27:59 +04:00
VIR_FREE ( domain_filename ) ;
VIR_FREE ( device_filename ) ;
2013-07-18 18:46:13 +04:00
VIR_FREE ( result_filename ) ;
VIR_FREE ( domain_xml ) ;
2013-06-21 18:27:59 +04:00
VIR_FREE ( device_xml ) ;
2013-07-18 18:46:13 +04:00
VIR_FREE ( result_xml ) ;
2013-06-21 18:27:59 +04:00
/* don't dispose test monitor with VM */
if ( priv )
priv - > mon = NULL ;
2013-07-02 12:16:30 +04:00
if ( keep ) {
test - > vm = vm ;
} else {
virObjectUnref ( vm ) ;
test - > vm = NULL ;
}
2013-06-21 18:27:59 +04:00
virDomainDeviceDefFree ( dev ) ;
virObjectUnref ( caps ) ;
qemuMonitorTestFree ( test_mon ) ;
return ( ( ret < 0 & & fail ) | | ( ! ret & & ! fail ) ) ? 0 : - 1 ;
}
static int
mymain ( void )
{
int ret = 0 ;
2013-07-02 12:16:30 +04:00
struct qemuHotplugTestData data = { 0 } ;
2013-06-21 18:27:59 +04:00
# if !WITH_YAJL
fputs ( " libvirt not compiled with yajl, skipping this test \n " , stderr ) ;
return EXIT_AM_SKIP ;
# endif
if ( virThreadInitialize ( ) < 0 | |
2015-09-15 09:16:02 +03:00
qemuTestDriverInit ( & driver ) < 0 )
2013-06-21 18:27:59 +04:00
return EXIT_FAILURE ;
virEventRegisterDefaultImpl ( ) ;
VIR_FREE ( driver . config - > spiceListen ) ;
VIR_FREE ( driver . config - > vncListen ) ;
2013-07-18 13:21:34 +04:00
/* some dummy values from 'config file' */
if ( VIR_STRDUP_QUIET ( driver . config - > spicePassword , " 123456 " ) < 0 )
return EXIT_FAILURE ;
2013-06-21 18:27:59 +04:00
2013-11-21 14:43:10 +04:00
if ( ! ( driver . domainEventState = virObjectEventStateNew ( ) ) )
2013-07-11 19:30:56 +04:00
return EXIT_FAILURE ;
2013-07-18 13:21:34 +04:00
driver . lockManager = virLockManagerPluginNew ( " nop " , " qemu " ,
driver . config - > configBaseDir ,
0 ) ;
if ( ! driver . lockManager )
return EXIT_FAILURE ;
2013-07-26 16:22:10 +04:00
/* wait only 100ms for DEVICE_DELETED event */
qemuDomainRemoveDeviceWaitTime = 100 ;
# define DO_TEST(file, ACTION, dev, event, fial, kep, ...) \
2013-07-18 13:07:21 +04:00
do { \
2013-07-02 12:16:30 +04:00
const char * my_mon [ ] = { __VA_ARGS__ , NULL } ; \
2013-07-18 13:07:21 +04:00
const char * name = file " " # ACTION " " dev ; \
data . action = ACTION ; \
2013-07-02 12:16:30 +04:00
data . domain_filename = file ; \
data . device_filename = dev ; \
data . fail = fial ; \
data . mon = my_mon ; \
data . keep = kep ; \
2013-07-26 16:22:10 +04:00
data . deviceDeletedEvent = event ; \
2013-09-20 22:13:35 +04:00
if ( virtTestRun ( name , testQemuHotplug , & data ) < 0 ) \
2013-07-02 12:16:30 +04:00
ret = - 1 ; \
2013-07-18 13:07:21 +04:00
} while ( 0 )
2013-07-02 12:16:30 +04:00
# define DO_TEST_ATTACH(file, dev, fial, kep, ...) \
2013-07-26 16:22:10 +04:00
DO_TEST ( file , ATTACH , dev , false , fial , kep , __VA_ARGS__ )
2013-07-02 12:16:30 +04:00
# define DO_TEST_DETACH(file, dev, fial, kep, ...) \
2013-07-26 16:22:10 +04:00
DO_TEST ( file , DETACH , dev , false , fial , kep , __VA_ARGS__ )
# define DO_TEST_ATTACH_EVENT(file, dev, fial, kep, ...) \
DO_TEST ( file , ATTACH , dev , true , fial , kep , __VA_ARGS__ )
# define DO_TEST_DETACH_EVENT(file, dev, fial, kep, ...) \
DO_TEST ( file , DETACH , dev , true , fial , kep , __VA_ARGS__ )
2013-07-02 12:16:30 +04:00
# define DO_TEST_UPDATE(file, dev, fial, kep, ...) \
2013-07-26 16:22:10 +04:00
DO_TEST ( file , UPDATE , dev , false , fial , kep , __VA_ARGS__ )
2013-06-21 18:27:59 +04:00
2013-07-26 17:06:37 +04:00
# define QMP_OK "{\"return\": {}}"
2013-07-18 13:21:34 +04:00
# define HMP(msg) "{\"return\": \"" msg "\"}"
2013-07-26 17:06:37 +04:00
2013-07-19 15:04:44 +04:00
# define QMP_DEVICE_DELETED(dev) \
" { " \
" \" timestamp \" : { " \
" \" seconds \" : 1374137171, " \
" \" microseconds \" : 2659 " \
" }, " \
" \" event \" : \" DEVICE_DELETED \" , " \
" \" data \" : { " \
" \" device \" : \" " dev " \" , " \
" \" path \" : \" /machine/peripheral/ " dev " \" " \
" } " \
" } \r \n "
2013-07-02 12:16:30 +04:00
DO_TEST_UPDATE ( " graphics-spice " , " graphics-spice-nochange " , false , false , NULL ) ;
DO_TEST_UPDATE ( " graphics-spice-timeout " , " graphics-spice-timeout-nochange " , false , false ,
2013-07-26 17:06:37 +04:00
" set_password " , QMP_OK , " expire_password " , QMP_OK ) ;
2013-07-02 12:16:30 +04:00
DO_TEST_UPDATE ( " graphics-spice-timeout " , " graphics-spice-timeout-password " , false , false ,
2013-07-26 17:06:37 +04:00
" set_password " , QMP_OK , " expire_password " , QMP_OK ) ;
2013-07-02 12:16:30 +04:00
DO_TEST_UPDATE ( " graphics-spice " , " graphics-spice-listen " , true , false , NULL ) ;
DO_TEST_UPDATE ( " graphics-spice-listen-network " , " graphics-spice-listen-network " , false , false ,
2013-07-26 17:06:37 +04:00
" set_password " , QMP_OK , " expire_password " , QMP_OK ) ;
2013-07-02 12:16:30 +04:00
/* Strange huh? Currently, only graphics can be updated :-P */
DO_TEST_UPDATE ( " disk-cdrom " , " disk-cdrom-nochange " , true , false , NULL ) ;
DO_TEST_ATTACH ( " console-compat-2 " , " console-virtio " , false , true ,
" chardev-add " , " { \" return \" : { \" pty \" : \" /dev/pts/26 \" }} " ,
2013-07-26 17:06:37 +04:00
" device_add " , QMP_OK ) ;
2013-07-02 12:16:30 +04:00
DO_TEST_DETACH ( " console-compat-2 " , " console-virtio " , false , false ,
2013-07-26 17:06:37 +04:00
" device_del " , QMP_OK ,
" chardev-remove " , QMP_OK ) ;
2013-06-21 18:27:59 +04:00
2013-07-18 13:21:34 +04:00
DO_TEST_ATTACH ( " hotplug-base " , " disk-virtio " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-virtio " , false , false ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
2013-07-19 15:04:44 +04:00
DO_TEST_ATTACH_EVENT ( " hotplug-base " , " disk-virtio " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-virtio " , true , true ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-virtio " , false , false ,
" device_del " , QMP_DEVICE_DELETED ( " virtio-disk4 " ) QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
2013-07-26 16:44:52 +04:00
DO_TEST_ATTACH ( " hotplug-base " , " disk-usb " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-usb " , false , false ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
DO_TEST_ATTACH_EVENT ( " hotplug-base " , " disk-usb " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-usb " , true , true ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-usb " , false , false ,
" device_del " , QMP_DEVICE_DELETED ( " usb-disk16 " ) QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
2013-07-26 17:28:33 +04:00
DO_TEST_ATTACH ( " hotplug-base " , " disk-scsi " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-scsi " , false , false ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
DO_TEST_ATTACH_EVENT ( " hotplug-base " , " disk-scsi " , false , true ,
" human-monitor-command " , HMP ( " OK \\ r \\ n " ) ,
" device_add " , QMP_OK ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-scsi " , true , true ,
" device_del " , QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
DO_TEST_DETACH ( " hotplug-base " , " disk-scsi " , false , false ,
" device_del " , QMP_DEVICE_DELETED ( " scsi0-0-0-5 " ) QMP_OK ,
" human-monitor-command " , HMP ( " " ) ) ;
2015-09-15 09:16:02 +03:00
qemuTestDriverFree ( & driver ) ;
2013-06-21 18:27:59 +04:00
return ( ret = = 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ;
}
VIRT_TEST_MAIN ( mymain )