2022-08-20 01:21:52 +03:00
# include <config.h>
# include <fcntl.h>
# include "internal.h"
# include "testutils.h"
# include "testutilsqemu.h"
# include "qemu/qemu_domain.h"
# include "qemu/qemu_nbdkit.h"
# define LIBVIRT_QEMU_NBDKITPRIV_H_ALLOW
# include "qemu/qemu_nbdkitpriv.h"
# include "vircommand.h"
# define LIBVIRT_VIRCOMMANDPRIV_H_ALLOW
# include "vircommandpriv.h"
# include "virutil.h"
# include "virsecret.h"
# include "datatypes.h"
# include "virmock.h"
# define VIR_FROM_THIS VIR_FROM_QEMU
static virQEMUDriver driver ;
/* Some mock implementations for testing */
# define PIPE_FD_START 777
static int mockpipefd = PIPE_FD_START ;
static int ( * real_virPipeQuiet ) ( int fds [ 2 ] ) ;
static void
init_syms ( void )
{
VIR_MOCK_REAL_INIT ( virPipeQuiet ) ;
}
static int
moveToStableFd ( int fd )
{
int newfd ;
/* don't overwrite an existing fd */
if ( fcntl ( mockpipefd , F_GETFD ) ! = - 1 )
abort ( ) ;
newfd = dup2 ( fd , mockpipefd + + ) ;
VIR_FORCE_CLOSE ( fd ) ;
return newfd ;
}
int
virPipeQuiet ( int fds [ 2 ] )
{
int tempfds [ 2 ] ;
init_syms ( ) ;
if ( real_virPipeQuiet ( tempfds ) < 0 )
return - 1 ;
if ( ( fds [ 0 ] = moveToStableFd ( tempfds [ 0 ] ) ) < 0 | |
( fds [ 1 ] = moveToStableFd ( tempfds [ 1 ] ) ) < 0 )
return - 1 ;
return 0 ;
}
int
virSecretGetSecretString ( virConnectPtr conn G_GNUC_UNUSED ,
virSecretLookupTypeDef * seclookupdef ,
virSecretUsageType secretUsageType ,
uint8_t * * secret ,
size_t * secret_size )
{
char uuidstr [ VIR_UUID_BUFLEN ] ;
const char * secretname = NULL ;
char * tmp = NULL ;
switch ( seclookupdef - > type ) {
case VIR_SECRET_LOOKUP_TYPE_UUID :
virUUIDFormat ( seclookupdef - > u . uuid , uuidstr ) ;
secretname = uuidstr ;
break ;
case VIR_SECRET_LOOKUP_TYPE_USAGE :
secretname = seclookupdef - > u . usage ;
break ;
case VIR_SECRET_LOOKUP_TYPE_NONE :
case VIR_SECRET_LOOKUP_TYPE_LAST :
default :
virReportEnumRangeError ( virSecretLookupType , seclookupdef - > type ) ;
return - 1 ;
} ;
/* For testing, just generate a value for the secret that includes the type
* and the id of the secret */
tmp = g_strdup_printf ( " %s-%s-secret " , virSecretUsageTypeToString ( secretUsageType ) , secretname ) ;
* secret = ( uint8_t * ) tmp ;
* secret_size = strlen ( tmp ) + 1 ;
return 0 ;
}
virConnectPtr virGetConnectSecret ( void )
{
return virGetConnect ( ) ;
}
/* end of mock implementations */
typedef struct {
const char * name ;
char * infile ;
char * outtemplate ;
qemuNbdkitCaps * nbdkitcaps ;
bool expectFail ;
} TestInfo ;
typedef enum {
NBDKIT_ARG_CAPS ,
NBDKIT_ARG_EXPECT_FAIL ,
NBDKIT_ARG_END
} NbdkitArgName ;
static void
testInfoSetPaths ( TestInfo * info )
{
2024-01-22 15:18:56 +03:00
info - > infile = g_strdup_printf ( " %s/qemuxmlconfdata/%s.xml " ,
2022-08-20 01:21:52 +03:00
abs_srcdir , info - > name ) ;
info - > outtemplate = g_strdup_printf ( " %s/qemunbdkitdata/%s " ,
abs_srcdir , info - > name ) ;
}
static void
testInfoClear ( TestInfo * info )
{
g_free ( info - > infile ) ;
g_free ( info - > outtemplate ) ;
g_clear_object ( & info - > nbdkitcaps ) ;
}
static void
testInfoSetArgs ( TestInfo * info , . . . )
{
va_list argptr ;
NbdkitArgName argname ;
unsigned int cap ;
va_start ( argptr , info ) ;
while ( ( argname = va_arg ( argptr , NbdkitArgName ) ) ! = NBDKIT_ARG_END ) {
switch ( argname ) {
case NBDKIT_ARG_CAPS :
while ( ( cap = va_arg ( argptr , unsigned int ) ) < QEMU_NBDKIT_CAPS_LAST )
qemuNbdkitCapsSet ( info - > nbdkitcaps , cap ) ;
break ;
case NBDKIT_ARG_EXPECT_FAIL :
info - > expectFail = va_arg ( argptr , unsigned int ) ;
break ;
case NBDKIT_ARG_END :
default :
break ;
}
}
}
static int
testNbdkit ( const void * data )
{
const TestInfo * info = data ;
g_autoptr ( virDomainDef ) def = NULL ;
size_t i ;
2024-01-26 19:41:58 +03:00
size_t n ;
2022-08-20 01:21:52 +03:00
int ret = 0 ;
2024-01-26 19:41:58 +03:00
virStorageSource * backing = NULL ;
g_autofree char * statedir = NULL ;
2022-08-20 01:21:52 +03:00
/* restart mock pipe fds so tests are consistent */
mockpipefd = PIPE_FD_START ;
if ( ! virFileExists ( info - > infile ) ) {
virReportError ( VIR_ERR_INTERNAL_ERROR ,
" Test input file '%s' is missing " , info - > infile ) ;
return - 1 ;
}
if ( ! ( def = virDomainDefParseFile ( info - > infile , driver . xmlopt , NULL ,
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE ) ) )
return - 1 ;
2024-01-26 19:41:58 +03:00
statedir = g_strdup_printf ( " /tmp/domain-%s " , def - > name ) ;
2022-08-20 01:21:52 +03:00
for ( i = 0 ; i < def - > ndisks ; i + + ) {
virDomainDiskDef * disk = def - > disks [ i ] ;
2024-01-26 19:41:58 +03:00
for ( n = 0 , backing = disk - > src ; backing ! = NULL ; n + + , backing = backing - > backingStore ) {
g_autofree char * alias = g_strdup_printf ( " disk%zi-src%zi " , i , n ) ;
g_autofree char * cmdfile = g_strdup_printf ( " %s.args.%s " ,
info - > outtemplate , alias ) ;
if ( qemuNbdkitInitStorageSource ( info - > nbdkitcaps , backing , statedir ,
alias , 101 , 101 ) ) {
qemuDomainStorageSourcePrivate * srcPriv =
qemuDomainStorageSourcePrivateFetch ( backing ) ;
g_autoptr ( virCommand ) cmd = NULL ;
g_autoptr ( virCommandDryRunToken ) dryRunToken = virCommandDryRunTokenNew ( ) ;
g_auto ( virBuffer ) buf = VIR_BUFFER_INITIALIZER ;
g_autofree char * actualCmdline = NULL ;
virCommandSendBuffer * sendbuffers ;
int nsendbuffers ;
size_t j ;
if ( srcPriv - > nbdkitProcess = = NULL )
continue ;
virCommandSetDryRun ( dryRunToken , & buf , true , true , NULL , NULL ) ;
cmd = qemuNbdkitProcessBuildCommand ( srcPriv - > nbdkitProcess ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
ret = - 1 ;
continue ;
}
virCommandPeekSendBuffers ( cmd , & sendbuffers , & nsendbuffers ) ;
2022-08-20 01:21:52 +03:00
2024-01-26 19:41:58 +03:00
if ( ! ( actualCmdline = virBufferContentAndReset ( & buf ) ) ) {
ret = - 1 ;
continue ;
}
2022-08-20 01:21:52 +03:00
2024-01-26 19:41:58 +03:00
if ( virTestCompareToFileFull ( actualCmdline , cmdfile , false ) < 0 )
ret = - 1 ;
2022-08-20 01:21:52 +03:00
2024-01-26 19:41:58 +03:00
for ( j = 0 ; j < nsendbuffers ; j + + ) {
virCommandSendBuffer * buffer = & sendbuffers [ j ] ;
g_autofree char * pipefile = g_strdup_printf ( " %s.pipe.%i " ,
cmdfile ,
buffer - > fd ) ;
if ( virTestCompareToFile ( ( const char * ) buffer - > buffer , pipefile ) < 0 )
ret = - 1 ;
}
} else {
if ( virFileExists ( cmdfile ) ) {
virReportError ( VIR_ERR_INTERNAL_ERROR , " %s " ,
" qemuNbdkitInitStorageSource() was not expected to fail " ) ;
2022-08-20 01:21:52 +03:00
ret = - 1 ;
2024-01-26 19:41:58 +03:00
}
2022-08-20 01:21:52 +03:00
}
}
}
if ( info - > expectFail ) {
if ( ret = = 0 ) {
ret = - 1 ;
VIR_TEST_DEBUG ( " Error expected but there wasn't any. " ) ;
} else {
ret = 0 ;
}
}
return ret ;
}
static int
mymain ( void )
{
g_autoptr ( GHashTable ) capslatest = testQemuGetLatestCaps ( ) ;
g_autoptr ( GHashTable ) capscache = virHashNew ( virObjectUnref ) ;
int ret = 0 ;
if ( qemuTestDriverInit ( & driver ) < 0 )
return EXIT_FAILURE ;
if ( testQemuInsertRealCaps ( driver . qemuCapsCache , " x86_64 " , " latest " , " " ,
capslatest , capscache , NULL , NULL ) < 0 ) {
ret = - 1 ;
goto cleanup ;
}
# define DO_TEST_FULL(_name, ...) \
do { \
TestInfo info = { \
. name = _name , \
. nbdkitcaps = qemuNbdkitCapsNew ( TEST_NBDKIT_PATH ) , \
} ; \
testInfoSetPaths ( & info ) ; \
testInfoSetArgs ( & info , __VA_ARGS__ ) ; \
virTestRunLog ( & ret , " nbdkit " _name , testNbdkit , & info ) ; \
testInfoClear ( & info ) ; \
} while ( 0 )
# define DO_TEST(_name, ...) \
DO_TEST_FULL ( _name , NBDKIT_ARG_CAPS , __VA_ARGS__ , QEMU_NBDKIT_CAPS_LAST , NBDKIT_ARG_END )
# define DO_TEST_FAILURE(_name, ...) \
DO_TEST_FULL ( _name , \
NBDKIT_ARG_EXPECT_FAIL , 1 , \
NBDKIT_ARG_CAPS , __VA_ARGS__ , QEMU_NBDKIT_CAPS_LAST , NBDKIT_ARG_END )
# define DO_TEST_NOCAPS(_name) \
DO_TEST_FULL ( _name , NBDKIT_ARG_END )
DO_TEST ( " disk-cdrom-network " , QEMU_NBDKIT_CAPS_PLUGIN_CURL ) ;
DO_TEST ( " disk-network-http " , QEMU_NBDKIT_CAPS_PLUGIN_CURL ) ;
DO_TEST ( " disk-network-source-curl-nbdkit-backing " , QEMU_NBDKIT_CAPS_PLUGIN_CURL ) ;
DO_TEST ( " disk-network-source-curl " , QEMU_NBDKIT_CAPS_PLUGIN_CURL ) ;
DO_TEST ( " disk-network-ssh " , QEMU_NBDKIT_CAPS_PLUGIN_SSH ) ;
2022-12-22 00:42:02 +03:00
DO_TEST ( " disk-network-ssh-password " , QEMU_NBDKIT_CAPS_PLUGIN_SSH ) ;
2022-12-23 01:56:47 +03:00
DO_TEST ( " disk-network-ssh-key " , QEMU_NBDKIT_CAPS_PLUGIN_SSH ) ;
2022-08-20 01:21:52 +03:00
cleanup :
qemuTestDriverFree ( & driver ) ;
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}
VIR_TEST_MAIN ( mymain )