Home | History | Annotate | Download | only in testsuite
      1 /*
      2  * Copyright (C) 2012-2013  ProFUSION embedded systems
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2.1 of the License, or (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public
     15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #pragma once
     19 
     20 #include <stdbool.h>
     21 #include <stdarg.h>
     22 #include <stdio.h>
     23 
     24 #include <shared/macro.h>
     25 
     26 struct test;
     27 typedef int (*testfunc)(const struct test *t);
     28 
     29 enum test_config {
     30 	/*
     31 	 * Where's the roots dir for this test. It will LD_PRELOAD path.so in
     32 	 * order to trap calls to functions using paths.
     33 	 */
     34 	TC_ROOTFS = 0,
     35 
     36 	/*
     37 	 * What's the desired string to be returned by `uname -r`. It will
     38 	 * trap calls to uname(3P) by LD_PRELOAD'ing uname.so and then filling
     39 	 * in the information in u.release.
     40 	 */
     41 	TC_UNAME_R,
     42 
     43 	/*
     44 	 * Fake calls to init_module(2), returning return-code and setting
     45 	 * errno to err-code. Set this variable with the following format:
     46 	 *
     47 	 *        modname:return-code:err-code
     48 	 *
     49 	 * When this variable is used, all calls to init_module() are trapped
     50 	 * and by default the return code is 0. In other words, they fake
     51 	 * "success" for all modules, except the ones in the list above, for
     52 	 * which the return codes are used.
     53 	 */
     54 	TC_INIT_MODULE_RETCODES,
     55 
     56 	/*
     57 	 * Fake calls to delete_module(2), returning return-code and setting
     58 	 * errno to err-code. Set this variable with the following format:
     59 	 *
     60 	 *        modname:return-code:err-code
     61 	 *
     62 	 * When this variable is used, all calls to init_module() are trapped
     63 	 * and by default the return code is 0. In other words, they fake
     64 	 * "success" for all modules, except the ones in the list above, for
     65 	 * which the return codes are used.
     66 	 */
     67 	TC_DELETE_MODULE_RETCODES,
     68 
     69 	_TC_LAST,
     70 };
     71 
     72 #define S_TC_ROOTFS "TESTSUITE_ROOTFS"
     73 #define S_TC_UNAME_R "TESTSUITE_UNAME_R"
     74 #define S_TC_INIT_MODULE_RETCODES "TESTSUITE_INIT_MODULE_RETCODES"
     75 #define S_TC_DELETE_MODULE_RETCODES "TESTSUITE_DELETE_MODULE_RETCODES"
     76 
     77 struct keyval {
     78 	const char *key;
     79 	const char *val;
     80 };
     81 
     82 struct test {
     83 	const char *name;
     84 	const char *description;
     85 	struct {
     86 		/* File with correct stdout */
     87 		const char *out;
     88 		/* File with correct stderr */
     89 		const char *err;
     90 
     91 		/*
     92 		 * whether to treat the correct files as regex to the real
     93 		 * output
     94 		 */
     95 		bool regex;
     96 
     97 		/*
     98 		 * Vector with pair of files
     99 		 * key = correct file
    100 		 * val = file to check
    101 		 */
    102 		const struct keyval *files;
    103 	} output;
    104 	/* comma-separated list of loaded modules at the end of the test */
    105 	const char *modules_loaded;
    106 	testfunc func;
    107 	const char *config[_TC_LAST];
    108 	const char *path;
    109 	const struct keyval *env_vars;
    110 	bool need_spawn;
    111 	bool expected_fail;
    112 	bool print_outputs;
    113 } __attribute__((aligned(8)));
    114 
    115 
    116 int test_init(const struct test *start, const struct test *stop,
    117 	      int argc, char *const argv[]);
    118 const struct test *test_find(const struct test *start, const struct test *stop,
    119 			     const char *name);
    120 int test_spawn_prog(const char *prog, const char *const args[]);
    121 int test_run(const struct test *t);
    122 
    123 #define TS_EXPORT __attribute__ ((visibility("default")))
    124 
    125 #define _LOG(prefix, fmt, ...) printf("TESTSUITE: " prefix fmt, ## __VA_ARGS__)
    126 #define LOG(fmt, ...) _LOG("", fmt, ## __VA_ARGS__)
    127 #define WARN(fmt, ...) _LOG("WARN: ", fmt, ## __VA_ARGS__)
    128 #define ERR(fmt, ...) _LOG("ERR: ", fmt, ## __VA_ARGS__)
    129 
    130 #define assert_return(expr, r)						\
    131 	do {								\
    132 		if ((!(expr))) {					\
    133 			ERR("Failed assertion: " #expr " %s:%d %s\n",	\
    134 			    __FILE__, __LINE__, __PRETTY_FUNCTION__);	\
    135 			return (r);					\
    136 		}							\
    137 	} while (false)
    138 
    139 
    140 /* Test definitions */
    141 #define DEFINE_TEST(_name, ...) \
    142 	static const struct test s##_name##UNIQ \
    143 	__attribute__((used, section("kmod_tests"), aligned(8))) = { \
    144 		.name = #_name, \
    145 		.func = _name, \
    146 		## __VA_ARGS__ \
    147 	};
    148 
    149 #define TESTSUITE_MAIN() \
    150 	extern struct test __start_kmod_tests[] __attribute__((weak, visibility("hidden")));	\
    151 	extern struct test __stop_kmod_tests[] __attribute__((weak, visibility("hidden")));	\
    152 	int main(int argc, char *argv[])							\
    153 	{											\
    154 		const struct test *t;								\
    155 		int arg;									\
    156 												\
    157 		arg = test_init(__start_kmod_tests, __stop_kmod_tests, argc, argv);		\
    158 		if (arg == 0)									\
    159 			return 0;								\
    160 		if (arg < 0)									\
    161 			return EXIT_FAILURE;							\
    162 												\
    163 		if (arg < argc) {								\
    164 			t = test_find(__start_kmod_tests, __stop_kmod_tests, argv[arg]);	\
    165 			if (t == NULL) {							\
    166 				fprintf(stderr, "could not find test %s\n", argv[arg]);		\
    167 				exit(EXIT_FAILURE);						\
    168 			}									\
    169 												\
    170 			return test_run(t);							\
    171 		}										\
    172 												\
    173 		for (t = __start_kmod_tests; t < __stop_kmod_tests; t++) {			\
    174 			if (test_run(t) != 0)							\
    175 				exit(EXIT_FAILURE);						\
    176 		}										\
    177 												\
    178 		exit(EXIT_SUCCESS);								\
    179 	}											\
    180 
    181 #ifdef noreturn
    182 # define __noreturn noreturn
    183 #elif __STDC_VERSION__ >= 201112L
    184 # define __noreturn _Noreturn
    185 #else
    186 # define __noreturn __attribute__((noreturn))
    187 #endif
    188