Test updates.
[m6w6/libmemcached] / tests / test.c
1 /* uTest
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 */
8
9 /*
10 Sample test application.
11 */
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20 #include <time.h>
21 #include <fnmatch.h>
22
23 #include "test.h"
24
25 static void world_stats_print(world_stats_st *stats)
26 {
27 fprintf(stderr, "Total\t\t\t\t%u\n", stats->total);
28 fprintf(stderr, "\tFailed\t\t\t%u\n", stats->failed);
29 fprintf(stderr, "\tSkipped\t\t\t%u\n", stats->skipped);
30 fprintf(stderr, "\tSucceeded\t\t%u\n", stats->success);
31 }
32
33 static long int timedif(struct timeval a, struct timeval b)
34 {
35 register int us, s;
36
37 us = (int)(a.tv_usec - b.tv_usec);
38 us /= 1000;
39 s = (int)(a.tv_sec - b.tv_sec);
40 s *= 1000;
41 return s + us;
42 }
43
44 const char *test_strerror(test_return_t code)
45 {
46 switch (code) {
47 case TEST_SUCCESS:
48 return "ok";
49 case TEST_FAILURE:
50 return "failed";
51 case TEST_MEMORY_ALLOCATION_FAILURE:
52 return "memory allocation";
53 case TEST_SKIPPED:
54 return "skipped";
55 case TEST_MAXIMUM_RETURN:
56 default:
57 fprintf(stderr, "Unknown return value\n");
58 abort();
59 }
60 }
61
62 void create_core(void)
63 {
64 if (getenv("LIBMEMCACHED_NO_COREDUMP") == NULL)
65 {
66 pid_t pid= fork();
67
68 if (pid == 0)
69 {
70 abort();
71 }
72 else
73 {
74 while (waitpid(pid, NULL, 0) != pid)
75 {
76 ;
77 }
78 }
79 }
80 }
81
82
83 static test_return_t _runner_default(test_callback_fn func, void *p)
84 {
85 if (func)
86 {
87 return func(p);
88 }
89 else
90 {
91 return TEST_SUCCESS;
92 }
93 }
94
95 static world_runner_st defualt_runners= {
96 _runner_default,
97 _runner_default,
98 _runner_default
99 };
100
101
102 int main(int argc, char *argv[])
103 {
104 test_return_t return_code;
105 unsigned int x;
106 char *collection_to_run= NULL;
107 char *wildcard= NULL;
108 world_st world;
109 collection_st *collection;
110 collection_st *next;
111 void *world_ptr;
112
113 world_stats_st stats;
114
115 memset(&stats, 0, sizeof(stats));
116 memset(&world, 0, sizeof(world));
117 get_world(&world);
118
119 if (! world.runner)
120 {
121 world.runner= &defualt_runners;
122 }
123
124 collection= world.collections;
125
126 if (world.create)
127 {
128 test_return_t error;
129 world_ptr= world.create(&error);
130 if (error != TEST_SUCCESS)
131 exit(1);
132 }
133 else
134 {
135 world_ptr= NULL;
136 }
137
138 if (argc > 1)
139 collection_to_run= argv[1];
140
141 if (argc == 3)
142 wildcard= argv[2];
143
144 for (next= collection; next->name; next++)
145 {
146 test_st *run;
147
148 run= next->tests;
149 if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
150 continue;
151
152 fprintf(stderr, "\n%s\n\n", next->name);
153
154 for (x= 0; run->name; run++)
155 {
156 struct timeval start_time, end_time;
157 long int load_time= 0;
158
159 if (wildcard && fnmatch(wildcard, run->name, 0))
160 continue;
161
162 fprintf(stderr, "Testing %s", run->name);
163
164 if (world.collection_startup)
165 {
166 world.collection_startup(world_ptr);
167 }
168
169 if (run->requires_flush && world.flush)
170 {
171 world.flush(world_ptr);
172 }
173
174 if (world.pre_run)
175 {
176 world.pre_run(world_ptr);
177 }
178
179
180 if (next->pre && world.runner->pre)
181 {
182 return_code= world.runner->pre(next->pre, world_ptr);
183
184 if (return_code != TEST_SUCCESS)
185 {
186 goto error;
187 }
188 }
189
190 gettimeofday(&start_time, NULL);
191 return_code= world.runner->run(run->test_fn, world_ptr);
192 gettimeofday(&end_time, NULL);
193 load_time= timedif(end_time, start_time);
194
195 if (next->post && world.runner->post)
196 {
197 (void) world.runner->post(next->post, world_ptr);
198 }
199
200 if (world.post_run)
201 {
202 world.post_run(world_ptr);
203 }
204
205 error:
206 stats.total++;
207
208 fprintf(stderr, "\t\t\t\t\t");
209
210 switch (return_code)
211 {
212 case TEST_SUCCESS:
213 fprintf(stderr, "%ld.%03ld ", load_time / 1000, load_time % 1000);
214 stats.success++;
215 break;
216 case TEST_FAILURE:
217 stats.failed++;
218 break;
219 case TEST_SKIPPED:
220 stats.skipped++;
221 break;
222 case TEST_MEMORY_ALLOCATION_FAILURE:
223 case TEST_MAXIMUM_RETURN:
224 default:
225 break;
226 }
227
228 fprintf(stderr, "[ %s ]\n", test_strerror(return_code));
229
230 if (world.on_error)
231 {
232 test_return_t rc;
233 rc= world.on_error(return_code, world_ptr);
234
235 if (rc != TEST_SUCCESS)
236 break;
237 }
238 }
239 }
240
241 fprintf(stderr, "All tests completed successfully\n\n");
242
243 if (world.destroy)
244 {
245 test_return_t error;
246 error= world.destroy(world_ptr);
247
248 if (error != TEST_SUCCESS)
249 {
250 fprintf(stderr, "Failure during shutdown.\n");
251 stats.failed++; // We do this to make our exit code return 1
252 }
253 }
254
255 world_stats_print(&stats);
256
257 return stats.failed == 0 ? 0 : 1;
258 }