diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5be81d2213..562c1c7717 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -182,6 +182,7 @@ test_programs = virshtest sockettest \
virpcitest \
virendiantest \
virfiletest \
+ virfilecachetest \
virfirewalltest \
viriscsitest \
virkeycodetest \
@@ -211,6 +212,7 @@ test_libraries = libshunload.la \
virrandommock.la \
virhostcpumock.la \
domaincapsmock.la \
+ virfilecachemock.la \
$(NULL)
if WITH_REMOTE
@@ -1137,6 +1139,12 @@ virhostcpumock_la_CFLAGS = $(AM_CFLAGS)
virhostcpumock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
virhostcpumock_la_LIBADD = $(MOCKLIBS_LIBS)
+virfilecachemock_la_SOURCES = \
+ virfilecachemock.c
+virfilecachemock_la_CFLAGS = $(AM_CFLAGS)
+virfilecachemock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+virfilecachemock_la_LIBADD = $(MOCKLIBS_LIBS)
+
if WITH_LINUX
vircaps2xmltest_SOURCES = \
vircaps2xmltest.c testutils.h testutils.c virfilewrapper.h virfilewrapper.c
@@ -1369,6 +1377,10 @@ virfiletest_SOURCES = \
virfiletest.c testutils.h testutils.c
virfiletest_LDADD = $(LDADDS)
+virfilecachetest_SOURCES = \
+ virfilecachetest.c testutils.h testutils.c
+virfilecachetest_LDADD = $(LDADDS)
+
virfirewalltest_SOURCES = \
virfirewalltest.c testutils.h testutils.c
virfirewalltest_LDADD = $(LDADDS) $(DBUS_LIBS)
diff --git a/tests/virfilecachedata/5f3154560c130108b282a2aa15b1658aa16923e46497dd8deeb6be287ddb0ca0.cache b/tests/virfilecachedata/5f3154560c130108b282a2aa15b1658aa16923e46497dd8deeb6be287ddb0ca0.cache
new file mode 100644
index 0000000000..72943a16fb
--- /dev/null
+++ b/tests/virfilecachedata/5f3154560c130108b282a2aa15b1658aa16923e46497dd8deeb6be287ddb0ca0.cache
@@ -0,0 +1 @@
+aaa
diff --git a/tests/virfilecachedata/9ca150bf3119b75dcac8e8bae4bc3a28e75bc3e262757001e8b953580f5e75ef.cache b/tests/virfilecachedata/9ca150bf3119b75dcac8e8bae4bc3a28e75bc3e262757001e8b953580f5e75ef.cache
new file mode 120000
index 0000000000..94df26de63
--- /dev/null
+++ b/tests/virfilecachedata/9ca150bf3119b75dcac8e8bae4bc3a28e75bc3e262757001e8b953580f5e75ef.cache
@@ -0,0 +1 @@
+5f3154560c130108b282a2aa15b1658aa16923e46497dd8deeb6be287ddb0ca0.cache
\ No newline at end of file
diff --git a/tests/virfilecachemock.c b/tests/virfilecachemock.c
new file mode 100644
index 0000000000..a7476bce2e
--- /dev/null
+++ b/tests/virfilecachemock.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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
+ * .
+ *
+ */
+
+#include
+
+#include
+
+#include "internal.h"
+
+
+int
+unlink(const char *path ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
diff --git a/tests/virfilecachetest.c b/tests/virfilecachetest.c
new file mode 100644
index 0000000000..9aa01ddb3a
--- /dev/null
+++ b/tests/virfilecachetest.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 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
+ * .
+ *
+ */
+
+#include
+
+#include "testutils.h"
+#include "virfile.h"
+#include "virfilecache.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+
+struct _testFileCacheObj {
+ virObject object;
+ char *data;
+};
+typedef struct _testFileCacheObj testFileCacheObj;
+typedef testFileCacheObj *testFileCacheObjPtr;
+
+
+static virClassPtr testFileCacheObjClass;
+
+
+static void
+testFileCacheObjDispose(void *opaque)
+{
+ testFileCacheObjPtr obj = opaque;
+ VIR_FREE(obj->data);
+}
+
+
+static int
+testFileCacheObjOnceInit(void)
+{
+ if (!(testFileCacheObjClass = virClassNew(virClassForObject(),
+ "testFileCacheObj",
+ sizeof(testFileCacheObj),
+ testFileCacheObjDispose)))
+ return -1;
+
+ return 0;
+}
+
+
+VIR_ONCE_GLOBAL_INIT(testFileCacheObj)
+
+
+static testFileCacheObjPtr
+testFileCacheObjNew(const char *data)
+{
+ testFileCacheObjPtr obj;
+
+ if (testFileCacheObjInitialize() < 0)
+ return NULL;
+
+ if (!(obj = virObjectNew(testFileCacheObjClass)))
+ return NULL;
+
+ if (VIR_STRDUP(obj->data, data) < 0)
+ goto error;
+
+ return obj;
+
+ error:
+ virObjectUnref(obj);
+ return NULL;
+}
+
+
+struct _testFileCachePriv {
+ bool dataSaved;
+ const char *newData;
+ const char *expectData;
+};
+typedef struct _testFileCachePriv testFileCachePriv;
+typedef testFileCachePriv *testFileCachePrivPtr;
+
+
+static bool
+testFileCacheIsValid(void *data,
+ void *priv)
+{
+ testFileCachePrivPtr testPriv = priv;
+ testFileCacheObjPtr obj = data;
+
+ return STREQ(testPriv->expectData, obj->data);
+}
+
+
+static void *
+testFileCacheNewData(const char *name ATTRIBUTE_UNUSED,
+ void *priv)
+{
+ testFileCachePrivPtr testPriv = priv;
+
+ return testFileCacheObjNew(testPriv->newData);
+}
+
+
+static void *
+testFileCacheLoadFile(const char *filename,
+ const char *name ATTRIBUTE_UNUSED,
+ void *priv ATTRIBUTE_UNUSED)
+{
+ testFileCacheObjPtr obj;
+ char *data;
+
+ if (virFileReadAll(filename, 20, &data) < 0)
+ return NULL;
+
+ obj = testFileCacheObjNew(data);
+
+ VIR_FREE(data);
+ return obj;
+}
+
+
+static int
+testFileCacheSaveFile(void *data ATTRIBUTE_UNUSED,
+ const char *filename ATTRIBUTE_UNUSED,
+ void *priv)
+{
+ testFileCachePrivPtr testPriv = priv;
+
+ testPriv->dataSaved = true;
+
+ return 0;
+}
+
+
+virFileCacheHandlers testFileCacheHandlers = {
+ .isValid = testFileCacheIsValid,
+ .newData = testFileCacheNewData,
+ .loadFile = testFileCacheLoadFile,
+ .saveFile = testFileCacheSaveFile
+};
+
+
+struct _testFileCacheData {
+ virFileCachePtr cache;
+ const char *name;
+ const char *newData;
+ const char *expectData;
+ bool expectSave;
+};
+typedef struct _testFileCacheData testFileCacheData;
+typedef testFileCacheData *testFileCacheDataPtr;
+
+
+static int
+testFileCache(const void *opaque)
+{
+ int ret = -1;
+ const testFileCacheData *data = opaque;
+ testFileCacheObjPtr obj = NULL;
+ testFileCachePrivPtr testPriv = virFileCacheGetPriv(data->cache);
+
+ testPriv->dataSaved = false;
+ testPriv->newData = data->newData;
+ testPriv->expectData = data->expectData;
+
+ if (!(obj = virFileCacheLookup(data->cache, data->name))) {
+ fprintf(stderr, "Getting cached data failed.\n");
+ goto cleanup;
+ }
+
+ if (!obj->data || STRNEQ(data->expectData, obj->data)) {
+ fprintf(stderr, "Expect data '%s', loaded data '%s'.\n",
+ data->expectData, NULLSTR(obj->data));
+ goto cleanup;
+ }
+
+ if (data->expectSave != testPriv->dataSaved) {
+ fprintf(stderr, "Expect data to be saved '%s', data saved '%s'.\n",
+ data->expectSave ? "yes" : "no",
+ testPriv->dataSaved ? "yes" : "no");
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ virObjectUnref(obj);
+ return ret;
+}
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+ testFileCachePriv testPriv = {0};
+ virFileCachePtr cache = NULL;
+
+ if (!(cache = virFileCacheNew(abs_srcdir "/virfilecachedata",
+ "cache", &testFileCacheHandlers)))
+ return EXIT_FAILURE;
+
+ virFileCacheSetPriv(cache, &testPriv);
+
+#define TEST_RUN(name, newData, expectData, expectSave) \
+ do { \
+ testFileCacheData data = { \
+ cache, name, newData, expectData, expectSave \
+ }; \
+ if (virTestRun(name, testFileCache, &data) < 0) \
+ ret = -1; \
+ } while (0)
+
+ /* The cache file name is created using:
+ * '$ echo -n $TEST_NAME | sha256sum' */
+ TEST_RUN("cacheValid", NULL, "aaa\n", false);
+ TEST_RUN("cacheInvalid", "bbb\n", "bbb\n", true);
+ TEST_RUN("cacheMissing", "ccc\n", "ccc\n", true);
+
+ virObjectUnref(cache);
+
+ return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virfilecachemock.so")