xref: /openbmc/linux/lib/kunit/kunit-test.c (revision ffcdf473)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit test for core test infrastructure.
4  *
5  * Copyright (C) 2019, Google LLC.
6  * Author: Brendan Higgins <brendanhiggins@google.com>
7  */
8 #include <kunit/test.h>
9 #include <kunit/test-bug.h>
10 
11 #include "try-catch-impl.h"
12 
13 struct kunit_try_catch_test_context {
14 	struct kunit_try_catch *try_catch;
15 	bool function_called;
16 };
17 
18 static void kunit_test_successful_try(void *data)
19 {
20 	struct kunit *test = data;
21 	struct kunit_try_catch_test_context *ctx = test->priv;
22 
23 	ctx->function_called = true;
24 }
25 
26 static void kunit_test_no_catch(void *data)
27 {
28 	struct kunit *test = data;
29 
30 	KUNIT_FAIL(test, "Catch should not be called\n");
31 }
32 
33 static void kunit_test_try_catch_successful_try_no_catch(struct kunit *test)
34 {
35 	struct kunit_try_catch_test_context *ctx = test->priv;
36 	struct kunit_try_catch *try_catch = ctx->try_catch;
37 
38 	kunit_try_catch_init(try_catch,
39 			     test,
40 			     kunit_test_successful_try,
41 			     kunit_test_no_catch);
42 	kunit_try_catch_run(try_catch, test);
43 
44 	KUNIT_EXPECT_TRUE(test, ctx->function_called);
45 }
46 
47 static void kunit_test_unsuccessful_try(void *data)
48 {
49 	struct kunit *test = data;
50 	struct kunit_try_catch_test_context *ctx = test->priv;
51 	struct kunit_try_catch *try_catch = ctx->try_catch;
52 
53 	kunit_try_catch_throw(try_catch);
54 	KUNIT_FAIL(test, "This line should never be reached\n");
55 }
56 
57 static void kunit_test_catch(void *data)
58 {
59 	struct kunit *test = data;
60 	struct kunit_try_catch_test_context *ctx = test->priv;
61 
62 	ctx->function_called = true;
63 }
64 
65 static void kunit_test_try_catch_unsuccessful_try_does_catch(struct kunit *test)
66 {
67 	struct kunit_try_catch_test_context *ctx = test->priv;
68 	struct kunit_try_catch *try_catch = ctx->try_catch;
69 
70 	kunit_try_catch_init(try_catch,
71 			     test,
72 			     kunit_test_unsuccessful_try,
73 			     kunit_test_catch);
74 	kunit_try_catch_run(try_catch, test);
75 
76 	KUNIT_EXPECT_TRUE(test, ctx->function_called);
77 }
78 
79 static int kunit_try_catch_test_init(struct kunit *test)
80 {
81 	struct kunit_try_catch_test_context *ctx;
82 
83 	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
84 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
85 	test->priv = ctx;
86 
87 	ctx->try_catch = kunit_kmalloc(test,
88 				       sizeof(*ctx->try_catch),
89 				       GFP_KERNEL);
90 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch);
91 
92 	return 0;
93 }
94 
95 static struct kunit_case kunit_try_catch_test_cases[] = {
96 	KUNIT_CASE(kunit_test_try_catch_successful_try_no_catch),
97 	KUNIT_CASE(kunit_test_try_catch_unsuccessful_try_does_catch),
98 	{}
99 };
100 
101 static struct kunit_suite kunit_try_catch_test_suite = {
102 	.name = "kunit-try-catch-test",
103 	.init = kunit_try_catch_test_init,
104 	.test_cases = kunit_try_catch_test_cases,
105 };
106 
107 /*
108  * Context for testing test managed resources
109  * is_resource_initialized is used to test arbitrary resources
110  */
111 struct kunit_test_resource_context {
112 	struct kunit test;
113 	bool is_resource_initialized;
114 	int allocate_order[2];
115 	int free_order[2];
116 };
117 
118 static int fake_resource_init(struct kunit_resource *res, void *context)
119 {
120 	struct kunit_test_resource_context *ctx = context;
121 
122 	res->data = &ctx->is_resource_initialized;
123 	ctx->is_resource_initialized = true;
124 	return 0;
125 }
126 
127 static void fake_resource_free(struct kunit_resource *res)
128 {
129 	bool *is_resource_initialized = res->data;
130 
131 	*is_resource_initialized = false;
132 }
133 
134 static void kunit_resource_test_init_resources(struct kunit *test)
135 {
136 	struct kunit_test_resource_context *ctx = test->priv;
137 
138 	kunit_init_test(&ctx->test, "testing_test_init_test", NULL);
139 
140 	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
141 }
142 
143 static void kunit_resource_test_alloc_resource(struct kunit *test)
144 {
145 	struct kunit_test_resource_context *ctx = test->priv;
146 	struct kunit_resource *res;
147 	kunit_resource_free_t free = fake_resource_free;
148 
149 	res = kunit_alloc_and_get_resource(&ctx->test,
150 					   fake_resource_init,
151 					   fake_resource_free,
152 					   GFP_KERNEL,
153 					   ctx);
154 
155 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
156 	KUNIT_EXPECT_PTR_EQ(test,
157 			    &ctx->is_resource_initialized,
158 			    (bool *)res->data);
159 	KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources));
160 	KUNIT_EXPECT_PTR_EQ(test, free, res->free);
161 
162 	kunit_put_resource(res);
163 }
164 
165 static inline bool kunit_resource_instance_match(struct kunit *test,
166 						 struct kunit_resource *res,
167 						 void *match_data)
168 {
169 	return res->data == match_data;
170 }
171 
172 /*
173  * Note: tests below use kunit_alloc_and_get_resource(), so as a consequence
174  * they have a reference to the associated resource that they must release
175  * via kunit_put_resource().  In normal operation, users will only
176  * have to do this for cases where they use kunit_find_resource(), and the
177  * kunit_alloc_resource() function will be used (which does not take a
178  * resource reference).
179  */
180 static void kunit_resource_test_destroy_resource(struct kunit *test)
181 {
182 	struct kunit_test_resource_context *ctx = test->priv;
183 	struct kunit_resource *res = kunit_alloc_and_get_resource(
184 			&ctx->test,
185 			fake_resource_init,
186 			fake_resource_free,
187 			GFP_KERNEL,
188 			ctx);
189 
190 	kunit_put_resource(res);
191 
192 	KUNIT_ASSERT_FALSE(test,
193 			   kunit_destroy_resource(&ctx->test,
194 						  kunit_resource_instance_match,
195 						  res->data));
196 
197 	KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
198 	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
199 }
200 
201 static void kunit_resource_test_remove_resource(struct kunit *test)
202 {
203 	struct kunit_test_resource_context *ctx = test->priv;
204 	struct kunit_resource *res = kunit_alloc_and_get_resource(
205 			&ctx->test,
206 			fake_resource_init,
207 			fake_resource_free,
208 			GFP_KERNEL,
209 			ctx);
210 
211 	/* The resource is in the list */
212 	KUNIT_EXPECT_FALSE(test, list_empty(&ctx->test.resources));
213 
214 	/* Remove the resource. The pointer is still valid, but it can't be
215 	 * found.
216 	 */
217 	kunit_remove_resource(test, res);
218 	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
219 	/* We haven't been freed yet. */
220 	KUNIT_EXPECT_TRUE(test, ctx->is_resource_initialized);
221 
222 	/* Removing the resource multiple times is valid. */
223 	kunit_remove_resource(test, res);
224 	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
225 	/* Despite having been removed twice (from only one reference), the
226 	 * resource still has not been freed.
227 	 */
228 	KUNIT_EXPECT_TRUE(test, ctx->is_resource_initialized);
229 
230 	/* Free the resource. */
231 	kunit_put_resource(res);
232 	KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
233 }
234 
235 static void kunit_resource_test_cleanup_resources(struct kunit *test)
236 {
237 	int i;
238 	struct kunit_test_resource_context *ctx = test->priv;
239 	struct kunit_resource *resources[5];
240 
241 	for (i = 0; i < ARRAY_SIZE(resources); i++) {
242 		resources[i] = kunit_alloc_and_get_resource(&ctx->test,
243 							    fake_resource_init,
244 							    fake_resource_free,
245 							    GFP_KERNEL,
246 							    ctx);
247 		kunit_put_resource(resources[i]);
248 	}
249 
250 	kunit_cleanup(&ctx->test);
251 
252 	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
253 }
254 
255 static void kunit_resource_test_mark_order(int order_array[],
256 					   size_t order_size,
257 					   int key)
258 {
259 	int i;
260 
261 	for (i = 0; i < order_size && order_array[i]; i++)
262 		;
263 
264 	order_array[i] = key;
265 }
266 
267 #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key)		       \
268 		kunit_resource_test_mark_order(ctx->order_field,	       \
269 					       ARRAY_SIZE(ctx->order_field),   \
270 					       key)
271 
272 static int fake_resource_2_init(struct kunit_resource *res, void *context)
273 {
274 	struct kunit_test_resource_context *ctx = context;
275 
276 	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2);
277 
278 	res->data = ctx;
279 
280 	return 0;
281 }
282 
283 static void fake_resource_2_free(struct kunit_resource *res)
284 {
285 	struct kunit_test_resource_context *ctx = res->data;
286 
287 	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
288 }
289 
290 static int fake_resource_1_init(struct kunit_resource *res, void *context)
291 {
292 	struct kunit_test_resource_context *ctx = context;
293 	struct kunit_resource *res2;
294 
295 	res2 = kunit_alloc_and_get_resource(&ctx->test,
296 					    fake_resource_2_init,
297 					    fake_resource_2_free,
298 					    GFP_KERNEL,
299 					    ctx);
300 
301 	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
302 
303 	res->data = ctx;
304 
305 	kunit_put_resource(res2);
306 
307 	return 0;
308 }
309 
310 static void fake_resource_1_free(struct kunit_resource *res)
311 {
312 	struct kunit_test_resource_context *ctx = res->data;
313 
314 	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1);
315 }
316 
317 /*
318  * TODO(brendanhiggins@google.com): replace the arrays that keep track of the
319  * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro
320  * to assert allocation and freeing order when the feature becomes available.
321  */
322 static void kunit_resource_test_proper_free_ordering(struct kunit *test)
323 {
324 	struct kunit_test_resource_context *ctx = test->priv;
325 	struct kunit_resource *res;
326 
327 	/* fake_resource_1 allocates a fake_resource_2 in its init. */
328 	res = kunit_alloc_and_get_resource(&ctx->test,
329 					   fake_resource_1_init,
330 					   fake_resource_1_free,
331 					   GFP_KERNEL,
332 					   ctx);
333 
334 	/*
335 	 * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
336 	 * before returning to fake_resource_1_init, it should be the first to
337 	 * put its key in the allocate_order array.
338 	 */
339 	KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2);
340 	KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1);
341 
342 	kunit_put_resource(res);
343 
344 	kunit_cleanup(&ctx->test);
345 
346 	/*
347 	 * Because fake_resource_2 finishes allocation before fake_resource_1,
348 	 * fake_resource_1 should be freed first since it could depend on
349 	 * fake_resource_2.
350 	 */
351 	KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1);
352 	KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
353 }
354 
355 static void kunit_resource_test_static(struct kunit *test)
356 {
357 	struct kunit_test_resource_context ctx;
358 	struct kunit_resource res;
359 
360 	KUNIT_EXPECT_EQ(test, kunit_add_resource(test, NULL, NULL, &res, &ctx),
361 			0);
362 
363 	KUNIT_EXPECT_PTR_EQ(test, res.data, (void *)&ctx);
364 
365 	kunit_cleanup(test);
366 
367 	KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
368 }
369 
370 static void kunit_resource_test_named(struct kunit *test)
371 {
372 	struct kunit_resource res1, res2, *found = NULL;
373 	struct kunit_test_resource_context ctx;
374 
375 	KUNIT_EXPECT_EQ(test,
376 			kunit_add_named_resource(test, NULL, NULL, &res1,
377 						 "resource_1", &ctx),
378 			0);
379 	KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx);
380 
381 	KUNIT_EXPECT_EQ(test,
382 			kunit_add_named_resource(test, NULL, NULL, &res1,
383 						 "resource_1", &ctx),
384 			-EEXIST);
385 
386 	KUNIT_EXPECT_EQ(test,
387 			kunit_add_named_resource(test, NULL, NULL, &res2,
388 						 "resource_2", &ctx),
389 			0);
390 
391 	found = kunit_find_named_resource(test, "resource_1");
392 
393 	KUNIT_EXPECT_PTR_EQ(test, found, &res1);
394 
395 	if (found)
396 		kunit_put_resource(&res1);
397 
398 	KUNIT_EXPECT_EQ(test, kunit_destroy_named_resource(test, "resource_2"),
399 			0);
400 
401 	kunit_cleanup(test);
402 
403 	KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
404 }
405 
406 static int kunit_resource_test_init(struct kunit *test)
407 {
408 	struct kunit_test_resource_context *ctx =
409 			kzalloc(sizeof(*ctx), GFP_KERNEL);
410 
411 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
412 
413 	test->priv = ctx;
414 
415 	kunit_init_test(&ctx->test, "test_test_context", NULL);
416 
417 	return 0;
418 }
419 
420 static void kunit_resource_test_exit(struct kunit *test)
421 {
422 	struct kunit_test_resource_context *ctx = test->priv;
423 
424 	kunit_cleanup(&ctx->test);
425 	kfree(ctx);
426 }
427 
428 static struct kunit_case kunit_resource_test_cases[] = {
429 	KUNIT_CASE(kunit_resource_test_init_resources),
430 	KUNIT_CASE(kunit_resource_test_alloc_resource),
431 	KUNIT_CASE(kunit_resource_test_destroy_resource),
432 	KUNIT_CASE(kunit_resource_test_remove_resource),
433 	KUNIT_CASE(kunit_resource_test_cleanup_resources),
434 	KUNIT_CASE(kunit_resource_test_proper_free_ordering),
435 	KUNIT_CASE(kunit_resource_test_static),
436 	KUNIT_CASE(kunit_resource_test_named),
437 	{}
438 };
439 
440 static struct kunit_suite kunit_resource_test_suite = {
441 	.name = "kunit-resource-test",
442 	.init = kunit_resource_test_init,
443 	.exit = kunit_resource_test_exit,
444 	.test_cases = kunit_resource_test_cases,
445 };
446 
447 static void kunit_log_test(struct kunit *test)
448 {
449 	struct kunit_suite suite;
450 
451 	suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL);
452 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log);
453 
454 	kunit_log(KERN_INFO, test, "put this in log.");
455 	kunit_log(KERN_INFO, test, "this too.");
456 	kunit_log(KERN_INFO, &suite, "add to suite log.");
457 	kunit_log(KERN_INFO, &suite, "along with this.");
458 
459 #ifdef CONFIG_KUNIT_DEBUGFS
460 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
461 				     strstr(test->log, "put this in log."));
462 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
463 				     strstr(test->log, "this too."));
464 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
465 				     strstr(suite.log, "add to suite log."));
466 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
467 				     strstr(suite.log, "along with this."));
468 #else
469 	KUNIT_EXPECT_NULL(test, test->log);
470 #endif
471 }
472 
473 static void kunit_log_newline_test(struct kunit *test)
474 {
475 	kunit_info(test, "Add newline\n");
476 	if (test->log) {
477 		KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"),
478 			"Missing log line, full log:\n%s", test->log);
479 		KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n"));
480 	} else {
481 		kunit_skip(test, "only useful when debugfs is enabled");
482 	}
483 }
484 
485 static struct kunit_case kunit_log_test_cases[] = {
486 	KUNIT_CASE(kunit_log_test),
487 	KUNIT_CASE(kunit_log_newline_test),
488 	{}
489 };
490 
491 static struct kunit_suite kunit_log_test_suite = {
492 	.name = "kunit-log-test",
493 	.test_cases = kunit_log_test_cases,
494 };
495 
496 static void kunit_status_set_failure_test(struct kunit *test)
497 {
498 	struct kunit fake;
499 
500 	kunit_init_test(&fake, "fake test", NULL);
501 
502 	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SUCCESS);
503 	kunit_set_failure(&fake);
504 	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
505 }
506 
507 static void kunit_status_mark_skipped_test(struct kunit *test)
508 {
509 	struct kunit fake;
510 
511 	kunit_init_test(&fake, "fake test", NULL);
512 
513 	/* Before: Should be SUCCESS with no comment. */
514 	KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
515 	KUNIT_EXPECT_STREQ(test, fake.status_comment, "");
516 
517 	/* Mark the test as skipped. */
518 	kunit_mark_skipped(&fake, "Accepts format string: %s", "YES");
519 
520 	/* After: Should be SKIPPED with our comment. */
521 	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SKIPPED);
522 	KUNIT_EXPECT_STREQ(test, fake.status_comment, "Accepts format string: YES");
523 }
524 
525 static struct kunit_case kunit_status_test_cases[] = {
526 	KUNIT_CASE(kunit_status_set_failure_test),
527 	KUNIT_CASE(kunit_status_mark_skipped_test),
528 	{}
529 };
530 
531 static struct kunit_suite kunit_status_test_suite = {
532 	.name = "kunit_status",
533 	.test_cases = kunit_status_test_cases,
534 };
535 
536 static void kunit_current_test(struct kunit *test)
537 {
538 	/* Check results of both current->kunit_test and
539 	 * kunit_get_current_test() are equivalent to current test.
540 	 */
541 	KUNIT_EXPECT_PTR_EQ(test, test, current->kunit_test);
542 	KUNIT_EXPECT_PTR_EQ(test, test, kunit_get_current_test());
543 }
544 
545 static void kunit_current_fail_test(struct kunit *test)
546 {
547 	struct kunit fake;
548 
549 	kunit_init_test(&fake, "fake test", NULL);
550 	KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
551 
552 	/* Set current->kunit_test to fake test. */
553 	current->kunit_test = &fake;
554 
555 	kunit_fail_current_test("This should make `fake` test fail.");
556 	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
557 	kunit_cleanup(&fake);
558 
559 	/* Reset current->kunit_test to current test. */
560 	current->kunit_test = test;
561 }
562 
563 static struct kunit_case kunit_current_test_cases[] = {
564 	KUNIT_CASE(kunit_current_test),
565 	KUNIT_CASE(kunit_current_fail_test),
566 	{}
567 };
568 
569 static struct kunit_suite kunit_current_test_suite = {
570 	.name = "kunit_current",
571 	.test_cases = kunit_current_test_cases,
572 };
573 
574 kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
575 		  &kunit_log_test_suite, &kunit_status_test_suite,
576 		  &kunit_current_test_suite);
577 
578 MODULE_LICENSE("GPL v2");
579