Skip to content

Commit 6c96697

Browse files
82marbagwipawel
authored andcommitted
tests: refactor test execution
Tests are now compiled into the kernel image and executed individually by specifying the test name as an option while booting with grub. The README file has been updated to show an example; another is in grub-test.cfg. Signed-off-by: Daniele Ahmed <ahmeddan amazon c;0m >
1 parent 103dd3f commit 6c96697

File tree

6 files changed

+223
-120
lines changed

6 files changed

+223
-120
lines changed

Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ COMMON_INCLUDES += -I$(PFMLIB_INCLUDE)
7171
endif
7272

7373
COMMON_FLAGS := $(COMMON_INCLUDES) -pipe -MP -MMD -m64 -D__x86_64__
74-
ifneq ($(UNITTEST),)
75-
COMMON_FLAGS += -DKTF_UNIT_TEST
76-
endif
7774

7875
ifeq ($(CONFIG_LIBPFM),y)
7976
COMMON_FLAGS += -DKTF_PMU

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ vcpus=1
136136

137137
You need to generate a bootable ISO for this.
138138

139+
### Adding new tests
140+
141+
New tests can be added by adding a new function in a file in the `tests` folder. Each test signature must
142+
be the same as `test_fn` provided in `test.h`. Tests can be enabled in `grub.cfg` by adding the option with key `tests` and values
143+
the comma-separated list of function names, such as `tests=test1,test2,unit_tests`.
144+
139145
## Style
140146

141147
The style for this project is defined in `.clang-format` file in the main directory of this repository.

grub/boot/grub/grub-test.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ terminal_input --append serial
55
terminal_output --append serial
66

77
menuentry "kernel64" {
8-
multiboot /boot/kernel64.bin integer=42 boolean=1 string=foo badstring=toolong booleantwo
8+
multiboot /boot/kernel64.bin integer=42 boolean=1 string=foo badstring=toolong booleantwo tests=unit_tests
99
boot
1010
}

include/test.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2021 Amazon.com, Inc. or its affiliates.
3+
* All Rights Reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright notice,
11+
* this list of conditions and the following disclaimer in the documentation
12+
* and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
#ifndef KTF_TEST_H
26+
#define KTF_TEST_H
27+
28+
#define MAX_OPT_TESTS_LEN 128
29+
30+
typedef int(test_fn)(void *arg);
31+
32+
#endif /* KTF_TEST_H */

tests/test.c

Lines changed: 40 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -24,134 +24,58 @@
2424
*/
2525
#include <console.h>
2626
#include <ktf.h>
27-
#include <real_mode.h>
2827
#include <sched.h>
29-
30-
#ifdef KTF_UNIT_TEST
31-
#include <cmdline.h>
32-
#include <cpuid.h>
3328
#include <string.h>
29+
#include <symbols.h>
30+
#include <test.h>
3431

35-
extern char *kernel_cmdline;
36-
37-
static char opt_string[4];
38-
string_cmd("string", opt_string);
39-
40-
static char opt_badstring[5];
41-
string_cmd("badstring", opt_badstring);
42-
43-
static unsigned long opt_ulong;
44-
ulong_cmd("integer", opt_ulong);
45-
46-
static bool opt_bool = 0;
47-
bool_cmd("boolean", opt_bool);
48-
49-
static bool opt_booltwo = 0;
50-
bool_cmd("booleantwo", opt_booltwo);
51-
52-
static char memmove_string[4];
53-
static char range_string[] = "123456";
54-
static char *src, *dst;
32+
static const char opt_test_delims[] = ",";
33+
#include <cmdline.h>
5534

