]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - tools/perf/tests/builtin-test.c
perf test: Add infrastructure to run shell based tests
[thirdparty/kernel/stable.git] / tools / perf / tests / builtin-test.c
index 3ccfd58a8c3cf3e8b16cc513a67324b8f11eae7b..2bd158e3c02fa448d60a03869dc9efa8dc667849 100644 (file)
@@ -6,7 +6,10 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 #include "builtin.h"
 #include "hist.h"
 #include "intlist.h"
 #include "debug.h"
 #include "color.h"
 #include <subcmd/parse-options.h>
+#include "string2.h"
 #include "symbol.h"
 #include <linux/kernel.h>
+#include <subcmd/exec-cmd.h>
 
 static bool dont_fork;
 
@@ -179,7 +184,7 @@ static struct test generic_tests[] = {
        },
        {
                .desc = "Session topology",
-               .func = test_session_topology,
+               .func = test__session_topology,
        },
        {
                .desc = "BPF filter",
@@ -325,7 +330,7 @@ static int run_test(struct test *test, int subtest)
                        }
                }
 
-               err = test->func(subtest);
+               err = test->func(test, subtest);
                if (!dont_fork)
                        exit(err);
        }
@@ -383,12 +388,143 @@ static int test_and_print(struct test *t, bool force_skip, int subtest)
        return err;
 }
 
+static const char *shell_test__description(char *description, size_t size,
+                                          const char *path, const char *name)
+{
+       FILE *fp;
+       char filename[PATH_MAX];
+
+       path__join(filename, sizeof(filename), path, name);
+       fp = fopen(filename, "r");
+       if (!fp)
+               return NULL;
+
+       description = fgets(description, size, fp);
+       fclose(fp);
+
+       return description ? trim(description + 1) : NULL;
+}
+
+#define for_each_shell_test(dir, ent)          \
+       while ((ent = readdir(dir)) != NULL)    \
+               if (ent->d_type == DT_REG && ent->d_name[0] != '.')
+
+static const char *shell_tests__dir(char *path, size_t size)
+{
+       const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
+        char *exec_path;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
+               struct stat st;
+               if (!lstat(devel_dirs[i], &st)) {
+                       scnprintf(path, size, "%s/shell", devel_dirs[i]);
+                       if (!lstat(devel_dirs[i], &st))
+                               return path;
+               }
+       }
+
+        /* Then installed path. */
+        exec_path = get_argv_exec_path();
+        scnprintf(path, size, "%s/tests/shell", exec_path);
+       free(exec_path);
+       return path;
+}
+
+static int shell_tests__max_desc_width(void)
+{
+       DIR *dir;
+       struct dirent *ent;
+       char path_dir[PATH_MAX];
+       const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
+       int width = 0;
+
+       if (path == NULL)
+               return -1;
+
+       dir = opendir(path);
+       if (!dir)
+               return -1;
+
+       for_each_shell_test(dir, ent) {
+               char bf[256];
+               const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name);
+
+               if (desc) {
+                       int len = strlen(desc);
+
+                       if (width < len)
+                               width = len;
+               }
+       }
+
+       closedir(dir);
+       return width;
+}
+
+struct shell_test {
+       const char *dir;
+       const char *file;
+};
+
+static int shell_test__run(struct test *test, int subdir __maybe_unused)
+{
+       int err;
+       char script[PATH_MAX];
+       struct shell_test *st = test->priv;
+
+       path__join(script, sizeof(script), st->dir, st->file);
+
+       err = system(script);
+       if (!err)
+               return TEST_OK;
+
+       return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
+}
+
+static int run_shell_tests(int argc, const char *argv[], int i, int width)
+{
+       DIR *dir;
+       struct dirent *ent;
+       char path_dir[PATH_MAX];
+       struct shell_test st = {
+               .dir = shell_tests__dir(path_dir, sizeof(path_dir)),
+       };
+
+       if (st.dir == NULL)
+               return -1;
+
+       dir = opendir(st.dir);
+       if (!dir)
+               return -1;
+
+       for_each_shell_test(dir, ent) {
+               int curr = i++;
+               char desc[256];
+               struct test test = {
+                       .desc = shell_test__description(desc, sizeof(desc), st.dir, ent->d_name),
+                       .func = shell_test__run,
+                       .priv = &st,
+               };
+
+               if (!perf_test__matches(&test, curr, argc, argv))
+                       continue;
+
+               st.file = ent->d_name;
+               pr_info("%2d: %-*s:", i, width, test.desc);
+               test_and_print(&test, false, -1);
+       }
+
+       closedir(dir);
+       return 0;
+}
+
 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 {
        struct test *t;
        unsigned int j;
        int i = 0;
-       int width = 0;
+       int width = shell_tests__max_desc_width();
 
        for_each_test(j, t) {
                int len = strlen(t->desc);
@@ -455,6 +591,36 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
                }
        }
 
+       return run_shell_tests(argc, argv, i, width);
+}
+
+static int perf_test__list_shell(int argc, const char **argv, int i)
+{
+       DIR *dir;
+       struct dirent *ent;
+       char path_dir[PATH_MAX];
+       const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
+
+       if (path == NULL)
+               return -1;
+
+       dir = opendir(path);
+       if (!dir)
+               return -1;
+
+       for_each_shell_test(dir, ent) {
+               char bf[256];
+               const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name);
+
+               ++i;
+
+               if (argc > 1 && !strstr(desc, argv[1]))
+                       continue;
+
+               pr_info("%2d: %s\n", i, desc);
+       }
+
+       closedir(dir);
        return 0;
 }
 
@@ -465,12 +631,16 @@ static int perf_test__list(int argc, const char **argv)
        int i = 0;
 
        for_each_test(j, t) {
+               ++i;
+
                if (argc > 1 && !strstr(t->desc, argv[1]))
                        continue;
 
-               pr_info("%2d: %s\n", ++i, t->desc);
+               pr_info("%2d: %s\n", i, t->desc);
        }
 
+       perf_test__list_shell(argc, argv, i);
+
        return 0;
 }