Updates from Monty for Pandora
[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 #include <stdint.h>
23
24 #include "test.h"
25
26 static void world_stats_print(world_stats_st *stats)
27 {
28 fputc('\n', stderr);
29 fprintf(stderr, "Total Collections\t\t\t\t%u\n", stats->collection_total);
30 fprintf(stderr, "\tFailed Collections\t\t\t%u\n", stats->collection_failed);
31 fprintf(stderr, "\tSkipped Collections\t\t\t%u\n", stats->collection_skipped);
32 fprintf(stderr, "\tSucceeded Collections\t\t%u\n", stats->collection_success);
33 fputc('\n', stderr);
34 fprintf(stderr, "Total\t\t\t\t%u\n", stats->total);
35 fprintf(stderr, "\tFailed\t\t\t%u\n", stats->failed);
36 fprintf(stderr, "\tSkipped\t\t\t%u\n", stats->skipped);
37 fprintf(stderr, "\tSucceeded\t\t%u\n", stats->success);
38 }
39
40 static long int timedif(struct timeval a, struct timeval b)
41 {
42 long us, s;
43
44 us = (int)(a.tv_usec - b.tv_usec);
45 us /= 1000;
46 s = (int)(a.tv_sec - b.tv_sec);
47 s *= 1000;
48 return s + us;
49 }
50
51 const char *test_strerror(test_return_t code)
52 {
53 switch (code) {
54 case TEST_SUCCESS:
55 return "ok";
56 case TEST_FAILURE:
57 return "failed";
58 case TEST_MEMORY_ALLOCATION_FAILURE:
59 return "memory allocation";
60 case TEST_SKIPPED:
61 return "skipped";
62 case TEST_MAXIMUM_RETURN:
63 default:
64 fprintf(stderr, "Unknown return value\n");
65 abort();
66 }
67 }
68
69 void create_core(void)
70 {
71 if (getenv("LIBMEMCACHED_NO_COREDUMP") == NULL)
72 {
73 pid_t pid= fork();
74
75 if (pid == 0)
76 {
77 abort();
78 }
79 else
80 {
81 while (waitpid(pid, NULL, 0) != pid)
82 {
83 ;
84 }
85 }
86 }
87 }
88
89
90 static test_return_t _runner_default(test_callback_fn func, void *p)
91 {
92 if (func)
93 {
94 return func(p);
95 }
96 else
97 {
98 return TEST_SUCCESS;
99 }
100 }
101
102 static world_runner_st defualt_runners= {
103 _runner_default,
104 _runner_default,
105 _runner_default
106 };
107
108 static test_return_t _default_callback(void *p)
109 {
110 (void)p;
111
112 return TEST_SUCCESS;
113 }
114
115 static inline void set_default_fn(test_callback_fn *fn)
116 {
117 if (*fn == NULL)
118 {
119 *fn= _default_callback;
120 }
121 }
122
123 static collection_st *init_world(world_st *world)
124 {
125 if (! world->runner)
126 {
127 world->runner= &defualt_runners;
128 }
129
130 set_default_fn(&world->collection.startup);
131 set_default_fn(&world->collection.shutdown);
132
133 return world->collections;
134 }
135
136
137 int main(int argc, char *argv[])
138 {
139 test_return_t return_code;
140 unsigned int x;
141 char *collection_to_run= NULL;
142 char *wildcard= NULL;
143 world_st world;
144 collection_st *collection;
145 collection_st *next;
146 void *world_ptr;
147
148 world_stats_st stats;
149
150 memset(&stats, 0, sizeof(stats));
151 memset(&world, 0, sizeof(world));
152 get_world(&world);
153
154 collection= init_world(&world);
155
156 if (world.create)
157 {
158 test_return_t error;
159 world_ptr= world.create(&error);
160 if (error != TEST_SUCCESS)
161 exit(1);
162 }
163 else
164 {
165 world_ptr= NULL;
166 }
167
168 if (argc > 1)
169 collection_to_run= argv[1];
170
171 if (argc == 3)
172 wildcard= argv[2];
173
174 for (next= collection; next->name; next++)
175 {
176 test_return_t collection_rc= TEST_SUCCESS;
177 test_st *run;
178 bool failed= false;
179 bool skipped= false;
180
181 run= next->tests;
182 if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
183 continue;
184
185 stats.collection_total++;
186
187 collection_rc= world.collection.startup(world_ptr);
188
189 switch (collection_rc)
190 {
191 case TEST_SUCCESS:
192 fprintf(stderr, "\n%s\n\n", next->name);
193 break;
194 case TEST_FAILURE:
195 fprintf(stderr, "\n%s [ failed ]\n\n", next->name);
196 stats.failed++;
197 continue;
198 case TEST_SKIPPED:
199 fprintf(stderr, "\n%s [ skipping ]\n\n", next->name);
200 stats.skipped++;
201 continue;
202 case TEST_MEMORY_ALLOCATION_FAILURE:
203 case TEST_MAXIMUM_RETURN:
204 default:
205 assert(0);
206 break;
207 }
208
209 for (x= 0; run->name; run++)
210 {
211 struct timeval start_time, end_time;
212 long int load_time= 0;
213
214 if (wildcard && fnmatch(wildcard, run->name, 0))
215 continue;
216
217 fprintf(stderr, "Testing %s", run->name);
218
219 if (world.test.startup)
220 {
221 world.test.startup(world_ptr);
222 }
223
224 if (run->requires_flush && world.test.flush)
225 {
226 world.test.flush(world_ptr);
227 }
228
229 if (world.test.pre_run)
230 {
231 world.test.pre_run(world_ptr);
232 }
233
234
235 // Runner code
236 {
237 if (next->pre && world.runner->pre)
238 {
239 return_code= world.runner->pre(next->pre, world_ptr);
240
241 if (return_code != TEST_SUCCESS)
242 {
243 goto error;
244 }
245 }
246
247 gettimeofday(&start_time, NULL);
248 return_code= world.runner->run(run->test_fn, world_ptr);
249 gettimeofday(&end_time, NULL);
250 load_time= timedif(end_time, start_time);
251
252 if (next->post && world.runner->post)
253 {
254 (void) world.runner->post(next->post, world_ptr);
255 }
256 }
257
258 if (world.test.post_run)
259 {
260 world.test.post_run(world_ptr);
261 }
262
263 error:
264 stats.total++;
265
266 fprintf(stderr, "\t\t\t\t\t");
267
268 switch (return_code)
269 {
270 case TEST_SUCCESS:
271 fprintf(stderr, "%ld.%03ld ", load_time / 1000, load_time % 1000);
272 stats.success++;
273 break;
274 case TEST_FAILURE:
275 stats.failed++;
276 failed= true;
277 break;
278 case TEST_SKIPPED:
279 stats.skipped++;
280 skipped= true;
281 break;
282 case TEST_MEMORY_ALLOCATION_FAILURE:
283 fprintf(stderr, "Exhausted memory, quitting\n");
284 abort();
285 case TEST_MAXIMUM_RETURN:
286 default:
287 assert(0); // Coding error.
288 break;
289 }
290
291 fprintf(stderr, "[ %s ]\n", test_strerror(return_code));
292
293 if (world.test.on_error)
294 {
295 test_return_t rc;
296 rc= world.test.on_error(return_code, world_ptr);
297
298 if (rc != TEST_SUCCESS)
299 break;
300 }
301 }
302
303 if (failed)
304 {
305 stats.collection_failed++;
306 }
307
308 if (skipped)
309 {
310 stats.collection_skipped++;
311 }
312
313 if (! failed && ! skipped)
314 {
315 stats.collection_success++;
316 }
317
318 world.collection.shutdown(world_ptr);
319 }
320
321 if (stats.collection_failed || stats.collection_skipped)
322 {
323 fprintf(stderr, "Some test failures and/or skipped test occurred.\n\n");
324 }
325 else
326 {
327 fprintf(stderr, "All tests completed successfully\n\n");
328 }
329
330 if (world.destroy)
331 {
332 test_return_t error;
333 error= world.destroy(world_ptr);
334
335 if (error != TEST_SUCCESS)
336 {
337 fprintf(stderr, "Failure during shutdown.\n");
338 stats.failed++; // We do this to make our exit code return 1
339 }
340 }
341
342 world_stats_print(&stats);
343
344 return stats.failed == 0 ? 0 : 1;
345 }