blob: ccb8d2e332f7fe4c9fe7809e5d3e60abcc4cd432 [file] [log] [blame]
Brendan Higginse4eb1172019-09-23 02:02:40 -07001// 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
Alan Maguire9bbb11c2020-01-06 22:28:19 +000010#include "try-catch-impl.h"
11
Brendan Higginse4eb1172019-09-23 02:02:40 -070012struct 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);
Brendan Higginse4aea8f2019-09-23 02:02:41 -070083 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
Brendan Higginse4eb1172019-09-23 02:02:40 -070084 test->priv = ctx;
85
86 ctx->try_catch = kunit_kmalloc(test,
87 sizeof(*ctx->try_catch),
88 GFP_KERNEL);
Brendan Higginse4aea8f2019-09-23 02:02:41 -070089 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch);
Brendan Higginse4eb1172019-09-23 02:02:40 -070090
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};
Avinash Kondareddy73ba5aa2019-09-23 02:02:42 -0700105
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->allocation = &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->allocation;
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");
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->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
162static 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
182static 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
201static 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
218static 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
229static 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
236static 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
253static 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 */
265static 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
295static 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
309static 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
317static 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
326static 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};
Alan Maguirec475c772020-01-06 22:28:20 +0000332kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite);
333
334MODULE_LICENSE("GPL v2");