xref: /aosp_15_r20/external/kmod/testsuite/testsuite.h (revision cc4ad7da8cefe208cb129ac2aa9a357c7c72deb2)
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 	/* allow to skip tests that don't meet compile-time dependencies */
113 	bool skip;
114 	bool print_outputs;
115 } __attribute__((aligned(8)));
116 
117 
118 int test_init(const struct test *start, const struct test *stop,
119 	      int argc, char *const argv[]);
120 const struct test *test_find(const struct test *start, const struct test *stop,
121 			     const char *name);
122 int test_spawn_prog(const char *prog, const char *const args[]);
123 int test_run(const struct test *t);
124 
125 #define TS_EXPORT __attribute__ ((visibility("default")))
126 
127 #define _LOG(prefix, fmt, ...) printf("TESTSUITE: " prefix fmt, ## __VA_ARGS__)
128 #define LOG(fmt, ...) _LOG("", fmt, ## __VA_ARGS__)
129 #define WARN(fmt, ...) _LOG("WARN: ", fmt, ## __VA_ARGS__)
130 #define ERR(fmt, ...) _LOG("ERR: ", fmt, ## __VA_ARGS__)
131 
132 #define assert_return(expr, r)						\
133 	do {								\
134 		if ((!(expr))) {					\
135 			ERR("Failed assertion: " #expr " %s:%d %s\n",	\
136 			    __FILE__, __LINE__, __PRETTY_FUNCTION__);	\
137 			return (r);					\
138 		}							\
139 	} while (false)
140 
141 
142 /* Test definitions */
143 #define DEFINE_TEST_WITH_FUNC(_name, _func, ...) \
144 	static const struct test UNIQ(s##_name) \
145 	__attribute__((used, section("kmod_tests"), aligned(8))) = { \
146 		.name = #_name, \
147 		.func = _func, \
148 		## __VA_ARGS__ \
149 	};
150 
151 #define DEFINE_TEST(_name, ...) DEFINE_TEST_WITH_FUNC(_name, _name, __VA_ARGS__)
152 
153 #define TESTSUITE_MAIN() \
154 	extern struct test __start_kmod_tests[] __attribute__((weak, visibility("hidden")));	\
155 	extern struct test __stop_kmod_tests[] __attribute__((weak, visibility("hidden")));	\
156 	int main(int argc, char *argv[])							\
157 	{											\
158 		const struct test *t;								\
159 		int arg;									\
160 												\
161 		arg = test_init(__start_kmod_tests, __stop_kmod_tests, argc, argv);		\
162 		if (arg == 0)									\
163 			return 0;								\
164 		if (arg < 0)									\
165 			return EXIT_FAILURE;							\
166 												\
167 		if (arg < argc) {								\
168 			t = test_find(__start_kmod_tests, __stop_kmod_tests, argv[arg]);	\
169 			if (t == NULL) {							\
170 				fprintf(stderr, "could not find test %s\n", argv[arg]);		\
171 				exit(EXIT_FAILURE);						\
172 			}									\
173 												\
174 			return test_run(t);							\
175 		}										\
176 												\
177 		for (t = __start_kmod_tests; t < __stop_kmod_tests; t++) {			\
178 			if (test_run(t) != 0)							\
179 				exit(EXIT_FAILURE);						\
180 		}										\
181 												\
182 		exit(EXIT_SUCCESS);								\
183 	}											\
184 
185 #ifdef noreturn
186 # define __noreturn noreturn
187 #elif __STDC_VERSION__ >= 201112L
188 # define __noreturn _Noreturn
189 #else
190 # define __noreturn __attribute__((noreturn))
191 #endif
192