linux/lib/kunit/kunit-test.c
<<
>>
Prefs
   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
  12struct kunit_try_catch_test_context {
  13        struct kunit_try_catch *try_catch;
  14        bool function_called;
  15};
  16
  17static 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
  25static 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
  32static 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
  46static 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
  56static 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
  64static 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
  78static 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
  94static 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
 100static 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 */
 110struct 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
 117static 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
 126static void fake_resource_free(struct kunit_resource *res)
 127{
 128        bool *is_resource_initialized = res->data;
 129
 130        *is_resource_initialized = false;
 131}
 132
 133static 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
 142static 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 */
 172static 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
 193static 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
 213static 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
 230static 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
 241static 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
 248static 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
 268static 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 */
 280static 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
 313static 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
 328static 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
 364static 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
 378static 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
 386static 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
 397static 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
 404static void kunit_log_test(struct kunit *test);
 405
 406static struct kunit_case kunit_log_test_cases[] = {
 407        KUNIT_CASE(kunit_log_test),
 408        {}
 409};
 410
 411static struct kunit_suite kunit_log_test_suite = {
 412        .name = "kunit-log-test",
 413        .test_cases = kunit_log_test_cases,
 414};
 415
 416static void kunit_log_test(struct kunit *test)
 417{
 418        struct kunit_suite suite;
 419
 420        suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL);
 421        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log);
 422
 423        kunit_log(KERN_INFO, test, "put this in log.");
 424        kunit_log(KERN_INFO, test, "this too.");
 425        kunit_log(KERN_INFO, &suite, "add to suite log.");
 426        kunit_log(KERN_INFO, &suite, "along with this.");
 427
 428#ifdef CONFIG_KUNIT_DEBUGFS
 429        KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
 430                                     strstr(test->log, "put this in log."));
 431        KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
 432                                     strstr(test->log, "this too."));
 433        KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
 434                                     strstr(suite.log, "add to suite log."));
 435        KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
 436                                     strstr(suite.log, "along with this."));
 437#else
 438        KUNIT_EXPECT_PTR_EQ(test, test->log, (char *)NULL);
 439#endif
 440}
 441
 442static void kunit_status_set_failure_test(struct kunit *test)
 443{
 444        struct kunit fake;
 445
 446        kunit_init_test(&fake, "fake test", NULL);
 447
 448        KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SUCCESS);
 449        kunit_set_failure(&fake);
 450        KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
 451}
 452
 453static void kunit_status_mark_skipped_test(struct kunit *test)
 454{
 455        struct kunit fake;
 456
 457        kunit_init_test(&fake, "fake test", NULL);
 458
 459        /* Before: Should be SUCCESS with no comment. */
 460        KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
 461        KUNIT_EXPECT_STREQ(test, fake.status_comment, "");
 462
 463        /* Mark the test as skipped. */
 464        kunit_mark_skipped(&fake, "Accepts format string: %s", "YES");
 465
 466        /* After: Should be SKIPPED with our comment. */
 467        KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SKIPPED);
 468        KUNIT_EXPECT_STREQ(test, fake.status_comment, "Accepts format string: YES");
 469}
 470
 471static struct kunit_case kunit_status_test_cases[] = {
 472        KUNIT_CASE(kunit_status_set_failure_test),
 473        KUNIT_CASE(kunit_status_mark_skipped_test),
 474        {}
 475};
 476
 477static struct kunit_suite kunit_status_test_suite = {
 478        .name = "kunit_status",
 479        .test_cases = kunit_status_test_cases,
 480};
 481
 482kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
 483                  &kunit_log_test_suite, &kunit_status_test_suite);
 484
 485MODULE_LICENSE("GPL v2");
 486