xref: /kernel/linux/linux-6.6/lib/kunit/kunit-test.c (revision 62306a36)
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
13struct kunit_try_catch_test_context {
14	struct kunit_try_catch *try_catch;
15	bool function_called;
16};
17
18static 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
26static 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
33static 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
47static 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
57static 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
65static 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
79static 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
95static 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
101static 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 */
111struct kunit_test_resource_context {
112	struct kunit test;
113	bool is_resource_initialized;
114	int allocate_order[2];
115	int free_order[4];
116};
117
118static 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
127static void fake_resource_free(struct kunit_resource *res)
128{
129	bool *is_resource_initialized = res->data;
130
131	*is_resource_initialized = false;
132}
133
134static 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
143static 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
165static 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 */
180static 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
201static 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
235static 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
255static 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
272static 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
283static 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
290static 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
310static 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 */
322static 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
355static 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
370static 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
406static void increment_int(void *ctx)
407{
408	int *i = (int *)ctx;
409	(*i)++;
410}
411
412static void kunit_resource_test_action(struct kunit *test)
413{
414	int num_actions = 0;
415
416	kunit_add_action(test, increment_int, &num_actions);
417	KUNIT_EXPECT_EQ(test, num_actions, 0);
418	kunit_cleanup(test);
419	KUNIT_EXPECT_EQ(test, num_actions, 1);
420
421	/* Once we've cleaned up, the action queue is empty. */
422	kunit_cleanup(test);
423	KUNIT_EXPECT_EQ(test, num_actions, 1);
424
425	/* Check the same function can be deferred multiple times. */
426	kunit_add_action(test, increment_int, &num_actions);
427	kunit_add_action(test, increment_int, &num_actions);
428	kunit_cleanup(test);
429	KUNIT_EXPECT_EQ(test, num_actions, 3);
430}
431static void kunit_resource_test_remove_action(struct kunit *test)
432{
433	int num_actions = 0;
434
435	kunit_add_action(test, increment_int, &num_actions);
436	KUNIT_EXPECT_EQ(test, num_actions, 0);
437
438	kunit_remove_action(test, increment_int, &num_actions);
439	kunit_cleanup(test);
440	KUNIT_EXPECT_EQ(test, num_actions, 0);
441}
442static void kunit_resource_test_release_action(struct kunit *test)
443{
444	int num_actions = 0;
445
446	kunit_add_action(test, increment_int, &num_actions);
447	KUNIT_EXPECT_EQ(test, num_actions, 0);
448	/* Runs immediately on trigger. */
449	kunit_release_action(test, increment_int, &num_actions);
450	KUNIT_EXPECT_EQ(test, num_actions, 1);
451
452	/* Doesn't run again on test exit. */
453	kunit_cleanup(test);
454	KUNIT_EXPECT_EQ(test, num_actions, 1);
455}
456static void action_order_1(void *ctx)
457{
458	struct kunit_test_resource_context *res_ctx = (struct kunit_test_resource_context *)ctx;
459
460	KUNIT_RESOURCE_TEST_MARK_ORDER(res_ctx, free_order, 1);
461	kunit_log(KERN_INFO, current->kunit_test, "action_order_1");
462}
463static void action_order_2(void *ctx)
464{
465	struct kunit_test_resource_context *res_ctx = (struct kunit_test_resource_context *)ctx;
466
467	KUNIT_RESOURCE_TEST_MARK_ORDER(res_ctx, free_order, 2);
468	kunit_log(KERN_INFO, current->kunit_test, "action_order_2");
469}
470static void kunit_resource_test_action_ordering(struct kunit *test)
471{
472	struct kunit_test_resource_context *ctx = test->priv;
473
474	kunit_add_action(test, action_order_1, ctx);
475	kunit_add_action(test, action_order_2, ctx);
476	kunit_add_action(test, action_order_1, ctx);
477	kunit_add_action(test, action_order_2, ctx);
478	kunit_remove_action(test, action_order_1, ctx);
479	kunit_release_action(test, action_order_2, ctx);
480	kunit_cleanup(test);
481
482	/* [2 is triggered] [2], [(1 is cancelled)] [1] */
483	KUNIT_EXPECT_EQ(test, ctx->free_order[0], 2);
484	KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
485	KUNIT_EXPECT_EQ(test, ctx->free_order[2], 1);
486}
487
488static int kunit_resource_test_init(struct kunit *test)
489{
490	struct kunit_test_resource_context *ctx =
491			kzalloc(sizeof(*ctx), GFP_KERNEL);
492
493	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
494
495	test->priv = ctx;
496
497	kunit_init_test(&ctx->test, "test_test_context", NULL);
498
499	return 0;
500}
501
502static void kunit_resource_test_exit(struct kunit *test)
503{
504	struct kunit_test_resource_context *ctx = test->priv;
505
506	kunit_cleanup(&ctx->test);
507	kfree(ctx);
508}
509
510static struct kunit_case kunit_resource_test_cases[] = {
511	KUNIT_CASE(kunit_resource_test_init_resources),
512	KUNIT_CASE(kunit_resource_test_alloc_resource),
513	KUNIT_CASE(kunit_resource_test_destroy_resource),
514	KUNIT_CASE(kunit_resource_test_remove_resource),
515	KUNIT_CASE(kunit_resource_test_cleanup_resources),
516	KUNIT_CASE(kunit_resource_test_proper_free_ordering),
517	KUNIT_CASE(kunit_resource_test_static),
518	KUNIT_CASE(kunit_resource_test_named),
519	KUNIT_CASE(kunit_resource_test_action),
520	KUNIT_CASE(kunit_resource_test_remove_action),
521	KUNIT_CASE(kunit_resource_test_release_action),
522	KUNIT_CASE(kunit_resource_test_action_ordering),
523	{}
524};
525
526static struct kunit_suite kunit_resource_test_suite = {
527	.name = "kunit-resource-test",
528	.init = kunit_resource_test_init,
529	.exit = kunit_resource_test_exit,
530	.test_cases = kunit_resource_test_cases,
531};
532
533static void kunit_log_test(struct kunit *test)
534{
535	struct kunit_suite suite;
536
537	suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL);
538	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log);
539
540	kunit_log(KERN_INFO, test, "put this in log.");
541	kunit_log(KERN_INFO, test, "this too.");
542	kunit_log(KERN_INFO, &suite, "add to suite log.");
543	kunit_log(KERN_INFO, &suite, "along with this.");
544
545#ifdef CONFIG_KUNIT_DEBUGFS
546	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
547				     strstr(test->log, "put this in log."));
548	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
549				     strstr(test->log, "this too."));
550	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
551				     strstr(suite.log, "add to suite log."));
552	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
553				     strstr(suite.log, "along with this."));
554#else
555	KUNIT_EXPECT_NULL(test, test->log);
556#endif
557}
558
559static void kunit_log_newline_test(struct kunit *test)
560{
561	kunit_info(test, "Add newline\n");
562	if (test->log) {
563		KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"),
564			"Missing log line, full log:\n%s", test->log);
565		KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n"));
566	} else {
567		kunit_skip(test, "only useful when debugfs is enabled");
568	}
569}
570
571static struct kunit_case kunit_log_test_cases[] = {
572	KUNIT_CASE(kunit_log_test),
573	KUNIT_CASE(kunit_log_newline_test),
574	{}
575};
576
577static struct kunit_suite kunit_log_test_suite = {
578	.name = "kunit-log-test",
579	.test_cases = kunit_log_test_cases,
580};
581
582static void kunit_status_set_failure_test(struct kunit *test)
583{
584	struct kunit fake;
585
586	kunit_init_test(&fake, "fake test", NULL);
587
588	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SUCCESS);
589	kunit_set_failure(&fake);
590	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
591}
592
593static void kunit_status_mark_skipped_test(struct kunit *test)
594{
595	struct kunit fake;
596
597	kunit_init_test(&fake, "fake test", NULL);
598
599	/* Before: Should be SUCCESS with no comment. */
600	KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
601	KUNIT_EXPECT_STREQ(test, fake.status_comment, "");
602
603	/* Mark the test as skipped. */
604	kunit_mark_skipped(&fake, "Accepts format string: %s", "YES");
605
606	/* After: Should be SKIPPED with our comment. */
607	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SKIPPED);
608	KUNIT_EXPECT_STREQ(test, fake.status_comment, "Accepts format string: YES");
609}
610
611static struct kunit_case kunit_status_test_cases[] = {
612	KUNIT_CASE(kunit_status_set_failure_test),
613	KUNIT_CASE(kunit_status_mark_skipped_test),
614	{}
615};
616
617static struct kunit_suite kunit_status_test_suite = {
618	.name = "kunit_status",
619	.test_cases = kunit_status_test_cases,
620};
621
622static void kunit_current_test(struct kunit *test)
623{
624	/* Check results of both current->kunit_test and
625	 * kunit_get_current_test() are equivalent to current test.
626	 */
627	KUNIT_EXPECT_PTR_EQ(test, test, current->kunit_test);
628	KUNIT_EXPECT_PTR_EQ(test, test, kunit_get_current_test());
629}
630
631static void kunit_current_fail_test(struct kunit *test)
632{
633	struct kunit fake;
634
635	kunit_init_test(&fake, "fake test", NULL);
636	KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
637
638	/* Set current->kunit_test to fake test. */
639	current->kunit_test = &fake;
640
641	kunit_fail_current_test("This should make `fake` test fail.");
642	KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
643	kunit_cleanup(&fake);
644
645	/* Reset current->kunit_test to current test. */
646	current->kunit_test = test;
647}
648
649static struct kunit_case kunit_current_test_cases[] = {
650	KUNIT_CASE(kunit_current_test),
651	KUNIT_CASE(kunit_current_fail_test),
652	{}
653};
654
655static struct kunit_suite kunit_current_test_suite = {
656	.name = "kunit_current",
657	.test_cases = kunit_current_test_cases,
658};
659
660kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
661		  &kunit_log_test_suite, &kunit_status_test_suite,
662		  &kunit_current_test_suite);
663
664MODULE_LICENSE("GPL v2");
665