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