aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2010-02-20 21:48:29 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2010-02-20 21:48:29 -0500
commitf3d21c128e5b40acd1f15e3ddcd7fd54ca3a9bed (patch)
treedf9d7ed4b1948e04437d046b5ed2f85949993edb /tests
parent8a1912c177e978574250cf80f8a50edf7424b158 (diff)
Introduce test framework for LITMUS^RT.
This is the beginning of the LITMUS^RT testsuite. The main design goals are flexibility and ease of test writing. To create a new test, simply write a test case in any C file in the tests/ subdirectory. The buildsystem will find the test and hook it up with the testrunner. Have a look at tests/fdso.c and include/tests.h to get an idea for what tests look like. Tests can be executed with the 'runtests' tool. Each testcase is executed in a separate process in order to ensure that tests do not influence each other.
Diffstat (limited to 'tests')
-rw-r--r--tests/fdso.c82
-rwxr-xr-xtests/make_catalog.py95
-rw-r--r--tests/runner.c77
3 files changed, 254 insertions, 0 deletions
diff --git a/tests/fdso.c b/tests/fdso.c
new file mode 100644
index 0000000..fb8a5bd
--- /dev/null
+++ b/tests/fdso.c
@@ -0,0 +1,82 @@
1#include <fcntl.h>
2#include <unistd.h>
3
4#include <stdio.h>
5
6
7#include "tests.h"
8
9#include "litmus.h"
10
11
12TESTCASE(fmlp_not_active, C_EDF | PFAIR | LINUX,
13 "don't open FMLP semaphores if FMLP is not supported")
14{
15 int fd;
16
17 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) );
18
19 ASSERT(fd != -1);
20
21 SYSCALL_FAILS(EBUSY, open_fmlp_sem(fd, 0) );
22
23 SYSCALL( close(fd) );
24
25 SYSCALL( remove(".fmlp_locks") );
26}
27
28
29TESTCASE(invalid_od, ALL,
30 "reject invalid object descriptors")
31{
32 SYSCALL_FAILS( EINVAL, fmlp_down(3) );
33
34 SYSCALL_FAILS( EINVAL, fmlp_up(3) );
35
36 SYSCALL_FAILS( EINVAL, od_close(3) );
37
38
39 SYSCALL_FAILS( EINVAL, fmlp_down(-1) );
40
41 SYSCALL_FAILS( EINVAL, fmlp_up(-1) );
42
43 SYSCALL_FAILS( EINVAL, od_close(-1) );
44}
45
46TESTCASE(not_inherit_od, GSN_EDF | PSN_EDF,
47 "don't inherit FDSO handles across fork")
48{
49 int fd, od, pid, status;
50
51 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) );
52
53 SYSCALL( od = open_fmlp_sem(fd, 0) );
54
55 SYSCALL( fmlp_down(od) );
56
57 SYSCALL( fmlp_up(od) );
58
59 pid = fork();
60
61 ASSERT( pid != -1 );
62
63 if (pid == 0) {
64 /* child */
65 SYSCALL_FAILS(EINVAL, fmlp_down(od) );
66 SYSCALL_FAILS(EINVAL, fmlp_up(od) );
67 exit(0);
68 } else {
69 SYSCALL( fmlp_down(od) );
70 SYSCALL( fmlp_up(od) );
71 SYSCALL( waitpid(pid, &status, 0) );
72 ASSERT(WEXITSTATUS(status) == 0);
73 }
74
75 SYSCALL( od_close(od) );
76
77 SYSCALL( close(fd) );
78
79 SYSCALL( remove(".fmlp_locks") );
80}
81
82
diff --git a/tests/make_catalog.py b/tests/make_catalog.py
new file mode 100755
index 0000000..75b6aca
--- /dev/null
+++ b/tests/make_catalog.py
@@ -0,0 +1,95 @@
1#!/usr/bin/env python
2
3import re
4import sys
5
6class TestCase(object):
7 def __init__(self, function, plugins, desc):
8 self.function = function
9 self.plugins = plugins
10 self.desc = desc
11
12 def __str__(self):
13 return 'TESTCASE(%s, %s, "%s")' % \
14 (self.function, " | ".join(self.plugins), self.desc)
15
16
17class Finder(object):
18 def __init__(self):
19 self.found = []
20 self.regex = re.compile(
21 "TESTCASE\\("
22 "\\s*([a-zA-z_0-9]+)\\s*," # function name
23 "\\s*([- |a-zA-z_0-9]+)\\s*," # plugins
24 "\\s*\"([^\"]*)\"\\s*" # description
25 "\\)"
26 , re.MULTILINE)
27
28 def search_file(self, fname):
29 f = open(fname, "r")
30 src = ''.join(f)
31 f.close()
32 matches = self.regex.findall(src)
33 del src
34
35 for m in matches:
36 name = m[0]
37 plugins = m[1].split('|')
38 desc = m[2]
39 plugins = [p.strip() for p in plugins]
40 self.found.append(TestCase(name, plugins, desc))
41
42
43def search_files(args=sys.argv[1:]):
44 f = Finder()
45 for fname in args:
46 try:
47 f.search_file(fname)
48 except IOError, msg:
49 sys.stderr.write("%s: %s\n" % (fname, msg))
50 sys.exit(1)
51 return f.found
52
53
54def create_tc_tables(out=sys.stdout):
55 def _(o):
56 out.write("%s\n" % str(o))
57
58 tests = search_files()
59
60 plugins = set()
61 for tc in tests:
62 for p in tc.plugins:
63 plugins.add(p)
64
65 plugins.discard('ALL')
66
67 _('#include "tests.h"')
68
69 for tc in tests:
70 _('void test_%s(void);' % tc.function)
71
72 _('struct testcase test_catalog[] = {')
73 for tc in tests:
74 _('\t{test_%s, "%s"},' % (tc.function, tc.desc))
75 _('};')
76
77 for p in plugins:
78 count = 0
79 _('int %s_TESTS[] = {' % p)
80 for (i, tc) in enumerate(tests):
81 if p in tc.plugins or 'ALL' in tc.plugins:
82 _('\t%d,' % i)
83 count += 1
84 _('};')
85 _('#define NUM_%s_TESTS %d' % (p, count))
86
87 _('struct testsuite testsuite[] = {')
88 for p in plugins:
89 _('\t{"%s", %s_TESTS, NUM_%s_TESTS},' % (p.replace('_', '-'), p, p))
90 _('};')
91 _('#define NUM_PLUGINS %s' % len(plugins))
92
93if __name__ == '__main__':
94 create_tc_tables()
95
diff --git a/tests/runner.c b/tests/runner.c
new file mode 100644
index 0000000..f2e42b2
--- /dev/null
+++ b/tests/runner.c
@@ -0,0 +1,77 @@
1#include <fcntl.h>
2#include <unistd.h>
3
4#include <sys/wait.h>
5
6#include <string.h>
7#include <stdio.h>
8
9
10/* auto generated by SConstruct */
11#include "__test_catalog.inc"
12
13#include "litmus.h"
14
15int run_test(struct testcase *tc) {
16 int status;
17 pid_t pid;
18
19 printf("** Testing: %s... ", tc->description);
20 fflush(stdout);
21 SYSCALL( pid = fork() );
22 if (pid == 0) {
23 /* child: init liblitmus and carry out test */
24 SYSCALL( init_litmus() );
25 tc->function();
26 exit(0);
27 } else {
28 /* parent: wait for completion of test */
29 SYSCALL( waitpid(pid, &status, 0) );
30 if (WEXITSTATUS(status) == 0)
31 printf("ok.\n");
32 }
33 return WEXITSTATUS(status) == 0;
34}
35
36int run_tests(int* testidx, int num_tests, const char* plugin)
37{
38 int idx, i;
39 int ok = 0;
40
41 printf("** Running tests for %s.\n", plugin);
42 for (i = 0; i < num_tests; i++) {
43 idx = testidx[i];
44 ok += run_test(test_catalog + idx);
45 }
46 return ok;
47}
48
49#define streq(s1, s2) (!strcmp(s1, s2))
50
51int main(int argc, char** argv)
52{
53 int ok, i;
54
55 printf("** LITMUS^RT test suite.\n");
56
57 if (argc == 2) {
58 for (i = 0; i < NUM_PLUGINS; i++)
59 if (streq(testsuite[i].plugin, argv[1])) {
60 ok = run_tests(testsuite[i].testcases,
61 testsuite[i].num_cases,
62 testsuite[i].plugin);
63 printf("** Result: %d ok, %d failed.\n",
64 ok, testsuite[i].num_cases - ok);
65 return ok == testsuite[i].num_cases ? 0 : 3;
66 }
67 fprintf(stderr, "** Unknown plugin: '%s'\n", argv[1]);
68 return 1;
69 } else {
70 fprintf(stderr, "Usage: %s <plugin name>\n", argv[0]);
71 fprintf(stderr, "Supported plugins: ");
72 for (i = 0; i < NUM_PLUGINS; i++)
73 fprintf(stderr, "%s ", testsuite[i].plugin);
74 fprintf(stderr, "\n");
75 return 2;
76 }
77}