2012-08-20 17:06:21 +04:00
/*
2013-01-31 05:50:09 +04:00
* Copyright ( C ) 2011 - 2013 Red Hat , Inc .
2012-08-20 17:06:21 +04:00
*
* 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
2012-09-21 02:30:55 +04:00
* License along with this library . If not , see
2012-08-20 17:06:21 +04:00
* < http : //www.gnu.org/licenses/>.
*
*/
# include <config.h>
# include <time.h>
2016-06-06 14:46:41 +03:00
# include "testutils.h"
2018-03-22 21:05:26 +03:00
# include "testutilsqemuschema.h"
2012-08-20 17:06:21 +04:00
# include "qemumonitortestutils.h"
2012-12-13 19:49:48 +04:00
# include "virthread.h"
2018-12-13 17:53:50 +03:00
# define LIBVIRT_QEMU_PROCESSPRIV_H_ALLOW
2013-07-26 16:22:10 +04:00
# include "qemu/qemu_processpriv.h"
2012-08-20 17:06:21 +04:00
# include "qemu/qemu_monitor.h"
2013-07-25 14:08:25 +04:00
# include "qemu/qemu_agent.h"
2012-08-20 17:06:21 +04:00
# include "rpc/virnetsocket.h"
2012-12-12 22:06:53 +04:00
# include "viralloc.h"
2012-12-12 21:59:27 +04:00
# include "virlog.h"
2012-12-13 22:21:53 +04:00
# include "virerror.h"
2020-02-12 17:56:29 +03:00
# include "vireventthread.h"
2012-08-20 17:06:21 +04:00
# define VIR_FROM_THIS VIR_FROM_NONE
2014-02-28 16:16:17 +04:00
VIR_LOG_INIT ( " tests.qemumonitortestutils " ) ;
2012-08-20 17:06:21 +04:00
struct _qemuMonitorTestItem {
2020-04-23 17:52:12 +03:00
char * identifier ;
2013-07-25 13:48:11 +04:00
qemuMonitorTestResponseCallback cb ;
void * opaque ;
virFreeCallback freecb ;
2012-08-20 17:06:21 +04:00
} ;
struct _qemuMonitorTest {
virMutex lock ;
virThread thread ;
bool quit ;
bool running ;
2013-10-02 20:20:18 +04:00
bool started ;
2012-08-20 17:06:21 +04:00
2020-04-23 17:57:31 +03:00
bool allowUnusedCommands ;
2020-04-29 12:03:02 +03:00
bool skipValidationDeprecated ;
bool skipValidationRemoved ;
2012-08-20 17:06:21 +04:00
char * incoming ;
size_t incomingLength ;
size_t incomingCapacity ;
char * outgoing ;
size_t outgoingLength ;
size_t outgoingCapacity ;
2021-03-11 10:16:13 +03:00
virNetSocket * server ;
virNetSocket * client ;
2012-08-20 17:06:21 +04:00
2020-02-12 17:56:29 +03:00
virEventThread * eventThread ;
2021-03-11 10:16:13 +03:00
qemuMonitor * mon ;
qemuAgent * agent ;
2012-08-20 17:06:21 +04:00
2012-11-12 18:33:55 +04:00
char * tmpdir ;
2012-08-20 17:06:21 +04:00
size_t nitems ;
2021-03-11 10:16:13 +03:00
qemuMonitorTestItem * * items ;
2012-08-20 17:06:21 +04:00
2021-03-11 10:16:13 +03:00
virDomainObj * vm ;
2020-10-22 20:04:18 +03:00
GHashTable * qapischema ;
2012-08-20 17:06:21 +04:00
} ;
2013-07-25 13:48:11 +04:00
static void
2021-03-11 10:16:13 +03:00
qemuMonitorTestItemFree ( qemuMonitorTestItem * item )
2013-07-25 13:48:11 +04:00
{
if ( ! item )
return ;
2020-04-23 17:52:12 +03:00
g_free ( item - > identifier ) ;
2013-07-25 13:48:11 +04:00
if ( item - > freecb )
( item - > freecb ) ( item - > opaque ) ;
2021-02-03 22:35:02 +03:00
g_free ( item ) ;
2013-07-25 13:48:11 +04:00
}
2012-08-20 17:06:21 +04:00
2013-07-18 18:17:31 +04:00
2012-08-20 17:06:21 +04:00
/*
2013-04-20 00:18:14 +04:00
* Appends data for a reply to the outgoing buffer
2012-08-20 17:06:21 +04:00
*/
2013-07-25 13:48:11 +04:00
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddResponse ( qemuMonitorTest * test ,
2016-06-07 14:46:01 +03:00
const char * response )
2012-08-20 17:06:21 +04:00
{
size_t want = strlen ( response ) + 2 ;
size_t have = test - > outgoingCapacity - test - > outgoingLength ;
2013-07-29 16:29:15 +04:00
VIR_DEBUG ( " Adding response to monitor command: '%s " , response ) ;
2012-08-20 17:06:21 +04:00
if ( have < want ) {
size_t need = want - have ;
2021-03-20 02:37:03 +03:00
VIR_EXPAND_N ( test - > outgoing , test - > outgoingCapacity , need ) ;
2012-08-20 17:06:21 +04:00
}
want - = 2 ;
2013-07-25 13:02:00 +04:00
memcpy ( test - > outgoing + test - > outgoingLength , response , want ) ;
memcpy ( test - > outgoing + test - > outgoingLength + want , " \r \n " , 2 ) ;
2012-08-20 17:06:21 +04:00
test - > outgoingLength + = want + 2 ;
return 0 ;
}
2016-12-01 11:22:44 +03:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddErrorResponseInternal ( qemuMonitorTest * test ,
2020-04-23 12:50:59 +03:00
const char * usermsg )
2012-08-20 17:06:21 +04:00
{
2020-07-03 02:35:41 +03:00
g_auto ( virBuffer ) buf = VIR_BUFFER_INITIALIZER ;
2019-10-15 16:16:31 +03:00
g_autofree char * escapemsg = NULL ;
g_autofree char * jsonmsg = NULL ;
2016-12-01 11:22:44 +03:00
char * tmp ;
if ( ! usermsg )
usermsg = " unexpected command " ;
2019-06-15 13:09:41 +03:00
virBufferEscape ( & buf , ' \\ ' , " \" " , " %s " , usermsg ) ;
escapemsg = virBufferContentAndReset ( & buf ) ;
2016-12-01 11:22:44 +03:00
2019-06-15 13:09:41 +03:00
/* replace newline/carriage return with space */
tmp = escapemsg ;
while ( * tmp ) {
if ( * tmp = = ' \r ' | | * tmp = = ' \n ' )
* tmp = ' ' ;
2016-12-01 11:22:44 +03:00
2019-06-15 13:09:41 +03:00
tmp + + ;
2012-08-20 17:06:21 +04:00
}
2016-12-01 11:22:44 +03:00
2019-06-15 13:09:41 +03:00
/* format the JSON error message */
2019-10-22 16:26:14 +03:00
jsonmsg = g_strdup_printf ( " { \" error \" : " " { \" desc \" : \" %s \" , "
" \" class \" : \" UnexpectedCommand \" } } " , escapemsg ) ;
2019-06-15 13:09:41 +03:00
return qemuMonitorTestAddResponse ( test , jsonmsg ) ;
2016-12-01 11:22:44 +03:00
}
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddInvalidCommandResponse ( qemuMonitorTest * test ,
2016-12-01 11:22:44 +03:00
const char * expectedcommand ,
const char * actualcommand )
{
2019-10-15 16:16:31 +03:00
g_autofree char * msg = NULL ;
2016-12-01 11:22:44 +03:00
2019-10-22 16:26:14 +03:00
msg = g_strdup_printf ( " expected command '%s' got '%s' " , expectedcommand ,
actualcommand ) ;
2016-12-01 11:22:44 +03:00
2020-04-23 12:50:59 +03:00
return qemuMonitorTestAddErrorResponseInternal ( test , msg ) ;
2012-08-20 17:06:21 +04:00
}
2019-10-15 14:35:07 +03:00
int G_GNUC_PRINTF ( 2 , 3 )
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddErrorResponse ( qemuMonitorTest * test , const char * errmsg , . . . )
2013-07-29 16:29:15 +04:00
{
va_list msgargs ;
2019-10-15 16:16:31 +03:00
g_autofree char * msg = NULL ;
g_autofree char * jsonmsg = NULL ;
2013-07-29 16:29:15 +04:00
int ret = - 1 ;
va_start ( msgargs , errmsg ) ;
2019-10-22 15:11:15 +03:00
msg = g_strdup_vprintf ( errmsg , msgargs ) ;
2013-07-29 16:29:15 +04:00
2019-10-22 16:26:14 +03:00
jsonmsg = g_strdup_printf ( " { \" error \" : " " { \" desc \" : \" %s \" , "
" \" class \" : \" UnexpectedCommand \" } } " , msg ) ;
2013-07-29 16:29:15 +04:00
2016-06-07 14:46:01 +03:00
ret = qemuMonitorTestAddResponse ( test , jsonmsg ) ;
2013-07-29 16:29:15 +04:00
va_end ( msgargs ) ;
return ret ;
}
2020-04-23 12:57:14 +03:00
static void G_GNUC_NORETURN G_GNUC_PRINTF ( 1 , 2 )
qemuMonitorTestError ( const char * errmsg ,
. . . )
{
va_list msgargs ;
va_start ( msgargs , errmsg ) ;
g_fprintf ( stderr , " \n " ) ;
g_vfprintf ( stderr , errmsg , msgargs ) ;
g_fprintf ( stderr , " \n " ) ;
exit ( EXIT_FAILURE ) ; /* exempt from syntax-check */
}
static void G_GNUC_NORETURN
qemuMonitorTestErrorInvalidCommand ( const char * expectedcommand ,
const char * actualcommand )
{
qemuMonitorTestError ( " expected command '%s' got '%s' " ,
expectedcommand , actualcommand ) ;
}
2013-07-18 18:17:31 +04:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommand ( qemuMonitorTest * test ,
2013-07-25 13:48:11 +04:00
const char * cmdstr )
2012-08-20 17:06:21 +04:00
{
2013-07-25 13:48:11 +04:00
int ret ;
2012-08-20 17:06:21 +04:00
2013-07-29 16:29:15 +04:00
VIR_DEBUG ( " Processing string from monitor handler: '%s " , cmdstr ) ;
2013-07-25 13:48:11 +04:00
if ( test - > nitems = = 0 ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " unexpected command: '%s' " , cmdstr ) ;
2012-08-20 17:06:21 +04:00
} else {
2021-03-11 10:16:13 +03:00
qemuMonitorTestItem * item = test - > items [ 0 ] ;
2013-07-25 13:48:11 +04:00
ret = ( item - > cb ) ( test , item , cmdstr ) ;
qemuMonitorTestItemFree ( item ) ;
if ( VIR_DELETE_ELEMENT ( test - > items , 0 , test - > nitems ) < 0 )
return - 1 ;
2012-08-20 17:06:21 +04:00
}
return ret ;
}
2013-07-18 18:17:31 +04:00
2012-08-20 17:06:21 +04:00
/*
* Handles read / write of monitor data on the monitor server side
*/
2013-07-18 18:17:31 +04:00
static void
2021-03-11 10:16:13 +03:00
qemuMonitorTestIO ( virNetSocket * sock ,
2013-07-18 18:17:31 +04:00
int events ,
void * opaque )
2012-08-20 17:06:21 +04:00
{
2021-03-11 10:16:13 +03:00
qemuMonitorTest * test = opaque ;
2012-08-20 17:06:21 +04:00
bool err = false ;
2022-02-08 17:31:35 +03:00
VIR_LOCK_GUARD lock = virLockGuardLock ( & test - > lock ) ;
2012-08-20 17:06:21 +04:00
2022-02-08 17:31:35 +03:00
if ( test - > quit )
2013-02-23 01:56:21 +04:00
return ;
2022-02-08 17:31:35 +03:00
2012-08-20 17:06:21 +04:00
if ( events & VIR_EVENT_HANDLE_WRITABLE ) {
ssize_t ret ;
if ( ( ret = virNetSocketWrite ( sock ,
test - > outgoing ,
test - > outgoingLength ) ) < 0 ) {
err = true ;
goto cleanup ;
}
memmove ( test - > outgoing ,
test - > outgoing + ret ,
test - > outgoingLength - ret ) ;
test - > outgoingLength - = ret ;
if ( ( test - > outgoingCapacity - test - > outgoingLength ) > 1024 )
VIR_SHRINK_N ( test - > outgoing , test - > outgoingCapacity , 1024 ) ;
}
if ( events & VIR_EVENT_HANDLE_READABLE ) {
ssize_t ret , used ;
char * t1 , * t2 ;
if ( ( test - > incomingCapacity - test - > incomingLength ) < 1024 ) {
2021-03-20 02:37:03 +03:00
VIR_EXPAND_N ( test - > incoming , test - > incomingCapacity , 1024 ) ;
2012-08-20 17:06:21 +04:00
}
if ( ( ret = virNetSocketRead ( sock ,
test - > incoming + test - > incomingLength ,
( test - > incomingCapacity - test - > incomingLength ) - 1 ) ) < 0 ) {
err = true ;
goto cleanup ;
}
test - > incomingLength + = ret ;
test - > incoming [ test - > incomingLength ] = ' \0 ' ;
/* Look to see if we've got a complete line, and
* if so , handle that command
*/
t1 = test - > incoming ;
2015-03-10 15:10:20 +03:00
while ( ( t2 = strstr ( t1 , " \n " ) ) | |
2019-06-14 21:39:24 +03:00
( test - > agent & & ( t2 = strstr ( t1 , " \r " ) ) ) ) {
2012-08-20 17:06:21 +04:00
* t2 = ' \0 ' ;
if ( qemuMonitorTestProcessCommand ( test , t1 ) < 0 ) {
err = true ;
goto cleanup ;
}
2013-07-25 14:03:29 +04:00
t1 = t2 + 1 ;
2012-08-20 17:06:21 +04:00
}
used = t1 - test - > incoming ;
memmove ( test - > incoming , t1 , test - > incomingLength - used ) ;
test - > incomingLength - = used ;
if ( ( test - > incomingCapacity - test - > incomingLength ) > 1024 ) {
VIR_SHRINK_N ( test - > incoming ,
test - > incomingCapacity ,
1024 ) ;
}
}
if ( events & ( VIR_EVENT_HANDLE_HANGUP |
VIR_EVENT_HANDLE_ERROR ) )
err = true ;
2014-03-25 10:53:44 +04:00
cleanup :
2012-08-20 17:06:21 +04:00
if ( err ) {
virNetSocketRemoveIOCallback ( sock ) ;
virNetSocketClose ( sock ) ;
2022-01-28 20:42:45 +03:00
g_clear_pointer ( & test - > client , virObjectUnref ) ;
2012-08-20 17:06:21 +04:00
} else {
events = VIR_EVENT_HANDLE_READABLE ;
if ( test - > outgoingLength )
events | = VIR_EVENT_HANDLE_WRITABLE ;
virNetSocketUpdateIOCallback ( sock , events ) ;
}
}
2013-07-18 18:17:31 +04:00
static void
qemuMonitorTestWorker ( void * opaque )
2012-08-20 17:06:21 +04:00
{
2021-03-11 10:16:13 +03:00
qemuMonitorTest * test = opaque ;
2012-08-20 17:06:21 +04:00
2022-02-08 17:31:35 +03:00
while ( true ) {
VIR_WITH_MUTEX_LOCK_GUARD ( & test - > lock ) {
if ( test - > quit ) {
test - > running = false ;
return ;
}
}
2012-08-20 17:06:21 +04:00
if ( virEventRunDefaultImpl ( ) < 0 ) {
2022-02-08 17:31:35 +03:00
VIR_WITH_MUTEX_LOCK_GUARD ( & test - > lock ) {
test - > quit = true ;
test - > running = false ;
return ;
}
2012-08-20 17:06:21 +04:00
}
}
}
2013-07-18 18:17:31 +04:00
2012-11-12 14:34:41 +04:00
static void
2019-10-14 15:45:03 +03:00
qemuMonitorTestFreeTimer ( int timer G_GNUC_UNUSED ,
void * opaque G_GNUC_UNUSED )
2012-11-12 14:34:41 +04:00
{
/* nothing to be done here */
}
2013-07-18 18:17:31 +04:00
void
2021-03-11 10:16:13 +03:00
qemuMonitorTestFree ( qemuMonitorTest * test )
2012-08-20 17:06:21 +04:00
{
size_t i ;
2012-11-12 14:34:41 +04:00
int timer = - 1 ;
2012-08-20 17:06:21 +04:00
if ( ! test )
return ;
2022-02-08 17:31:35 +03:00
VIR_WITH_MUTEX_LOCK_GUARD ( & test - > lock ) {
if ( test - > running ) {
test - > quit = true ;
/* HACK: Add a dummy timeout to break event loop */
timer = virEventAddTimeout ( 0 , qemuMonitorTestFreeTimer , NULL , NULL ) ;
}
2012-08-20 17:06:21 +04:00
}
if ( test - > client ) {
virNetSocketRemoveIOCallback ( test - > client ) ;
virNetSocketClose ( test - > client ) ;
virObjectUnref ( test - > client ) ;
}
virObjectUnref ( test - > server ) ;
if ( test - > mon ) {
2013-01-10 01:00:32 +04:00
virObjectUnlock ( test - > mon ) ;
2012-08-20 17:06:21 +04:00
qemuMonitorClose ( test - > mon ) ;
}
2013-07-25 14:08:25 +04:00
if ( test - > agent ) {
virObjectUnlock ( test - > agent ) ;
qemuAgentClose ( test - > agent ) ;
}
2020-02-12 17:56:29 +03:00
g_object_unref ( test - > eventThread ) ;
2012-08-20 17:06:21 +04:00
virObjectUnref ( test - > vm ) ;
2013-10-02 20:20:18 +04:00
if ( test - > started )
2013-07-22 18:57:08 +04:00
virThreadJoin ( & test - > thread ) ;
2012-08-20 17:06:21 +04:00
2012-11-12 14:34:41 +04:00
if ( timer ! = - 1 )
virEventRemoveTimeout ( timer ) ;
2021-02-03 22:35:02 +03:00
g_free ( test - > incoming ) ;
g_free ( test - > outgoing ) ;
2013-02-04 22:31:46 +04:00
2020-04-23 17:57:31 +03:00
for ( i = 0 ; i < test - > nitems ; i + + ) {
if ( ! test - > allowUnusedCommands ) {
g_fprintf ( stderr ,
" \n unused test monitor item '%s' " ,
NULLSTR ( test - > items [ i ] - > identifier ) ) ;
}
2012-08-20 17:06:21 +04:00
qemuMonitorTestItemFree ( test - > items [ i ] ) ;
2020-04-23 17:57:31 +03:00
}
2021-02-03 22:35:02 +03:00
g_free ( test - > items ) ;
2012-08-20 17:06:21 +04:00
2012-11-12 18:33:55 +04:00
if ( test - > tmpdir & & rmdir ( test - > tmpdir ) < 0 )
2019-10-02 18:30:36 +03:00
VIR_WARN ( " Failed to remove tempdir: %s " , g_strerror ( errno ) ) ;
2012-11-12 18:33:55 +04:00
2021-02-03 22:35:02 +03:00
g_free ( test - > tmpdir ) ;
2012-11-12 18:33:55 +04:00
2020-04-23 17:57:31 +03:00
if ( ! test - > allowUnusedCommands & &
test - > nitems ! = 0 ) {
qemuMonitorTestError ( " unused test monitor items are not allowed for this test \n " ) ;
}
2012-08-20 17:06:21 +04:00
virMutexDestroy ( & test - > lock ) ;
2021-02-03 22:35:02 +03:00
g_free ( test ) ;
2012-08-20 17:06:21 +04:00
}
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddHandler ( qemuMonitorTest * test ,
2020-04-23 17:52:12 +03:00
const char * identifier ,
2013-07-25 13:48:11 +04:00
qemuMonitorTestResponseCallback cb ,
void * opaque ,
virFreeCallback freecb )
2012-08-20 17:06:21 +04:00
{
2021-03-11 10:16:13 +03:00
qemuMonitorTestItem * item ;
2012-08-20 17:06:21 +04:00
2020-09-23 01:42:45 +03:00
item = g_new0 ( qemuMonitorTestItem , 1 ) ;
2012-08-20 17:06:21 +04:00
2020-04-23 17:52:12 +03:00
item - > identifier = g_strdup ( identifier ) ;
2013-07-25 13:48:11 +04:00
item - > cb = cb ;
item - > freecb = freecb ;
item - > opaque = opaque ;
2012-08-20 17:06:21 +04:00
2022-02-08 17:31:35 +03:00
VIR_WITH_MUTEX_LOCK_GUARD ( & test - > lock ) {
VIR_APPEND_ELEMENT ( test - > items , test - > nitems , item ) ;
}
2012-08-20 17:06:21 +04:00
return 0 ;
}
2013-07-25 13:48:11 +04:00
void *
2021-03-11 10:16:13 +03:00
qemuMonitorTestItemGetPrivateData ( qemuMonitorTestItem * item )
2013-07-25 13:48:11 +04:00
{
return item ? item - > opaque : NULL ;
}
2013-07-25 17:42:38 +04:00
typedef struct _qemuMonitorTestCommandArgs qemuMonitorTestCommandArgs ;
struct _qemuMonitorTestCommandArgs {
char * argname ;
char * argval ;
2013-07-25 13:48:11 +04:00
} ;
2013-07-25 17:42:38 +04:00
struct qemuMonitorTestHandlerData {
char * command_name ;
2016-11-25 12:43:23 +03:00
char * cmderr ;
2013-07-25 17:42:38 +04:00
char * response ;
size_t nargs ;
2021-03-11 10:16:13 +03:00
qemuMonitorTestCommandArgs * args ;
2016-09-27 18:11:55 +03:00
char * expectArgs ;
2013-07-25 17:42:38 +04:00
} ;
static void
qemuMonitorTestHandlerDataFree ( void * opaque )
{
struct qemuMonitorTestHandlerData * data = opaque ;
size_t i ;
if ( ! data )
return ;
for ( i = 0 ; i < data - > nargs ; i + + ) {
2021-02-03 22:35:02 +03:00
g_free ( data - > args [ i ] . argname ) ;
g_free ( data - > args [ i ] . argval ) ;
2013-07-25 17:42:38 +04:00
}
2021-02-03 22:35:02 +03:00
g_free ( data - > command_name ) ;
g_free ( data - > cmderr ) ;
g_free ( data - > response ) ;
g_free ( data - > args ) ;
g_free ( data - > expectArgs ) ;
g_free ( data ) ;
2013-07-25 17:42:38 +04:00
}
2018-03-22 21:05:26 +03:00
2020-04-29 11:38:16 +03:00
/* Returns -1 on error, 0 if validation was successful/not necessary */
2018-03-22 21:05:26 +03:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommandDefaultValidate ( qemuMonitorTest * test ,
2018-03-22 21:05:26 +03:00
const char * cmdname ,
2021-03-11 10:16:13 +03:00
virJSONValue * args )
2018-03-22 21:05:26 +03:00
{
2019-10-15 15:47:50 +03:00
g_auto ( virBuffer ) debug = VIR_BUFFER_INITIALIZER ;
2021-10-15 13:18:00 +03:00
bool allowIncomplete = false ;
2018-03-22 21:05:26 +03:00
2019-06-15 12:47:34 +03:00
if ( ! test - > qapischema )
2018-03-22 21:05:26 +03:00
return 0 ;
2019-06-15 12:47:34 +03:00
if ( test - > agent ) {
virReportError ( VIR_ERR_INTERNAL_ERROR , " %s " ,
" Command validation testing is not "
" implemented for the guest agent " ) ;
return - 1 ;
}
2021-10-15 13:18:00 +03:00
/* The schema of 'device_add' is incomplete so we relax the validator */
2018-03-22 21:05:26 +03:00
if ( STREQ ( cmdname , " device_add " ) )
2021-10-15 13:18:00 +03:00
allowIncomplete = true ;
2018-03-22 21:05:26 +03:00
2020-04-29 18:52:43 +03:00
if ( testQEMUSchemaValidateCommand ( cmdname , args , test - > qapischema ,
test - > skipValidationDeprecated ,
test - > skipValidationRemoved ,
2021-10-15 13:18:00 +03:00
allowIncomplete ,
2020-04-29 18:52:43 +03:00
& debug ) < 0 ) {
2020-03-04 12:22:25 +03:00
if ( virTestGetDebug ( ) = = 2 ) {
g_autofree char * argstr = NULL ;
2018-03-22 21:05:26 +03:00
2020-03-04 12:22:25 +03:00
if ( args )
argstr = virJSONValueToString ( args , true ) ;
2018-03-22 21:05:26 +03:00
2020-04-01 13:28:17 +03:00
fprintf ( stderr ,
" \n failed to validate arguments of '%s' against QAPI schema \n "
" args: \n %s \n validator output: \n %s \n " ,
cmdname , NULLSTR ( argstr ) , virBufferCurrentContent ( & debug ) ) ;
}
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " failed to validate arguments of '%s' "
" against QAPI schema "
" (to see debug output use VIR_TEST_DEBUG=2) " ,
cmdname ) ;
2019-06-15 12:54:03 +03:00
return - 1 ;
2018-03-22 21:05:26 +03:00
}
2019-06-15 12:54:03 +03:00
return 0 ;
2018-03-22 21:05:26 +03:00
}
2013-07-25 13:48:11 +04:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommandDefault ( qemuMonitorTest * test ,
qemuMonitorTestItem * item ,
2013-07-25 13:48:11 +04:00
const char * cmdstr )
{
2013-07-25 17:42:38 +04:00
struct qemuMonitorTestHandlerData * data = item - > opaque ;
2019-10-15 15:47:50 +03:00
g_autoptr ( virJSONValue ) val = NULL ;
2021-03-11 10:16:13 +03:00
virJSONValue * cmdargs = NULL ;
2013-07-25 13:48:11 +04:00
const char * cmdname ;
2019-06-15 13:09:41 +03:00
if ( ! ( val = virJSONValueFromString ( cmdstr ) ) )
return - 1 ;
2013-07-25 13:48:11 +04:00
2020-04-23 12:57:14 +03:00
if ( ! ( cmdname = virJSONValueObjectGetString ( val , " execute " ) ) ) {
qemuMonitorTestError ( " Missing command name in %s " , cmdstr ) ;
return - 1 ;
}
2013-07-25 13:48:11 +04:00
2019-06-15 13:09:41 +03:00
cmdargs = virJSONValueObjectGet ( val , " arguments " ) ;
2020-04-29 11:38:16 +03:00
if ( qemuMonitorTestProcessCommandDefaultValidate ( test , cmdname , cmdargs ) < 0 )
2019-06-15 12:43:09 +03:00
return - 1 ;
2018-03-22 21:05:26 +03:00
2019-06-15 12:43:09 +03:00
if ( data - > command_name & & STRNEQ ( data - > command_name , cmdname ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestErrorInvalidCommand ( data - > command_name , cmdname ) ;
return - 1 ;
2019-06-15 12:43:09 +03:00
} else {
return qemuMonitorTestAddResponse ( test , data - > response ) ;
2018-03-22 21:05:26 +03:00
}
2013-07-25 13:48:11 +04:00
}
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddItem ( qemuMonitorTest * test ,
2013-07-25 13:48:11 +04:00
const char * command_name ,
const char * response )
{
2013-07-25 17:42:38 +04:00
struct qemuMonitorTestHandlerData * data ;
2013-07-25 13:48:11 +04:00
2020-09-23 01:42:45 +03:00
data = g_new0 ( struct qemuMonitorTestHandlerData , 1 ) ;
2013-07-25 13:48:11 +04:00
2019-10-20 14:49:46 +03:00
data - > command_name = g_strdup ( command_name ) ;
data - > response = g_strdup ( response ) ;
2013-07-25 13:48:11 +04:00
return qemuMonitorTestAddHandler ( test ,
2020-04-23 17:52:12 +03:00
command_name ,
2013-07-25 13:48:11 +04:00
qemuMonitorTestProcessCommandDefault ,
2013-07-25 17:42:38 +04:00
data , qemuMonitorTestHandlerDataFree ) ;
2013-07-25 13:48:11 +04:00
}
2012-08-20 17:06:21 +04:00
2016-11-25 12:43:23 +03:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommandVerbatim ( qemuMonitorTest * test ,
qemuMonitorTestItem * item ,
2016-11-25 12:43:23 +03:00
const char * cmdstr )
{
struct qemuMonitorTestHandlerData * data = item - > opaque ;
2019-10-15 16:16:31 +03:00
g_autofree char * reformatted = NULL ;
2019-10-15 15:47:50 +03:00
g_autoptr ( virJSONValue ) json = NULL ;
2021-03-11 10:16:13 +03:00
virJSONValue * cmdargs ;
2019-06-07 11:38:06 +03:00
const char * cmdname ;
2016-11-25 12:43:23 +03:00
int ret = - 1 ;
/* JSON strings will be reformatted to simplify checking */
2019-06-15 13:09:41 +03:00
if ( ! ( json = virJSONValueFromString ( cmdstr ) ) | |
! ( reformatted = virJSONValueToString ( json , false ) ) )
return - 1 ;
2016-11-25 12:43:23 +03:00
2019-06-15 13:09:41 +03:00
cmdstr = reformatted ;
2019-06-07 11:38:06 +03:00
2019-06-15 13:09:41 +03:00
/* in this case we do a best-effort schema check if we can find the command */
if ( ( cmdname = virJSONValueObjectGetString ( json , " execute " ) ) ) {
cmdargs = virJSONValueObjectGet ( json , " arguments " ) ;
2020-04-29 11:38:16 +03:00
if ( qemuMonitorTestProcessCommandDefaultValidate ( test , cmdname , cmdargs ) < 0 )
2019-06-15 13:09:41 +03:00
return - 1 ;
2016-11-25 12:43:23 +03:00
}
if ( STREQ ( data - > command_name , cmdstr ) ) {
ret = qemuMonitorTestAddResponse ( test , data - > response ) ;
} else {
if ( data - > cmderr ) {
2021-11-30 20:16:32 +03:00
qemuMonitorTestError ( " %s: %s expected %s " ,
data - > cmderr , cmdstr , data - > command_name ) ;
2016-11-25 12:43:23 +03:00
} else {
2020-04-23 12:57:14 +03:00
qemuMonitorTestErrorInvalidCommand ( data - > command_name , cmdstr ) ;
2016-11-25 12:43:23 +03:00
}
}
return ret ;
}
/**
* qemuMonitorTestAddItemVerbatim :
* @ test : monitor test object
* @ command : full expected command syntax
* @ cmderr : possible explanation of expected command ( may be NULL )
* @ response : full reply of @ command
*
* Adds a test command for the simulated monitor . The full syntax is checked
* as specified in @ command . For JSON monitor tests formatting / whitespace is
* ignored . If the command on the monitor is not as expected an error containing
* @ cmderr is returned . Otherwise @ response is put as - is on the monitor .
*
* Returns 0 when command was successfully added , - 1 on error .
*/
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddItemVerbatim ( qemuMonitorTest * test ,
2016-11-25 12:43:23 +03:00
const char * command ,
const char * cmderr ,
const char * response )
{
struct qemuMonitorTestHandlerData * data ;
2020-09-23 01:42:45 +03:00
data = g_new0 ( struct qemuMonitorTestHandlerData , 1 ) ;
2016-11-25 12:43:23 +03:00
2019-10-20 14:49:46 +03:00
data - > response = g_strdup ( response ) ;
data - > cmderr = g_strdup ( cmderr ) ;
2016-11-25 12:43:23 +03:00
2019-06-15 13:09:41 +03:00
data - > command_name = virJSONStringReformat ( command , false ) ;
2016-11-25 12:43:23 +03:00
if ( ! data - > command_name )
goto error ;
return qemuMonitorTestAddHandler ( test ,
2020-04-23 17:52:12 +03:00
command ,
2016-11-25 12:43:23 +03:00
qemuMonitorTestProcessCommandVerbatim ,
data , qemuMonitorTestHandlerDataFree ) ;
error :
qemuMonitorTestHandlerDataFree ( data ) ;
return - 1 ;
}
2013-07-25 14:08:25 +04:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessGuestAgentSync ( qemuMonitorTest * test ,
qemuMonitorTestItem * item G_GNUC_UNUSED ,
2013-07-25 14:08:25 +04:00
const char * cmdstr )
{
2020-07-28 22:58:18 +03:00
g_autoptr ( virJSONValue ) val = NULL ;
2021-03-11 10:16:13 +03:00
virJSONValue * args ;
2013-07-25 14:08:25 +04:00
unsigned long long id ;
const char * cmdname ;
2020-07-28 22:57:28 +03:00
g_autofree char * retmsg = NULL ;
2013-07-25 14:08:25 +04:00
if ( ! ( val = virJSONValueFromString ( cmdstr ) ) )
return - 1 ;
2021-09-04 23:38:39 +03:00
if ( ! ( cmdname = virJSONValueObjectGetString ( val , " execute " ) ) )
return qemuMonitorTestAddErrorResponse ( test , " Missing guest-sync command name " ) ;
2013-07-25 14:08:25 +04:00
2021-09-04 23:38:39 +03:00
if ( STRNEQ ( cmdname , " guest-sync " ) )
return qemuMonitorTestAddInvalidCommandResponse ( test , " guest-sync " , cmdname ) ;
2013-07-25 14:08:25 +04:00
2021-09-04 23:38:39 +03:00
if ( ! ( args = virJSONValueObjectGet ( val , " arguments " ) ) )
return qemuMonitorTestAddErrorResponse ( test , " Missing arguments for guest-sync " ) ;
2013-07-25 14:08:25 +04:00
2021-09-04 23:38:39 +03:00
if ( virJSONValueObjectGetNumberUlong ( args , " id " , & id ) )
return qemuMonitorTestAddErrorResponse ( test , " Missing id for guest sync " ) ;
2013-07-25 14:08:25 +04:00
2019-10-22 16:26:14 +03:00
retmsg = g_strdup_printf ( " { \" return \" :%llu} " , id ) ;
2013-07-25 14:08:25 +04:00
2021-09-04 23:38:39 +03:00
return qemuMonitorTestAddResponse ( test , retmsg ) ;
2013-07-25 14:08:25 +04:00
}
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddAgentSyncResponse ( qemuMonitorTest * test )
2013-07-25 14:08:25 +04:00
{
if ( ! test - > agent ) {
virReportError ( VIR_ERR_INTERNAL_ERROR , " %s " ,
" This test is not an agent test " ) ;
return - 1 ;
}
return qemuMonitorTestAddHandler ( test ,
2020-04-23 17:52:12 +03:00
" agent-sync " ,
2013-07-25 14:08:25 +04:00
qemuMonitorTestProcessGuestAgentSync ,
NULL , NULL ) ;
}
2013-07-25 17:42:38 +04:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommandWithArgs ( qemuMonitorTest * test ,
qemuMonitorTestItem * item ,
2013-07-25 17:42:38 +04:00
const char * cmdstr )
{
struct qemuMonitorTestHandlerData * data = item - > opaque ;
2020-07-28 22:58:18 +03:00
g_autoptr ( virJSONValue ) val = NULL ;
2021-03-11 10:16:13 +03:00
virJSONValue * args ;
virJSONValue * argobj ;
2013-07-25 17:42:38 +04:00
const char * cmdname ;
size_t i ;
if ( ! ( val = virJSONValueFromString ( cmdstr ) ) )
return - 1 ;
if ( ! ( cmdname = virJSONValueObjectGetString ( val , " execute " ) ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Missing command name in %s " , cmdstr ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
}
2013-09-19 17:19:08 +04:00
if ( data - > command_name & &
STRNEQ ( data - > command_name , cmdname ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestErrorInvalidCommand ( data - > command_name , cmdname ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
}
if ( ! ( args = virJSONValueObjectGet ( val , " arguments " ) ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Missing arguments section for command '%s' " ,
NULLSTR ( data - > command_name ) ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
}
/* validate the args */
for ( i = 0 ; i < data - > nargs ; i + + ) {
2021-03-11 10:16:13 +03:00
qemuMonitorTestCommandArgs * arg = & data - > args [ i ] ;
2020-07-28 23:01:22 +03:00
g_autofree char * argstr = NULL ;
2013-07-25 17:42:38 +04:00
if ( ! ( argobj = virJSONValueObjectGet ( args , arg - > argname ) ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Missing argument '%s' for command '%s' " ,
arg - > argname ,
NULLSTR ( data - > command_name ) ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
}
/* convert the argument to string */
if ( ! ( argstr = virJSONValueToString ( argobj , false ) ) )
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
/* verify that the argument value is expected */
if ( STRNEQ ( argstr , arg - > argval ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Invalid value of argument '%s' of command '%s': "
" expected '%s' got '%s' " ,
arg - > argname ,
NULLSTR ( data - > command_name ) ,
arg - > argval , argstr ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2013-07-25 17:42:38 +04:00
}
}
/* arguments checked out, return the response */
2020-07-29 00:17:02 +03:00
return qemuMonitorTestAddResponse ( test , data - > response ) ;
2013-07-25 17:42:38 +04:00
}
2016-09-27 18:11:55 +03:00
2013-07-25 17:42:38 +04:00
/* this allows to add a responder that is able to check
* a ( shallow ) structure of arguments for a command */
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddItemParams ( qemuMonitorTest * test ,
2013-07-25 17:42:38 +04:00
const char * cmdname ,
const char * response ,
. . . )
{
struct qemuMonitorTestHandlerData * data ;
const char * argname ;
const char * argval ;
va_list args ;
va_start ( args , response ) ;
2020-09-23 01:42:45 +03:00
data = g_new0 ( struct qemuMonitorTestHandlerData , 1 ) ;
2013-07-25 17:42:38 +04:00
2019-10-20 14:49:46 +03:00
data - > command_name = g_strdup ( cmdname ) ;
data - > response = g_strdup ( response ) ;
2013-07-25 17:42:38 +04:00
while ( ( argname = va_arg ( args , char * ) ) ) {
size_t i ;
if ( ! ( argval = va_arg ( args , char * ) ) ) {
virReportError ( VIR_ERR_INTERNAL_ERROR ,
" Missing argument value for argument '%s' " ,
argname ) ;
goto error ;
}
i = data - > nargs ;
2021-03-20 02:37:03 +03:00
VIR_EXPAND_N ( data - > args , data - > nargs , 1 ) ;
2019-10-20 14:49:46 +03:00
data - > args [ i ] . argname = g_strdup ( argname ) ;
data - > args [ i ] . argval = g_strdup ( argval ) ;
2013-07-25 17:42:38 +04:00
}
va_end ( args ) ;
return qemuMonitorTestAddHandler ( test ,
2020-04-23 17:52:12 +03:00
cmdname ,
2013-07-25 17:42:38 +04:00
qemuMonitorTestProcessCommandWithArgs ,
data , qemuMonitorTestHandlerDataFree ) ;
2014-03-25 10:53:44 +04:00
error :
2013-07-25 17:42:38 +04:00
va_end ( args ) ;
qemuMonitorTestHandlerDataFree ( data ) ;
return - 1 ;
}
2016-09-27 18:11:55 +03:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestProcessCommandWithArgStr ( qemuMonitorTest * test ,
qemuMonitorTestItem * item ,
2016-09-27 18:11:55 +03:00
const char * cmdstr )
{
struct qemuMonitorTestHandlerData * data = item - > opaque ;
2020-07-28 22:58:18 +03:00
g_autoptr ( virJSONValue ) val = NULL ;
2021-03-11 10:16:13 +03:00
virJSONValue * args ;
2020-07-28 22:57:28 +03:00
g_autofree char * argstr = NULL ;
2016-09-27 18:11:55 +03:00
const char * cmdname ;
if ( ! ( val = virJSONValueFromString ( cmdstr ) ) )
return - 1 ;
if ( ! ( cmdname = virJSONValueObjectGetString ( val , " execute " ) ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Missing command name in %s " , cmdstr ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2016-09-27 18:11:55 +03:00
}
if ( STRNEQ ( data - > command_name , cmdname ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestErrorInvalidCommand ( data - > command_name , cmdname ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2016-09-27 18:11:55 +03:00
}
if ( ! ( args = virJSONValueObjectGet ( val , " arguments " ) ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " Missing arguments section for command '%s' " ,
data - > command_name ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2016-09-27 18:11:55 +03:00
}
/* convert the arguments to string */
if ( ! ( argstr = virJSONValueToString ( args , false ) ) )
2020-07-29 00:17:02 +03:00
return - 1 ;
2016-09-27 18:11:55 +03:00
/* verify that the argument value is expected */
if ( STRNEQ ( argstr , data - > expectArgs ) ) {
2020-04-23 12:57:14 +03:00
qemuMonitorTestError ( " %s: expected arguments: '%s', got: '%s' " ,
data - > command_name ,
data - > expectArgs , argstr ) ;
2020-07-29 00:17:02 +03:00
return - 1 ;
2016-09-27 18:11:55 +03:00
}
/* arguments checked out, return the response */
2020-07-29 00:17:02 +03:00
return qemuMonitorTestAddResponse ( test , data - > response ) ;
2016-09-27 18:11:55 +03:00
}
/**
* qemuMonitorTestAddItemExpect :
*
* @ test : test monitor object
* @ cmdname : command name
* @ cmdargs : expected arguments of the command
* @ apostrophe : convert apostrophes ( ' ) in @ cmdargs to quotes ( " )
* @ response : simulated response of the command
*
* Simulates a qemu monitor command . Checks that the ' arguments ' of the qmp
* command are expected . If @ apostrophe is true apostrophes are converted to
* quotes for simplification of writing the strings into code .
*/
int
2021-03-11 10:16:13 +03:00
qemuMonitorTestAddItemExpect ( qemuMonitorTest * test ,
2016-09-27 18:11:55 +03:00
const char * cmdname ,
const char * cmdargs ,
bool apostrophe ,
const char * response )
{
struct qemuMonitorTestHandlerData * data ;
2020-09-23 01:42:45 +03:00
data = g_new0 ( struct qemuMonitorTestHandlerData , 1 ) ;
2016-09-27 18:11:55 +03:00
2019-10-20 14:49:46 +03:00
data - > command_name = g_strdup ( cmdname ) ;
data - > response = g_strdup ( response ) ;
data - > expectArgs = g_strdup ( cmdargs ) ;
2016-09-27 18:11:55 +03:00
if ( apostrophe ) {
char * tmp = data - > expectArgs ;
while ( * tmp ! = ' \0 ' ) {
if ( * tmp = = ' \' ' )
* tmp = ' " ' ;
tmp + + ;
}
}
return qemuMonitorTestAddHandler ( test ,
2020-04-23 17:52:12 +03:00
cmdname ,
2016-09-27 18:11:55 +03:00
qemuMonitorTestProcessCommandWithArgStr ,
data , qemuMonitorTestHandlerDataFree ) ;
}
2013-07-18 18:17:31 +04:00
static void
2021-03-11 10:16:13 +03:00
qemuMonitorTestEOFNotify ( qemuMonitor * mon G_GNUC_UNUSED ,
2022-05-24 16:02:58 +03:00
virDomainObj * vm G_GNUC_UNUSED )
2012-08-20 17:06:21 +04:00
{
}
2013-07-18 18:17:31 +04:00
static void
2021-03-11 10:16:13 +03:00
qemuMonitorTestErrorNotify ( qemuMonitor * mon G_GNUC_UNUSED ,
2022-05-24 16:02:58 +03:00
virDomainObj * vm G_GNUC_UNUSED )
2012-08-20 17:06:21 +04:00
{
}
2013-07-25 13:48:11 +04:00
static qemuMonitorCallbacks qemuMonitorTestCallbacks = {
2012-08-20 17:06:21 +04:00
. eofNotify = qemuMonitorTestEOFNotify ,
. errorNotify = qemuMonitorTestErrorNotify ,
2013-07-26 16:22:10 +04:00
. domainDeviceDeleted = qemuProcessHandleDeviceDeleted ,
2012-08-20 17:06:21 +04:00
} ;
2013-07-18 18:17:31 +04:00
2013-07-25 14:08:25 +04:00
static void
2021-03-11 10:16:13 +03:00
qemuMonitorTestAgentNotify ( qemuAgent * agent G_GNUC_UNUSED ,
virDomainObj * vm G_GNUC_UNUSED )
2013-07-25 14:08:25 +04:00
{
}
static qemuAgentCallbacks qemuMonitorTestAgentCallbacks = {
. eofNotify = qemuMonitorTestAgentNotify ,
. errorNotify = qemuMonitorTestAgentNotify ,
} ;
2021-03-11 10:16:13 +03:00
static qemuMonitorTest *
qemuMonitorCommonTestNew ( virDomainXMLOption * xmlopt ,
virDomainObj * vm ,
virDomainChrSourceDef * src )
2012-08-20 17:06:21 +04:00
{
2021-11-01 11:51:01 +03:00
g_autoptr ( qemuMonitorTest ) test = NULL ;
2021-11-01 12:33:49 +03:00
g_autofree char * path = NULL ;
g_autofree char * tmpdir_template = NULL ;
2012-08-20 17:06:21 +04:00
2020-09-23 01:42:45 +03:00
test = g_new0 ( qemuMonitorTest , 1 ) ;
2012-08-20 17:06:21 +04:00
if ( virMutexInit ( & test - > lock ) < 0 ) {
virReportError ( VIR_ERR_INTERNAL_ERROR , " %s " ,
" Cannot initialize mutex " ) ;
VIR_FREE ( test ) ;
return NULL ;
}
2019-10-20 14:49:46 +03:00
tmpdir_template = g_strdup ( " /tmp/libvirt_XXXXXX " ) ;
2012-11-12 18:33:55 +04:00
2019-11-14 00:35:47 +03:00
if ( ! ( test - > tmpdir = g_mkdtemp ( tmpdir_template ) ) ) {
2012-11-12 18:33:55 +04:00
virReportSystemError ( errno , " %s " ,
" Failed to create temporary directory " ) ;
2021-11-01 12:20:57 +03:00
return NULL ;
2012-11-12 18:33:55 +04:00
}
tmpdir_template = NULL ;
2019-10-22 16:26:14 +03:00
path = g_strdup_printf ( " %s/qemumonitorjsontest.sock " , test - > tmpdir ) ;
2012-11-12 18:33:55 +04:00
2013-07-25 21:17:44 +04:00
if ( vm ) {
2017-04-03 11:24:39 +03:00
test - > vm = virObjectRef ( vm ) ;
2013-07-25 21:17:44 +04:00
} else {
test - > vm = virDomainObjNew ( xmlopt ) ;
if ( ! test - > vm )
2021-11-01 12:20:57 +03:00
return NULL ;
2021-08-03 12:00:48 +03:00
if ( ! ( test - > vm - > def = virDomainDefNew ( xmlopt ) ) )
2021-11-01 12:20:57 +03:00
return NULL ;
2013-07-25 21:17:44 +04:00
}
2012-08-20 17:06:21 +04:00
2013-10-09 15:13:45 +04:00
if ( virNetSocketNewListenUNIX ( path , 0700 , geteuid ( ) , getegid ( ) ,
2012-08-20 17:06:21 +04:00
& test - > server ) < 0 )
2021-11-01 12:20:57 +03:00
return NULL ;
2012-08-20 17:06:21 +04:00
2013-07-22 18:59:22 +04:00
memset ( src , 0 , sizeof ( * src ) ) ;
src - > type = VIR_DOMAIN_CHR_TYPE_UNIX ;
src - > data . nix . path = ( char * ) path ;
src - > data . nix . listen = false ;
2013-09-25 18:28:55 +04:00
path = NULL ;
2012-08-20 17:06:21 +04:00
if ( virNetSocketListen ( test - > server , 1 ) < 0 )
2021-11-01 12:20:57 +03:00
return NULL ;
2012-08-20 17:06:21 +04:00
2021-11-01 11:51:01 +03:00
return g_steal_pointer ( & test ) ;
2013-07-22 18:59:22 +04:00
}
static int
2021-03-11 10:16:13 +03:00
qemuMonitorCommonTestInit ( qemuMonitorTest * test )
2013-07-22 18:59:22 +04:00
{
2013-07-25 13:48:11 +04:00
int events = VIR_EVENT_HANDLE_READABLE ;
2013-07-22 18:59:22 +04:00
if ( ! test )
return - 1 ;
2012-08-20 17:06:21 +04:00
if ( virNetSocketAccept ( test - > server , & test - > client ) < 0 )
2020-01-07 00:57:49 +03:00
return - 1 ;
2012-08-20 17:06:21 +04:00
2013-07-22 18:59:22 +04:00
if ( ! test - > client )
2020-01-07 00:57:49 +03:00
return - 1 ;
2012-09-06 19:14:25 +04:00
2013-07-25 13:48:11 +04:00
if ( test - > outgoingLength > 0 )
events = VIR_EVENT_HANDLE_WRITABLE ;
2012-08-20 17:06:21 +04:00
if ( virNetSocketAddIOCallback ( test - > client ,
2013-07-25 13:48:11 +04:00
events ,
2012-08-20 17:06:21 +04:00
qemuMonitorTestIO ,
test ,
NULL ) < 0 )
2020-01-07 00:57:49 +03:00
return - 1 ;
2012-08-20 17:06:21 +04:00
2022-02-08 17:31:35 +03:00
VIR_WITH_MUTEX_LOCK_GUARD ( & test - > lock ) {
if ( virThreadCreate ( & test - > thread , true , qemuMonitorTestWorker , test ) < 0 )
return - 1 ;
test - > started = test - > running = true ;
2012-08-20 17:06:21 +04:00
}
2013-07-22 18:59:22 +04:00
return 0 ;
}
# define QEMU_JSON_GREETING "{\"QMP\":"\
" { \" version \" : " \
" { \" qemu \" : " \
" { \" micro \" : 1, " \
" \" minor \" : 0, " \
" \" major \" : 1 " \
" }, " \
" \" package \" : \" (qemu-kvm-1.0.1) " \
" \" }, " \
" \" capabilities \" : [] " \
" } " \
" } "
/* We skip the normal handshake reply of "{\"execute\":\"qmp_capabilities\"}" */
2020-02-12 17:56:29 +03:00
2021-03-11 10:16:13 +03:00
qemuMonitorTest *
qemuMonitorTestNew ( virDomainXMLOption * xmlopt ,
virDomainObj * vm ,
2018-03-22 21:05:26 +03:00
const char * greeting ,
2020-10-22 20:04:18 +03:00
GHashTable * schema )
2013-07-22 18:59:22 +04:00
{
2021-11-01 11:51:01 +03:00
g_autoptr ( qemuMonitorTest ) test = NULL ;
2013-07-22 18:59:22 +04:00
virDomainChrSourceDef src ;
2013-09-25 18:30:27 +04:00
memset ( & src , 0 , sizeof ( src ) ) ;
2013-07-25 21:17:44 +04:00
if ( ! ( test = qemuMonitorCommonTestNew ( xmlopt , vm , & src ) ) )
2013-07-22 18:59:22 +04:00
goto error ;
2020-02-12 17:56:29 +03:00
if ( ! ( test - > eventThread = virEventThreadNew ( " mon-test " ) ) )
goto error ;
2018-03-22 21:05:26 +03:00
test - > qapischema = schema ;
2013-07-22 18:59:22 +04:00
if ( ! ( test - > mon = qemuMonitorOpen ( test - > vm ,
& src ,
2020-02-12 17:54:19 +03:00
virEventThreadGetContext ( test - > eventThread ) ,
2022-05-24 16:02:58 +03:00
& qemuMonitorTestCallbacks ) ) )
2013-07-22 18:59:22 +04:00
goto error ;
virObjectLock ( test - > mon ) ;
2013-09-19 15:56:30 +04:00
if ( ! greeting )
2019-06-14 21:14:23 +03:00
greeting = QEMU_JSON_GREETING ;
2013-09-19 15:56:30 +04:00
2016-06-07 14:46:01 +03:00
if ( qemuMonitorTestAddResponse ( test , greeting ) < 0 )
2013-07-22 18:59:22 +04:00
goto error ;
if ( qemuMonitorCommonTestInit ( test ) < 0 )
goto error ;
virDomainChrSourceDefClear ( & src ) ;
2021-11-01 11:51:01 +03:00
return g_steal_pointer ( & test ) ;
2012-08-20 17:06:21 +04:00
2014-03-25 10:53:44 +04:00
error :
2013-07-25 14:08:25 +04:00
virDomainChrSourceDefClear ( & src ) ;
return NULL ;
}
2016-06-06 14:46:41 +03:00
2016-11-30 11:58:12 +03:00
/**
* qemuMonitorTestNewFromFile :
* @ fileName : File name to load monitor replies from
* @ xmlopt : XML parser configuration object
* @ simple : see below
*
* Create a JSON test monitor simulator object and fill it with replies
* specified in @ fileName . The file contains JSON reply objects separated by
* empty lines . If @ simple is true a generic QMP greeting is automatically
* added as the first reply , otherwise the first entry in the file is used .
*
* Returns the monitor object on success ; NULL on error .
*/
2021-03-11 10:16:13 +03:00
qemuMonitorTest *
2016-06-06 14:46:41 +03:00
qemuMonitorTestNewFromFile ( const char * fileName ,
2021-03-11 10:16:13 +03:00
virDomainXMLOption * xmlopt ,
2016-06-06 17:55:05 +03:00
bool simple )
2016-06-06 14:46:41 +03:00
{
2021-11-01 11:51:01 +03:00
g_autoptr ( qemuMonitorTest ) test = NULL ;
2020-07-28 22:57:28 +03:00
g_autofree char * json = NULL ;
2016-06-06 14:46:41 +03:00
char * tmp ;
char * singleReply ;
if ( virTestLoadFile ( fileName , & json ) < 0 )
2021-09-04 23:38:39 +03:00
return NULL ;
2016-06-06 14:46:41 +03:00
2019-06-14 21:10:15 +03:00
if ( simple & & ! ( test = qemuMonitorTestNewSimple ( xmlopt ) ) )
2021-09-04 23:38:39 +03:00
return NULL ;
2016-06-06 17:55:05 +03:00
2016-06-06 14:46:41 +03:00
/* Our JSON parser expects replies to be separated by a newline character.
* Hence we must preprocess the file a bit . */
tmp = singleReply = json ;
while ( ( tmp = strchr ( tmp , ' \n ' ) ) ) {
/* It is safe to touch tmp[1] since all strings ends with '\0'. */
bool eof = ! tmp [ 1 ] ;
if ( * ( tmp + 1 ) ! = ' \n ' ) {
* tmp = ' ' ;
tmp + + ;
} else {
/* Cut off a single reply. */
* ( tmp + 1 ) = ' \0 ' ;
if ( test ) {
if ( qemuMonitorTestAddItem ( test , NULL , singleReply ) < 0 )
2021-11-01 12:20:57 +03:00
return NULL ;
2016-06-06 14:46:41 +03:00
} else {
/* Create new mocked monitor with our greeting */
2022-05-24 16:02:58 +03:00
if ( ! ( test = qemuMonitorTestNew ( xmlopt , NULL ,
2018-03-22 21:05:26 +03:00
singleReply , NULL ) ) )
2021-11-01 12:20:57 +03:00
return NULL ;
2016-06-06 14:46:41 +03:00
}
if ( ! eof ) {
/* Move the @tmp and @singleReply. */
tmp + = 2 ;
singleReply = tmp ;
}
}
if ( eof )
break ;
}
if ( test & & qemuMonitorTestAddItem ( test , NULL , singleReply ) < 0 )
2021-11-01 12:20:57 +03:00
return NULL ;
2016-06-06 14:46:41 +03:00
2021-11-01 11:51:01 +03:00
return g_steal_pointer ( & test ) ;
2016-06-06 14:46:41 +03:00
}
2020-04-23 17:57:31 +03:00
/**
* qemuMonitorTestAllowUnusedCommands :
* @ test : test monitor object
*
* By default all test items / commands must be used by the test . This function
* allows to override the requirement for individual tests e . g . if it ' s necessary
* to test some negative scenarios which would not use all commands .
*/
void
2021-03-11 10:16:13 +03:00
qemuMonitorTestAllowUnusedCommands ( qemuMonitorTest * test )
2020-04-23 17:57:31 +03:00
{
test - > allowUnusedCommands = true ;
}
2020-04-29 12:03:02 +03:00
/**
* qemuMonitorTestSkipDeprecatedValidation :
* @ test : test monitor object
* @ allowRemoved : don ' t produce errors if command was removed from QMP schema
*
* By default if the QMP schema is provided all test items / commands are
* validated against the schema . This function allows to override the validation
* and additionally if @ allowRemoved is true and if such a command is no longer
* present in the QMP , only a warning is printed .
*
* ' @ allowRemoved ' must be used only if a suitable replacement is already in
* use and the code tests legacy interactions .
*
* Note that currently ' @ allowRemoved ' influences only removed commands . If an
* argument is removed it will still fail validation .
*/
void
2021-03-11 10:16:13 +03:00
qemuMonitorTestSkipDeprecatedValidation ( qemuMonitorTest * test ,
2020-04-29 12:03:02 +03:00
bool allowRemoved )
{
test - > skipValidationDeprecated = true ;
test - > skipValidationRemoved = allowRemoved ;
}
2016-11-30 16:43:50 +03:00
static int
2021-03-11 10:16:13 +03:00
qemuMonitorTestFullAddItem ( qemuMonitorTest * test ,
2016-11-30 16:43:50 +03:00
const char * filename ,
const char * command ,
const char * response ,
size_t line )
{
2020-07-28 22:57:28 +03:00
g_autofree char * cmderr = NULL ;
2016-11-30 16:43:50 +03:00
2019-10-22 16:26:14 +03:00
cmderr = g_strdup_printf ( " wrong expected command in %s:%zu: " , filename , line ) ;
2016-11-30 16:43:50 +03:00
2021-10-22 11:56:01 +03:00
return qemuMonitorTestAddItemVerbatim ( test , command , cmderr , response ) ;
2016-11-30 16:43:50 +03:00
}
/**
2021-12-21 16:51:26 +03:00
* qemuMonitorTestProcessFileEntries :
* @ inputstr : input file contents ( modified )
* @ fileName : File name of @ inputstr ( for error reporting )
* @ items : filled with command , reply tuples
* @ nitems : Count of elements in @ items .
2016-11-30 16:43:50 +03:00
*
2021-12-21 16:51:26 +03:00
* Process a monitor interaction file .
2016-11-30 16:43:50 +03:00
*
* The file contains a sequence of JSON commands and reply objects separated by
2021-12-21 16:51:26 +03:00
* empty lines . A command is followed by a reply .
2016-11-30 16:43:50 +03:00
*/
2021-12-21 16:51:26 +03:00
int
qemuMonitorTestProcessFileEntries ( char * inputstr ,
const char * fileName ,
struct qemuMonitorTestCommandReplyTuple * * items ,
size_t * nitems )
2016-11-30 16:43:50 +03:00
{
2021-12-21 16:51:26 +03:00
size_t nalloc = 0 ;
char * tmp = inputstr ;
2016-11-30 16:43:50 +03:00
size_t line = 0 ;
2021-12-21 16:51:26 +03:00
char * command = inputstr ;
2016-11-30 16:43:50 +03:00
char * response = NULL ;
size_t commandln = 0 ;
2021-12-21 16:51:26 +03:00
* items = NULL ;
* nitems = 0 ;
2016-11-30 16:43:50 +03:00
while ( ( tmp = strchr ( tmp , ' \n ' ) ) ) {
line + + ;
2018-05-03 12:38:23 +03:00
/* eof */
if ( ! tmp [ 1 ] )
break ;
2018-05-03 12:43:34 +03:00
/* concatenate block which was broken up for readability */
2016-11-30 16:43:50 +03:00
if ( * ( tmp + 1 ) ! = ' \n ' ) {
* tmp = ' ' ;
tmp + + ;
2018-05-03 12:43:34 +03:00
continue ;
}
2016-11-30 16:43:50 +03:00
2022-12-21 13:08:02 +03:00
/* We've seen a new line, increment the counter */
line + + ;
2018-05-03 12:43:34 +03:00
/* Cut off a single reply. */
* ( tmp + 1 ) = ' \0 ' ;
2016-11-30 16:43:50 +03:00
2018-05-03 12:43:34 +03:00
if ( response ) {
2021-12-21 16:51:26 +03:00
struct qemuMonitorTestCommandReplyTuple * item ;
VIR_RESIZE_N ( * items , nalloc , * nitems , 1 ) ;
item = * items + * nitems ;
item - > command = g_steal_pointer ( & command ) ;
item - > reply = g_steal_pointer ( & response ) ;
item - > line = commandln ;
( * nitems ) + + ;
2018-05-03 12:43:34 +03:00
}
2016-11-30 16:43:50 +03:00
2018-05-03 12:43:34 +03:00
/* Move the @tmp and @singleReply. */
tmp + = 2 ;
if ( ! command ) {
commandln = line ;
command = tmp ;
} else {
response = tmp ;
2016-11-30 16:43:50 +03:00
}
}
if ( command ) {
2021-12-21 16:51:26 +03:00
struct qemuMonitorTestCommandReplyTuple * item ;
2016-11-30 16:43:50 +03:00
if ( ! response ) {
virReportError ( VIR_ERR_INTERNAL_ERROR , " missing response for command "
" on line '%zu' in '%s' " , commandln , fileName ) ;
2021-12-21 16:51:26 +03:00
return - 1 ;
2016-11-30 16:43:50 +03:00
}
2021-12-21 16:51:26 +03:00
VIR_RESIZE_N ( * items , nalloc , * nitems , 1 ) ;
item = * items + * nitems ;
item - > command = g_steal_pointer ( & command ) ;
item - > reply = g_steal_pointer ( & response ) ;
item - > line = commandln ;
( * nitems ) + + ;
}
return 0 ;
}
/**
* qemuMonitorTestNewFromFileFull :
* @ fileName : File name to load monitor replies from
* @ driver : qemu driver object
* @ vm : domain object ( may be null if it ' s not needed by the test )
* @ qmpschema : QMP schema data hash table if QMP checking is required
*
* Create a JSON test monitor simulator object and fill it with expected command
* sequence and replies specified in @ fileName .
*
* The file contains a sequence of JSON commands and reply objects separated by
* empty lines . A command is followed by a reply . The QMP greeting is added
* automatically .
*
* Returns the monitor object on success ; NULL on error .
*/
qemuMonitorTest *
qemuMonitorTestNewFromFileFull ( const char * fileName ,
virQEMUDriver * driver ,
virDomainObj * vm ,
GHashTable * qmpschema )
{
g_autoptr ( qemuMonitorTest ) ret = NULL ;
g_autofree char * jsonstr = NULL ;
g_autofree struct qemuMonitorTestCommandReplyTuple * items = NULL ;
size_t nitems = 0 ;
size_t i ;
if ( virTestLoadFile ( fileName , & jsonstr ) < 0 )
return NULL ;
2022-05-24 16:02:58 +03:00
if ( ! ( ret = qemuMonitorTestNew ( driver - > xmlopt , vm , NULL , qmpschema ) ) )
2021-12-21 16:51:26 +03:00
return NULL ;
if ( qemuMonitorTestProcessFileEntries ( jsonstr , fileName , & items , & nitems ) < 0 )
return NULL ;
for ( i = 0 ; i < nitems ; i + + ) {
struct qemuMonitorTestCommandReplyTuple * item = items + i ;
if ( qemuMonitorTestFullAddItem ( ret , fileName , item - > command , item - > reply ,
item - > line ) < 0 )
2021-11-01 12:20:57 +03:00
return NULL ;
2016-11-30 16:43:50 +03:00
}
2021-11-01 11:51:01 +03:00
return g_steal_pointer ( & ret ) ;
2016-11-30 16:43:50 +03:00
}
2021-03-11 10:16:13 +03:00
qemuMonitorTest *
qemuMonitorTestNewAgent ( virDomainXMLOption * xmlopt )
2013-07-25 14:08:25 +04:00
{
2021-11-01 11:51:01 +03:00
g_autoptr ( qemuMonitorTest ) test = NULL ;
2013-07-25 14:08:25 +04:00
virDomainChrSourceDef src ;
2013-09-25 18:30:27 +04:00
memset ( & src , 0 , sizeof ( src ) ) ;
2013-07-25 21:17:44 +04:00
if ( ! ( test = qemuMonitorCommonTestNew ( xmlopt , NULL , & src ) ) )
2013-07-25 14:08:25 +04:00
goto error ;
2020-02-12 17:56:29 +03:00
if ( ! ( test - > eventThread = virEventThreadNew ( " agent-test " ) ) )
goto error ;
2013-07-25 14:08:25 +04:00
if ( ! ( test - > agent = qemuAgentOpen ( test - > vm ,
& src ,
2020-02-12 17:54:19 +03:00
virEventThreadGetContext ( test - > eventThread ) ,
2022-11-07 15:16:04 +03:00
& qemuMonitorTestAgentCallbacks ) ) )
2013-07-25 14:08:25 +04:00
goto error ;
virObjectLock ( test - > agent ) ;
if ( qemuMonitorCommonTestInit ( test ) < 0 )
goto error ;
virDomainChrSourceDefClear ( & src ) ;
2021-11-01 11:51:01 +03:00
return g_steal_pointer ( & test ) ;
2013-07-25 14:08:25 +04:00
2014-03-25 10:53:44 +04:00
error :
2013-07-25 14:08:25 +04:00
virDomainChrSourceDefClear ( & src ) ;
2013-07-22 18:59:22 +04:00
return NULL ;
2012-08-20 17:06:21 +04:00
}
2013-07-18 18:17:31 +04:00
2021-03-11 10:16:13 +03:00
qemuMonitor *
qemuMonitorTestGetMonitor ( qemuMonitorTest * test )
2012-08-20 17:06:21 +04:00
{
return test - > mon ;
}
2013-07-25 14:08:25 +04:00
2021-03-11 10:16:13 +03:00
qemuAgent *
qemuMonitorTestGetAgent ( qemuMonitorTest * test )
2013-07-25 14:08:25 +04:00
{
return test - > agent ;
}
2018-04-04 17:45:04 +03:00
2021-03-11 10:16:13 +03:00
virDomainObj *
qemuMonitorTestGetDomainObj ( qemuMonitorTest * test )
2018-04-04 17:45:04 +03:00
{
return test - > vm ;
}