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