diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2010-02-25 18:16:52 -0500 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2010-02-25 18:16:52 -0500 |
commit | f534210a79a04e1e9aeec7dcb8e900d933b8bae2 (patch) | |
tree | bedbe39d82dbb9759a22826a3cd394114ab5486d | |
parent | 8026e36c2901691bde793f85f7a0f8ca6e9c44dc (diff) | |
parent | f3d21c128e5b40acd1f15e3ddcd7fd54ca3a9bed (diff) |
Merge branch 'tests'
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | SConstruct | 12 | ||||
-rw-r--r-- | include/tests.h | 50 | ||||
-rw-r--r-- | tests/fdso.c | 82 | ||||
-rwxr-xr-x | tests/make_catalog.py | 95 | ||||
-rw-r--r-- | tests/runner.c | 77 |
6 files changed, 320 insertions, 0 deletions
@@ -2,7 +2,11 @@ | |||
2 | *.o | 2 | *.o |
3 | *.a | 3 | *.a |
4 | 4 | ||
5 | # generated files | ||
6 | tests/__test_catalog.inc | ||
7 | |||
5 | # executables | 8 | # executables |
9 | runtests | ||
6 | rt_launch | 10 | rt_launch |
7 | wait_test | 11 | wait_test |
8 | np_test | 12 | np_test |
@@ -130,3 +130,15 @@ rt.Program('rt_launch', ['bin/rt_launch.c', 'bin/common.c']) | |||
130 | rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c']) | 130 | rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c']) |
131 | rt.Program('release_ts', 'bin/release_ts.c') | 131 | rt.Program('release_ts', 'bin/release_ts.c') |
132 | rtm.Program('measure_syscall', 'bin/null_call.c') | 132 | rtm.Program('measure_syscall', 'bin/null_call.c') |
133 | |||
134 | |||
135 | # ##################################################################### | ||
136 | # Test suite. | ||
137 | |||
138 | mkc = Builder(action = 'tests/make_catalog.py $SOURCE > $TARGET') | ||
139 | test = mtrt.Clone() | ||
140 | test.Append(BUILDERS = {'TestCatalog' : mkc}) | ||
141 | test.Append(CPPPATH = ['tests/']) | ||
142 | |||
143 | catalog = test.TestCatalog('tests/__test_catalog.inc', Glob('tests/*.c')) | ||
144 | test.Program('runtests', Glob('tests/*.c')) | ||
diff --git a/include/tests.h b/include/tests.h new file mode 100644 index 0000000..3adba18 --- /dev/null +++ b/include/tests.h | |||
@@ -0,0 +1,50 @@ | |||
1 | #ifndef TESTS_H | ||
2 | #define TESTS_H | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <errno.h> | ||
7 | |||
8 | #define fail(fmt, args...) \ | ||
9 | do { \ | ||
10 | fprintf(stderr, "\n!! TEST FAILURE " fmt "\n at %s:%d (%s)\n", \ | ||
11 | ## args, __FILE__, __LINE__, __FUNCTION__); \ | ||
12 | fflush(stderr); \ | ||
13 | exit(200); \ | ||
14 | } while (0) | ||
15 | |||
16 | #define ASSERT(predicate) \ | ||
17 | do { \ | ||
18 | if (!(predicate)) \ | ||
19 | fail("%s", #predicate); \ | ||
20 | } while (0) | ||
21 | |||
22 | #define SYSCALL(call) \ | ||
23 | do { \ | ||
24 | if ((call) < 0) \ | ||
25 | fail("%s, %m", #call); \ | ||
26 | } while (0) | ||
27 | |||
28 | #define SYSCALL_FAILS(expected, call) \ | ||
29 | do { \ | ||
30 | if ((call) == 0 || errno != (expected)) \ | ||
31 | fail("%s, %m (expected: %s)", #call, #expected); \ | ||
32 | } while (0) | ||
33 | |||
34 | |||
35 | typedef void (*testfun_t)(void); | ||
36 | |||
37 | struct testcase { | ||
38 | testfun_t function; | ||
39 | const char* description; | ||
40 | }; | ||
41 | |||
42 | struct testsuite { | ||
43 | const char* plugin; | ||
44 | int* testcases; | ||
45 | int num_cases; | ||
46 | }; | ||
47 | |||
48 | #define TESTCASE(function, plugins, description) void test_ ## function (void) | ||
49 | |||
50 | #endif | ||
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 | |||
12 | TESTCASE(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 | |||
29 | TESTCASE(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 | |||
46 | TESTCASE(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 | |||
3 | import re | ||
4 | import sys | ||
5 | |||
6 | class 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 | |||
17 | class 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 | |||
43 | def 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 | |||
54 | def 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 | |||
93 | if __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 | |||
15 | int 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 | |||
36 | int 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 | |||
51 | int 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 | } | ||