cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kunit-test.c (13924B)


      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_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
    227static 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);
    239		kunit_put_resource(resources[i]);
    240	}
    241
    242	kunit_cleanup(&ctx->test);
    243
    244	KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
    245}
    246
    247static 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
    264static 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
    270	res->data = ctx;
    271
    272	return 0;
    273}
    274
    275static void fake_resource_2_free(struct kunit_resource *res)
    276{
    277	struct kunit_test_resource_context *ctx = res->data;
    278
    279	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
    280}
    281
    282static int fake_resource_1_init(struct kunit_resource *res, void *context)
    283{
    284	struct kunit_test_resource_context *ctx = context;
    285	struct kunit_resource *res2;
    286
    287	res2 = kunit_alloc_and_get_resource(&ctx->test,
    288					    fake_resource_2_init,
    289					    fake_resource_2_free,
    290					    GFP_KERNEL,
    291					    ctx);
    292
    293	KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
    294
    295	res->data = ctx;
    296
    297	kunit_put_resource(res2);
    298
    299	return 0;
    300}
    301
    302static void fake_resource_1_free(struct kunit_resource *res)
    303{
    304	struct kunit_test_resource_context *ctx = res->data;
    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 */
    314static void kunit_resource_test_proper_free_ordering(struct kunit *test)
    315{
    316	struct kunit_test_resource_context *ctx = test->priv;
    317	struct kunit_resource *res;
    318
    319	/* fake_resource_1 allocates a fake_resource_2 in its init. */
    320	res = kunit_alloc_and_get_resource(&ctx->test,
    321					   fake_resource_1_init,
    322					   fake_resource_1_free,
    323					   GFP_KERNEL,
    324					   ctx);
    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
    334	kunit_put_resource(res);
    335
    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
    347static 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
    362static 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
    398static 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
    407	kunit_init_test(&ctx->test, "test_test_context", NULL);
    408
    409	return 0;
    410}
    411
    412static 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
    420static 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),
    424	KUNIT_CASE(kunit_resource_test_remove_resource),
    425	KUNIT_CASE(kunit_resource_test_cleanup_resources),
    426	KUNIT_CASE(kunit_resource_test_proper_free_ordering),
    427	KUNIT_CASE(kunit_resource_test_static),
    428	KUNIT_CASE(kunit_resource_test_named),
    429	{}
    430};
    431
    432static 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};
    438
    439static void kunit_log_test(struct kunit *test);
    440
    441static struct kunit_case kunit_log_test_cases[] = {
    442	KUNIT_CASE(kunit_log_test),
    443	{}
    444};
    445
    446static struct kunit_suite kunit_log_test_suite = {
    447	.name = "kunit-log-test",
    448	.test_cases = kunit_log_test_cases,
    449};
    450
    451static void kunit_log_test(struct kunit *test)
    452{
    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);
    457
    458	kunit_log(KERN_INFO, test, "put this in log.");
    459	kunit_log(KERN_INFO, test, "this too.");
    460	kunit_log(KERN_INFO, &suite, "add to suite log.");
    461	kunit_log(KERN_INFO, &suite, "along with this.");
    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,
    469				     strstr(suite.log, "add to suite log."));
    470	KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
    471				     strstr(suite.log, "along with this."));
    472#else
    473	KUNIT_EXPECT_NULL(test, test->log);
    474#endif
    475}
    476
    477static 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
    488static 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
    506static 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
    512static struct kunit_suite kunit_status_test_suite = {
    513	.name = "kunit_status",
    514	.test_cases = kunit_status_test_cases,
    515};
    516
    517kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
    518		  &kunit_log_test_suite, &kunit_status_test_suite);
    519
    520MODULE_LICENSE("GPL v2");