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->allocation = &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->allocation; 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"); 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->allocation); 158 KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources)); 159 KUNIT_EXPECT_PTR_EQ(test, free, res->free); 160 } 161 162 static void kunit_resource_test_destroy_resource(struct kunit *test) 163 { 164 struct kunit_test_resource_context *ctx = test->priv; 165 struct kunit_resource *res = kunit_alloc_and_get_resource( 166 &ctx->test, 167 fake_resource_init, 168 fake_resource_free, 169 GFP_KERNEL, 170 ctx); 171 172 KUNIT_ASSERT_FALSE(test, 173 kunit_resource_destroy(&ctx->test, 174 kunit_resource_instance_match, 175 res->free, 176 res->allocation)); 177 178 KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized); 179 KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 180 } 181 182 static void kunit_resource_test_cleanup_resources(struct kunit *test) 183 { 184 int i; 185 struct kunit_test_resource_context *ctx = test->priv; 186 struct kunit_resource *resources[5]; 187 188 for (i = 0; i < ARRAY_SIZE(resources); i++) { 189 resources[i] = kunit_alloc_and_get_resource(&ctx->test, 190 fake_resource_init, 191 fake_resource_free, 192 GFP_KERNEL, 193 ctx); 194 } 195 196 kunit_cleanup(&ctx->test); 197 198 KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 199 } 200 201 static void kunit_resource_test_mark_order(int order_array[], 202 size_t order_size, 203 int key) 204 { 205 int i; 206 207 for (i = 0; i < order_size && order_array[i]; i++) 208 ; 209 210 order_array[i] = key; 211 } 212 213 #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \ 214 kunit_resource_test_mark_order(ctx->order_field, \ 215 ARRAY_SIZE(ctx->order_field), \ 216 key) 217 218 static int fake_resource_2_init(struct kunit_resource *res, void *context) 219 { 220 struct kunit_test_resource_context *ctx = context; 221 222 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2); 223 224 res->allocation = ctx; 225 226 return 0; 227 } 228 229 static void fake_resource_2_free(struct kunit_resource *res) 230 { 231 struct kunit_test_resource_context *ctx = res->allocation; 232 233 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2); 234 } 235 236 static int fake_resource_1_init(struct kunit_resource *res, void *context) 237 { 238 struct kunit_test_resource_context *ctx = context; 239 240 kunit_alloc_and_get_resource(&ctx->test, 241 fake_resource_2_init, 242 fake_resource_2_free, 243 GFP_KERNEL, 244 ctx); 245 246 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1); 247 248 res->allocation = ctx; 249 250 return 0; 251 } 252 253 static void fake_resource_1_free(struct kunit_resource *res) 254 { 255 struct kunit_test_resource_context *ctx = res->allocation; 256 257 KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1); 258 } 259 260 /* 261 * TODO(brendanhiggins@google.com): replace the arrays that keep track of the 262 * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro 263 * to assert allocation and freeing order when the feature becomes available. 264 */ 265 static void kunit_resource_test_proper_free_ordering(struct kunit *test) 266 { 267 struct kunit_test_resource_context *ctx = test->priv; 268 269 /* fake_resource_1 allocates a fake_resource_2 in its init. */ 270 kunit_alloc_and_get_resource(&ctx->test, 271 fake_resource_1_init, 272 fake_resource_1_free, 273 GFP_KERNEL, 274 ctx); 275 276 /* 277 * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER 278 * before returning to fake_resource_1_init, it should be the first to 279 * put its key in the allocate_order array. 280 */ 281 KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2); 282 KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1); 283 284 kunit_cleanup(&ctx->test); 285 286 /* 287 * Because fake_resource_2 finishes allocation before fake_resource_1, 288 * fake_resource_1 should be freed first since it could depend on 289 * fake_resource_2. 290 */ 291 KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1); 292 KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2); 293 } 294 295 static int kunit_resource_test_init(struct kunit *test) 296 { 297 struct kunit_test_resource_context *ctx = 298 kzalloc(sizeof(*ctx), GFP_KERNEL); 299 300 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 301 302 test->priv = ctx; 303 304 kunit_init_test(&ctx->test, "test_test_context"); 305 306 return 0; 307 } 308 309 static void kunit_resource_test_exit(struct kunit *test) 310 { 311 struct kunit_test_resource_context *ctx = test->priv; 312 313 kunit_cleanup(&ctx->test); 314 kfree(ctx); 315 } 316 317 static struct kunit_case kunit_resource_test_cases[] = { 318 KUNIT_CASE(kunit_resource_test_init_resources), 319 KUNIT_CASE(kunit_resource_test_alloc_resource), 320 KUNIT_CASE(kunit_resource_test_destroy_resource), 321 KUNIT_CASE(kunit_resource_test_cleanup_resources), 322 KUNIT_CASE(kunit_resource_test_proper_free_ordering), 323 {} 324 }; 325 326 static struct kunit_suite kunit_resource_test_suite = { 327 .name = "kunit-resource-test", 328 .init = kunit_resource_test_init, 329 .exit = kunit_resource_test_exit, 330 .test_cases = kunit_resource_test_cases, 331 }; 332 kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite); 333 334 MODULE_LICENSE("GPL v2"); 335