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 10 #include "try-catch-impl.h" 11 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); 83 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 84 test->priv = ctx; 85 86 ctx->try_catch = kunit_kmalloc(test, 87 sizeof(*ctx->try_catch), 88 GFP_KERNEL); 89 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch); 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 }; 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 121 res->data = &ctx->is_resource_initialized; 122 ctx->is_resource_initialized = true; 123 return 0; 124 } 125 126 static void fake_resource_free(struct kunit_resource *res) 127 { 128 bool *is_resource_initialized = res->data; 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 137 kunit_init_test(&ctx->test, "testing_test_init_test", NULL); 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, 157 (bool *)res->data); 158 KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources)); 159 KUNIT_EXPECT_PTR_EQ(test, free, res->free); 160 161 kunit_put_resource(res); 162 } 163 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 */ 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 182 kunit_put_resource(res); 183 184 KUNIT_ASSERT_FALSE(test, 185 kunit_destroy_resource(&ctx->test, 186 kunit_resource_instance_match, 187 res->data)); 188 189 KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized); 190 KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 191 } 192 193 static void kunit_resource_test_cleanup_resources(struct kunit *test) 194 { 195 int i; 196 struct kunit_test_resource_context *ctx = test->priv; 197 struct kunit_resource *resources[5]; 198 199 for (i = 0; i < ARRAY_SIZE(resources); i++) { 200 resources[i] = kunit_alloc_and_get_resource(&ctx->test, 201 fake_resource_init, 202 fake_resource_free, 203 GFP_KERNEL, 204 ctx); 205 kunit_put_resource(resources[i]); 206 } 207 208 kunit_cleanup(&ctx->test); 209 210 KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 211 } 212 213 static void kunit_resource_test_mark_order(int order_array[], 214 size_t order_size, 215 int key) 216 { 217 int i; 218 219 for (i = 0; i < order_size && order_array[i]; i++) 220 ; 221 222 order_array[i] = key; 223 } 224 225 #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \ 226 kunit_resource_test_mark_order(ctx->order_field, \ 227 ARRAY_SIZE(ctx->order_field), \ 228 key) 229 230 static int fake_resource_2_init(struct kunit_resource *res, void *context) 231 { 232 struct kunit_test_resource_context *ctx = context; 233 234 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2); 235 236 res->data = ctx; 237 238 return 0; 239 } 240 241 static void fake_resource_2_free(struct kunit_resource *res) 242 { 243 struct kunit_test_resource_context *ctx = res->data; 244 245 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2); 246 } 247 248 static int fake_resource_1_init(struct kunit_resource *res, void *context) 249 { 250 struct kunit_test_resource_context *ctx = context; 251 struct kunit_resource *res2; 252 253 res2 = kunit_alloc_and_get_resource(&ctx->test, 254 fake_resource_2_init, 255 fake_resource_2_free, 256 GFP_KERNEL, 257 ctx); 258 259 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1); 260 261 res->data = ctx; 262 263 kunit_put_resource(res2); 264 265 return 0; 266 } 267 268 static void fake_resource_1_free(struct kunit_resource *res) 269 { 270 struct kunit_test_resource_context *ctx = res->data; 271 272 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1); 273 } 274 275 /* 276 * TODO(brendanhiggins@google.com): replace the arrays that keep track of the 277 * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro 278 * to assert allocation and freeing order when the feature becomes available. 279 */ 280 static void kunit_resource_test_proper_free_ordering(struct kunit *test) 281 { 282 struct kunit_test_resource_context *ctx = test->priv; 283 struct kunit_resource *res; 284 285 /* fake_resource_1 allocates a fake_resource_2 in its init. */ 286 res = kunit_alloc_and_get_resource(&ctx->test, 287 fake_resource_1_init, 288 fake_resource_1_free, 289 GFP_KERNEL, 290 ctx); 291 292 /* 293 * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER 294 * before returning to fake_resource_1_init, it should be the first to 295 * put its key in the allocate_order array. 296 */ 297 KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2); 298 KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1); 299 300 kunit_put_resource(res); 301 302 kunit_cleanup(&ctx->test); 303 304 /* 305 * Because fake_resource_2 finishes allocation before fake_resource_1, 306 * fake_resource_1 should be freed first since it could depend on 307 * fake_resource_2. 308 */ 309 KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1); 310 KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2); 311 } 312 313 static void kunit_resource_test_static(struct kunit *test) 314 { 315 struct kunit_test_resource_context ctx; 316 struct kunit_resource res; 317 318 KUNIT_EXPECT_EQ(test, kunit_add_resource(test, NULL, NULL, &res, &ctx), 319 0); 320 321 KUNIT_EXPECT_PTR_EQ(test, res.data, (void *)&ctx); 322 323 kunit_cleanup(test); 324 325 KUNIT_EXPECT_TRUE(test, list_empty(&test->resources)); 326 } 327 328 static void kunit_resource_test_named(struct kunit *test) 329 { 330 struct kunit_resource res1, res2, *found = NULL; 331 struct kunit_test_resource_context ctx; 332 333 KUNIT_EXPECT_EQ(test, 334 kunit_add_named_resource(test, NULL, NULL, &res1, 335 "resource_1", &ctx), 336 0); 337 KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx); 338 339 KUNIT_EXPECT_EQ(test, 340 kunit_add_named_resource(test, NULL, NULL, &res1, 341 "resource_1", &ctx), 342 -EEXIST); 343 344 KUNIT_EXPECT_EQ(test, 345 kunit_add_named_resource(test, NULL, NULL, &res2, 346 "resource_2", &ctx), 347 0); 348 349 found = kunit_find_named_resource(test, "resource_1"); 350 351 KUNIT_EXPECT_PTR_EQ(test, found, &res1); 352 353 if (found) 354 kunit_put_resource(&res1); 355 356 KUNIT_EXPECT_EQ(test, kunit_destroy_named_resource(test, "resource_2"), 357 0); 358 359 kunit_cleanup(test); 360 361 KUNIT_EXPECT_TRUE(test, list_empty(&test->resources)); 362 } 363 364 static int kunit_resource_test_init(struct kunit *test) 365 { 366 struct kunit_test_resource_context *ctx = 367 kzalloc(sizeof(*ctx), GFP_KERNEL); 368 369 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 370 371 test->priv = ctx; 372 373 kunit_init_test(&ctx->test, "test_test_context", NULL); 374 375 return 0; 376 } 377 378 static void kunit_resource_test_exit(struct kunit *test) 379 { 380 struct kunit_test_resource_context *ctx = test->priv; 381 382 kunit_cleanup(&ctx->test); 383 kfree(ctx); 384 } 385 386 static struct kunit_case kunit_resource_test_cases[] = { 387 KUNIT_CASE(kunit_resource_test_init_resources), 388 KUNIT_CASE(kunit_resource_test_alloc_resource), 389 KUNIT_CASE(kunit_resource_test_destroy_resource), 390 KUNIT_CASE(kunit_resource_test_cleanup_resources), 391 KUNIT_CASE(kunit_resource_test_proper_free_ordering), 392 KUNIT_CASE(kunit_resource_test_static), 393 KUNIT_CASE(kunit_resource_test_named), 394 {} 395 }; 396 397 static struct kunit_suite kunit_resource_test_suite = { 398 .name = "kunit-resource-test", 399 .init = kunit_resource_test_init, 400 .exit = kunit_resource_test_exit, 401 .test_cases = kunit_resource_test_cases, 402 }; 403 404 static void kunit_log_test(struct kunit *test); 405 406 static struct kunit_case kunit_log_test_cases[] = { 407 KUNIT_CASE(kunit_log_test), 408 {} 409 }; 410 411 static struct kunit_suite kunit_log_test_suite = { 412 .name = "kunit-log-test", 413 .test_cases = kunit_log_test_cases, 414 }; 415 416 static void kunit_log_test(struct kunit *test) 417 { 418 struct kunit_suite *suite = &kunit_log_test_suite; 419 420 kunit_log(KERN_INFO, test, "put this in log."); 421 kunit_log(KERN_INFO, test, "this too."); 422 kunit_log(KERN_INFO, suite, "add to suite log."); 423 kunit_log(KERN_INFO, suite, "along with this."); 424 425 #ifdef CONFIG_KUNIT_DEBUGFS 426 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 427 strstr(test->log, "put this in log.")); 428 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 429 strstr(test->log, "this too.")); 430 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 431 strstr(suite->log, "add to suite log.")); 432 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 433 strstr(suite->log, "along with this.")); 434 #else 435 KUNIT_EXPECT_PTR_EQ(test, test->log, (char *)NULL); 436 KUNIT_EXPECT_PTR_EQ(test, suite->log, (char *)NULL); 437 #endif 438 } 439 440 static void kunit_status_set_failure_test(struct kunit *test) 441 { 442 struct kunit fake; 443 444 kunit_init_test(&fake, "fake test", NULL); 445 446 KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SUCCESS); 447 kunit_set_failure(&fake); 448 KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE); 449 } 450 451 static void kunit_status_mark_skipped_test(struct kunit *test) 452 { 453 struct kunit fake; 454 455 kunit_init_test(&fake, "fake test", NULL); 456 457 /* Before: Should be SUCCESS with no comment. */ 458 KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS); 459 KUNIT_EXPECT_STREQ(test, fake.status_comment, ""); 460 461 /* Mark the test as skipped. */ 462 kunit_mark_skipped(&fake, "Accepts format string: %s", "YES"); 463 464 /* After: Should be SKIPPED with our comment. */ 465 KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SKIPPED); 466 KUNIT_EXPECT_STREQ(test, fake.status_comment, "Accepts format string: YES"); 467 } 468 469 static struct kunit_case kunit_status_test_cases[] = { 470 KUNIT_CASE(kunit_status_set_failure_test), 471 KUNIT_CASE(kunit_status_mark_skipped_test), 472 {} 473 }; 474 475 static struct kunit_suite kunit_status_test_suite = { 476 .name = "kunit_status", 477 .test_cases = kunit_status_test_cases, 478 }; 479 480 kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite, 481 &kunit_log_test_suite, &kunit_status_test_suite); 482 483 MODULE_LICENSE("GPL v2"); 484