LCOV - code coverage report
Current view: top level - lib/kunit - executor.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 68 96 70.8 %
Date: 2023-08-24 13:40:31 Functions: 7 8 87.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : 
       3             : #include <linux/reboot.h>
       4             : #include <kunit/test.h>
       5             : #include <linux/glob.h>
       6             : #include <linux/moduleparam.h>
       7             : 
       8             : /*
       9             :  * These symbols point to the .kunit_test_suites section and are defined in
      10             :  * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
      11             :  */
      12             : extern struct kunit_suite * const __kunit_suites_start[];
      13             : extern struct kunit_suite * const __kunit_suites_end[];
      14             : 
      15             : #if IS_BUILTIN(CONFIG_KUNIT)
      16             : 
      17             : static char *filter_glob_param;
      18             : static char *action_param;
      19             : 
      20             : module_param_named(filter_glob, filter_glob_param, charp, 0);
      21             : MODULE_PARM_DESC(filter_glob,
      22             :                 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
      23             : module_param_named(action, action_param, charp, 0);
      24             : MODULE_PARM_DESC(action,
      25             :                  "Changes KUnit executor behavior, valid values are:\n"
      26             :                  "<none>: run the tests like normal\n"
      27             :                  "'list' to list test names instead of running them.\n");
      28             : 
      29             : /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
      30             : struct kunit_test_filter {
      31             :         char *suite_glob;
      32             :         char *test_glob;
      33             : };
      34             : 
      35             : /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
      36           1 : static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
      37             :                                     const char *filter_glob)
      38             : {
      39           1 :         const int len = strlen(filter_glob);
      40           1 :         const char *period = strchr(filter_glob, '.');
      41             : 
      42           1 :         if (!period) {
      43           1 :                 parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL);
      44           1 :                 parsed->test_glob = NULL;
      45           1 :                 strcpy(parsed->suite_glob, filter_glob);
      46             :                 return;
      47             :         }
      48             : 
      49           0 :         parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL);
      50           0 :         parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL);
      51             : 
      52           0 :         strncpy(parsed->suite_glob, filter_glob, period - filter_glob);
      53           0 :         strncpy(parsed->test_glob, period + 1, len - (period - filter_glob));
      54             : }
      55             : 
      56             : /* Create a copy of suite with only tests that match test_glob. */
      57             : static struct kunit_suite *
      58           1 : kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
      59             : {
      60           1 :         int n = 0;
      61             :         struct kunit_case *filtered, *test_case;
      62             :         struct kunit_suite *copy;
      63             : 
      64          18 :         kunit_suite_for_each_test_case(suite, test_case) {
      65          17 :                 if (!test_glob || glob_match(test_glob, test_case->name))
      66          17 :                         ++n;
      67             :         }
      68             : 
      69           1 :         if (n == 0)
      70             :                 return NULL;
      71             : 
      72           1 :         copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL);
      73           1 :         if (!copy)
      74             :                 return ERR_PTR(-ENOMEM);
      75             : 
      76           2 :         filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
      77           1 :         if (!filtered) {
      78           0 :                 kfree(copy);
      79           0 :                 return ERR_PTR(-ENOMEM);
      80             :         }
      81             : 
      82           1 :         n = 0;
      83          18 :         kunit_suite_for_each_test_case(suite, test_case) {
      84          17 :                 if (!test_glob || glob_match(test_glob, test_case->name))
      85          17 :                         filtered[n++] = *test_case;
      86             :         }
      87             : 
      88           1 :         copy->test_cases = filtered;
      89           1 :         return copy;
      90             : }
      91             : 
      92             : static char *kunit_shutdown;
      93             : core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
      94             : 
      95             : /* Stores an array of suites, end points one past the end */
      96             : struct suite_set {
      97             :         struct kunit_suite * const *start;
      98             :         struct kunit_suite * const *end;
      99             : };
     100             : 
     101           1 : static void kunit_free_suite_set(struct suite_set suite_set)
     102             : {
     103             :         struct kunit_suite * const *suites;
     104             : 
     105           2 :         for (suites = suite_set.start; suites < suite_set.end; suites++)
     106           1 :                 kfree(*suites);
     107           1 :         kfree(suite_set.start);
     108           1 : }
     109             : 
     110           1 : static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
     111             :                                             const char *filter_glob,
     112             :                                             int *err)
     113             : {
     114             :         int i;
     115             :         struct kunit_suite **copy, *filtered_suite;
     116             :         struct suite_set filtered;
     117             :         struct kunit_test_filter filter;
     118             : 
     119           1 :         const size_t max = suite_set->end - suite_set->start;
     120             : 
     121           1 :         copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
     122           1 :         filtered.start = copy;
     123           1 :         if (!copy) { /* won't be able to run anything, return an empty set */
     124           0 :                 filtered.end = copy;
     125           0 :                 return filtered;
     126             :         }
     127             : 
     128           1 :         kunit_parse_filter_glob(&filter, filter_glob);
     129             : 
     130          17 :         for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
     131          16 :                 if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
     132          15 :                         continue;
     133             : 
     134           1 :                 filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
     135           1 :                 if (IS_ERR(filtered_suite)) {
     136           0 :                         *err = PTR_ERR(filtered_suite);
     137           0 :                         return filtered;
     138             :                 }
     139           1 :                 if (!filtered_suite)
     140           0 :                         continue;
     141             : 
     142           1 :                 *copy++ = filtered_suite;
     143             :         }
     144           1 :         filtered.end = copy;
     145             : 
     146           1 :         kfree(filter.suite_glob);
     147           1 :         kfree(filter.test_glob);
     148           1 :         return filtered;
     149             : }
     150             : 
     151           1 : static void kunit_handle_shutdown(void)
     152             : {
     153           1 :         if (!kunit_shutdown)
     154             :                 return;
     155             : 
     156           1 :         if (!strcmp(kunit_shutdown, "poweroff"))
     157           0 :                 kernel_power_off();
     158           1 :         else if (!strcmp(kunit_shutdown, "halt"))
     159           1 :                 kernel_halt();
     160           0 :         else if (!strcmp(kunit_shutdown, "reboot"))
     161           0 :                 kernel_restart(NULL);
     162             : 
     163             : }
     164             : 
     165           1 : static void kunit_exec_run_tests(struct suite_set *suite_set)
     166             : {
     167           1 :         size_t num_suites = suite_set->end - suite_set->start;
     168             : 
     169           1 :         pr_info("KTAP version 1\n");
     170           1 :         pr_info("1..%zu\n", num_suites);
     171             : 
     172           1 :         __kunit_test_suites_init(suite_set->start, num_suites);
     173           1 : }
     174             : 
     175           0 : static void kunit_exec_list_tests(struct suite_set *suite_set)
     176             : {
     177             :         struct kunit_suite * const *suites;
     178             :         struct kunit_case *test_case;
     179             : 
     180             :         /* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
     181           0 :         pr_info("KTAP version 1\n");
     182             : 
     183           0 :         for (suites = suite_set->start; suites < suite_set->end; suites++)
     184           0 :                 kunit_suite_for_each_test_case((*suites), test_case) {
     185           0 :                         pr_info("%s.%s\n", (*suites)->name, test_case->name);
     186             :                 }
     187           0 : }
     188             : 
     189           1 : int kunit_run_all_tests(void)
     190             : {
     191           1 :         struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
     192           1 :         int err = 0;
     193           1 :         if (!kunit_enabled()) {
     194           0 :                 pr_info("kunit: disabled\n");
     195           0 :                 goto out;
     196             :         }
     197             : 
     198           1 :         if (filter_glob_param) {
     199           1 :                 suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
     200           1 :                 if (err) {
     201           0 :                         pr_err("kunit executor: error filtering suites: %d\n", err);
     202           0 :                         goto out;
     203             :                 }
     204             :         }
     205             : 
     206           1 :         if (!action_param)
     207           1 :                 kunit_exec_run_tests(&suite_set);
     208           0 :         else if (strcmp(action_param, "list") == 0)
     209           0 :                 kunit_exec_list_tests(&suite_set);
     210             :         else
     211           0 :                 pr_err("kunit executor: unknown action '%s'\n", action_param);
     212             : 
     213           1 :         if (filter_glob_param) { /* a copy was made of each suite */
     214           1 :                 kunit_free_suite_set(suite_set);
     215             :         }
     216             : 
     217             : out:
     218           1 :         kunit_handle_shutdown();
     219           0 :         return err;
     220             : }
     221             : 
     222             : #if IS_BUILTIN(CONFIG_KUNIT_TEST)
     223             : #include "executor_test.c"
     224             : #endif
     225             : 
     226             : #endif /* IS_BUILTIN(CONFIG_KUNIT) */

Generated by: LCOV version 1.14