This mock (which is actually not mock at all, see later) can redirect all accesses to a path into another path. There is no need to create mocks for particular directories, you just create a directory with all the data a redirect the test there. In the future, this should also be able to register callbacks for calls/paths, e.g. when the test is going to write into anything under "/sys/devices", call function fce(); Then in the open() call we would add information about the fd into some structure and in write() we would call fce() with parameters like @path to write to, @data to be written and pointer to optional return value, so that fce() itself could stop the call from happening or change its behaviour. But that's an idea for a latter day. This is not a mock because it will not be preloaded, but compiled in the test itself. See future patches for usage. Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx> --- cfg.mk | 4 +- tests/Makefile.am | 2 +- tests/virfilewrapper.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/virfilewrapper.h | 31 ++++++ 4 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 tests/virfilewrapper.c create mode 100644 tests/virfilewrapper.h diff --git a/cfg.mk b/cfg.mk index c04a9911eb78..ed4129e418bc 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1129,7 +1129,7 @@ exclude_file_name_regexp--sc_copyright_usage = \ ^COPYING(|\.LESSER)$$ exclude_file_name_regexp--sc_flags_usage = \ - ^(cfg\.mk|docs/|src/util/virnetdevtap\.c$$|tests/(vir(cgroup|pci|test|usb)|nss|qemuxml2argv)mock\.c$$) + ^(cfg\.mk|docs/|src/util/virnetdevtap\.c$$|tests/((vir(cgroup|pci|test|usb)|nss|qemuxml2argv)mock|virfilewrapper)\.c$$) exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \ ^(src/rpc/gendispatch\.pl$$|tests/) @@ -1258,7 +1258,7 @@ exclude_file_name_regexp--sc_prohibit_always-defined_macros = \ ^tests/virtestmock.c$$ exclude_file_name_regexp--sc_prohibit_readdir = \ - ^tests/.*mock\.c$$ + ^tests/(.*mock|virfilewrapper)\.c$$ exclude_file_name_regexp--sc_prohibit_cross_inclusion = \ ^(src/util/virclosecallbacks\.h|src/util/virhostdev\.h)$$ diff --git a/tests/Makefile.am b/tests/Makefile.am index 279e9b7da866..2685098f4343 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1156,7 +1156,7 @@ virnumamock_la_CFLAGS = $(AM_CFLAGS) virnumamock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) virnumamock_la_LIBADD = $(MOCKLIBS_LIBS) else ! WITH_LINUX -EXTRA_DIST += vircaps2xmltest.c virnumamock.c +EXTRA_DIST += vircaps2xmltest.c virnumamock.c virfilewrapper.c virfilewrapper.h endif ! WITH_LINUX if WITH_NSS diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c new file mode 100644 index 000000000000..81537a6baf61 --- /dev/null +++ b/tests/virfilewrapper.c @@ -0,0 +1,281 @@ +/* + * virfilewrapper.c: Wrapper for universal file access + * + * 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/>. + */ + +#include <config.h> + +#include "virmock.h" +#include "virfilewrapper.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> + +#include "viralloc.h" +#include "virstring.h" +#include "virfile.h" + + +/* Mapping for prefix overrides */ +static size_t noverrides; +static const char **overrides; + +/* nprefixes == noverrides, but two variables make it easier to use + * VIR_*_ELEMENT macros */ +static size_t nprefixes; +static const char **prefixes; + +/* TODO: callbacks */ + + +static int (*real_open)(const char *path, int flags, ...); +static FILE *(*real_fopen)(const char *path, const char *mode); +static int (*real_access)(const char *path, int mode); +static int (*real_stat)(const char *path, struct stat *sb); +static int (*real___xstat)(int ver, const char *path, struct stat *sb); +static int (*real_lstat)(const char *path, struct stat *sb); +static int (*real___lxstat)(int ver, const char *path, struct stat *sb); +static int (*real_mkdir)(const char *path, mode_t mode); +static DIR *(*real_opendir)(const char *path); + +static void init_syms(void) +{ + if (real_fopen) + return; + + VIR_MOCK_REAL_INIT(fopen); + VIR_MOCK_REAL_INIT(access); + VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); + VIR_MOCK_REAL_INIT_ALT(stat, __xstat); + VIR_MOCK_REAL_INIT(mkdir); + VIR_MOCK_REAL_INIT(open); + VIR_MOCK_REAL_INIT(opendir); +} + + +int +virFileWrapperAddPrefix(const char *prefix, + const char *override) +{ + /* Both parameters are mandatory */ + if (!prefix || !override) + return -1; + + init_syms(); + + if (VIR_APPEND_ELEMENT_QUIET(prefixes, nprefixes, prefix) < 0 || + VIR_APPEND_ELEMENT_QUIET(overrides, noverrides, override) < 0) { + VIR_FREE(prefixes); + VIR_FREE(overrides); + return -1; + } + + return 0; +} + + +void +virFileWrapperRemovePrefix(const char *prefix) +{ + size_t i = 0; + + for (i = 0; i < noverrides; i++) { + if (STREQ(prefixes[i], prefix)) + break; + } + + if (i == noverrides) + return; + + VIR_DELETE_ELEMENT(overrides, i, noverrides); + VIR_DELETE_ELEMENT(prefixes, i, nprefixes); +} + +void +virFileWrapperClearPrefixes(void) +{ + nprefixes = 0; + noverrides = 0; + + VIR_FREE(prefixes); + VIR_FREE(overrides); +} + +static char * +virFileWrapperOverridePrefix(const char *path) +{ + char *ret = NULL; + size_t i = 0; + + for (i = 0; i < noverrides; i++) { + const char *tmp = STRSKIP(path, prefixes[i]); + + if (!tmp) + continue; + + if (virAsprintfQuiet(&ret, "%s%s", overrides[i], tmp) < 0) + return NULL; + + break; + } + + if (!ret) + ignore_value(VIR_STRDUP_QUIET(ret, path)); + + return ret; +} + + +#define PATH_OVERRIDE(newpath, path) \ + do { \ + init_syms(); \ + \ + newpath = virFileWrapperOverridePrefix(path); \ + if (!newpath) \ + abort(); \ + } while (0) + + +FILE *fopen(const char *path, const char *mode) +{ + FILE *ret = NULL; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_fopen(newpath, mode); + + VIR_FREE(newpath); + + return ret; +} + +int access(const char *path, int mode) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_access(newpath, mode); + + VIR_FREE(newpath); + + return ret; +} + +int __lxstat(int ver, const char *path, struct stat *sb) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real___lxstat(ver, newpath, sb); + + VIR_FREE(newpath); + + return ret; +} + +int lstat(const char *path, struct stat *sb) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_lstat(newpath, sb); + + VIR_FREE(newpath); + + return ret; +} + +int __xstat(int ver, const char *path, struct stat *sb) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real___xstat(ver, newpath, sb); + + VIR_FREE(newpath); + + return ret; +} + +int stat(const char *path, struct stat *sb) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_stat(newpath, sb); + + VIR_FREE(newpath); + + return ret; +} + +int mkdir(const char *path, mode_t mode) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_mkdir(newpath, mode); + + VIR_FREE(newpath); + + return ret; +} + +int open(const char *path, int flags, ...) +{ + int ret = -1; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_open(newpath, flags); + + VIR_FREE(newpath); + + return ret; +} + +DIR *opendir(const char *path) +{ + DIR *ret = NULL; + char *newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + ret = real_opendir(newpath); + + VIR_FREE(newpath); + + return ret; +} diff --git a/tests/virfilewrapper.h b/tests/virfilewrapper.h new file mode 100644 index 000000000000..612322c1d044 --- /dev/null +++ b/tests/virfilewrapper.h @@ -0,0 +1,31 @@ +/* + * virfilewrapper.h: Wrapper for universal file access + * + * 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/>. + */ + +#ifndef __VIR_FILE_MOCK_H__ + +int +virFileWrapperAddPrefix(const char *prefix, + const char *override); + +void +virFileWrapperRemovePrefix(const char *prefix); + +void +virFileWrapperClearPrefixes(void); + +#endif /* __VIR_FILE_MOCK_H__ */ -- 2.12.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list