--- /dev/null
+/*
+ * Copyright (C) 2014 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/>.
+ *
+ * Author: Jan Tomko <jtomko@redhat.com>
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#include "viralloc.h"
+#include "virfile.h"
+#include "virstring.h"
+#include "virusb.h"
+
+#define USB_SYSFS "/sys/bus/usb"
+#define FAKE_USB_SYSFS "virusbtestdata/sys_bus_usb"
+
+static int (*realopen)(const char *pathname, int flags, ...);
+static DIR *(*realopendir)(const char *name);
+
+static void init_syms(void)
+{
+ if (realopen)
+ return;
+
+ realopen = dlsym(RTLD_NEXT, "open");
+ realopendir = dlsym(RTLD_NEXT, "opendir");
+ if (!realopen || !realopendir) {
+ fprintf(stderr, "Error getting symbols");
+ abort();
+ }
+}
+
+static char *get_fake_path(const char *real_path)
+{
+ const char *p = NULL;
+ char *path = NULL;
+
+ if ((p = STRSKIP(real_path, USB_SYSFS)) &&
+ virAsprintfQuiet(&path, "%s/%s/%s", abs_srcdir, FAKE_USB_SYSFS, p) < 0)
+ goto error;
+ else if (!p && VIR_STRDUP_QUIET(path, real_path) < 0)
+ goto error;
+
+ return path;
+
+error:
+ errno = ENOMEM;
+ return NULL;
+}
+
+DIR *opendir(const char *name)
+{
+ char *path;
+ DIR* ret;
+
+ init_syms();
+
+ path = get_fake_path(name);
+
+ ret = realopendir(path);
+ VIR_FREE(path);
+ return ret;
+}
+
+int open(const char *pathname, int flags, ...)
+{
+ char *path;
+ int ret;
+
+ init_syms();
+
+ path = get_fake_path(pathname);
+ if (!path)
+ return -1;
+ ret = realopen(path, flags);
+ VIR_FREE(path);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013-2014 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/>.
+ *
+ * Author: Jan Tomko <jtomko@redhat.com>
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "viralloc.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virusb.h"
+
+#include "testutils.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+typedef enum {
+ FIND_BY_ALL,
+ FIND_BY_VENDOR,
+ FIND_BY_BUS
+} testUSBFindFlags;
+
+struct findTestInfo {
+ const char *name;
+ unsigned int vendor;
+ unsigned int product;
+ unsigned int bus;
+ unsigned int devno;
+ const char *vroot;
+ bool mandatory;
+ int how;
+ bool expectFailure;
+};
+
+static int testDeviceFileActor(virUSBDevicePtr dev,
+ const char *path,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ char *str = NULL;
+ int ret = 0;
+
+ if (virAsprintf(&str, USB_DEVFS "%03d/%03d",
+ virUSBDeviceGetBus(dev),
+ virUSBDeviceGetDevno(dev)) < 0)
+ return -1;
+
+ if (STRNEQ(path, str)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "Device path '%s' does not match expected '%s'",
+ path, str);
+ ret = -1;
+ }
+ VIR_FREE(str);
+ return ret;
+}
+
+static int testDeviceFind(const void *opaque)
+{
+ const struct findTestInfo *info = opaque;
+ int ret = -1;
+ virUSBDevicePtr dev = NULL;
+ virUSBDeviceListPtr devs = NULL;
+ int rv = 0;
+ size_t i, ndevs = 0;
+
+ switch (info->how) {
+ case FIND_BY_ALL:
+ rv = virUSBDeviceFind(info->vendor, info->product,
+ info->bus, info->devno,
+ info->vroot, info->mandatory, &dev);
+ break;
+ case FIND_BY_VENDOR:
+ rv = virUSBDeviceFindByVendor(info->vendor, info->product,
+ info->vroot, info->mandatory, &devs);
+ break;
+ case FIND_BY_BUS:
+ rv = virUSBDeviceFindByBus(info->bus, info->devno,
+ info->vroot, info->mandatory, &dev);
+ break;
+ }
+
+ if (info->expectFailure) {
+ if (rv == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ "unexpected success");
+ } else {
+ ret = 0;
+ }
+ goto cleanup;
+ } else if (rv < 0) {
+ goto cleanup;
+ }
+
+ switch (info->how) {
+ case FIND_BY_ALL:
+ case FIND_BY_BUS:
+ if (virUSBDeviceFileIterate(dev, testDeviceFileActor, NULL) < 0)
+ goto cleanup;
+ break;
+
+ case FIND_BY_VENDOR:
+ ndevs = virUSBDeviceListCount(devs);
+
+ for (i = 0; i < ndevs; i++) {
+ virUSBDevicePtr device = virUSBDeviceListGet(devs, i);
+ if (virUSBDeviceFileIterate(device, testDeviceFileActor, NULL) < 0)
+ goto cleanup;
+ }
+ break;
+ }
+
+ ret = 0;
+
+cleanup:
+ virObjectUnref(devs);
+ virUSBDeviceFree(dev);
+ return ret;
+}
+
+
+static int
+mymain(void)
+{
+ int rv = 0;
+
+#define DO_TEST_FIND_FULL(name, vend, prod, bus, devno, vroot, mand, how, fail) \
+ do { \
+ struct findTestInfo data = { name, vend, prod, bus, \
+ devno, vroot, mand, how, fail \
+ }; \
+ if (virtTestRun("USBDeviceFind " name, testDeviceFind, &data) < 0) \
+ rv = -1; \
+ } while (0)
+
+#define DO_TEST_FIND(name, vend, prod, bus, devno) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \
+ FIND_BY_ALL, false)
+#define DO_TEST_FIND_FAIL(name, vend, prod, bus, devno) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \
+ FIND_BY_ALL, true)
+
+#define DO_TEST_FIND_BY_BUS(name, bus, devno) \
+ DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \
+ FIND_BY_BUS, false)
+#define DO_TEST_FIND_BY_BUS_FAIL(name, bus, devno) \
+ DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \
+ FIND_BY_BUS, true)
+
+#define DO_TEST_FIND_BY_VENDOR(name, vend, prod) \
+ DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \
+ FIND_BY_VENDOR, false)
+#define DO_TEST_FIND_BY_VENDOR_FAIL(name, vend, prod) \
+ DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \
+ FIND_BY_VENDOR, true)
+
+ DO_TEST_FIND("Nexus", 0x18d1, 0x4e22, 1, 20);
+ DO_TEST_FIND_FAIL("Nexus wrong devnum", 0x18d1, 0x4e22, 1, 25);
+ DO_TEST_FIND_FAIL("Bogus", 0xf00d, 0xbeef, 1024, 768);
+
+ DO_TEST_FIND_BY_BUS("integrated camera", 1, 5);
+ DO_TEST_FIND_BY_BUS_FAIL("wrong bus/devno combination", 2, 20);
+ DO_TEST_FIND_BY_BUS_FAIL("missing bus", 5, 20);
+ DO_TEST_FIND_BY_BUS_FAIL("missing devnum", 1, 158);
+
+ DO_TEST_FIND_BY_VENDOR("Nexus (multiple results)", 0x18d1, 0x4e22);
+ DO_TEST_FIND_BY_VENDOR_FAIL("Bogus vendor and product", 0xf00d, 0xbeef);
+ DO_TEST_FIND_BY_VENDOR_FAIL("Valid vendor", 0x1d6b, 0xbeef);
+
+ if (rv < 0)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
+
+VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virusbmock.so")