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