2016-06-07 18:54:43 +02:00
/*
* Copyright ( C ) 2016 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>
# include "testutils.h"
# include "virlog.h"
# include "virxml.h"
# define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT ( " tests.schematest " ) ;
2020-10-07 10:26:56 +02:00
struct testSchemaEntry {
const char * dir ;
2020-10-06 17:25:52 +02:00
/* if dirRegex is non-NULL the provided regular expression is used to match
* the file names in a directory ( without path prefixed ) and only matching
* files are validated */
2023-12-15 21:47:17 +01:00
const char * * exceptions ; /* optional NULL terminated list of filenames inside
directory where the expected validation result is
inverted */
2024-08-08 09:14:11 +02:00
const char * * skip ; /* optional NULL terminated list of files to skip altogether */
2020-10-06 17:25:52 +02:00
const char * dirRegex ;
2020-10-07 10:26:56 +02:00
const char * file ;
} ;
2016-06-07 18:54:43 +02:00
struct testSchemaData {
2021-03-11 08:16:13 +01:00
virXMLValidator * validator ;
2023-12-15 21:47:17 +01:00
bool exception ;
2016-06-07 18:54:43 +02:00
const char * xml_path ;
} ;
static int
2020-10-07 10:26:56 +02:00
testSchemaValidateXML ( const void * args )
2016-06-07 18:54:43 +02:00
{
const struct testSchemaData * data = args ;
2023-08-15 14:20:58 +02:00
/* invalid XMLs have a '-invalid.' suffix, but not necessarily at the end
2023-12-16 20:12:05 +01:00
* of the file name e . g . in case of qemuxmlconftest with real capabilities */
2023-08-15 14:20:58 +02:00
bool shouldFail = ! ! strstr ( data - > xml_path , " -invalid. " ) ;
2020-10-07 10:26:56 +02:00
g_autoptr ( xmlDoc ) xml = NULL ;
2016-06-07 18:54:43 +02:00
2023-12-15 21:47:17 +01:00
if ( data - > exception )
shouldFail = ! shouldFail ;
2022-09-23 14:49:01 +02:00
if ( ! ( xml = virXMLParseFileCtxt ( data - > xml_path , NULL ) ) )
2016-06-07 18:54:43 +02:00
return - 1 ;
2020-10-07 10:26:56 +02:00
if ( ( virXMLValidatorValidate ( data - > validator , xml ) < 0 ) ! = shouldFail )
return - 1 ;
2016-06-07 18:54:43 +02:00
2020-10-07 10:26:56 +02:00
return 0 ;
}
static int
testSchemaFile ( const char * schema ,
2021-03-11 08:16:13 +01:00
virXMLValidator * validator ,
2023-12-15 21:47:17 +01:00
const char * path ,
bool exception )
2020-10-07 10:26:56 +02:00
{
g_autofree char * test_name = NULL ;
struct testSchemaData data = {
. validator = validator ,
. xml_path = path ,
2023-12-15 21:47:17 +01:00
. exception = exception ,
2020-10-07 10:26:56 +02:00
} ;
test_name = g_strdup_printf ( " Checking %s against %s " , path , schema ) ;
return virTestRun ( test_name , testSchemaValidateXML , & data ) ;
2016-06-07 18:54:43 +02:00
}
static int
testSchemaDir ( const char * schema ,
2021-03-11 08:16:13 +01:00
virXMLValidator * validator ,
2020-10-06 17:25:52 +02:00
const char * dir_path ,
2023-12-15 21:47:17 +01:00
const struct testSchemaEntry * entry )
2016-06-07 18:54:43 +02:00
{
2020-10-25 17:50:51 -04:00
g_autoptr ( DIR ) dir = NULL ;
2016-06-07 18:54:43 +02:00
struct dirent * ent ;
int ret = 0 ;
int rc ;
2020-10-06 17:25:52 +02:00
g_autoptr ( GRegex ) filter = NULL ;
2016-06-07 18:54:43 +02:00
2019-11-19 11:55:05 +01:00
if ( virDirOpen ( & dir , dir_path ) < 0 ) {
virTestPropagateLibvirtError ( ) ;
2016-06-07 18:54:43 +02:00
return - 1 ;
2019-11-19 11:55:05 +01:00
}
2016-06-07 18:54:43 +02:00
2023-12-15 21:47:17 +01:00
if ( entry - > dirRegex ) {
2020-10-06 17:25:52 +02:00
g_autoptr ( GError ) err = NULL ;
2023-12-15 21:47:17 +01:00
if ( ! ( filter = g_regex_new ( entry - > dirRegex , 0 , 0 , & err ) ) ) {
VIR_TEST_VERBOSE ( " \n failed to compile regex '%s': %s " , entry - > dirRegex , err - > message ) ;
2020-10-06 17:25:52 +02:00
return - 1 ;
}
}
2016-06-07 18:54:43 +02:00
while ( ( rc = virDirRead ( dir , & ent , dir_path ) ) > 0 ) {
2019-11-19 11:16:34 +01:00
g_autofree char * xml_path = NULL ;
2023-12-15 21:47:17 +01:00
bool exception = false ;
2019-11-19 11:16:34 +01:00
2019-03-07 09:40:54 +01:00
if ( ! virStringHasSuffix ( ent - > d_name , " .xml " ) )
2016-06-07 18:54:43 +02:00
continue ;
2018-12-17 13:17:26 +00:00
if ( ent - > d_name [ 0 ] = = ' . ' )
continue ;
2024-08-27 14:14:37 +02:00
if ( virFileIsLink ( ent - > d_name ) )
2024-01-23 13:59:11 +01:00
continue ;
2020-10-06 17:25:52 +02:00
if ( filter & &
! g_regex_match ( filter , ent - > d_name , 0 , NULL ) )
continue ;
2016-06-07 18:54:43 +02:00
2024-08-08 09:14:11 +02:00
if ( entry - > skip & &
g_strv_contains ( entry - > skip , ent - > d_name ) )
continue ;
2023-12-15 21:47:17 +01:00
if ( entry - > exceptions )
exception = g_strv_contains ( entry - > exceptions , ent - > d_name ) ;
2019-10-22 15:26:14 +02:00
xml_path = g_strdup_printf ( " %s/%s " , dir_path , ent - > d_name ) ;
2016-06-07 18:54:43 +02:00
2023-12-15 21:47:17 +01:00
if ( testSchemaFile ( schema , validator , xml_path , exception ) < 0 )
2016-06-07 18:54:43 +02:00
ret = - 1 ;
}
2019-11-19 11:55:05 +01:00
if ( rc < 0 ) {
virTestPropagateLibvirtError ( ) ;
2016-06-07 18:54:43 +02:00
ret = - 1 ;
2019-11-19 11:55:05 +01:00
}
2016-06-07 18:54:43 +02:00
return ret ;
}
2020-10-07 10:26:56 +02:00
/**
* testSchemaGrammarReport :
*
* We need to parse the schema regardless since it ' s necessary also when tests
* are skipped using VIR_TEST_RANGE so this function merely reports whether the
* schema was parsed successfully via virTestRun .
*/
2016-06-07 18:54:43 +02:00
static int
2020-10-07 10:26:56 +02:00
testSchemaGrammarReport ( const void * opaque )
2016-06-07 18:54:43 +02:00
{
2020-10-07 10:26:56 +02:00
const virXMLValidator * validator = opaque ;
2016-06-07 18:54:43 +02:00
2020-10-07 10:26:56 +02:00
if ( ! validator )
return - 1 ;
2016-06-07 18:54:43 +02:00
2020-10-07 10:26:56 +02:00
return 0 ;
}
2021-03-11 08:16:13 +01:00
static virXMLValidator *
2020-10-07 10:26:56 +02:00
testSchemaGrammarLoad ( const char * schema )
{
g_autofree char * testname = NULL ;
2021-03-11 08:16:13 +01:00
virXMLValidator * ret ;
2020-10-07 10:26:56 +02:00
2022-10-20 10:30:00 +02:00
ret = virXMLValidatorInit ( schema ) ;
2020-10-07 10:26:56 +02:00
testname = g_strdup_printf ( " test schema grammar file: '%s' " , schema ) ;
ignore_value ( virTestRun ( testname , testSchemaGrammarReport , ret ) ) ;
2016-06-07 18:54:43 +02:00
return ret ;
}
2016-08-02 09:11:33 +02:00
static int
2020-10-07 10:26:56 +02:00
testSchemaEntries ( const char * schema ,
const struct testSchemaEntry * entries ,
size_t nentries )
2016-08-02 09:11:33 +02:00
{
2020-10-07 10:26:56 +02:00
g_autoptr ( virXMLValidator ) validator = NULL ;
size_t i ;
int ret = 0 ;
2016-08-02 09:11:33 +02:00
2020-10-07 10:26:56 +02:00
if ( ! ( validator = testSchemaGrammarLoad ( schema ) ) )
2019-11-19 11:16:34 +01:00
return - 1 ;
2016-08-02 09:11:33 +02:00
2020-10-07 10:26:56 +02:00
for ( i = 0 ; i < nentries ; i + + ) {
const struct testSchemaEntry * entry = entries + i ;
if ( ! entry - > file = = ! entry - > dir ) {
VIR_TEST_VERBOSE ( " \n must specify exactly one of 'dir' and 'file' for struct testSchemaEntry \n " ) ;
ret = - 1 ;
continue ;
}
if ( entry - > dir ) {
g_autofree char * path = g_strdup_printf ( " %s/%s " , abs_top_srcdir , entry - > dir ) ;
2023-12-15 21:47:17 +01:00
if ( testSchemaDir ( schema , validator , path , entry ) < 0 )
2020-10-07 10:26:56 +02:00
ret = - 1 ;
}
if ( entry - > file ) {
g_autofree char * path = g_strdup_printf ( " %s/%s " , abs_top_srcdir , entry - > file ) ;
2023-12-15 21:47:17 +01:00
if ( testSchemaFile ( schema , validator , path , false ) < 0 )
2020-10-07 10:26:56 +02:00
ret = - 1 ;
}
}
return ret ;
2016-08-02 09:11:33 +02:00
}
2020-10-07 10:26:56 +02:00
static const struct testSchemaEntry schemaCapability [ ] = {
{ . dir = " tests/capabilityschemadata " } ,
{ . dir = " tests/vircaps2xmldata " } ,
2020-10-07 13:58:24 +02:00
{ . dir = " tests/qemucaps2xmloutdata " } ,
2020-10-07 10:26:56 +02:00
} ;
2023-12-15 21:47:17 +01:00
/* give exceptions for output files of invalid input XMLs */
2024-01-22 16:49:18 +01:00
static const char * exceptions_qemuxmlconfdata [ ] = {
2023-12-15 21:47:17 +01:00
" disk-cdrom-empty-network-invalid.x86_64-latest.xml " ,
2023-12-16 20:18:13 +01:00
" numatune-auto-nodeset-invalid.x86_64-latest.xml " ,
2023-12-15 21:47:17 +01:00
NULL
} ;
2024-08-08 09:14:11 +02:00
/* skip tests with completely broken XML */
static const char * skip_qemuxmlconfdata [ ] = {
" broken-xml-invalid.xml " ,
NULL
} ;
2020-10-07 10:26:56 +02:00
static const struct testSchemaEntry schemaDomain [ ] = {
{ . dir = " tests/domainschemadata " } ,
2024-01-22 16:49:18 +01:00
{ . dir = " tests/qemuxmlconfdata " ,
. exceptions = exceptions_qemuxmlconfdata ,
2024-08-08 09:14:11 +02:00
. skip = skip_qemuxmlconfdata ,
2023-12-15 21:47:17 +01:00
} ,
2024-01-22 16:49:18 +01:00
{ . dir = " tests/xmconfigdata " } ,
2020-10-07 10:26:56 +02:00
{ . dir = " tests/lxcxml2xmldata " } ,
{ . dir = " tests/lxcxml2xmloutdata " } ,
{ . dir = " tests/bhyvexml2argvdata " } ,
{ . dir = " tests/bhyvexml2xmloutdata " } ,
{ . dir = " tests/genericxml2xmlindata " } ,
{ . dir = " tests/genericxml2xmloutdata " } ,
{ . dir = " tests/xlconfigdata " } ,
{ . dir = " tests/libxlxml2domconfigdata " } ,
{ . dir = " tests/qemuhotplugtestdomains " } ,
2020-10-06 17:28:44 +02:00
{ . dir = " examples/xml/test/ " ,
. dirRegex = " testdom.* " } ,
2020-10-07 11:40:39 +02:00
{ . dir = " tests/qemuhotplugtestcpus " } ,
{ . dir = " tests/securityselinuxlabeldata " } ,
{ . dir = " tests/domainconfdata " } ,
{ . dir = " tests/lxcconf2xmldata " } ,
{ . dir = " tests/qemumemlockdata " } ,
{ . dir = " tests/vmx2xmldata " } ,
{ . dir = " tests/xml2vmxdata " } ,
{ . dir = " tests/bhyveargv2xmldata " } ,
{ . dir = " tests/qemuagentdata " } ,
2023-08-24 14:40:47 +02:00
{ . dir = " tests/chxml2xmlin " } ,
{ . dir = " tests/chxml2xmlout " } ,
2020-10-07 10:26:56 +02:00
} ;
static const struct testSchemaEntry schemaDomainCaps [ ] = {
{ . dir = " tests/domaincapsdata " } ,
} ;
static const struct testSchemaEntry schemaDomainBackup [ ] = {
{ . dir = " tests/domainbackupxml2xmlin " } ,
{ . dir = " tests/domainbackupxml2xmlout " } ,
} ;
static const struct testSchemaEntry schemaDomainCheckpoint [ ] = {
{ . dir = " tests/qemudomaincheckpointxml2xmlin " } ,
{ . dir = " tests/qemudomaincheckpointxml2xmlout " } ,
} ;
static const struct testSchemaEntry schemaDomainSnapshot [ ] = {
{ . dir = " tests/qemudomainsnapshotxml2xmlin " } ,
{ . dir = " tests/qemudomainsnapshotxml2xmlout " } ,
} ;
static const struct testSchemaEntry schemaInterface [ ] = {
{ . dir = " tests/interfaceschemadata " } ,
} ;
static const struct testSchemaEntry schemaNetwork [ ] = {
{ . dir = " src/network " } ,
{ . dir = " tests/networkxml2xmlin " } ,
{ . dir = " tests/networkxml2xmlout " } ,
{ . dir = " tests/networkxml2confdata " } ,
2020-10-06 17:28:44 +02:00
{ . dir = " examples/xml/test/ " ,
. dirRegex = " testnet.* " } ,
2020-10-07 13:58:24 +02:00
{ . dir = " tests/networkxml2xmlupdateout " } ,
{ . dir = " tests/networkxml2firewalldata " } ,
2020-10-07 10:26:56 +02:00
} ;
static const struct testSchemaEntry schemaNetworkport [ ] = {
{ . dir = " tests/virnetworkportxml2xmldata " } ,
} ;
static const struct testSchemaEntry schemaNodedev [ ] = {
{ . dir = " tests/nodedevschemadata " } ,
2022-08-22 13:39:26 +02:00
{ . dir = " tests/nodedevxml2xmlout " } ,
2020-10-06 17:28:44 +02:00
{ . file = " examples/xml/test/testdev.xml " } ,
2020-10-07 10:26:56 +02:00
} ;
static const struct testSchemaEntry schemaNwfilter [ ] = {
{ . dir = " tests/nwfilterxml2xmlout " } ,
2020-10-07 11:33:30 +02:00
{ . dir = " src/nwfilter/xml " } ,
2020-10-07 13:58:24 +02:00
{ . dir = " tests/nwfilterxml2xmlin " } ,
{ . dir = " tests/nwfilterxml2firewalldata " } ,
2020-10-07 10:26:56 +02:00
} ;
static const struct testSchemaEntry schemaNwfilterbinding [ ] = {
{ . dir = " tests/virnwfilterbindingxml2xmldata " } ,
} ;
static const struct testSchemaEntry schemaSecret [ ] = {
{ . dir = " tests/secretxml2xmlin " } ,
} ;
static const struct testSchemaEntry schemaStoragepoolcaps [ ] = {
{ . dir = " tests/storagepoolcapsschemadata " } ,
} ;
static const struct testSchemaEntry schemaStoragePool [ ] = {
{ . dir = " tests/storagepoolxml2xmlin " } ,
{ . dir = " tests/storagepoolxml2xmlout " } ,
{ . dir = " tests/storagepoolschemadata " } ,
2020-10-06 17:28:44 +02:00
{ . dir = " examples/xml/storage " ,
. dirRegex = " pool-.* " } ,
2020-10-06 17:28:44 +02:00
{ . file = " examples/xml/test/testpool.xml " } ,
2020-10-07 10:26:56 +02:00
} ;
static const struct testSchemaEntry schemaStorageVol [ ] = {
{ . dir = " tests/storagevolxml2xmlin " } ,
{ . dir = " tests/storagevolxml2xmlout " } ,
{ . dir = " tests/storagevolschemadata " } ,
2020-10-06 17:28:44 +02:00
{ . dir = " examples/xml/storage " ,
. dirRegex = " vol-.* " } ,
2020-10-06 17:28:44 +02:00
{ . file = " examples/xml/test/testvol.xml " } ,
2020-10-07 10:26:56 +02:00
} ;
2020-10-08 12:01:29 +02:00
static const struct testSchemaEntry testsCpuBaseline [ ] = {
{ . dir = " tests/cputestdata " } ,
2020-10-07 16:52:14 +02:00
} ;
2020-10-07 10:26:56 +02:00
2022-10-20 13:32:34 +02:00
static const struct testSchemaEntry testDevice [ ] = {
{ . dir = " tests/qemuhotplugtestdevices " } ,
{ . dir = " tests/qemublocktestdata/imagecreate " } ,
{ . dir = " tests/qemublocktestdata/xml2json " } ,
} ;
2016-06-07 18:54:43 +02:00
static int
mymain ( void )
{
int ret = 0 ;
2020-10-07 10:26:56 +02:00
2022-10-20 10:30:00 +02:00
# define SCHEMAS_PATH abs_top_srcdir " / src / conf / schemas / "
2020-10-08 12:01:29 +02:00
# define INTERNAL_SCHEMAS_PATH abs_builddir " / schemas / "
2022-03-22 09:18:57 +01:00
2020-10-07 10:26:56 +02:00
# define DO_TEST(sch, ent) \
if ( testSchemaEntries ( ( sch ) , ( ent ) , G_N_ELEMENTS ( ent ) ) < 0 ) \
ret = - 1 ;
2022-03-22 09:18:57 +01:00
DO_TEST ( SCHEMAS_PATH " capability.rng " , schemaCapability ) ;
DO_TEST ( SCHEMAS_PATH " domain.rng " , schemaDomain ) ;
DO_TEST ( SCHEMAS_PATH " domaincaps.rng " , schemaDomainCaps ) ;
DO_TEST ( SCHEMAS_PATH " domainbackup.rng " , schemaDomainBackup ) ;
DO_TEST ( SCHEMAS_PATH " domaincheckpoint.rng " , schemaDomainCheckpoint ) ;
DO_TEST ( SCHEMAS_PATH " domainsnapshot.rng " , schemaDomainSnapshot ) ;
DO_TEST ( SCHEMAS_PATH " interface.rng " , schemaInterface ) ;
DO_TEST ( SCHEMAS_PATH " network.rng " , schemaNetwork ) ;
DO_TEST ( SCHEMAS_PATH " networkport.rng " , schemaNetworkport ) ;
DO_TEST ( SCHEMAS_PATH " nodedev.rng " , schemaNodedev ) ;
DO_TEST ( SCHEMAS_PATH " nwfilter.rng " , schemaNwfilter ) ;
DO_TEST ( SCHEMAS_PATH " nwfilterbinding.rng " , schemaNwfilterbinding ) ;
DO_TEST ( SCHEMAS_PATH " secret.rng " , schemaSecret ) ;
DO_TEST ( SCHEMAS_PATH " storagepoolcaps.rng " , schemaStoragepoolcaps ) ;
DO_TEST ( SCHEMAS_PATH " storagepool.rng " , schemaStoragePool ) ;
DO_TEST ( SCHEMAS_PATH " storagevol.rng " , schemaStorageVol ) ;
2020-10-08 12:01:29 +02:00
DO_TEST ( INTERNAL_SCHEMAS_PATH " cpu-baseline.rng " , testsCpuBaseline ) ;
2022-10-20 13:32:34 +02:00
DO_TEST ( INTERNAL_SCHEMAS_PATH " device.rng " , testDevice ) ;
2016-06-07 18:54:43 +02:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}
2017-03-29 16:45:42 +02:00
VIR_TEST_MAIN ( mymain )