162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * KUnit test for the KUnit executor. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2021, Google LLC. 662306a36Sopenharmony_ci * Author: Daniel Latypov <dlatypov@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <kunit/test.h> 1062306a36Sopenharmony_ci#include <kunit/attributes.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic void free_suite_set_at_end(struct kunit *test, const void *to_free); 1362306a36Sopenharmony_cistatic struct kunit_suite *alloc_fake_suite(struct kunit *test, 1462306a36Sopenharmony_ci const char *suite_name, 1562306a36Sopenharmony_ci struct kunit_case *test_cases); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic void dummy_test(struct kunit *test) {} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic struct kunit_case dummy_test_cases[] = { 2062306a36Sopenharmony_ci /* .run_case is not important, just needs to be non-NULL */ 2162306a36Sopenharmony_ci { .name = "test1", .run_case = dummy_test }, 2262306a36Sopenharmony_ci { .name = "test2", .run_case = dummy_test }, 2362306a36Sopenharmony_ci {}, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void parse_filter_test(struct kunit *test) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct kunit_glob_filter filter = {NULL, NULL}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci kunit_parse_glob_filter(&filter, "suite"); 3162306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite"); 3262306a36Sopenharmony_ci KUNIT_EXPECT_FALSE(test, filter.test_glob); 3362306a36Sopenharmony_ci kfree(filter.suite_glob); 3462306a36Sopenharmony_ci kfree(filter.test_glob); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci kunit_parse_glob_filter(&filter, "suite.test"); 3762306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite"); 3862306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, filter.test_glob, "test"); 3962306a36Sopenharmony_ci kfree(filter.suite_glob); 4062306a36Sopenharmony_ci kfree(filter.test_glob); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void filter_suites_test(struct kunit *test) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct kunit_suite *subsuite[3] = {NULL, NULL}; 4662306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 4762306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[2], 4862306a36Sopenharmony_ci }; 4962306a36Sopenharmony_ci struct kunit_suite_set got; 5062306a36Sopenharmony_ci int err = 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases); 5362306a36Sopenharmony_ci subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Want: suite1, suite2, NULL -> suite2, NULL */ 5662306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err); 5762306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 5862306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 5962306a36Sopenharmony_ci free_suite_set_at_end(test, &got); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Validate we just have suite2 */ 6262306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); 6362306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Contains one element (end is 1 past end) */ 6662306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, got.end - got.start, 1); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void filter_suites_test_glob_test(struct kunit *test) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct kunit_suite *subsuite[3] = {NULL, NULL}; 7262306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 7362306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[2], 7462306a36Sopenharmony_ci }; 7562306a36Sopenharmony_ci struct kunit_suite_set got; 7662306a36Sopenharmony_ci int err = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases); 7962306a36Sopenharmony_ci subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Want: suite1, suite2, NULL -> suite2 (just test1), NULL */ 8262306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, &err); 8362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 8462306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 8562306a36Sopenharmony_ci free_suite_set_at_end(test, &got); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Validate we just have suite2 */ 8862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); 8962306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2"); 9062306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, got.end - got.start, 1); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Now validate we just have test2 */ 9362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases); 9462306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->test_cases[0].name, "test2"); 9562306a36Sopenharmony_ci KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void filter_suites_to_empty_test(struct kunit *test) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct kunit_suite *subsuite[3] = {NULL, NULL}; 10162306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 10262306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[2], 10362306a36Sopenharmony_ci }; 10462306a36Sopenharmony_ci struct kunit_suite_set got; 10562306a36Sopenharmony_ci int err = 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases); 10862306a36Sopenharmony_ci subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err); 11162306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 11262306a36Sopenharmony_ci free_suite_set_at_end(test, &got); /* just in case */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end, 11562306a36Sopenharmony_ci "should be empty to indicate no match"); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void parse_filter_attr_test(struct kunit *test) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci int j, filter_count; 12162306a36Sopenharmony_ci struct kunit_attr_filter *parsed_filters; 12262306a36Sopenharmony_ci char filters[] = "speed>slow, module!=example", *filter = filters; 12362306a36Sopenharmony_ci int err = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci filter_count = kunit_get_filter_count(filters); 12662306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, filter_count, 2); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci parsed_filters = kunit_kcalloc(test, filter_count, sizeof(*parsed_filters), 12962306a36Sopenharmony_ci GFP_KERNEL); 13062306a36Sopenharmony_ci for (j = 0; j < filter_count; j++) { 13162306a36Sopenharmony_ci parsed_filters[j] = kunit_next_attr_filter(&filter, &err); 13262306a36Sopenharmony_ci KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter from '%s'", filters); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[0]), "speed"); 13662306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, parsed_filters[0].input, ">slow"); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[1]), "module"); 13962306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, parsed_filters[1].input, "!=example"); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic struct kunit_case dummy_attr_test_cases[] = { 14362306a36Sopenharmony_ci /* .run_case is not important, just needs to be non-NULL */ 14462306a36Sopenharmony_ci { .name = "slow", .run_case = dummy_test, .module_name = "dummy", 14562306a36Sopenharmony_ci .attr.speed = KUNIT_SPEED_SLOW }, 14662306a36Sopenharmony_ci { .name = "normal", .run_case = dummy_test, .module_name = "dummy" }, 14762306a36Sopenharmony_ci {}, 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void filter_attr_test(struct kunit *test) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct kunit_suite *subsuite[3] = {NULL, NULL}; 15362306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 15462306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[2], 15562306a36Sopenharmony_ci }; 15662306a36Sopenharmony_ci struct kunit_suite_set got; 15762306a36Sopenharmony_ci char filter[] = "speed>slow"; 15862306a36Sopenharmony_ci int err = 0; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "normal_suite", dummy_attr_test_cases); 16162306a36Sopenharmony_ci subsuite[1] = alloc_fake_suite(test, "slow_suite", dummy_attr_test_cases); 16262306a36Sopenharmony_ci subsuite[1]->attr.speed = KUNIT_SPEED_SLOW; // Set suite attribute 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Want: normal_suite(slow, normal), slow_suite(slow, normal), 16662306a36Sopenharmony_ci * NULL -> normal_suite(normal), NULL 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * The normal test in slow_suite is filtered out because the speed 16962306a36Sopenharmony_ci * attribute is unset and thus, the filtering is based on the parent attribute 17062306a36Sopenharmony_ci * of slow. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err); 17362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 17462306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 17562306a36Sopenharmony_ci free_suite_set_at_end(test, &got); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Validate we just have normal_suite */ 17862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); 17962306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, got.start[0]->name, "normal_suite"); 18062306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, got.end - got.start, 1); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Now validate we just have normal test case */ 18362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases); 18462306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[0].name, "normal"); 18562306a36Sopenharmony_ci KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void filter_attr_empty_test(struct kunit *test) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct kunit_suite *subsuite[3] = {NULL, NULL}; 19162306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 19262306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[2], 19362306a36Sopenharmony_ci }; 19462306a36Sopenharmony_ci struct kunit_suite_set got; 19562306a36Sopenharmony_ci char filter[] = "module!=dummy"; 19662306a36Sopenharmony_ci int err = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "suite1", dummy_attr_test_cases); 19962306a36Sopenharmony_ci subsuite[1] = alloc_fake_suite(test, "suite2", dummy_attr_test_cases); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err); 20262306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 20362306a36Sopenharmony_ci free_suite_set_at_end(test, &got); /* just in case */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end, 20662306a36Sopenharmony_ci "should be empty to indicate no match"); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void filter_attr_skip_test(struct kunit *test) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct kunit_suite *subsuite[2] = {NULL}; 21262306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 21362306a36Sopenharmony_ci .start = subsuite, .end = &subsuite[1], 21462306a36Sopenharmony_ci }; 21562306a36Sopenharmony_ci struct kunit_suite_set got; 21662306a36Sopenharmony_ci char filter[] = "speed>slow"; 21762306a36Sopenharmony_ci int err = 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci subsuite[0] = alloc_fake_suite(test, "suite", dummy_attr_test_cases); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Want: suite(slow, normal), NULL -> suite(slow with SKIP, normal), NULL */ 22262306a36Sopenharmony_ci got = kunit_filter_suites(&suite_set, NULL, filter, "skip", &err); 22362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 22462306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, err, 0); 22562306a36Sopenharmony_ci free_suite_set_at_end(test, &got); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Validate we have both the slow and normal test */ 22862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases); 22962306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, kunit_suite_num_test_cases(got.start[0]), 2); 23062306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[0].name, "slow"); 23162306a36Sopenharmony_ci KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[1].name, "normal"); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Now ensure slow is skipped and normal is not */ 23462306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, got.start[0]->test_cases[0].status, KUNIT_SKIPPED); 23562306a36Sopenharmony_ci KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].status); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic struct kunit_case executor_test_cases[] = { 23962306a36Sopenharmony_ci KUNIT_CASE(parse_filter_test), 24062306a36Sopenharmony_ci KUNIT_CASE(filter_suites_test), 24162306a36Sopenharmony_ci KUNIT_CASE(filter_suites_test_glob_test), 24262306a36Sopenharmony_ci KUNIT_CASE(filter_suites_to_empty_test), 24362306a36Sopenharmony_ci KUNIT_CASE(parse_filter_attr_test), 24462306a36Sopenharmony_ci KUNIT_CASE(filter_attr_test), 24562306a36Sopenharmony_ci KUNIT_CASE(filter_attr_empty_test), 24662306a36Sopenharmony_ci KUNIT_CASE(filter_attr_skip_test), 24762306a36Sopenharmony_ci {} 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic struct kunit_suite executor_test_suite = { 25162306a36Sopenharmony_ci .name = "kunit_executor_test", 25262306a36Sopenharmony_ci .test_cases = executor_test_cases, 25362306a36Sopenharmony_ci}; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cikunit_test_suites(&executor_test_suite); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* Test helpers */ 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void free_suite_set(void *suite_set) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci kunit_free_suite_set(*(struct kunit_suite_set *)suite_set); 26262306a36Sopenharmony_ci kfree(suite_set); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* Use the resource API to register a call to free_suite_set. 26662306a36Sopenharmony_ci * Since we never actually use the resource, it's safe to use on const data. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_cistatic void free_suite_set_at_end(struct kunit *test, const void *to_free) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct kunit_suite_set *free; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (!((struct kunit_suite_set *)to_free)->start) 27362306a36Sopenharmony_ci return; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci free = kzalloc(sizeof(struct kunit_suite_set), GFP_KERNEL); 27662306a36Sopenharmony_ci *free = *(struct kunit_suite_set *)to_free; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci kunit_add_action(test, free_suite_set, (void *)free); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic struct kunit_suite *alloc_fake_suite(struct kunit *test, 28262306a36Sopenharmony_ci const char *suite_name, 28362306a36Sopenharmony_ci struct kunit_case *test_cases) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct kunit_suite *suite; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* We normally never expect to allocate suites, hence the non-const cast. */ 28862306a36Sopenharmony_ci suite = kunit_kzalloc(test, sizeof(*suite), GFP_KERNEL); 28962306a36Sopenharmony_ci strncpy((char *)suite->name, suite_name, sizeof(suite->name) - 1); 29062306a36Sopenharmony_ci suite->test_cases = test_cases; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return suite; 29362306a36Sopenharmony_ci} 294