Add a ->modules_loaded member to struct test, which is a comma-separated
list of modules that should be present after the test finishes. Both
missing and excess modules cause an error.
---
 testsuite/test-init.c     |    1 +
 testsuite/test-modprobe.c |   13 +++-
 testsuite/testsuite.c     |  158 ++++++++++++++++++++++++++++++++++++++++++++-
 testsuite/testsuite.h     |    2 +
 4 files changed, 168 insertions(+), 6 deletions(-)

diff --git a/testsuite/test-init.c b/testsuite/test-init.c
index 63b6501..d2aa4bd 100644
--- a/testsuite/test-init.c
+++ b/testsuite/test-init.c
@@ -74,6 +74,7 @@ static DEFINE_TEST(test_insert,
                [TC_ROOTFS] = TESTSUITE_ROOTFS "test-init/",
                [TC_INIT_MODULE_RETCODES] = "bla:1:20",
        },
+       .modules_loaded = "ext4",
        .need_spawn = true);
 
 static noreturn int test_remove(const struct test *t)
diff --git a/testsuite/test-modprobe.c b/testsuite/test-modprobe.c
index 637d363..c3ef31e 100644
--- a/testsuite/test-modprobe.c
+++ b/testsuite/test-modprobe.c
@@ -91,7 +91,9 @@ static DEFINE_TEST(modprobe_show_alias_to_none,
        },
        .output = {
                .out = TESTSUITE_ROOTFS 
"test-modprobe/show-depends/correct-psmouse.txt",
-       });
+       },
+       .modules_loaded = "",
+       );
 
 
 static noreturn int modprobe_builtin(const struct test *t)
@@ -131,7 +133,9 @@ static DEFINE_TEST(modprobe_softdep_loop,
                [TC_UNAME_R] = "4.4.4",
                [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/softdep-loop",
                [TC_INIT_MODULE_RETCODES] = "",
-       });
+       },
+       .modules_loaded = "btusb,bluetooth",
+       );
 
 static noreturn int modprobe_install_cmd_loop(const struct test *t)
 {
@@ -156,6 +160,7 @@ static DEFINE_TEST(modprobe_install_cmd_loop,
                { "MODPROBE", ABS_TOP_BUILDDIR "/tools/modprobe" },
                { }
                },
+       .modules_loaded = "snd,snd-pcm",
        );
 
 static noreturn int modprobe_param_kcmdline(const struct test *t)
@@ -178,7 +183,9 @@ static DEFINE_TEST(modprobe_param_kcmdline,
        },
        .output = {
                .out = TESTSUITE_ROOTFS 
"test-modprobe/module-param-kcmdline/correct.txt",
-       });
+       },
+       .modules_loaded = "",
+       );
 
 
 static const struct test *tests[] = {
diff --git a/testsuite/testsuite.c b/testsuite/testsuite.c
index 9877a64..f0fb393 100644
--- a/testsuite/testsuite.c
+++ b/testsuite/testsuite.c
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <limits.h>
+#include <dirent.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -528,12 +529,158 @@ fail:
        return true;
 }
 