56-
static void cpu_freq_expect(const char *cpu_str, uint64_t expectation) {
57-
uint64_t result = get_cpu_freq(cpu_str);
58-
if (result != expectation) {
59-
printk("Could not parse cpu frequency from string '%s'\n", cpu_str);
60-
printk("Expectation vs. result: %llu vs. %llu\n", expectation, result);
61-
BUG();
35+
enum get_next_test_result {
36+
TESTS_DONE,
37+
TESTS_FOUND,
38+
TESTS_ERROR,
39+
};
40+
typedef enum get_next_test_result get_next_test_result_t;
41+
42+
static char opt_tests[MAX_OPT_TESTS_LEN];
43+
string_cmd("tests", opt_tests);
44+
45+
static get_next_test_result_t get_next_test(test_fn **out_test_fn, char **out_name) {
46+
static char *opt = opt_tests;
47+
48+
*out_name = strtok(opt, opt_test_delims);
49+
50+
opt = NULL;
51+
if (*out_name) {
52+
*out_test_fn = symbol_address(*out_name);
53+
if (!*out_test_fn) {
54+
printk("Symbol for test %s not found\n", *out_name);
55+
return TESTS_ERROR;
56+
}
57+
return TESTS_FOUND;
6258
}
63-
64-
printk("Got CPU string '%s' and frequency '%llu'\n", cpu_str, result);
65-
return;
59+
return TESTS_DONE;
6660
}
6761

68-
static int __user_text func(void *arg) { return 0; }
69-
70-
static int ktf_unit_tests(void) {
71-
usermode_call(func, NULL);
72-
73-
printk("\nLet the UNITTESTs begin\n");
74-
printk("Commandline parsing: %s\n", kernel_cmdline);
75-
76-
if (strcmp(opt_string, "foo")) {
77-
printk("String parameter opt_string != foo: %s\n", opt_string);
78-
BUG();
79-
}
80-
else {
81-
printk("String parameter parsing works!\n");
82-
}
83-
84-
if (strcmp(opt_badstring, "tool")) {
85-
printk("String parameter opt_badstring != tool: %s\n", opt_badstring);
86-
BUG();
87-
}
88-
else {
89-
printk("String parameter parsing works!\n");
90-
}
91-
92-
if (opt_ulong != 42) {
93-
printk("Integer parameter opt_ulong != 42: %d\n", opt_ulong);
94-
BUG();
95-
}
96-
else {
97-
printk("Integer parameter parsing works!\n");
98-
}
62+
void test_main(void) {
63+
char *name;
64+
test_fn *fn = NULL;
65+
unsigned n = 0;
9966

100-
if (!opt_bool || !opt_booltwo) {
101-
printk("Boolean parameter opt_bool != true: %d\n", opt_bool);
102-
printk("Boolean parameter opt_booltwo != true: %d\n", opt_booltwo);
103-
BUG();
104-
}
105-
else {
106-
printk("Boolean parameter parsing works!\n");
107-
}
67+
printk("\nRunning tests\n");
10868

109-
printk("\nMemmove testing:\n");
110-
(void) memmove(memmove_string, opt_string, sizeof(opt_string));
111-
if (!strcmp(memmove_string, opt_string)) {
112-
printk("Moving around memory works!\n");
113-
}
114-
else {
115-
printk("Memmove'ing did not work: %s (%p) != %s (%p)\n", memmove_string,
116-
memmove_string, opt_string, opt_string);
117-
}
69+
while (get_next_test(&fn, &name) == TESTS_FOUND) {
70+
int rc;
11871

119-
src = (char *) range_string;
120-
dst = (char *) range_string + 2;
121-
(void) memmove(dst, src, 4);
122-
if (!strcmp(range_string, "121234")) {
123-
printk("Moving around memory with overlaping ranges works!\n");
72+
printk("Running test: %s\n", name);
73+
rc = fn(NULL);
74+
printk("Test %s returned: 0x%x\n", name, rc);
75+
n++;
12476
}
125-
else {
126-
printk("Overlaping memmove'ing did not work: %s != %s\n", range_string, "121234");
127-
}
128-
129-
cpu_freq_expect("Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz", 3500000000);
130-
cpu_freq_expect("Intel(R) Celeron(R) CPU J1900 @ 1.99GHz", 1990000000);
131-
cpu_freq_expect("AMD G-T48L Processor", 0);
132-
cpu_freq_expect("Intel(R) Atom(TM) CPU E3815 @ 1.46GHz", 1460000000);
133-
cpu_freq_expect("Intel(R) Atom(TM) CPU E620 @ 600MHz", 600000000);
134-
cpu_freq_expect("VIA C7 Processor 1000MHz", 1000000000);
135-
cpu_freq_expect("Intel(R) Core(TM) i7 CPU 950 @ 3.07GHz", 3070000000);
136-
cpu_freq_expect("AMD Ryzen Threadripper 1950X 16-Core Processor", 0);
137-
cpu_freq_expect("Prototyp Amazing Foo One @ 1GHz", 1000000000);
138-
cpu_freq_expect("Prototyp Amazing Foo Two @ 1.00GHz", 1000000000);
139-
140-
printk("Long mode to real mode transition:\n");
141-
long_to_real();
142-
143-
return 0;
144-
}
145-
#else
146-
static int ktf_unit_tests(void) { return 0; }
147-
#endif
148-
149-
void test_main(void) {
150-
printk("\nTest:\n");
151-
152-
ktf_unit_tests();
15377

15478
wait_for_all_tasks();
15579

156-
printk("Test done\n");
80+
printk("Tests completed: %u\n", n);
15781
}

tests/unittests.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) 2021 Amazon.com, Inc. or its affiliates.
3+
* All Rights Reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright notice,
11+
* this list of conditions and the following disclaimer in the documentation
12+
* and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
#include <console.h>
26+
#include <cpuid.h>
27+
#include <ktf.h>
28+
#include <real_mode.h>
29+
#include <sched.h>
30+
#include <string.h>
31+
#include <symbols.h>
32+
#include <test.h>
33+
34+
extern char *kernel_cmdline;
35+
#include <cmdline.h>
36+
37+
static char opt_string[4];
38+
string_cmd("string", opt_string);
39+
40+
static char opt_badstring[5];
41+
string_cmd("badstring", opt_badstring);
42+
43+
static unsigned long opt_ulong;
44+
ulong_cmd("integer", opt_ulong);
45+
46+
static bool opt_bool = 0;
47+
bool_cmd("boolean", opt_bool);
48+
49+
static bool opt_booltwo = 0;
50+
bool_cmd("booleantwo", opt_booltwo);
51+
52+
static char memmove_string[4];
53+
static char range_string[] = "123456";
54+
static char *src, *dst;
55+
56+
static void cpu_freq_expect(const char *cpu_str, uint64_t expectation) {
57+
uint64_t result = get_cpu_freq(cpu_str);
58+
if (result != expectation) {
59+
printk("Could not parse cpu frequency from string '%s'\n", cpu_str);
60+
printk("Expectation vs. result: %llu vs. %llu\n", expectation, result);
61+
BUG();
62+
}
63+
64+
printk("Got CPU string '%s' and frequency '%llu'\n", cpu_str, result);
65+
return;
66+
}
67+
68+
static int __user_text func(void *arg) { return 0; }
69+
70+
int unit_tests(void *_unused) {
71+
usermode_call(func, NULL);
72+
73+
printk("\nLet the UNITTESTs begin\n");
74+
printk("Commandline parsing: %s\n", kernel_cmdline);
75+
76+
if (strcmp(opt_string, "foo")) {
77+
printk("String parameter opt_string != foo: %s\n", opt_string);
78+
BUG();
79+
}
80+
else {
81+
printk("String parameter parsing works!\n");
82+
}
83+
84+
if (strcmp(opt_badstring, "tool")) {
85+
printk("String parameter opt_badstring != tool: %s\n", opt_badstring);
86+
BUG();
87+
}
88+
else {
89+
printk("String parameter parsing works!\n");
90+
}
91+
92+
if (opt_ulong != 42) {
93+
printk("Integer parameter opt_ulong != 42: %d\n", opt_ulong);
94+
BUG();
95+
}
96+
else {
97+
printk("Integer parameter parsing works!\n");
98+
}
99+
100+
if (!opt_bool || !opt_booltwo) {
101+
printk("Boolean parameter opt_bool != true: %d\n", opt_bool);
102+
printk("Boolean parameter opt_booltwo != true: %d\n", opt_booltwo);
103+
BUG();
104+
}
105+
else {
106+
printk("Boolean parameter parsing works!\n");
107+
}
108+
109+
printk("\nMemmove testing:\n");
110+
(void) memmove(memmove_string, opt_string, sizeof(opt_string));
111+
if (!strcmp(memmove_string, opt_string)) {
112+
printk("Moving around memory works!\n");
113+
}
114+
else {
115+
printk("Memmove'ing did not work: %s (%p) != %s (%p)\n", memmove_string,
116+
memmove_string, opt_string, opt_string);
117+
}
118+
119+
src = (char *) range_string;
120+
dst = (char *) range_string + 2;
121+
(void) memmove(dst, src, 4);
122+
if (!strcmp(range_string, "121234")) {
123+
printk("Moving around memory with overlaping ranges works!\n");
124+
}
125+
else {
126+
printk("Overlaping memmove'ing did not work: %s != %s\n", range_string, "121234");
127+
}
128+
129+
cpu_freq_expect("Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz", 3500000000);
130+
cpu_freq_expect("Intel(R) Celeron(R) CPU J1900 @ 1.99GHz", 1990000000);
131+
cpu_freq_expect("AMD G-T48L Processor", 0);
132+
cpu_freq_expect("Intel(R) Atom(TM) CPU E3815 @ 1.46GHz", 1460000000);
133+
cpu_freq_expect("Intel(R) Atom(TM) CPU E620 @ 600MHz", 600000000);
134+
cpu_freq_expect("VIA C7 Processor 1000MHz", 1000000000);
135+
cpu_freq_expect("Intel(R) Core(TM) i7 CPU 950 @ 3.07GHz", 3070000000);
136+
cpu_freq_expect("AMD Ryzen Threadripper 1950X 16-Core Processor", 0);
137+
cpu_freq_expect("Prototyp Amazing Foo One @ 1GHz", 1000000000);
138+
cpu_freq_expect("Prototyp Amazing Foo Two @ 1.00GHz", 1000000000);
139+
140+
printk("Long mode to real mode transition:\n");
141+
long_to_real();
142+
143+
return 0;
144+
}

0 commit comments

Comments
 (0)