Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1/* SPDX-License-Identifier: GPL-2.0 */
  2/*
  3 * Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
  4 * Copyright (c) 2024 David Vernet <dvernet@meta.com>
  5 * Copyright (c) 2024 Tejun Heo <tj@kernel.org>
  6 */
  7#include <stdio.h>
  8#include <unistd.h>
  9#include <signal.h>
 10#include <libgen.h>
 11#include <bpf/bpf.h>
 12#include "scx_test.h"
 13
 14const char help_fmt[] =
 15"The runner for sched_ext tests.\n"
 16"\n"
 17"The runner is statically linked against all testcases, and runs them all serially.\n"
 18"It's required for the testcases to be serial, as only a single host-wide sched_ext\n"
 19"scheduler may be loaded at any given time."
 20"\n"
 21"Usage: %s [-t TEST] [-h]\n"
 22"\n"
 23"  -t TEST       Only run tests whose name includes this string\n"
 24"  -s            Include print output for skipped tests\n"
 25"  -q            Don't print the test descriptions during run\n"
 26"  -h            Display this help and exit\n";
 27
 28static volatile int exit_req;
 29static bool quiet, print_skipped;
 30
 31#define MAX_SCX_TESTS 2048
 32
 33static struct scx_test __scx_tests[MAX_SCX_TESTS];
 34static unsigned __scx_num_tests = 0;
 35
 36static void sigint_handler(int simple)
 37{
 38	exit_req = 1;
 39}
 40
 41static void print_test_preamble(const struct scx_test *test, bool quiet)
 42{
 43	printf("===== START =====\n");
 44	printf("TEST: %s\n", test->name);
 45	if (!quiet)
 46		printf("DESCRIPTION: %s\n", test->description);
 47	printf("OUTPUT:\n");
 48}
 49
 50static const char *status_to_result(enum scx_test_status status)
 51{
 52	switch (status) {
 53	case SCX_TEST_PASS:
 54	case SCX_TEST_SKIP:
 55		return "ok";
 56	case SCX_TEST_FAIL:
 57		return "not ok";
 58	default:
 59		return "<UNKNOWN>";
 60	}
 61}
 62
 63static void print_test_result(const struct scx_test *test,
 64			      enum scx_test_status status,
 65			      unsigned int testnum)
 66{
 67	const char *result = status_to_result(status);
 68	const char *directive = status == SCX_TEST_SKIP ? "SKIP " : "";
 69
 70	printf("%s %u %s # %s\n", result, testnum, test->name, directive);
 71	printf("=====  END  =====\n");
 72}
 73
 74static bool should_skip_test(const struct scx_test *test, const char * filter)
 75{
 76	return !strstr(test->name, filter);
 77}
 78
 79static enum scx_test_status run_test(const struct scx_test *test)
 80{
 81	enum scx_test_status status;
 82	void *context = NULL;
 83
 84	if (test->setup) {
 85		status = test->setup(&context);
 86		if (status != SCX_TEST_PASS)
 87			return status;
 88	}
 89
 90	status = test->run(context);
 91
 92	if (test->cleanup)
 93		test->cleanup(context);
 94
 95	return status;
 96}
 97
 98static bool test_valid(const struct scx_test *test)
 99{
100	if (!test) {
101		fprintf(stderr, "NULL test detected\n");
102		return false;
103	}
104
105	if (!test->name) {
106		fprintf(stderr,
107			"Test with no name found. Must specify test name.\n");
108		return false;
109	}
110
111	if (!test->description) {
112		fprintf(stderr, "Test %s requires description.\n", test->name);
113		return false;
114	}
115
116	if (!test->run) {
117		fprintf(stderr, "Test %s has no run() callback\n", test->name);
118		return false;
119	}
120
121	return true;
122}
123
124int main(int argc, char **argv)
125{
126	const char *filter = NULL;
127	unsigned testnum = 0, i;
128	unsigned passed = 0, skipped = 0, failed = 0;
129	int opt;
130
131	signal(SIGINT, sigint_handler);
132	signal(SIGTERM, sigint_handler);
133
134	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
135
136	while ((opt = getopt(argc, argv, "qst:h")) != -1) {
137		switch (opt) {
138		case 'q':
139			quiet = true;
140			break;
141		case 's':
142			print_skipped = true;
143			break;
144		case 't':
145			filter = optarg;
146			break;
147		default:
148			fprintf(stderr, help_fmt, basename(argv[0]));
149			return opt != 'h';
150		}
151	}
152
153	for (i = 0; i < __scx_num_tests; i++) {
154		enum scx_test_status status;
155		struct scx_test *test = &__scx_tests[i];
156
157		if (filter && should_skip_test(test, filter)) {
158			/*
159			 * Printing the skipped tests and their preambles can
160			 * add a lot of noise to the runner output. Printing
161			 * this is only really useful for CI, so let's skip it
162			 * by default.
163			 */
164			if (print_skipped) {
165				print_test_preamble(test, quiet);
166				print_test_result(test, SCX_TEST_SKIP, ++testnum);
167			}
168			continue;
169		}
170
171		print_test_preamble(test, quiet);
172		status = run_test(test);
173		print_test_result(test, status, ++testnum);
174		switch (status) {
175		case SCX_TEST_PASS:
176			passed++;
177			break;
178		case SCX_TEST_SKIP:
179			skipped++;
180			break;
181		case SCX_TEST_FAIL:
182			failed++;
183			break;
184		}
185	}
186	printf("\n\n=============================\n\n");
187	printf("RESULTS:\n\n");
188	printf("PASSED:  %u\n", passed);
189	printf("SKIPPED: %u\n", skipped);
190	printf("FAILED:  %u\n", failed);
191
192	return 0;
193}
194
195void scx_test_register(struct scx_test *test)
196{
197	SCX_BUG_ON(!test_valid(test), "Invalid test found");
198	SCX_BUG_ON(__scx_num_tests >= MAX_SCX_TESTS, "Maximum tests exceeded");
199
200	__scx_tests[__scx_num_tests++] = *test;
201}