xref: /linux/kernel/trace/rv/rv_monitors_test.c (revision 55ee4b931a7ffedc886175d265dd6e6d08fd4151)
18da2a883SGabriele Monaco // SPDX-License-Identifier: GPL-2.0
28da2a883SGabriele Monaco /*
38da2a883SGabriele Monaco  * Copyright (C) 2026-2029 Red Hat, Inc. Gabriele Monaco <gmonaco@redhat.com>
48da2a883SGabriele Monaco  *
58da2a883SGabriele Monaco  * RV monitor kunit tests:
68da2a883SGabriele Monaco  *   Tests the RV monitors by triggering fake events to verify monitor
78da2a883SGabriele Monaco  *   behavior and reactions. Tests start from the first defined event and
88da2a883SGabriele Monaco  *   trigger events in order to verify error detection.
98da2a883SGabriele Monaco  */
108da2a883SGabriele Monaco #include <rv/kunit.h>
118da2a883SGabriele Monaco #include <kunit/test-bug.h>
128da2a883SGabriele Monaco #include <linux/kernel.h>
138da2a883SGabriele Monaco #include <linux/rv.h>
148da2a883SGabriele Monaco #include "rv.h"
158da2a883SGabriele Monaco 
168da2a883SGabriele Monaco /*
178da2a883SGabriele Monaco  * An easy way to pass the context is to use kunit_get_current_test()->priv,
188da2a883SGabriele Monaco  * but this doesn't always work (e.g. a reactor running from another context
198da2a883SGabriele Monaco  * like softirq). Store the current value here whenever a test is running.
208da2a883SGabriele Monaco  */
218da2a883SGabriele Monaco static struct rv_kunit_ctx *active_ctx;
228da2a883SGabriele Monaco 
238da2a883SGabriele Monaco __printf(1, 0)
248da2a883SGabriele Monaco static void rv_kunit_mock_react(const char *msg, va_list args)
258da2a883SGabriele Monaco {
268da2a883SGabriele Monaco 	if (active_ctx)
278da2a883SGabriele Monaco 		++active_ctx->reactions;
288da2a883SGabriele Monaco }
298da2a883SGabriele Monaco 
308da2a883SGabriele Monaco /*
318da2a883SGabriele Monaco  * teardown_test - Disable the monitor for a kunit test
328da2a883SGabriele Monaco  *
338da2a883SGabriele Monaco  * Since per-task monitors are special, make sure we reset all the ones we
348da2a883SGabriele Monaco  * started manually here, if required.
358da2a883SGabriele Monaco  */
368da2a883SGabriele Monaco void teardown_test(void *arg)
378da2a883SGabriele Monaco {
388da2a883SGabriele Monaco 	const struct rv_kunit_mon *mon = arg;
398da2a883SGabriele Monaco 	struct kunit *test = kunit_get_current_test();
408da2a883SGabriele Monaco 
418da2a883SGabriele Monaco 	if (test) {
428da2a883SGabriele Monaco 		struct rv_kunit_ctx *ctx = test->priv;
438da2a883SGabriele Monaco 
448da2a883SGabriele Monaco 		RV_KUNIT_EXPECT_NO_REACTION(test, ctx);
458da2a883SGabriele Monaco 
468da2a883SGabriele Monaco 		if (mon->is_per_task && mon->task_reset) {
478da2a883SGabriele Monaco 			for (int i = 0; i < ctx->mock_task_count; i++)
488da2a883SGabriele Monaco 				mon->task_reset(ctx->mock_tasks[i]);
498da2a883SGabriele Monaco 			synchronize_rcu();
508da2a883SGabriele Monaco 		}
518da2a883SGabriele Monaco 	}
528da2a883SGabriele Monaco 
538da2a883SGabriele Monaco 	mon->rv_this->enabled = 0;
548da2a883SGabriele Monaco 
558da2a883SGabriele Monaco 	if (mon->rv_this->reactor)
568da2a883SGabriele Monaco 		mon->rv_this->react = mon->rv_this->reactor->react;
578da2a883SGabriele Monaco 	else
588da2a883SGabriele Monaco 		mon->rv_this->react = NULL;
598da2a883SGabriele Monaco 	active_ctx = NULL;
60cf8f191cSGabriele Monaco 	rv_mock_current(NULL);
618da2a883SGabriele Monaco 
628da2a883SGabriele Monaco 	if (mon->is_per_task)
638da2a883SGabriele Monaco 		*mon->task_slot = RV_PER_TASK_MONITOR_INIT;
648da2a883SGabriele Monaco 	else
658da2a883SGabriele Monaco 		mon->monitor_destroy();
668da2a883SGabriele Monaco }
678da2a883SGabriele Monaco 
688da2a883SGabriele Monaco /*
698da2a883SGabriele Monaco  * prepare_test - Enable the monitor for a kunit test
708da2a883SGabriele Monaco  *
718da2a883SGabriele Monaco  * Do the bare minimum to set up the monitor, per-task monitors are special as
728da2a883SGabriele Monaco  * "real" initialisation/destruction iterates over real tasks, and may register
738da2a883SGabriele Monaco  * handlers. All we need is to select the right slot in the task_struct.
748da2a883SGabriele Monaco  */
758da2a883SGabriele Monaco void prepare_test(struct kunit *test, const struct rv_kunit_mon *mon)
768da2a883SGabriele Monaco {
778da2a883SGabriele Monaco 	KUNIT_ASSERT_FALSE(test, mon->rv_this->enabled);
788da2a883SGabriele Monaco 
798da2a883SGabriele Monaco 	active_ctx = test->priv;
808da2a883SGabriele Monaco 	mon->rv_this->react = rv_kunit_mock_react;
818da2a883SGabriele Monaco 
828da2a883SGabriele Monaco 	if (mon->is_per_task)
838da2a883SGabriele Monaco 		*mon->task_slot = 0;
848da2a883SGabriele Monaco 	else
858da2a883SGabriele Monaco 		KUNIT_ASSERT_EQ(test, mon->monitor_init(), 0);
868da2a883SGabriele Monaco 
878da2a883SGabriele Monaco 	mon->rv_this->enabled = 1;
888da2a883SGabriele Monaco 
898da2a883SGabriele Monaco 	KUNIT_ASSERT_EQ(test, 0,
908da2a883SGabriele Monaco 			kunit_add_action_or_reset(test, teardown_test, (void *)mon));
918da2a883SGabriele Monaco }
928da2a883SGabriele Monaco 
938da2a883SGabriele Monaco struct task_struct *rv_kunit_alloc_mock_task(struct kunit *test)
948da2a883SGabriele Monaco {
958da2a883SGabriele Monaco 	struct rv_kunit_ctx *ctx = test->priv;
968da2a883SGabriele Monaco 	struct task_struct *tsk;
978da2a883SGabriele Monaco 
988da2a883SGabriele Monaco 	KUNIT_ASSERT_LT(test, ctx->mock_task_count, RV_KUNIT_MAX_MOCK_TASKS);
998da2a883SGabriele Monaco 
1008da2a883SGabriele Monaco 	tsk = kunit_kzalloc(test, sizeof(struct task_struct), GFP_KERNEL);
1018da2a883SGabriele Monaco 	KUNIT_ASSERT_NOT_NULL(test, tsk);
1028da2a883SGabriele Monaco 
1038da2a883SGabriele Monaco 	if (!IS_ENABLED(CONFIG_THREAD_INFO_IN_TASK)) {
1048da2a883SGabriele Monaco 		tsk->stack = kunit_kzalloc(test, sizeof(struct thread_info), GFP_KERNEL);
1058da2a883SGabriele Monaco 		KUNIT_ASSERT_NOT_NULL(test, tsk->stack);
1068da2a883SGabriele Monaco 	}
1078da2a883SGabriele Monaco 
1088da2a883SGabriele Monaco 	ctx->mock_tasks[ctx->mock_task_count++] = tsk;
1098da2a883SGabriele Monaco 	return tsk;
1108da2a883SGabriele Monaco }
1118da2a883SGabriele Monaco 
1128da2a883SGabriele Monaco static int rv_mon_test_init(struct kunit *test)
1138da2a883SGabriele Monaco {
1148da2a883SGabriele Monaco 	struct rv_kunit_ctx *ctx;
1158da2a883SGabriele Monaco 
1168da2a883SGabriele Monaco 	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
1178da2a883SGabriele Monaco 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
1188da2a883SGabriele Monaco 
1198da2a883SGabriele Monaco 	test->priv = ctx;
1208da2a883SGabriele Monaco 
1218da2a883SGabriele Monaco 	return 0;
1228da2a883SGabriele Monaco }
1238da2a883SGabriele Monaco 
1248da2a883SGabriele Monaco static void __maybe_unused rv_test_stub(struct kunit *test)
1258da2a883SGabriele Monaco {
1268da2a883SGabriele Monaco 	kunit_skip(test, "Monitor not enabled\n");
1278da2a883SGabriele Monaco }
1288da2a883SGabriele Monaco 
1298da2a883SGabriele Monaco /*
1308da2a883SGabriele Monaco  * rv_test_dummy - test reactions work as expected
1318da2a883SGabriele Monaco  */
1328da2a883SGabriele Monaco static void rv_test_dummy(struct kunit *test)
1338da2a883SGabriele Monaco {
1348da2a883SGabriele Monaco 	struct rv_kunit_ctx *ctx = test->priv;
1358da2a883SGabriele Monaco 	static struct rv_monitor dummy_monitor = {
1368da2a883SGabriele Monaco 		.name = "dummy",
1378da2a883SGabriele Monaco 		.react = rv_kunit_mock_react,
1388da2a883SGabriele Monaco 	};
1398da2a883SGabriele Monaco 
1408da2a883SGabriele Monaco 	active_ctx = ctx;
1418da2a883SGabriele Monaco 
1428da2a883SGabriele Monaco 	RV_KUNIT_EXPECT_REACTION_HERE(test, ctx)
1438da2a883SGabriele Monaco 		rv_react(&dummy_monitor, "dummy");
1448da2a883SGabriele Monaco 	RV_KUNIT_EXPECT_NO_REACTION(test, ctx);
1458da2a883SGabriele Monaco 
1468da2a883SGabriele Monaco 	active_ctx = NULL;
1478da2a883SGabriele Monaco }
1488da2a883SGabriele Monaco 
1498da2a883SGabriele Monaco #include "monitors/sco/sco_kunit.c"
1508da2a883SGabriele Monaco #include "monitors/sssw/sssw_kunit.c"
1518da2a883SGabriele Monaco #include "monitors/sts/sts_kunit.c"
1528da2a883SGabriele Monaco #include "monitors/opid/opid_kunit.c"
1538da2a883SGabriele Monaco #include "monitors/nomiss/nomiss_kunit.c"
154*51f3fe70SGabriele Monaco #include "monitors/pagefault/pagefault_kunit.c"
155*51f3fe70SGabriele Monaco #include "monitors/sleep/sleep_kunit.c"
1568da2a883SGabriele Monaco 
1578da2a883SGabriele Monaco static struct kunit_case rv_mon_test_cases[] = {
1588da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_dummy),
1598da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_sco),
1608da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_sssw),
1618da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_sts),
1628da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_opid),
1638da2a883SGabriele Monaco 	KUNIT_CASE(rv_test_nomiss),
164*51f3fe70SGabriele Monaco 	KUNIT_CASE(rv_test_pagefault),
165*51f3fe70SGabriele Monaco 	KUNIT_CASE(rv_test_sleep),
1668da2a883SGabriele Monaco 	{}
1678da2a883SGabriele Monaco };
1688da2a883SGabriele Monaco 
1698da2a883SGabriele Monaco static struct kunit_suite rv_mon_test_suite = {
1708da2a883SGabriele Monaco 	.name = "rv_mon",
1718da2a883SGabriele Monaco 	.suite_init = rv_set_testing,
1728da2a883SGabriele Monaco 	.suite_exit = rv_clear_testing,
1738da2a883SGabriele Monaco 	.init = rv_mon_test_init,
1748da2a883SGabriele Monaco 	.test_cases = rv_mon_test_cases,
1758da2a883SGabriele Monaco };
1768da2a883SGabriele Monaco 
1778da2a883SGabriele Monaco kunit_test_suites(&rv_mon_test_suite);
1788da2a883SGabriele Monaco 
1798da2a883SGabriele Monaco MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
1808da2a883SGabriele Monaco MODULE_DESCRIPTION("RV monitor kunit tests: test monitors by triggering reactions");
1818da2a883SGabriele Monaco MODULE_LICENSE("GPL");
1828da2a883SGabriele Monaco MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
183