mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	list: test: Test the klist structure
Add KUnit tests to the klist linked-list structure. These perform testing for different variations of node add and node delete in the klist data structure (<linux/klist.h>). Limitation: Since we use a static global variable, and if multiple instances of this test are run concurrently, the test may fail. Signed-off-by: Sadiya Kazi <sadiyakazi@google.com> Reviewed-by: Brendan Higgins <brendanhiggins@google.com> Reviewed-by: David Gow <davidgow@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									7232282dd4
								
							
						
					
					
						commit
						57b4f760f9
					
				
					 1 changed files with 299 additions and 1 deletions
				
			
		
							
								
								
									
										300
									
								
								lib/list-test.c
									
									
									
									
									
								
							
							
						
						
									
										300
									
								
								lib/list-test.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <kunit/test.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
#include <linux/klist.h>
 | 
			
		||||
 | 
			
		||||
struct list_test_struct {
 | 
			
		||||
	int data;
 | 
			
		||||
| 
						 | 
				
			
			@ -1199,6 +1200,303 @@ static struct kunit_suite hlist_test_module = {
 | 
			
		|||
	.test_cases = hlist_test_cases,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
kunit_test_suites(&list_test_module, &hlist_test_module);
 | 
			
		||||
 | 
			
		||||
struct klist_test_struct {
 | 
			
		||||
	int data;
 | 
			
		||||
	struct klist klist;
 | 
			
		||||
	struct klist_node klist_node;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int node_count;
 | 
			
		||||
static struct klist_node *last_node;
 | 
			
		||||
 | 
			
		||||
static void check_node(struct klist_node *node_ptr)
 | 
			
		||||
{
 | 
			
		||||
	node_count++;
 | 
			
		||||
	last_node = node_ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void check_delete_node(struct klist_node *node_ptr)
 | 
			
		||||
{
 | 
			
		||||
	node_count--;
 | 
			
		||||
	last_node = node_ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_add_tail(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, NULL);
 | 
			
		||||
 | 
			
		||||
	klist_add_tail(&a, &mylist);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 1);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &a);
 | 
			
		||||
 | 
			
		||||
	klist_add_tail(&b, &mylist);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 2);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &b);
 | 
			
		||||
 | 
			
		||||
	/* should be [list] -> a -> b */
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_add_head(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, NULL);
 | 
			
		||||
 | 
			
		||||
	klist_add_head(&a, &mylist);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 1);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &a);
 | 
			
		||||
 | 
			
		||||
	klist_add_head(&b, &mylist);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 2);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &b);
 | 
			
		||||
 | 
			
		||||
	/* should be [list] -> b -> a */
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_add_behind(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b, c, d;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, NULL);
 | 
			
		||||
 | 
			
		||||
	klist_add_head(&a, &mylist);
 | 
			
		||||
	klist_add_head(&b, &mylist);
 | 
			
		||||
 | 
			
		||||
	klist_add_behind(&c, &a);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 3);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
 | 
			
		||||
 | 
			
		||||
	klist_add_behind(&d, &b);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 4);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
 | 
			
		||||
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	/* should be [list] -> b -> d -> a -> c*/
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_add_before(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b, c, d;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, NULL);
 | 
			
		||||
 | 
			
		||||
	klist_add_head(&a, &mylist);
 | 
			
		||||
	klist_add_head(&b, &mylist);
 | 
			
		||||
	klist_add_before(&c, &a);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 3);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
 | 
			
		||||
 | 
			
		||||
	klist_add_before(&d, &b);
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 4);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
 | 
			
		||||
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	/* should be [list] -> b -> d -> a -> c*/
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Verify that klist_del() delays the deletion of a node until there
 | 
			
		||||
 * are no other references to it
 | 
			
		||||
 */
 | 
			
		||||
static void klist_test_del_refcount_greater_than_zero(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b, c, d;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, &check_delete_node);
 | 
			
		||||
 | 
			
		||||
	/* Add nodes a,b,c,d to the list*/
 | 
			
		||||
	klist_add_tail(&a, &mylist);
 | 
			
		||||
	klist_add_tail(&b, &mylist);
 | 
			
		||||
	klist_add_tail(&c, &mylist);
 | 
			
		||||
	klist_add_tail(&d, &mylist);
 | 
			
		||||
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	/* Advance the iterator to point to node c*/
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
 | 
			
		||||
 | 
			
		||||
	/* Try to delete node c while there is a reference to it*/
 | 
			
		||||
	klist_del(&c);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Verify that node c is still attached to the list even after being
 | 
			
		||||
	 * deleted. Since the iterator still points to c, the reference count is not
 | 
			
		||||
	 * decreased to 0
 | 
			
		||||
	 */
 | 
			
		||||
	KUNIT_EXPECT_TRUE(test, klist_node_attached(&c));
 | 
			
		||||
 | 
			
		||||
	/* Check that node c has not been removed yet*/
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 4);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Since the iterator is no longer pointing to node c, node c is removed
 | 
			
		||||
	 * from the list
 | 
			
		||||
	 */
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 3);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Verify that klist_del() deletes a node immediately when there are no
 | 
			
		||||
 * other references to it.
 | 
			
		||||
 */
 | 
			
		||||
