Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: test: add tests for KUnit managed resources

Add unit tests for KUnit managed resources. KUnit managed resources
(struct kunit_resource) are resources that are automatically cleaned up
at the end of a KUnit test, similar to the concept of devm_* managed
resources.

Signed-off-by: Avinash Kondareddy <akndr41@gmail.com>
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Avinash Kondareddy and committed by
Shuah Khan
73ba5aaf e4aea8f8

+228
+228
lib/kunit/test-test.c
··· 101 101 .test_cases = kunit_try_catch_test_cases, 102 102 }; 103 103 kunit_test_suite(kunit_try_catch_test_suite); 104 + 105 + /* 106 + * Context for testing test managed resources 107 + * is_resource_initialized is used to test arbitrary resources 108 + */ 109 + struct kunit_test_resource_context { 110 + struct kunit test; 111 + bool is_resource_initialized; 112 + int allocate_order[2]; 113 + int free_order[2]; 114 + }; 115 + 116 + static int fake_resource_init(struct kunit_resource *res, void *context) 117 + { 118 + struct kunit_test_resource_context *ctx = context; 119 + 120 + res->allocation = &ctx->is_resource_initialized; 121 + ctx->is_resource_initialized = true; 122 + return 0; 123 + } 124 + 125 + static void fake_resource_free(struct kunit_resource *res) 126 + { 127 + bool *is_resource_initialized = res->allocation; 128 + 129 + *is_resource_initialized = false; 130 + } 131 + 132 + static void kunit_resource_test_init_resources(struct kunit *test) 133 + { 134 + struct kunit_test_resource_context *ctx = test->priv; 135 + 136 + kunit_init_test(&ctx->test, "testing_test_init_test"); 137 + 138 + KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 139 + } 140 + 141 + static void kunit_resource_test_alloc_resource(struct kunit *test) 142 + { 143 + struct kunit_test_resource_context *ctx = test->priv; 144 + struct kunit_resource *res; 145 + kunit_resource_free_t free = fake_resource_free; 146 + 147 + res = kunit_alloc_and_get_resource(&ctx->test, 148 + fake_resource_init, 149 + fake_resource_free, 150 + GFP_KERNEL, 151 + ctx); 152 + 153 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res); 154 + KUNIT_EXPECT_PTR_EQ(test, 155 + &ctx->is_resource_initialized, 156 + (bool *) res->allocation); 157 + KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources)); 158 + KUNIT_EXPECT_PTR_EQ(test, free, res->free); 159 + } 160 + 161 + static void kunit_resource_test_destroy_resource(struct kunit *test) 162 + { 163 + struct kunit_test_resource_context *ctx = test->priv; 164 + struct kunit_resource *res = kunit_alloc_and_get_resource( 165 + &ctx->test, 166 + fake_resource_init, 167 + fake_resource_free, 168 + GFP_KERNEL, 169 + ctx); 170 + 171 + KUNIT_ASSERT_FALSE(test, 172 + kunit_resource_destroy(&ctx->test, 173 + kunit_resource_instance_match, 174 + res->free, 175 + res->allocation)); 176 + 177 + KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized); 178 + KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 179 + } 180 + 181 + static void kunit_resource_test_cleanup_resources(struct kunit *test) 182 + { 183 + int i; 184 + struct kunit_test_resource_context *ctx = test->priv; 185 + struct kunit_resource *resources[5]; 186 + 187 + for (i = 0; i < ARRAY_SIZE(resources); i++) { 188 + resources[i] = kunit_alloc_and_get_resource(&ctx->test, 189 + fake_resource_init, 190 + fake_resource_free, 191 + GFP_KERNEL, 192 + ctx); 193 + } 194 + 195 + kunit_cleanup(&ctx->test); 196 + 197 + KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources)); 198 + } 199 + 200 + static void kunit_resource_test_mark_order(int order_array[], 201 + size_t order_size, 202 + int key) 203 + { 204 + int i; 205 + 206 + for (i = 0; i < order_size && order_array[i]; i++) 207 + ; 208 + 209 + order_array[i] = key; 210 + } 211 + 212 + #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \ 213 + kunit_resource_test_mark_order(ctx->order_field, \ 214 + ARRAY_SIZE(ctx->order_field), \ 215 + key) 216 + 217 + static int fake_resource_2_init(struct kunit_resource *res, void *context) 218 + { 219 + struct kunit_test_resource_context *ctx = context; 220 + 221 + KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2); 222 + 223 + res->allocation = ctx; 224 + 225 + return 0; 226 + } 227 + 228 + static void fake_resource_2_free(struct kunit_resource *res) 229 + { 230 + struct kunit_test_resource_context *ctx = res->allocation; 231 + 232 + KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2); 233 + } 234 + 235 + static int fake_resource_1_init(struct kunit_resource *res, void *context) 236 + { 237 + struct kunit_test_resource_context *ctx = context; 238 + 239 + kunit_alloc_and_get_resource(&ctx->test, 240 + fake_resource_2_init, 241 + fake_resource_2_free, 242 + GFP_KERNEL, 243 + ctx); 244 + 245 + KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1); 246 + 247 + res->allocation = ctx; 248 + 249 + return 0; 250 + } 251 + 252 + static void fake_resource_1_free(struct kunit_resource *res) 253 + { 254 + struct kunit_test_resource_context *ctx = res->allocation; 255 + 256 + KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1); 257 + } 258 + 259 + /* 260 + * TODO(brendanhiggins@google.com): replace the arrays that keep track of the 261 + * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro 262 + * to assert allocation and freeing order when the feature becomes available. 263 + */ 264 + static void kunit_resource_test_proper_free_ordering(struct kunit *test) 265 + { 266 + struct kunit_test_resource_context *ctx = test->priv; 267 + 268 + /* fake_resource_1 allocates a fake_resource_2 in its init. */ 269 + kunit_alloc_and_get_resource(&ctx->test, 270 + fake_resource_1_init, 271 + fake_resource_1_free, 272 + GFP_KERNEL, 273 + ctx); 274 + 275 + /* 276 + * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER 277 + * before returning to fake_resource_1_init, it should be the first to 278 + * put its key in the allocate_order array. 279 + */ 280 + KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2); 281 + KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1); 282 + 283 + kunit_cleanup(&ctx->test); 284 + 285 + /* 286 + * Because fake_resource_2 finishes allocation before fake_resource_1, 287 + * fake_resource_1 should be freed first since it could depend on 288 + * fake_resource_2. 289 + */ 290 + KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1); 291 + KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2); 292 + } 293 + 294 + static int kunit_resource_test_init(struct kunit *test) 295 + { 296 + struct kunit_test_resource_context *ctx = 297 + kzalloc(sizeof(*ctx), GFP_KERNEL); 298 + 299 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 300 + 301 + test->priv = ctx; 302 + 303 + kunit_init_test(&ctx->test, "test_test_context"); 304 + 305 + return 0; 306 + } 307 + 308 + static void kunit_resource_test_exit(struct kunit *test) 309 + { 310 + struct kunit_test_resource_context *ctx = test->priv; 311 + 312 + kunit_cleanup(&ctx->test); 313 + kfree(ctx); 314 + } 315 + 316 + static struct kunit_case kunit_resource_test_cases[] = { 317 + KUNIT_CASE(kunit_resource_test_init_resources), 318 + KUNIT_CASE(kunit_resource_test_alloc_resource), 319 + KUNIT_CASE(kunit_resource_test_destroy_resource), 320 + KUNIT_CASE(kunit_resource_test_cleanup_resources), 321 + KUNIT_CASE(kunit_resource_test_proper_free_ordering), 322 + {} 323 + }; 324 + 325 + static struct kunit_suite kunit_resource_test_suite = { 326 + .name = "kunit-resource-test", 327 + .init = kunit_resource_test_init, 328 + .exit = kunit_resource_test_exit, 329 + .test_cases = kunit_resource_test_cases, 330 + }; 331 + kunit_test_suite(kunit_resource_test_suite);