Skip to content

Commit 4d557cb

Browse files
diegodvvkees
authored andcommitted
lib/tests/kfifo_kunit.c: add tests for the kfifo structure
Add KUnit tests for the kfifo data structure. They test the vast majority of macros defined in the kfifo header (include/linux/kfifo.h). These are inspired by the existing tests for the doubly linked list in lib/tests/list-test.c (previously at lib/list-test.c) [1]. Note that this patch depends on the patch that moves the KUnit tests on lib/ into lib/tests/ [2]. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6 [2] https://lore.kernel.org/all/20240720181025.work.002-kees@kernel.org/ Signed-off-by: Diego Vieira <diego.daniel.professional@gmail.com> Reviewed-by: David Gow <davidgow@google.com> Reviewed-by: Rae Moar <rmoar@google.com> Link: https://lore.kernel.org/r/20241202075545.3648096-5-davidgow@google.com Signed-off-by: Kees Cook <kees@kernel.org>
1 parent db6fe4d commit 4d557cb

3 files changed

Lines changed: 239 additions & 0 deletions

File tree

lib/Kconfig.debug

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,6 +2691,20 @@ config SYSCTL_KUNIT_TEST
26912691

26922692
If unsure, say N.
26932693

2694+
config KFIFO_KUNIT_TEST
2695+
tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
2696+
depends on KUNIT
2697+
default KUNIT_ALL_TESTS
2698+
help
2699+
This builds the generic FIFO implementation KUnit test suite.
2700+
It tests that the API and basic functionality of the kfifo type
2701+
and associated macros.
2702+
2703+
For more information on KUnit and unit tests in general please refer
2704+
to the KUnit documentation in Documentation/dev-tools/kunit/.
2705+
2706+
If unsure, say N.
2707+
26942708
config LIST_KUNIT_TEST
26952709
tristate "KUnit Test for Kernel Linked-list structures" if !KUNIT_ALL_TESTS
26962710
depends on KUNIT

lib/tests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o
2323
obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o
2424
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
2525
obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
26+
obj-$(CONFIG_KFIFO_KUNIT_TEST) += kfifo_kunit.o
2627
obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
2728
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
2829
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o

