Add unit test for hostdev common library. Current tests are based on virpcimock. Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx> --- .gitignore | 1 + tests/Makefile.am | 5 + tests/virhostdevtest.c | 507 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+) create mode 100644 tests/virhostdevtest.c diff --git a/.gitignore b/.gitignore index cb60734..56d9414 100644 --- a/.gitignore +++ b/.gitignore @@ -203,6 +203,7 @@ /tests/virendiantest /tests/virfiletest /tests/virhashtest +/tests/virhostdevtest /tests/viridentitytest /tests/virkeycodetest /tests/virkeyfiletest diff --git a/tests/Makefile.am b/tests/Makefile.am index cd91734..c601030 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -150,6 +150,7 @@ test_programs = virshtest sockettest \ virkmodtest \ vircapstest \ domainconftest \ + virhostdevtest \ $(NULL) if WITH_REMOTE @@ -812,6 +813,10 @@ vircgroupmock_la_CFLAGS = $(AM_CFLAGS) vircgroupmock_la_LDFLAGS = -module -avoid-version \ -rpath /evil/libtool/hack/to/force/shared/lib/creation +virhostdevtest_SOURCES = \ + virhostdevtest.c testutils.h testutils.c +virhostdevtest_LDADD = $(LDADDS) + virpcitest_SOURCES = \ virpcitest.c testutils.h testutils.c virpcitest_LDADD = $(LDADDS) diff --git a/tests/virhostdevtest.c b/tests/virhostdevtest.c new file mode 100644 index 0000000..f6d7e1d --- /dev/null +++ b/tests/virhostdevtest.c @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * 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/>. + * + * Author: Chunyan Liu <cyliu@xxxxxxxx> + */ + +#include <config.h> + +#include "testutils.h" + +#ifdef __linux__ + +# include <stdlib.h> +# include <stdio.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <fcntl.h> +# include "virlog.h" +# include "virhostdev.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +# define CHECK_LIST_COUNT(list, cnt) \ + if ((count = virPCIDeviceListCount(list)) != cnt) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "Unexpected count of items in " #list ": %d, " \ + "expecting %zu", count, (size_t) cnt); \ + goto cleanup; \ + } + +# define TEST_STATE_DIR abs_builddir "/hostdevmgr" +static const char *drv_name = "test_driver"; +static const char *dom_name = "test_domain"; +static const unsigned char *uuid = + (unsigned char *)("f92360b0-2541-8791-fb32-d1f838811541"); +static int nhostdevs = 3; +static virDomainHostdevDefPtr hostdevs[] = {NULL, NULL, NULL}; +static virPCIDevicePtr dev[] = {NULL, NULL, NULL}; +static virHostdevManagerPtr mgr = NULL; + +static void +myCleanup(void) +{ + size_t i; + for (i = 0; i < nhostdevs; i++) { + virPCIDeviceFree(dev[i]); + virDomainHostdevDefFree(hostdevs[i]); + } + + if (mgr) { + virObjectUnref(mgr->activePciHostdevs); + virObjectUnref(mgr->inactivePciHostdevs); + virObjectUnref(mgr->activeUsbHostdevs); + VIR_FREE(mgr->stateDir); + VIR_FREE(mgr); + } +} + +static int +myInit(void) +{ + size_t i; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevSubsys subsys; + hostdevs[i] = virDomainHostdevDefAlloc(); + if (!hostdevs[i]) + goto cleanup; + hostdevs[i]->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; + subsys.u.pci.addr.domain = 0; + subsys.u.pci.addr.bus = 0; + subsys.u.pci.addr.slot = i + 1; + subsys.u.pci.addr.function = 0; + subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM; + hostdevs[i]->source.subsys = subsys; + } + + for (i = 0; i < nhostdevs; i++) { + if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)) || + virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0) + goto cleanup; + } + + if (VIR_ALLOC(mgr) < 0) + goto cleanup; + if ((mgr->activePciHostdevs = virPCIDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) + goto cleanup; + if (VIR_STRDUP(mgr->stateDir, TEST_STATE_DIR) < 0) + goto cleanup; + if (virFileMakePath(mgr->stateDir) < 0) + goto cleanup; + + return 0; + +cleanup: + myCleanup(); + return -1; +} + +# if HAVE_LINUX_KVM_H +# include <linux/kvm.h> +static bool +virHostdevHostSupportsPassthroughKVM(void) +{ + int kvmfd = -1; + bool ret = false; + + if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0) + goto cleanup; + +# ifdef KVM_CAP_IOMMU + if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0) + goto cleanup; + + ret = true; +# endif + +cleanup: + VIR_FORCE_CLOSE(kvmfd); + + return ret; +} +# else +static bool +virHostdevHostSupportsPassthroughKVM(void) +{ + return false; +} +# endif + +static int +testVirHostdevPreparePciHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1, count2; + + for (i = 0; i < nhostdevs; i++) + hostdevs[i]->managed = false; + + /* Test invalid args */ + VIR_DEBUG("Test hostdev mgr=NULL\n"); + if (!virHostdevPreparePciHostdevs(NULL, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0)) + goto cleanup; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + + /* Test normal functionality */ + VIR_DEBUG("Test 0 hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + NULL, 0, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + /* Test unmanaged hostdevs */ + VIR_DEBUG("Test >=1 unmanaged hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2 - 3); + + /* Test conflict */ + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + &hostdevs[0], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, "test_domain1", uuid, + &hostdevs[1], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, "test_driver1", dom_name, uuid, + &hostdevs[2], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1, count2; + + for (i = 0; i < nhostdevs; i++) { + if (hostdevs[i]->managed != false) { + VIR_DEBUG("invalid test\n"); + return -1; + } + } + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + virHostdevReAttachPciHostdevs(NULL, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, NULL, 0, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 unmanaged hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 - 3); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2 + 3); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevPreparePciHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + for (i = 0; i < nhostdevs; i++) + hostdevs[i]->managed = true; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + /* Test normal functionality */ + VIR_DEBUG("Test >=1 hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + + /* Test conflict */ + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + &hostdevs[0], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, "test_domain1", uuid, + &hostdevs[1], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, "test_driver1", dom_name, uuid, + &hostdevs[2], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + for (i = 0; i < nhostdevs; i++) { + if (hostdevs[i]->managed != true) { + VIR_DEBUG("invalid test\n"); + return -1; + } + } + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + virHostdevReAttachPciHostdevs(NULL, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, NULL, 0, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 - 3); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevDetachPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + if (!virHostdevPciNodeDeviceDetach(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceDetach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + count1 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + if (virHostdevPciNodeDeviceDetach(mgr, dev[i]) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count1 + 1); + } + + ret = 0; + +cleanup: + return ret; +} +static int +testVirHostdevResetPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + + if (!virHostdevPciNodeDeviceReset(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceReAttach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + if (virHostdevPciNodeDeviceReset(mgr, dev[i]) < 0) + goto cleanup; + } + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + if (!virHostdevPciNodeDeviceReAttach(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceReAttach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + count1 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + if (virHostdevPciNodeDeviceReAttach(mgr, dev[i]) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count1 - 1); + } + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevUpdateActivePciHostdevs(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + int count, count1; + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + if (!virHostdevUpdateActivePciHostdevs(NULL, hostdevs, nhostdevs, + drv_name, dom_name)) + goto cleanup; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + if (virHostdevUpdateActivePciHostdevs(mgr, NULL, 0, + drv_name, dom_name) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 hostdevs\n"); + if (virHostdevUpdateActivePciHostdevs(mgr, hostdevs, nhostdevs, + drv_name, dom_name) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + + ret = 0; + +cleanup: + return ret; +} + +# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX" + +static int +mymain(void) +{ + int ret = 0; + char *fakesysfsdir; + + if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakesysfsdir)) { + fprintf(stderr, "Cannot create fakesysfsdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1); + +# define DO_TEST(fnc) \ + do { \ + VIR_DEBUG("\nTesting: %s", #fnc); \ + if (virtTestRun(#fnc, fnc, NULL) < 0) \ + ret = -1; \ + } while (0) + + if (myInit() < 0) + fprintf(stderr, "Init data structures failed."); + + DO_TEST(testVirHostdevDetachPciNodeDevice); + if (virHostdevHostSupportsPassthroughKVM()) { + /* following tests would check KVM support */ + DO_TEST(testVirHostdevPreparePciHostdevs_unmanaged); + DO_TEST(testVirHostdevReAttachPciHostdevs_unmanaged); + } + DO_TEST(testVirHostdevResetPciNodeDevice); + DO_TEST(testVirHostdevReAttachPciNodeDevice); + if (virHostdevHostSupportsPassthroughKVM()) { + /* following tests would check KVM support */ + DO_TEST(testVirHostdevPreparePciHostdevs_managed); + DO_TEST(testVirHostdevReAttachPciHostdevs_managed); + } + DO_TEST(testVirHostdevUpdateActivePciHostdevs); + + myCleanup(); + + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakesysfsdir); + + VIR_FREE(fakesysfsdir); + + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virpcimock.so") +#else +int +main(void) +{ + return EXIT_AM_SKIP; +} +#endif -- 1.9.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list