mirror of
https://github.com/libvirt/libvirt.git
synced 2026-10-02 12:20:06 -05:00
Use newly introduced testutils APIs to detect unused files. This is pretty much straightforward except for one test case: hostdev. This test case queries sysfs under the hood and thus is expected to succeed on Linux and fail everywhere else. Though, hostdev.expect.xml is thus used on Linux only. Therefore, do not collect it on non-Linux platforms. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
383 lines
12 KiB
C
383 lines
12 KiB
C
#include <config.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "internal.h"
|
|
#include "testutils.h"
|
|
#include "network_conf.h"
|
|
#include "bridge_driver.h"
|
|
#define LIBVIRT_BRIDGE_DRIVER_PRIV_H_ALLOW
|
|
#include "bridge_driver_priv.h"
|
|
#define LIBVIRT_VIRCOMMANDPRIV_H_ALLOW
|
|
#include "vircommandpriv.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
typedef enum {
|
|
TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS,
|
|
TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE,
|
|
TEST_COMPARE_NET_XML2XML_RESULT_FAIL_VALIDATE,
|
|
TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT,
|
|
TEST_COMPARE_NET_XML2XML_RESULT_FAIL_COMPARE,
|
|
} testCompareNetXML2XMLResult;
|
|
|
|
struct _testInfo {
|
|
const char *name;
|
|
unsigned int flags;
|
|
testCompareNetXML2XMLResult expectResult;
|
|
virNetworkXMLOption *xmlopt; /* borrowed, immutable */
|
|
dnsmasqCaps *caps;
|
|
virNetworkDef *def;
|
|
char *inxml;
|
|
char *outxml;
|
|
char *outconf;
|
|
char *outhostsfile;
|
|
GHashTable *existingTestCases;
|
|
};
|
|
|
|
typedef struct _testInfo testInfo;
|
|
void testInfoFree(testInfo *info);
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(testInfo, testInfoFree);
|
|
|
|
void testInfoFree(testInfo *info)
|
|
{
|
|
if (!info)
|
|
return;
|
|
|
|
virNetworkDefFree(info->def);
|
|
VIR_FREE(info->inxml);
|
|
VIR_FREE(info->outxml);
|
|
VIR_FREE(info->outconf);
|
|
VIR_FREE(info->outhostsfile);
|
|
VIR_FREE(info);
|
|
}
|
|
|
|
static int
|
|
testCompareXMLToXMLFiles(const void *data)
|
|
{
|
|
testInfo *info = (void *) data;
|
|
g_autofree char *actual = NULL;
|
|
int ret;
|
|
testCompareNetXML2XMLResult result = TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS;
|
|
g_autoptr(virNetworkDef) def = NULL;
|
|
|
|
virTestCaseMarkUsed(info->existingTestCases, info->inxml);
|
|
if (!(def = virNetworkDefParse(NULL, info->inxml, info->xmlopt, false))) {
|
|
result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE;
|
|
goto cleanup;
|
|
}
|
|
if (info->expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE)
|
|
goto cleanup;
|
|
|
|
if (networkValidateTests(def) < 0) {
|
|
result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_VALIDATE;
|
|
goto cleanup;
|
|
}
|
|
if (info->expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_VALIDATE)
|
|
goto cleanup;
|
|
|
|
if (!(actual = virNetworkDefFormat(def, info->xmlopt, info->flags))) {
|
|
result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT;
|
|
goto cleanup;
|
|
}
|
|
if (info->expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT)
|
|
goto cleanup;
|
|
|
|
virTestCaseMarkUsed(info->existingTestCases, info->outxml);
|
|
if (virTestCompareToFile(actual, info->outxml) < 0) {
|
|
result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_COMPARE;
|
|
goto cleanup;
|
|
}
|
|
if (info->expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_COMPARE)
|
|
goto cleanup;
|
|
|
|
cleanup:
|
|
if (result == info->expectResult) {
|
|
ret = 0;
|
|
if (info->expectResult != TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS) {
|
|
VIR_TEST_DEBUG("Got expected failure code=%d msg=%s",
|
|
result, virGetLastErrorMessage());
|
|
} else {
|
|
info->def = g_steal_pointer(&def);
|
|
}
|
|
} else {
|
|
ret = -1;
|
|
VIR_TEST_DEBUG("Expected result code=%d but received code=%d",
|
|
info->expectResult, result);
|
|
}
|
|
virResetLastError();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
testCompareXMLToConfFiles(const void *data)
|
|
{
|
|
testInfo *info = (void *) data;
|
|
char *confactual = NULL;
|
|
g_autofree char *hostsfileactual = NULL;
|
|
int ret = -1;
|
|
virNetworkDef *def = NULL;
|
|
virNetworkObj *obj = NULL;
|
|
g_autofree char *pidfile = NULL;
|
|
g_autoptr(dnsmasqContext) dctx = NULL;
|
|
bool compareFailed = false;
|
|
|
|
if (!(obj = virNetworkObjNew()))
|
|
goto cleanup;
|
|
|
|
if (!(def = g_steal_pointer(&info->def))) {
|
|
/* Previous test wasn't executed. */
|
|
virTestCaseMarkUsed(info->existingTestCases, info->inxml);
|
|
if (!(def = virNetworkDefParse(NULL, info->inxml, info->xmlopt, false)))
|
|
goto cleanup;
|
|
|
|
if (networkValidateTests(def) < 0) {
|
|
virNetworkDefFree(def);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
virNetworkObjSetDef(obj, def);
|
|
|
|
if (!networkNeedsDnsmasq(def)) {
|
|
ret = EXIT_AM_SKIP;
|
|
goto cleanup;
|
|
}
|
|
|
|
dctx = dnsmasqContextNew(def->name, "/var/lib/libvirt/dnsmasq");
|
|
|
|
if (dctx == NULL)
|
|
goto cleanup;
|
|
|
|
if (networkDnsmasqConfContents(obj, pidfile, &confactual,
|
|
&hostsfileactual, dctx, info->caps) < 0)
|
|
goto cleanup;
|
|
|
|
/* Any changes to this function ^^ should be reflected here too. */
|
|
#ifndef __linux__
|
|
{
|
|
char * tmp;
|
|
|
|
if (!(tmp = virStringReplace(confactual,
|
|
"except-interface=lo0\n",
|
|
"except-interface=lo\n")))
|
|
goto cleanup;
|
|
VIR_FREE(confactual);
|
|
confactual = g_steal_pointer(&tmp);
|
|
}
|
|
#endif
|
|
|
|
virTestCaseMarkUsed(info->existingTestCases, info->outconf);
|
|
if (virTestCompareToFile(confactual, info->outconf) < 0)
|
|
compareFailed = true;
|
|
|
|
if (hostsfileactual) {
|
|
virTestCaseMarkUsed(info->existingTestCases, info->outhostsfile);
|
|
if (virTestCompareToFile(hostsfileactual, info->outhostsfile) < 0) {
|
|
compareFailed = true;
|
|
}
|
|
} else {
|
|
if (virFileExists(info->outhostsfile)) {
|
|
VIR_TEST_DEBUG("%s: hostsfile exists but the configuration did not specify any host",
|
|
info->outhostsfile);
|
|
compareFailed = true;
|
|
}
|
|
}
|
|
|
|
if (compareFailed)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
VIR_FREE(confactual);
|
|
virNetworkObjEndAPI(&obj);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
buildCapsCallback(const char *const*args,
|
|
const char *const*env G_GNUC_UNUSED,
|
|
const char *input G_GNUC_UNUSED,
|
|
char **output,
|
|
char **error G_GNUC_UNUSED,
|
|
int *status,
|
|
void *opaque G_GNUC_UNUSED)
|
|
{
|
|
if (STREQ(args[0], "/usr/sbin/dnsmasq") && STREQ(args[1], "--version")) {
|
|
*output = g_strdup("Dnsmasq version 2.67\n");
|
|
*status = EXIT_SUCCESS;
|
|
} else {
|
|
*status = EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
static dnsmasqCaps *
|
|
buildCaps(void)
|
|
{
|
|
g_autoptr(dnsmasqCaps) caps = NULL;
|
|
g_autoptr(virCommandDryRunToken) dryRunToken = virCommandDryRunTokenNew();
|
|
|
|
virCommandSetDryRun(dryRunToken, NULL, true, true, buildCapsCallback, NULL);
|
|
|
|
caps = dnsmasqCapsNewFromBinary();
|
|
|
|
return g_steal_pointer(&caps);
|
|
}
|
|
|
|
|
|
static void
|
|
testRun(const char *name,
|
|
int *ret,
|
|
virNetworkXMLOption *xmlopt,
|
|
dnsmasqCaps *caps,
|
|
testCompareNetXML2XMLResult expectResult,
|
|
GHashTable *existingTestCases,
|
|
unsigned int flags)
|
|
{
|
|
g_autofree char *name_xml2xml = g_strdup_printf("Network XML-2-XML %s", name);
|
|
g_autofree char *name_xml2conf = g_strdup_printf("Network XML-2-Conf %s", name);
|
|
g_autoptr(testInfo) info = g_new0(testInfo, 1);
|
|
|
|
info->name = name;
|
|
info->flags = flags;
|
|
info->expectResult = expectResult;
|
|
info->xmlopt = xmlopt;
|
|
info->caps = caps;
|
|
info->inxml = g_strdup_printf("%s/networkxmlconfdata/%s.xml", abs_srcdir, name);
|
|
info->outxml = g_strdup_printf("%s/networkxmlconfdata/%s.expect.xml", abs_srcdir, name);
|
|
info->outconf = g_strdup_printf("%s/networkxmlconfdata/%s.conf", abs_srcdir, name);
|
|
info->outhostsfile = g_strdup_printf("%s/networkxmlconfdata/%s.hostsfile", abs_srcdir, name);
|
|
info->existingTestCases = existingTestCases;
|
|
|
|
virTestRunLog(ret, name_xml2xml, testCompareXMLToXMLFiles, info);
|
|
|
|
if (expectResult == TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS)
|
|
virTestRunLog(ret, name_xml2conf, testCompareXMLToConfFiles, info);
|
|
}
|
|
|
|
|
|
static bool
|
|
testCaseEnumerate(struct dirent *ent)
|
|
{
|
|
#ifndef __linux__
|
|
/* This test case is ran only on Linux. See comment in mymain(). */
|
|
if (STREQ(ent->d_name, "hostdev.expect.xml"))
|
|
return false;
|
|
#endif
|
|
return virStringHasSuffix(ent->d_name, ".xml") ||
|
|
virStringHasSuffix(ent->d_name, ".conf") ||
|
|
virStringHasSuffix(ent->d_name, ".hostsfile");
|
|
}
|
|
|
|
|
|
static int
|
|
mymain(void)
|
|
{
|
|
g_autoptr(virNetworkXMLOption) xmlopt = NULL;
|
|
g_autoptr(dnsmasqCaps) caps = NULL;
|
|
g_autoptr(GHashTable) existingTestCases = NULL;
|
|
int ret = 0;
|
|
|
|
if (virTestEnumerateTestCases(abs_srcdir "/networkxmlconfdata",
|
|
testCaseEnumerate,
|
|
&existingTestCases) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (!(xmlopt = networkDnsmasqCreateXMLConf()))
|
|
return -1;
|
|
|
|
if (!(caps = buildCaps()))
|
|
return -1;
|
|
|
|
#define DO_TEST_FULL(name, flags, expectResult) \
|
|
testRun(name, &ret, xmlopt, caps, expectResult, existingTestCases, flags)
|
|
#define DO_TEST(name) \
|
|
DO_TEST_FULL(name, 0, TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS)
|
|
#define DO_TEST_FLAGS(name, flags) \
|
|
DO_TEST_FULL(name, flags, TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS)
|
|
#define DO_TEST_PARSE_ERROR(name) \
|
|
DO_TEST_FULL(name, 0, TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE)
|
|
#define DO_TEST_VALIDATE_ERROR(name) \
|
|
DO_TEST_FULL(name, 0, TEST_COMPARE_NET_XML2XML_RESULT_FAIL_VALIDATE)
|
|
|
|
DO_TEST("dhcp6-network");
|
|
DO_TEST("dhcp6-nat-network");
|
|
DO_TEST("dhcp6host-routed-network");
|
|
DO_TEST("empty-allow-ipv6");
|
|
DO_TEST("isolated-network");
|
|
DO_TEST("routed-network");
|
|
DO_TEST("routed-network-no-dns");
|
|
DO_TEST_PARSE_ERROR("routed-network-no-dns-extra-elements");
|
|
DO_TEST("open-network");
|
|
DO_TEST_PARSE_ERROR("open-network-with-forward-dev");
|
|
DO_TEST("nat-network");
|
|
DO_TEST("netboot-network");
|
|
DO_TEST("netboot-proxy-network");
|
|
DO_TEST("netboot-tftp");
|
|
DO_TEST("nat-network-dns-txt-record");
|
|
DO_TEST("nat-network-dns-srv-record");
|
|
DO_TEST("nat-network-dns-srv-records");
|
|
DO_TEST("nat-network-dns-srv-record-minimal");
|
|
DO_TEST("nat-network-dns-hosts");
|
|
DO_TEST("nat-network-dns-forward-plain");
|
|
DO_TEST("nat-network-dns-forwarders");
|
|
DO_TEST("nat-network-dns-forwarder-no-resolv");
|
|
DO_TEST("nat-network-dns-local-domain");
|
|
DO_TEST("nat-network-forward-nat-ipv6");
|
|
DO_TEST("nat-network-forward-nat-address");
|
|
DO_TEST("nat-network-forward-nat-no-address");
|
|
DO_TEST("nat-network-name-with-quotes");
|
|
DO_TEST("nat-network-mtu");
|
|
DO_TEST("8021Qbh-net");
|
|
DO_TEST("direct-net");
|
|
DO_TEST("host-bridge-net");
|
|
DO_TEST("vepa-net");
|
|
DO_TEST("bandwidth-network");
|
|
DO_TEST("openvswitch-net");
|
|
DO_TEST_VALIDATE_ERROR("passthrough-pf");
|
|
#ifdef __linux__
|
|
DO_TEST("hostdev");
|
|
#else
|
|
/* Our test runners call networkValidateTests() which for
|
|
* <forward mode='hostdev'/> means validating that PCI
|
|
* devices are VFs. It's done so by querying sysfs which
|
|
* obviously works on Linux only. Thus, expect a validation
|
|
* error elsewhere. */
|
|
DO_TEST_VALIDATE_ERROR("hostdev");
|
|
#endif
|
|
DO_TEST_FLAGS("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
|
|
DO_TEST_FLAGS("hostdev-pf-driver-model", VIR_NETWORK_XML_INACTIVE);
|
|
DO_TEST("ptr-domains-auto");
|
|
DO_TEST_VALIDATE_ERROR("passthrough-address-crash");
|
|
DO_TEST("nat-network-explicit-flood");
|
|
DO_TEST("host-bridge-no-flood");
|
|
DO_TEST_PARSE_ERROR("hostdev-duplicate");
|
|
DO_TEST_PARSE_ERROR("passthrough-duplicate");
|
|
DO_TEST("metadata");
|
|
DO_TEST("set-mtu");
|
|
DO_TEST("dnsmasq-options");
|
|
DO_TEST("leasetime-seconds");
|
|
DO_TEST("leasetime-minutes");
|
|
DO_TEST("leasetime-hours");
|
|
DO_TEST("leasetime-infinite");
|
|
DO_TEST("isolated-ports");
|
|
|
|
if (virTestCheckUnusedTestCases(existingTestCases) < 0)
|
|
ret = -1;
|
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
VIR_TEST_MAIN_PRELOAD(mymain,
|
|
VIR_TEST_MOCK("virpci"),
|
|
VIR_TEST_MOCK("virdnsmasq"),
|
|
VIR_TEST_MOCK("virrandom"))
|