lib/tests/kfifo_kunit.c

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* KUnit test for the generic kernel FIFO implementation.
4+
*
5+
* Copyright (C) 2024 Diego Vieira <diego.daniel.professional@gmail.com>
6+
*/
7+
#include <kunit/test.h>
8+
9+
#include <linux/kfifo.h>
10+
11+
#define KFIFO_SIZE 32
12+
#define N_ELEMENTS 5
13+
14+
static void kfifo_test_reset_should_clear_the_fifo(struct kunit *test)
15+
{
16+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
17+
18+
kfifo_put(&my_fifo, 1);
19+
kfifo_put(&my_fifo, 2);
20+
kfifo_put(&my_fifo, 3);
21+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
22+
23+
kfifo_reset(&my_fifo);
24+
25+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
26+
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
27+
}
28+
29+
static void kfifo_test_define_should_define_an_empty_fifo(struct kunit *test)
30+
{
31+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
32+
33+
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
34+
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
35+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
36+
}
37+
38+
static void kfifo_test_len_should_ret_n_of_stored_elements(struct kunit *test)
39+
{
40+
u8 buffer1[N_ELEMENTS];
41+
42+
for (int i = 0; i < N_ELEMENTS; i++)
43+
buffer1[i] = i + 1;
44+
45+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
46+
47+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
48+
49+
kfifo_in(&my_fifo, buffer1, N_ELEMENTS);
50+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS);
51+
52+
kfifo_in(&my_fifo, buffer1, N_ELEMENTS);
53+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS * 2);
54+
55+
kfifo_reset(&my_fifo);
56+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
57+
}
58+
59+
static void kfifo_test_put_should_insert_and_get_should_pop(struct kunit *test)
60+
{
61+
u8 out_data = 0;
62+
int processed_elements;
63+
u8 elements[] = { 3, 5, 11 };
64+
65+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
66+
67+
// If the fifo is empty, get returns 0
68+
processed_elements = kfifo_get(&my_fifo, &out_data);
69+
KUNIT_EXPECT_EQ(test, processed_elements, 0);
70+
KUNIT_EXPECT_EQ(test, out_data, 0);
71+
72+
for (int i = 0; i < 3; i++)
73+
kfifo_put(&my_fifo, elements[i]);
74+
75+
for (int i = 0; i < 3; i++) {
76+
processed_elements = kfifo_get(&my_fifo, &out_data);
77+
KUNIT_EXPECT_EQ(test, processed_elements, 1);
78+
KUNIT_EXPECT_EQ(test, out_data, elements[i]);
79+
}
80+
}
81+
82+
static void kfifo_test_in_should_insert_multiple_elements(struct kunit *test)
83+
{
84+
u8 in_buffer[] = { 11, 25, 65 };
85+
u8 out_data;
86+
int processed_elements;
87+
88+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
89+
90+
kfifo_in(&my_fifo, in_buffer, 3);
91+
92+
for (int i = 0; i < 3; i++) {
93+
processed_elements = kfifo_get(&my_fifo, &out_data);
94+
KUNIT_EXPECT_EQ(test, processed_elements, 1);
95+
KUNIT_EXPECT_EQ(test, out_data, in_buffer[i]);
96+
}
97+
}
98+
99+
static void kfifo_test_out_should_pop_multiple_elements(struct kunit *test)
100+
{
101+
u8 in_buffer[] = { 11, 25, 65 };
102+
u8 out_buffer[3];
103+
int copied_elements;
104+
105+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
106+
107+
for (int i = 0; i < 3; i++)
108+
kfifo_put(&my_fifo, in_buffer[i]);
109+
110+
copied_elements = kfifo_out(&my_fifo, out_buffer, 3);
111+
KUNIT_EXPECT_EQ(test, copied_elements, 3);
112+
113+
for (int i = 0; i < 3; i++)
114+
KUNIT_EXPECT_EQ(test, out_buffer[i], in_buffer[i]);
115+
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
116+
}
117+
118+
static void kfifo_test_dec_init_should_define_an_empty_fifo(struct kunit *test)
119+
{
120+
DECLARE_KFIFO(my_fifo, u8, KFIFO_SIZE);
121+
122+
INIT_KFIFO(my_fifo);
123+
124+
// my_fifo is a struct with an inplace buffer
125+
KUNIT_EXPECT_FALSE(test, __is_kfifo_ptr(&my_fifo));
126+
127+
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
128+
}
129+
130+
static void kfifo_test_define_should_equal_declare_init(struct kunit *test)
131+
{
132+
// declare a variable my_fifo of type struct kfifo of u8
133+
DECLARE_KFIFO(my_fifo1, u8, KFIFO_SIZE);
134+
// initialize the my_fifo variable
135+
INIT_KFIFO(my_fifo1);
136+
137+
// DEFINE_KFIFO declares the variable with the initial value
138+
// essentially the same as calling DECLARE_KFIFO and INIT_KFIFO
139+
DEFINE_KFIFO(my_fifo2, u8, KFIFO_SIZE);
140+
141+
// my_fifo1 and my_fifo2 have the same size
142+
KUNIT_EXPECT_EQ(test, sizeof(my_fifo1), sizeof(my_fifo2));
143+
KUNIT_EXPECT_EQ(test, kfifo_initialized(&my_fifo1),
144+
kfifo_initialized(&my_fifo2));
145+
KUNIT_EXPECT_EQ(test, kfifo_is_empty(&my_fifo1),
146+
kfifo_is_empty(&my_fifo2));
147+
}
148+
149+
static void kfifo_test_alloc_should_initiliaze_a_ptr_fifo(struct kunit *test)
150+
{
151+
int ret;
152+
DECLARE_KFIFO_PTR(my_fifo, u8);
153+
154+
INIT_KFIFO(my_fifo);
155+
156+
// kfifo_initialized returns false signaling the buffer pointer is NULL
157+
KUNIT_EXPECT_FALSE(test, kfifo_initialized(&my_fifo));
158+
159+
// kfifo_alloc allocates the buffer
160+
ret = kfifo_alloc(&my_fifo, KFIFO_SIZE, GFP_KERNEL);
161+
KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Memory allocation should succeed");
162+
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
163+
164+
// kfifo_free frees the buffer
165+
kfifo_free(&my_fifo);
166+
}
167+
168+
static void kfifo_test_peek_should_not_remove_elements(struct kunit *test)
169+
{
170+
u8 out_data;
171+
int processed_elements;
172+
173+
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
174+
175+
// If the fifo is empty, peek returns 0
176+
processed_elements = kfifo_peek(&my_fifo, &out_data);
177+
KUNIT_EXPECT_EQ(test, processed_elements, 0);
178+
179+
kfifo_put(&my_fifo, 3);
180+
kfifo_put(&my_fifo, 5);
181+
kfifo_put(&my_fifo, 11);
182+
183+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
184+
185+
processed_elements = kfifo_peek(&my_fifo, &out_data);
186+
KUNIT_EXPECT_EQ(test, processed_elements, 1);
187+
KUNIT_EXPECT_EQ(test, out_data, 3);
188+
189+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
190+
191+
// Using peek doesn't remove the element
192+
// so the read element and the fifo length
193+
// remains the same
194+
processed_elements = kfifo_peek(&my_fifo, &out_data);
195+
KUNIT_EXPECT_EQ(test, processed_elements, 1);
196+
KUNIT_EXPECT_EQ(test, out_data, 3);
197+
198+
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
199+
}
200+
201+
static struct kunit_case kfifo_test_cases[] = {
202+
KUNIT_CASE(kfifo_test_reset_should_clear_the_fifo),
203+
KUNIT_CASE(kfifo_test_define_should_define_an_empty_fifo),
204+
KUNIT_CASE(kfifo_test_len_should_ret_n_of_stored_elements),
205+
KUNIT_CASE(kfifo_test_put_should_insert_and_get_should_pop),
206+
KUNIT_CASE(kfifo_test_in_should_insert_multiple_elements),
207+
KUNIT_CASE(kfifo_test_out_should_pop_multiple_elements),
208+
KUNIT_CASE(kfifo_test_dec_init_should_define_an_empty_fifo),
209+
KUNIT_CASE(kfifo_test_define_should_equal_declare_init),
210+
KUNIT_CASE(kfifo_test_alloc_should_initiliaze_a_ptr_fifo),
211+
KUNIT_CASE(kfifo_test_peek_should_not_remove_elements),
212+
{},
213+
};
214+
215+
static struct kunit_suite kfifo_test_module = {
216+
.name = "kfifo",
217+
.test_cases = kfifo_test_cases,
218+
};
219+
220+
kunit_test_suites(&kfifo_test_module);
221+
222+
MODULE_LICENSE("GPL");
223+
MODULE_AUTHOR("Diego Vieira <diego.daniel.professional@gmail.com>");
224+
MODULE_DESCRIPTION("KUnit test for the kernel FIFO");

0 commit comments

Comments
 (0)