revocable: Add Kunit test cases

Add Kunit test cases for the revocable API.

The test cases cover the following scenarios:
- Basic: Verifies that a consumer can successfully access the resource
  provided via the provider.
- Revocation: Verifies that after the provider revokes the resource,
  the consumer correctly receives a NULL pointer on a subsequent access.
- Try Access Macro: Same as "Revocation" but uses the
  REVOCABLE_TRY_ACCESS_WITH() and REVOCABLE_TRY_ACCESS_SCOPED().

A way to run the test:
$ ./tools/testing/kunit/kunit.py run \
        --kconfig_add CONFIG_REVOCABLE_KUNIT_TEST=y \
        revocable_test

Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Link: https://patch.msgid.link/20260116080235.350305-3-tzungbi@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Tzung-Bi Shih 2026-01-16 08:02:34 +00:00 committed by Greg Kroah-Hartman
parent 62eb557580
commit cd7693419b
4 changed files with 151 additions and 0 deletions

View file

@ -22373,6 +22373,7 @@ M: Tzung-Bi Shih <tzungbi@kernel.org>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/base/revocable.c
F: drivers/base/revocable_test.c
F: include/linux/revocable.h
RFKILL

View file

@ -250,3 +250,11 @@ config FW_DEVLINK_SYNC_STATE_TIMEOUT
work on.
endmenu
# Kunit test cases
config REVOCABLE_KUNIT_TEST
tristate "Kunit tests for revocable" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
Kunit tests for the revocable API.

View file

@ -35,3 +35,6 @@ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
# define_trace.h needs to know how to find our header
CFLAGS_trace.o := -I$(src)
obj-$(CONFIG_TRACING) += trace.o
# Kunit test cases
obj-$(CONFIG_REVOCABLE_KUNIT_TEST) += revocable_test.o

View file

@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2026 Google LLC
*
* Kunit tests for the revocable API.
*
* The test cases cover the following scenarios:
*
* - Basic: Verifies that a consumer can successfully access the resource
* provided via the provider.
*
* - Revocation: Verifies that after the provider revokes the resource,
* the consumer correctly receives a NULL pointer on a subsequent access.
*
* - Try Access Macro: Same as "Revocation" but uses the
* REVOCABLE_TRY_ACCESS_WITH() and REVOCABLE_TRY_ACCESS_SCOPED().
*/
#include <kunit/test.h>
#include <linux/revocable.h>
static void revocable_test_basic(struct kunit *test)
{
struct revocable_provider *rp;
struct revocable *rev;
void *real_res = (void *)0x12345678, *res;
rp = revocable_provider_alloc(real_res);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp);
rev = revocable_alloc(rp);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rev);
res = revocable_try_access(rev);
KUNIT_EXPECT_PTR_EQ(test, res, real_res);
revocable_withdraw_access(rev);
revocable_free(rev);
revocable_provider_revoke(rp);
}
static void revocable_test_revocation(struct kunit *test)
{
struct revocable_provider *rp;
struct revocable *rev;
void *real_res = (void *)0x12345678, *res;
rp = revocable_provider_alloc(real_res);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp);
rev = revocable_alloc(rp);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rev);
res = revocable_try_access(rev);
KUNIT_EXPECT_PTR_EQ(test, res, real_res);
revocable_withdraw_access(rev);
revocable_provider_revoke(rp);
res = revocable_try_access(rev);
KUNIT_EXPECT_PTR_EQ(test, res, NULL);
revocable_withdraw_access(rev);
revocable_free(rev);
}
static void revocable_test_try_access_macro(struct kunit *test)
{
struct revocable_provider *rp;
struct revocable *rev;
void *real_res = (void *)0x12345678, *res;
rp = revocable_provider_alloc(real_res);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp);
rev = revocable_alloc(rp);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rev);
{
REVOCABLE_TRY_ACCESS_WITH(rev, res);
KUNIT_EXPECT_PTR_EQ(test, res, real_res);
}
revocable_provider_revoke(rp);
{
REVOCABLE_TRY_ACCESS_WITH(rev, res);
KUNIT_EXPECT_PTR_EQ(test, res, NULL);
}
revocable_free(rev);
}
static void revocable_test_try_access_macro2(struct kunit *test)
{
struct revocable_provider *rp;
struct revocable *rev;
void *real_res = (void *)0x12345678, *res;
bool accessed;
rp = revocable_provider_alloc(real_res);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp);
rev = revocable_alloc(rp);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rev);
accessed = false;
REVOCABLE_TRY_ACCESS_SCOPED(rev, res) {
KUNIT_EXPECT_PTR_EQ(test, res, real_res);
accessed = true;
}
KUNIT_EXPECT_TRUE(test, accessed);
revocable_provider_revoke(rp);
accessed = false;
REVOCABLE_TRY_ACCESS_SCOPED(rev, res) {
KUNIT_EXPECT_PTR_EQ(test, res, NULL);
accessed = true;
}
KUNIT_EXPECT_TRUE(test, accessed);
revocable_free(rev);
}
static struct kunit_case revocable_test_cases[] = {
KUNIT_CASE(revocable_test_basic),
KUNIT_CASE(revocable_test_revocation),
KUNIT_CASE(revocable_test_try_access_macro),
KUNIT_CASE(revocable_test_try_access_macro2),
{}
};
static struct kunit_suite revocable_test_suite = {
.name = "revocable_test",
.test_cases = revocable_test_cases,
};
kunit_test_suite(revocable_test_suite);