123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * KUnit test for core test infrastructure.
- *
- * Copyright (C) 2019, Google LLC.
- * Author: Brendan Higgins <[email protected]>
- */
- #include <kunit/test.h>
- #include "try-catch-impl.h"
- struct kunit_try_catch_test_context {
- struct kunit_try_catch *try_catch;
- bool function_called;
- };
- static void kunit_test_successful_try(void *data)
- {
- struct kunit *test = data;
- struct kunit_try_catch_test_context *ctx = test->priv;
- ctx->function_called = true;
- }
- static void kunit_test_no_catch(void *data)
- {
- struct kunit *test = data;
- KUNIT_FAIL(test, "Catch should not be called\n");
- }
- static void kunit_test_try_catch_successful_try_no_catch(struct kunit *test)
- {
- struct kunit_try_catch_test_context *ctx = test->priv;
- struct kunit_try_catch *try_catch = ctx->try_catch;
- kunit_try_catch_init(try_catch,
- test,
- kunit_test_successful_try,
- kunit_test_no_catch);
- kunit_try_catch_run(try_catch, test);
- KUNIT_EXPECT_TRUE(test, ctx->function_called);
- }
- static void kunit_test_unsuccessful_try(void *data)
- {
- struct kunit *test = data;
- struct kunit_try_catch_test_context *ctx = test->priv;
- struct kunit_try_catch *try_catch = ctx->try_catch;
- kunit_try_catch_throw(try_catch);
- KUNIT_FAIL(test, "This line should never be reached\n");
- }
- static void kunit_test_catch(void *data)
- {
- struct kunit *test = data;
- struct kunit_try_catch_test_context *ctx = test->priv;
- ctx->function_called = true;
- }
- static void kunit_test_try_catch_unsuccessful_try_does_catch(struct kunit *test)
- {
- struct kunit_try_catch_test_context *ctx = test->priv;
- struct kunit_try_catch *try_catch = ctx->try_catch;
- kunit_try_catch_init(try_catch,
- test,
- kunit_test_unsuccessful_try,
- kunit_test_catch);
- kunit_try_catch_run(try_catch, test);
- KUNIT_EXPECT_TRUE(test, ctx->function_called);
- }
- static int kunit_try_catch_test_init(struct kunit *test)
- {
- struct kunit_try_catch_test_context *ctx;
- ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- test->priv = ctx;
- ctx->try_catch = kunit_kmalloc(test,
- sizeof(*ctx->try_catch),
- GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch);
- return 0;
- }
- static struct kunit_case kunit_try_catch_test_cases[] = {
- KUNIT_CASE(kunit_test_try_catch_successful_try_no_catch),
- KUNIT_CASE(kunit_test_try_catch_unsuccessful_try_does_catch),
- {}
- };
- static struct kunit_suite kunit_try_catch_test_suite = {
- .name = "kunit-try-catch-test",
- .init = kunit_try_catch_test_init,
- .test_cases = kunit_try_catch_test_cases,
- };
- /*
- * Context for testing test managed resources
- * is_resource_initialized is used to test arbitrary resources
- */
- struct kunit_test_resource_context {
- struct kunit test;
- bool is_resource_initialized;
- int allocate_order[2];
- int free_order[2];
- };
- static int fake_resource_init(struct kunit_resource *res, void *context)
- {
- struct kunit_test_resource_context *ctx = context;
- res->data = &ctx->is_resource_initialized;
- ctx->is_resource_initialized = true;
- return 0;
- }
- static void fake_resource_free(struct kunit_resource *res)
- {
- bool *is_resource_initialized = res->data;
- *is_resource_initialized = false;
- }
- static void kunit_resource_test_init_resources(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- kunit_init_test(&ctx->test, "testing_test_init_test", NULL);
- KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
- }
- static void kunit_resource_test_alloc_resource(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- struct kunit_resource *res;
- kunit_resource_free_t free = fake_resource_free;
- res = kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_init,
- fake_resource_free,
- GFP_KERNEL,
- ctx);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
- KUNIT_EXPECT_PTR_EQ(test,
- &ctx->is_resource_initialized,
- (bool *)res->data);
- KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources));
- KUNIT_EXPECT_PTR_EQ(test, free, res->free);
- kunit_put_resource(res);
- }
- static inline bool kunit_resource_instance_match(struct kunit *test,
- struct kunit_resource *res,
- void *match_data)
- {
- return res->data == match_data;
- }
- /*
- * Note: tests below use kunit_alloc_and_get_resource(), so as a consequence
- * they have a reference to the associated resource that they must release
- * via kunit_put_resource(). In normal operation, users will only
- * have to do this for cases where they use kunit_find_resource(), and the
- * kunit_alloc_resource() function will be used (which does not take a
- * resource reference).
- */
- static void kunit_resource_test_destroy_resource(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- struct kunit_resource *res = kunit_alloc_and_get_resource(
- &ctx->test,
- fake_resource_init,
- fake_resource_free,
- GFP_KERNEL,
- ctx);
- kunit_put_resource(res);
- KUNIT_ASSERT_FALSE(test,
- kunit_destroy_resource(&ctx->test,
- kunit_resource_instance_match,
- res->data));
- KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
- KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
- }
- static void kunit_resource_test_remove_resource(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- struct kunit_resource *res = kunit_alloc_and_get_resource(
- &ctx->test,
- fake_resource_init,
- fake_resource_free,
- GFP_KERNEL,
- ctx);
- /* The resource is in the list */
- KUNIT_EXPECT_FALSE(test, list_empty(&ctx->test.resources));
- /* Remove the resource. The pointer is still valid, but it can't be
- * found.
- */
- kunit_remove_resource(test, res);
- KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
- /* We haven't been freed yet. */
- KUNIT_EXPECT_TRUE(test, ctx->is_resource_initialized);
- /* Removing the resource multiple times is valid. */
- kunit_remove_resource(test, res);
- KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
- /* Despite having been removed twice (from only one reference), the
- * resource still has not been freed.
- */
- KUNIT_EXPECT_TRUE(test, ctx->is_resource_initialized);
- /* Free the resource. */
- kunit_put_resource(res);
- KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
- }
- static void kunit_resource_test_cleanup_resources(struct kunit *test)
- {
- int i;
- struct kunit_test_resource_context *ctx = test->priv;
- struct kunit_resource *resources[5];
- for (i = 0; i < ARRAY_SIZE(resources); i++) {
- resources[i] = kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_init,
- fake_resource_free,
- GFP_KERNEL,
- ctx);
- kunit_put_resource(resources[i]);
- }
- kunit_cleanup(&ctx->test);
- KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
- }
- static void kunit_resource_test_mark_order(int order_array[],
- size_t order_size,
- int key)
- {
- int i;
- for (i = 0; i < order_size && order_array[i]; i++)
- ;
- order_array[i] = key;
- }
- #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \
- kunit_resource_test_mark_order(ctx->order_field, \
- ARRAY_SIZE(ctx->order_field), \
- key)
- static int fake_resource_2_init(struct kunit_resource *res, void *context)
- {
- struct kunit_test_resource_context *ctx = context;
- KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2);
- res->data = ctx;
- return 0;
- }
- static void fake_resource_2_free(struct kunit_resource *res)
- {
- struct kunit_test_resource_context *ctx = res->data;
- KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
- }
- static int fake_resource_1_init(struct kunit_resource *res, void *context)
- {
- struct kunit_test_resource_context *ctx = context;
- struct kunit_resource *res2;
- res2 = kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_2_init,
- fake_resource_2_free,
- GFP_KERNEL,
- ctx);
- KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
- res->data = ctx;
- kunit_put_resource(res2);
- return 0;
- }
- static void fake_resource_1_free(struct kunit_resource *res)
- {
- struct kunit_test_resource_context *ctx = res->data;
- KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1);
- }
- /*
- * TODO([email protected]): replace the arrays that keep track of the
- * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro
- * to assert allocation and freeing order when the feature becomes available.
- */
- static void kunit_resource_test_proper_free_ordering(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- struct kunit_resource *res;
- /* fake_resource_1 allocates a fake_resource_2 in its init. */
- res = kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_1_init,
- fake_resource_1_free,
- GFP_KERNEL,
- ctx);
- /*
- * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
- * before returning to fake_resource_1_init, it should be the first to
- * put its key in the allocate_order array.
- */
- KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2);
- KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1);
- kunit_put_resource(res);
- kunit_cleanup(&ctx->test);
- /*
- * Because fake_resource_2 finishes allocation before fake_resource_1,
- * fake_resource_1 should be freed first since it could depend on
- * fake_resource_2.
- */
- KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1);
- KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
- }
- static void kunit_resource_test_static(struct kunit *test)
- {
- struct kunit_test_resource_context ctx;
- struct kunit_resource res;
- KUNIT_EXPECT_EQ(test, kunit_add_resource(test, NULL, NULL, &res, &ctx),
- 0);
- KUNIT_EXPECT_PTR_EQ(test, res.data, (void *)&ctx);
- kunit_cleanup(test);
- KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
- }
- static void kunit_resource_test_named(struct kunit *test)
- {
- struct kunit_resource res1, res2, *found = NULL;
- struct kunit_test_resource_context ctx;
- KUNIT_EXPECT_EQ(test,
- kunit_add_named_resource(test, NULL, NULL, &res1,
- "resource_1", &ctx),
- 0);
- KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx);
- KUNIT_EXPECT_EQ(test,
- kunit_add_named_resource(test, NULL, NULL, &res1,
- "resource_1", &ctx),
- -EEXIST);
- KUNIT_EXPECT_EQ(test,
- kunit_add_named_resource(test, NULL, NULL, &res2,
- "resource_2", &ctx),
- 0);
- found = kunit_find_named_resource(test, "resource_1");
- KUNIT_EXPECT_PTR_EQ(test, found, &res1);
- if (found)
- kunit_put_resource(&res1);
- KUNIT_EXPECT_EQ(test, kunit_destroy_named_resource(test, "resource_2"),
- 0);
- kunit_cleanup(test);
- KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
- }
- static int kunit_resource_test_init(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx =
- kzalloc(sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- test->priv = ctx;
- kunit_init_test(&ctx->test, "test_test_context", NULL);
- return 0;
- }
- static void kunit_resource_test_exit(struct kunit *test)
- {
- struct kunit_test_resource_context *ctx = test->priv;
- kunit_cleanup(&ctx->test);
- kfree(ctx);
- }
- static struct kunit_case kunit_resource_test_cases[] = {
- KUNIT_CASE(kunit_resource_test_init_resources),
- KUNIT_CASE(kunit_resource_test_alloc_resource),
- KUNIT_CASE(kunit_resource_test_destroy_resource),
- KUNIT_CASE(kunit_resource_test_remove_resource),
- KUNIT_CASE(kunit_resource_test_cleanup_resources),
- KUNIT_CASE(kunit_resource_test_proper_free_ordering),
- KUNIT_CASE(kunit_resource_test_static),
- KUNIT_CASE(kunit_resource_test_named),
- {}
- };
- static struct kunit_suite kunit_resource_test_suite = {
- .name = "kunit-resource-test",
- .init = kunit_resource_test_init,
- .exit = kunit_resource_test_exit,
- .test_cases = kunit_resource_test_cases,
- };
- static void kunit_log_test(struct kunit *test);
- static struct kunit_case kunit_log_test_cases[] = {
- KUNIT_CASE(kunit_log_test),
- {}
- };
- static struct kunit_suite kunit_log_test_suite = {
- .name = "kunit-log-test",
- .test_cases = kunit_log_test_cases,
- };
- static void kunit_log_test(struct kunit *test)
- {
- struct kunit_suite suite;
- suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log);
- kunit_log(KERN_INFO, test, "put this in log.");
- kunit_log(KERN_INFO, test, "this too.");
- kunit_log(KERN_INFO, &suite, "add to suite log.");
- kunit_log(KERN_INFO, &suite, "along with this.");
- #ifdef CONFIG_KUNIT_DEBUGFS
- KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
- strstr(test->log, "put this in log."));
- KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
- strstr(test->log, "this too."));
- KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
- strstr(suite.log, "add to suite log."));
- KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
- strstr(suite.log, "along with this."));
- #else
- KUNIT_EXPECT_NULL(test, test->log);
- #endif
- }
- static void kunit_status_set_failure_test(struct kunit *test)
- {
- struct kunit fake;
- kunit_init_test(&fake, "fake test", NULL);
- KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SUCCESS);
- kunit_set_failure(&fake);
- KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
- }
- static void kunit_status_mark_skipped_test(struct kunit *test)
- {
- struct kunit fake;
- kunit_init_test(&fake, "fake test", NULL);
- /* Before: Should be SUCCESS with no comment. */
- KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
- KUNIT_EXPECT_STREQ(test, fake.status_comment, "");
- /* Mark the test as skipped. */
- kunit_mark_skipped(&fake, "Accepts format string: %s", "YES");
- /* After: Should be SKIPPED with our comment. */
- KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_SKIPPED);
- KUNIT_EXPECT_STREQ(test, fake.status_comment, "Accepts format string: YES");
- }
- static struct kunit_case kunit_status_test_cases[] = {
- KUNIT_CASE(kunit_status_set_failure_test),
- KUNIT_CASE(kunit_status_mark_skipped_test),
- {}
- };
- static struct kunit_suite kunit_status_test_suite = {
- .name = "kunit_status",
- .test_cases = kunit_status_test_cases,
- };
- kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
- &kunit_log_test_suite, &kunit_status_test_suite);
- MODULE_LICENSE("GPL v2");
|