static void klist_test_del_refcount_zero(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a, b, c, d;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, &check_delete_node);
 | 
			
		||||
 | 
			
		||||
	/* Add nodes a,b,c,d to the list*/
 | 
			
		||||
	klist_add_tail(&a, &mylist);
 | 
			
		||||
	klist_add_tail(&b, &mylist);
 | 
			
		||||
	klist_add_tail(&c, &mylist);
 | 
			
		||||
	klist_add_tail(&d, &mylist);
 | 
			
		||||
	/* Delete node c*/
 | 
			
		||||
	klist_del(&c);
 | 
			
		||||
 | 
			
		||||
	/* Check that node c is deleted from the list*/
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 3);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
 | 
			
		||||
 | 
			
		||||
	/* Should be [list] -> a -> b -> d*/
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_remove(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	/* This test doesn't check correctness under concurrent access */
 | 
			
		||||
	struct klist_node a, b, c, d;
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
	struct klist_iter i;
 | 
			
		||||
 | 
			
		||||
	node_count = 0;
 | 
			
		||||
	klist_init(&mylist, &check_node, &check_delete_node);
 | 
			
		||||
 | 
			
		||||
	/* Add nodes a,b,c,d to the list*/
 | 
			
		||||
	klist_add_tail(&a, &mylist);
 | 
			
		||||
	klist_add_tail(&b, &mylist);
 | 
			
		||||
	klist_add_tail(&c, &mylist);
 | 
			
		||||
	klist_add_tail(&d, &mylist);
 | 
			
		||||
	/* Delete node c*/
 | 
			
		||||
	klist_remove(&c);
 | 
			
		||||
 | 
			
		||||
	/* Check the nodes in the list*/
 | 
			
		||||
	KUNIT_EXPECT_EQ(test, node_count, 3);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
 | 
			
		||||
 | 
			
		||||
	/* should be [list] -> a -> b -> d*/
 | 
			
		||||
	klist_iter_init(&mylist, &i);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
 | 
			
		||||
	KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
 | 
			
		||||
	KUNIT_EXPECT_NULL(test, klist_next(&i));
 | 
			
		||||
 | 
			
		||||
	klist_iter_exit(&i);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void klist_test_node_attached(struct kunit *test)
 | 
			
		||||
{
 | 
			
		||||
	struct klist_node a = {};
 | 
			
		||||
	struct klist mylist;
 | 
			
		||||
 | 
			
		||||
	klist_init(&mylist, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	KUNIT_EXPECT_FALSE(test, klist_node_attached(&a));
 | 
			
		||||
	klist_add_head(&a, &mylist);
 | 
			
		||||
	KUNIT_EXPECT_TRUE(test, klist_node_attached(&a));
 | 
			
		||||
	klist_del(&a);
 | 
			
		||||
	KUNIT_EXPECT_FALSE(test, klist_node_attached(&a));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct kunit_case klist_test_cases[] = {
 | 
			
		||||
	KUNIT_CASE(klist_test_add_tail),
 | 
			
		||||
	KUNIT_CASE(klist_test_add_head),
 | 
			
		||||
	KUNIT_CASE(klist_test_add_behind),
 | 
			
		||||
	KUNIT_CASE(klist_test_add_before),
 | 
			
		||||
	KUNIT_CASE(klist_test_del_refcount_greater_than_zero),
 | 
			
		||||
	KUNIT_CASE(klist_test_del_refcount_zero),
 | 
			
		||||
	KUNIT_CASE(klist_test_remove),
 | 
			
		||||
	KUNIT_CASE(klist_test_node_attached),
 | 
			
		||||
	{},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct kunit_suite klist_test_module = {
 | 
			
		||||
	.name = "klist",
 | 
			
		||||
	.test_cases = klist_test_cases,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
kunit_test_suites(&list_test_module, &hlist_test_module, &klist_test_module);
 | 
			
		||||
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue