testsuite: trap calls to delete_module() including simple test
authorLucas De Marchi <lucas.demarchi@profusion.mobi>
Thu, 26 Jan 2012 18:10:41 +0000 (16:10 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Thu, 26 Jan 2012 18:14:18 +0000 (16:14 -0200)
Makefile.am
TODO
testsuite/delete_module.c [new file with mode: 0644]
testsuite/test-init.c
testsuite/testsuite.c
testsuite/testsuite.h

index 242d3e6..22e882b 100644 (file)
@@ -134,7 +134,8 @@ endif
 # ------------------------------------------------------------------------------
 
 TESTSUITE_OVERRIDE_LIBS = testsuite/uname.la testsuite/path.la \
-                         testsuite/init_module.la
+                         testsuite/init_module.la \
+                         testsuite/delete_module.la
 TESTSUITE_OVERRIDE_LIBS_LDFLAGS = avoid-version -module -shared -export-dynamic \
                                  -rpath /nowhere -ldl
 
@@ -143,6 +144,7 @@ check_LTLIBRARIES = $(TESTSUITE_OVERRIDE_LIBS)
 testsuite_uname_la_LDFLAGS = $(TESTSUITE_OVERRIDE_LIBS_LDFLAGS)
 testsuite_path_la_LDFLAGS = $(TESTSUITE_OVERRIDE_LIBS_LDFLAGS)
 
+testsuite_delete_module_la_LDFLAGS = $(TESTSUITE_OVERRIDE_LIBS_LDFLAGS)
 testsuite_init_module_la_LDFLAGS = $(TESTSUITE_OVERRIDE_LIBS_LDFLAGS)
 testsuite_init_module_la_SOURCES = testsuite/init_module.c \
                                   testsuite/stripped_module.h
diff --git a/TODO b/TODO
index e2317ff..1d6a5fe 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,9 +8,6 @@ Features:
 * index: drop the "open(), seek(), read()" implementation and use another one
   with mmap(). When lookup() is called and the file is not mmaped, mmap it.
 
-* create test-mock library to be LD_PRELOAD'ed before running the binaries
-  so we're able to create unit tests
-
 * review API, maybe unify all of these setters:
    - kmod_module_version_get_symbol()
    - kmod_module_version_get_crc()
diff --git a/testsuite/delete_module.c b/testsuite/delete_module.c
new file mode 100644 (file)
index 0000000..eee47a9
--- /dev/null
@@ -0,0 +1,141 @@
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "testsuite.h"
+
+struct mod {
+       struct mod *next;
+       int ret;
+       int errcode;
+       char name[];
+};
+
+static struct mod *modules;
+static bool need_init = true;
+
+static void parse_retcodes(struct mod *_modules, const char *s)
+{
+       const char *p;
+
+       if (s == NULL)
+               return;
+
+       for (p = s;;) {
+               struct mod *mod;
+               const char *modname;
+               char *end;
+               size_t modnamelen;
+               int ret, errcode;
+               long l;
+
+               modname = p;
+               if (modname == NULL || modname[0] == '\0')
+                       break;
+
+               modnamelen = strcspn(s, ":");
+               if (modname[modnamelen] != ':')
+                       break;
+
+               p = modname + modnamelen + 1;
+               if (p == NULL)
+                       break;
+
+               l = strtol(p, &end, 0);
+               if (end == p || *end != ':')
+                       break;
+               ret = (int) l;
+               p = end + 1;
+
+               l = strtol(p, &end, 0);
+               if (*end == ':')
+                       p = end + 1;
+               else if (*end != '\0')
+                       break;
+
+               errcode = (int) l;
+
+               mod = malloc(sizeof(*mod) + modnamelen + 1);
+               if (mod == NULL)
+                       break;
+
+               memcpy(mod->name, modname, modnamelen);
+               mod->name[modnamelen] = '\0';
+               mod->ret = ret;
+               mod->errcode = errcode;
+               mod->next = _modules;
+               _modules = mod;
+       }
+}
+
+static struct mod *find_module(struct mod *_modules, const char *modname)
+{
+       struct mod *mod;
+
+       for (mod = _modules; mod != NULL; mod = mod->next) {
+               if (strcmp(mod->name, modname))
+                       return mod;
+       }
+
+       return NULL;
+}
+
+static void init_retcodes(void)
+{
+       const char *s;
+
+       if (!need_init)
+               return;
+
+       need_init = false;
+       s = getenv(S_TC_DELETE_MODULE_RETCODES);
+       if (s == NULL) {
+               fprintf(stderr, "TRAP delete_module(): missing export %s?\n",
+                                               S_TC_DELETE_MODULE_RETCODES);
+       }
+
+       parse_retcodes(modules, s);
+}
+
+TS_EXPORT long delete_module(const char *name, unsigned int flags);
+
+/*
+ * FIXME: change /sys/module/<modname> to fake-remove a module
+ *
+ * Default behavior is to exit successfully. If this is not the intended
+ * behavior, set TESTSUITE_DELETE_MODULE_RETCODES env var.
+ */
+long delete_module(const char *modname, unsigned int flags)
+{
+       struct mod *mod;
+
+       init_retcodes();
+       mod = find_module(modules, modname);
+       if (mod == NULL)
+               return 0;
+
+       errno = mod->errcode;
+       return mod->ret;
+}
+
+/* the test is going away anyway, but lets keep valgrind happy */
+void free_resources(void) __attribute__((destructor));
+void free_resources(void)
+{
+       while (modules) {
+               struct mod *mod = modules->next;
+               free(modules);
+               modules = mod;
+       }
+}
index ade1bde..24e7034 100644 (file)
@@ -64,9 +64,47 @@ static const struct test stest_insert = {
        .need_spawn = true,
 };
 
+static int test_remove(const struct test *t)
+{
+       struct kmod_ctx *ctx;
+       struct kmod_module *mod;
+       const char *null_config = NULL;
+       int err;
+
+       ctx = kmod_new(NULL, &null_config);
+       if (ctx == NULL)
+               exit(EXIT_FAILURE);
+
+       err = kmod_module_new_from_name(ctx, "ext4", &mod);
+       if (err != 0) {
+               ERR("could not create module from name: %m\n");
+               exit(EXIT_FAILURE);
+       }
+
+       err = kmod_module_remove_module(mod, 0);
+       if (err != 0) {
+               ERR("could not remove module: %m\n");
+               exit(EXIT_FAILURE);
+       }
+       kmod_unref(ctx);
+
+       exit(EXIT_SUCCESS);
+}
+static const struct test stest_remove = {
+       .name = "test_remove",
+       .description = "test if libkmod's remove_module returns ok",
+       .func = test_remove,
+       .config = {
+               [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modinfo/",
+               [TC_DELETE_MODULE_RETCODES] = "bla:1:20",
+       },
+       .need_spawn = true,
+};
+
 static const struct test *tests[] = {
        &stest_initlib,
        &stest_insert,
+       &stest_remove,
        NULL,
 };
 
index b66427f..1f824f1 100644 (file)
@@ -35,6 +35,7 @@ struct _env_config {
        [TC_UNAME_R] = { S_TC_UNAME_R, OVERRIDE_LIBDIR  "uname.so" },
        [TC_ROOTFS] = { S_TC_ROOTFS, OVERRIDE_LIBDIR "path.so" },
        [TC_INIT_MODULE_RETCODES] = { S_TC_INIT_MODULE_RETCODES, OVERRIDE_LIBDIR "init_module.so" },
+       [TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
 };
 
 static void help(void)
index 68c82bb..834ca46 100644 (file)
@@ -11,12 +11,14 @@ enum test_config {
        TC_ROOTFS = 0,
        TC_UNAME_R,
        TC_INIT_MODULE_RETCODES,
+       TC_DELETE_MODULE_RETCODES,
        _TC_LAST,
 };
 
 #define S_TC_ROOTFS "TESTSUITE_ROOTFS"
 #define S_TC_UNAME_R "TESTSUITE_UNAME_R"
 #define S_TC_INIT_MODULE_RETCODES "TESTSUITE_INIT_MODULE_RETCODES"
+#define S_TC_DELETE_MODULE_RETCODES "TESTSUITE_DELETE_MODULE_RETCODES"
 
 
 struct test {