diff --git a/tests/Makefile.am b/tests/Makefile.am
index d4eedaf17c98c67296227638ea8c36e4a3e88877..076734feda701de06991f10e13788d6bb0840bca 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -206,6 +206,7 @@ test_libraries = libshunload.la \
virnetdevmock.la \
virrandommock.la \
virhostcpumock.la \
+ virnumamock.la \
domaincapsmock.la \
$(NULL)
@@ -1124,6 +1125,12 @@ virhostcpumock_la_CFLAGS = $(AM_CFLAGS)
virhostcpumock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
virhostcpumock_la_LIBADD = $(MOCKLIBS_LIBS)
+virnumamock_la_SOURCES = \
+ virnumamock.c
+virnumamock_la_CFLAGS = $(AM_CFLAGS)
+virnumamock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+virnumamock_la_LIBADD = $(MOCKLIBS_LIBS)
+
if WITH_NSS
nsstest_SOURCES = \
nsstest.c testutils.h testutils.c
diff --git a/tests/virnumamock.c b/tests/virnumamock.c
new file mode 100644
index 0000000000000000000000000000000000000000..89e420fa4173acdabf3c37219dbc07e4df7c8773
--- /dev/null
+++ b/tests/virnumamock.c
@@ -0,0 +1,191 @@
+/*
+ * virnumamock.c: Mock some virNuma functions using virsysfs
+ *
+ * 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
+ * .
+ */
+
+#include
+
+#include "internal.h"
+#include "virmock.h"
+#include "virnuma.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virsysfspriv.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+static int numa_avail = -1;
+
+
+/*
+ * Poor man's mocked NUMA guesser. We basically check if
+ * /sys/devices/system/node (where /sys/devices/system can already be mocked or
+ * changed in the tests) exists and cache the result.
+ */
+bool
+virNumaIsAvailable(void)
+{
+ if (numa_avail < 0) {
+ char *sysfs_node_path = NULL;
+
+ if (virAsprintfQuiet(&sysfs_node_path, "%s/node", virSysfsGetSystemPath()) < 0)
+ return false;
+
+ numa_avail = virFileExists(sysfs_node_path);
+
+ VIR_FREE(sysfs_node_path);
+ }
+
+ /*
+ * Quite a few more things need to be mocked if NUMA is not available and
+ * you are using this file. Do not remove the abort() call below unless you
+ * make sure all under virCapabilitiesInitNUMAFake() is mocked (and whatever
+ * might have changed since this comment was added. You are welcome.
+ */
+ if (!numa_avail)
+ abort();
+
+ return numa_avail;
+}
+
+int
+virNumaGetMaxNode(void)
+{
+ int ret = -1;
+ virBitmapPtr map = NULL;
+
+ if (virSysfsGetValueBitmap("node/online", &map) < 0)
+ return -1;
+
+ ret = virBitmapLastSetBit(map);
+ virBitmapFree(map);
+ return ret;
+}
+
+bool
+virNumaNodeIsAvailable(int node)
+{
+ bool ret = false;
+ virBitmapPtr map = NULL;
+
+ if (virSysfsGetValueBitmap("node/online", &map) < 0)
+ return false;
+
+ ret = virBitmapIsBitSet(map, node);
+ virBitmapFree(map);
+ return ret;
+}
+
+int
+virNumaGetNodeMemory(int node,
+ unsigned long long *memsize,
+ unsigned long long *memfree)
+{
+ const unsigned long long base = 1 << 30;
+
+ if (memsize)
+ *memsize = base * (node + 1);
+
+ if (memfree)
+ *memfree = base;
+
+ return 0;
+}
+
+int
+virNumaGetDistances(int node ATTRIBUTE_UNUSED,
+ int **distances,
+ int *ndistances)
+{
+ *distances = NULL;
+ *ndistances = 0;
+ return 0;
+}
+
+/*
+ * TODO: Adapt virNumaGetHugePageInfo{Path,Dir} to use virsysfs so that the
+ * paths can be modified and this function can be thrown away and instead we'd
+ * have copied info from /sys (as we do with /sys/devices/system).
+ */
+int
+virNumaGetPages(int node,
+ unsigned int **pages_size,
+ unsigned int **pages_avail,
+ unsigned int **pages_free,
+ size_t *npages)
+{
+ const int pages_def[] = { 4, 2 * 1024, 1 * 1024 * 1024};
+ const int npages_def = ARRAY_CARDINALITY(pages_def);
+ size_t i = 0;
+
+ if (pages_size)
+ *pages_size = NULL;
+
+ if (pages_avail)
+ *pages_avail = NULL;
+
+ if (pages_free)
+ *pages_free = NULL;
+
+ *npages = 0;
+
+ if ((pages_size && VIR_ALLOC_N(*pages_size, npages_def) < 0) ||
+ (pages_avail && VIR_ALLOC_N(*pages_avail, npages_def) < 0) ||
+ (pages_free && VIR_ALLOC_N(*pages_free, npages_def) < 0)) {
+ VIR_FREE(*pages_size);
+ VIR_FREE(*pages_avail);
+ return -1;
+ }
+
+ *npages = npages_def;
+ if (pages_size)
+ memcpy(*pages_size, pages_def, sizeof(pages_def));
+
+ node++;
+ if (node <= 0)
+ node = 32;
+
+ if (pages_avail || pages_free) {
+ for (i = 0; i < *npages; i++) {
+ if (pages_avail)
+ (*pages_avail)[i] = (node + i) * 2 << 10;
+ if (pages_free)
+ (*pages_free)[i] = (node + i) * 1 << 10;
+ }
+ }
+
+ return 0;
+}
+
+int
+virNumaGetNodeCPUs(int node, virBitmapPtr *cpus)
+{
+ int ret = -1;
+ char *cpulist = NULL;
+
+ if (virSysfsGetNodeValueString(node, "cpulist", &cpulist) < 0)
+ return -1;
+
+ *cpus = virBitmapParseUnlimited(cpulist);
+ if (!cpus)
+ goto cleanup;
+
+ ret = virBitmapCountBits(*cpus);
+ cleanup:
+ VIR_FREE(cpulist);
+ return ret;
+}