+static int cmp_modnames(const void *m1, const void *m2)
+{
+       const char *s1 = *(char * const *)m1;
+       const char *s2 = *(char * const *)m2;
+       int i;
+
+       for (i = 0;; i++) {
+               char c1 = s1[i], c2 = s2[i];
+               if (c1 == ',')
+                       c1 = '\0';
+               if (c1 == '-')
+                       c1 = '_';
+               if (c2 == ',')
+                       c2 = '\0';
+               if (c2 == '-')
+                       c2 = '_';
+
+               if (c1 == '\0' && c2 == '\0')
+                       return 0;
+               if (c1 != c2)
+                       return c1 - c2;
+       }
+}
+
+static const char ** read_expected_modules(const struct test *t, int * count)
+{
+       const char **res;
+       int len;
+       int i;
+       const char *p;
+
+       /*
+        * Store pointers to elements of t->modules_loaded into res
+        * (comma is considered equivalent to NUL)
+        */
+       if (t->modules_loaded[0] == '\0') {
+               *count = 0;
+               return NULL;
+       }
+       len = 1;
+       for (p = t->modules_loaded; *p; p++)
+               if (*p == ',')
+                       len++;
+       res = malloc(sizeof(char *) * len);
+       if (!res) {
+               perror("malloc");
+               *count = -1;
+               return NULL;
+       }
+       i = 0;
+       res[i] = t->modules_loaded;
+       for (p = t->modules_loaded; *p; p++)
+               if (*p == ',')
+                       res[++i] = p + 1;
+       *count = len;
+       return res;
+}
+
+static char ** read_loaded_modules(const struct test *t, int * count)
+{
+       char *dirname;
+       DIR *dir;
+       struct dirent *dirent;
+       int i;
+       int len = 0;
+       char **res = NULL;
+
+       /* Store the entries in /sys/module to res */
+       dirname = malloc(PATH_MAX + 1);
+       if (!dirname) {
+               perror("malloc");
+               *count = -1;
+               return res;
+       }
+       snprintf(dirname, PATH_MAX, "%s/sys/module",
+                       t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "");
+       dir = opendir(dirname);
+       /* not an error, simply return empty list */
+       if (!dir)
+               goto out_dirname;
+       while ((dirent = readdir(dir))) {
+               if (dirent->d_name[0] == '.')
+                       continue;
+               len++;
+       }
+       res = malloc(sizeof(char *) * len);
+       if (!res) {
+               perror("malloc");
+               len = -1;
+               goto out_dir;
+       }
+       rewinddir(dir);
+       i = 0;
+       while ((dirent = readdir(dir))) {
+               if (dirent->d_name[0] == '.')
+                       continue;
+               res[i] = strdup(dirent->d_name);
+               if (!res[i]) {
+                       for (i--; i >= 0; i--)
+                               free(res[i]);
+                       free(res);
+                       res = NULL;
+                       len = -1;
+                       goto out_dir;
+               }
+               i++;
+       }
+out_dir:
+       closedir(dir);
+out_dirname:
+       free(dirname);
+       *count = len;
+       return res;
+}
+
+static int check_loaded_modules(const struct test *t)
+{
+       int l1, l2, i;
+       const char **a1;
+       char **a2;
+       int err = false;
+
+       a1 = read_expected_modules(t, &l1);
+       if (l1 < 0)
+               return err;
+       a2 = read_loaded_modules(t, &l2);
+       if (l2 < 0)
+               goto out_a1;
+       /* TODO: Report which modules are missing/superfluous */
+       if (l1 != l2)
+               goto out_a2;
+       qsort(a1, l1, sizeof(char *), cmp_modnames);
+       qsort(a2, l2, sizeof(char *), cmp_modnames);
+       for (i = 0; i < l1; i++)
+               if (cmp_modnames(&a1[i], &a2[i]) != 0)
+                       goto out_a2;
+       err = true;
+out_a2:
+       for (i = 0; i < l2; i++)
+               free(a2[i]);
+       free(a2);
+out_a1:
+       free(a1);
+       return err;
+}
+
 static inline int test_run_parent(const struct test *t, int fdout[2],
                                int fderr[2], int fdmonitor[2], pid_t child)
 {
        pid_t pid;
        int err;
-       bool matchout;
+       bool matchout, match_modules;
 
        /* Close write-fds */
        if (t->output.out != NULL)
@@ -578,16 +725,21 @@ static inline int test_run_parent(const struct test *t, 
int fdout[2],
 
        if (matchout)
                matchout = check_generated_files(t);
+       if (t->modules_loaded)
+               match_modules = check_loaded_modules(t);
+       else
+               match_modules = true;
 
        if (t->expected_fail == false) {
                if (err == 0) {
-                       if (matchout)
+                       if (matchout && match_modules)
                                LOG("%sPASSED%s: %s\n",
                                        ANSI_HIGHLIGHT_GREEN_ON, 
ANSI_HIGHLIGHT_OFF,
                                        t->name);
                        else {
-                               ERR("%sFAILED%s: exit ok but outputs do not 
match: %s\n",
+                               ERR("%sFAILED%s: exit ok but %s do not match: 
%s\n",
                                        ANSI_HIGHLIGHT_RED_ON, 
ANSI_HIGHLIGHT_OFF,
+                                       matchout ? "loaded modules" : "outputs",
                                        t->name);
                                err = EXIT_FAILURE;
                        }
diff --git a/testsuite/testsuite.h b/testsuite/testsuite.h
index 97183cd..f2a75e5 100644
--- a/testsuite/testsuite.h
+++ b/testsuite/testsuite.h
@@ -95,6 +95,8 @@ struct test {
                 */
                const struct keyval *files;
        } output;
+       /* comma-separated list of loaded modules at the end of the test */
+       const char *modules_loaded;
        testfunc func;
        const char *config[_TC_LAST];
        const char *path;
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to