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