Merge in code changes for all of the new parser.
[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 <libmemcached/memcached.h>
28
29 #include <libtest/test.h>
30 #include <libtest/failed.h>
31
32 static void world_stats_print(world_stats_st *stats)
33 {
34 fputc('\n', stderr);
35 fprintf(stderr, "Total Collections\t\t\t\t%u\n", stats->collection_total);
36 fprintf(stderr, "\tFailed Collections\t\t\t%u\n", stats->collection_failed);
37 fprintf(stderr, "\tSkipped Collections\t\t\t%u\n", stats->collection_skipped);
38 fprintf(stderr, "\tSucceeded Collections\t\t%u\n", stats->collection_success);
39 fputc('\n', stderr);
40 fprintf(stderr, "Total\t\t\t\t%u\n", stats->total);
41 fprintf(stderr, "\tFailed\t\t\t%u\n", stats->failed);
42 fprintf(stderr, "\tSkipped\t\t\t%u\n", stats->skipped);
43 fprintf(stderr, "\tSucceeded\t\t%u\n", stats->success);
44 }
45
46 long int timedif(struct timeval a, struct timeval b)
47 {
48 long us, s;
49
50 us = (int)(a.tv_usec - b.tv_usec);
51 us /= 1000;
52 s = (int)(a.tv_sec - b.tv_sec);
53 s *= 1000;
54 return s + us;
55 }
56
57 const char *test_strerror(test_return_t code)
58 {
59 switch (code) {
60 case TEST_SUCCESS:
61 return "ok";
62 case TEST_FAILURE:
63 return "failed";
64 case TEST_MEMORY_ALLOCATION_FAILURE:
65 return "memory allocation";
66 case TEST_SKIPPED:
67 return "skipped";
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 collection_st *next;
152 void *world_ptr;
153
154 world_stats_st stats;
155
156 #ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
157 if (sasl_client_init(NULL) != SASL_OK)
158 {
159 fprintf(stderr, "Failed to initialize sasl library!\n");
160 return EXIT_FAILURE;
161 }
162 #endif
163
164 memset(&stats, 0, sizeof(stats));
165 memset(&world, 0, sizeof(world));
166 get_world(&world);
167
168 collection= init_world(&world);
169
170 if (world.create)
171 {
172 test_return_t error;
173 world_ptr= world.create(&error);
174 if (error != TEST_SUCCESS)
175 exit(1);
176 }
177 else
178 {
179 world_ptr= NULL;
180 }
181
182 if (argc > 1)
183 collection_to_run= argv[1];
184
185 if (argc == 3)
186 wildcard= argv[2];
187
188 for (next= collection; next->name; next++)
189 {
190 test_return_t collection_rc= TEST_SUCCESS;
191 test_st *run;
192 bool failed= false;
193 bool skipped= false;
194
195 run= next->tests;
196 if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
197 continue;
198
199 stats.collection_total++;
200
201 collection_rc= world.collection.startup(world_ptr);
202
203 if (collection_rc != TEST_SUCCESS)
204 goto skip_pre;
205
206 if (next->pre)
207 {
208 collection_rc= world.runner->pre(next->pre, world_ptr);
209 }
210
211 skip_pre:
212 switch (collection_rc)
213 {
214 case TEST_SUCCESS:
215 fprintf(stderr, "\n%s\n\n", next->name);
216 break;
217 case TEST_FAILURE:
218 fprintf(stderr, "\n%s [ failed ]\n\n", next->name);
219 stats.collection_failed++;
220 goto cleanup;
221 case TEST_SKIPPED:
222 fprintf(stderr, "\n%s [ skipping ]\n\n", next->name);
223 stats.collection_skipped++;
224 goto cleanup;
225 case TEST_MEMORY_ALLOCATION_FAILURE:
226 case TEST_MAXIMUM_RETURN:
227 default:
228 assert(0);
229 break;
230 }
231
232
233 for (x= 0; run->name; run++)
234 {
235 struct timeval start_time, end_time;
236 long int load_time= 0;
237
238 if (wildcard && fnmatch(wildcard, run->name, 0))
239 continue;
240
241 fprintf(stderr, "Testing %s", run->name);
242
243 if (world.test.startup)
244 {
245 world.test.startup(world_ptr);
246 }
247
248 if (run->requires_flush && world.test.flush)
249 {
250 world.test.flush(world_ptr);
251 }
252
253 if (world.test.pre_run)
254 {
255 world.test.pre_run(world_ptr);
256 }
257
258
259 // Runner code
260 {
261 #if 0
262 if (next->pre && world.runner->pre)
263 {
264 return_code= world.runner->pre(next->pre, world_ptr);
265
266 if (return_code != TEST_SUCCESS)
267 {
268 goto error;
269 }
270 }
271 #endif
272
273 gettimeofday(&start_time, NULL);
274 return_code= world.runner->run(run->test_fn, world_ptr);
275 gettimeofday(&end_time, NULL);
276 load_time= timedif(end_time, start_time);
277
278 #if 0
279 if (next->post && world.runner->post)
280 {
281 (void) world.runner->post(next->post, world_ptr);
282 }
283 #endif
284 }
285
286 if (world.test.post_run)
287 {
288 world.test.post_run(world_ptr);
289 }
290
291 stats.total++;
292
293 fprintf(stderr, "\t\t\t\t\t");
294
295 switch (return_code)
296 {
297 case TEST_SUCCESS:
298 fprintf(stderr, "%ld.%03ld ", load_time / 1000, load_time % 1000);
299 stats.success++;
300 break;
301 case TEST_FAILURE:
302 #if 0
303 push_failed_test(next->name, run->name);
304 #endif
305 stats.failed++;
306 failed= true;
307 break;
308 case TEST_SKIPPED:
309 stats.skipped++;
310 skipped= true;
311 break;
312 case TEST_MEMORY_ALLOCATION_FAILURE:
313 fprintf(stderr, "Exhausted memory, quitting\n");
314 abort();
315 case TEST_MAXIMUM_RETURN:
316 default:
317 assert(0); // Coding error.
318 break;
319 }
320
321 fprintf(stderr, "[ %s ]\n", test_strerror(return_code));
322
323 if (world.test.on_error)
324 {
325 test_return_t rc;
326 rc= world.test.on_error(return_code, world_ptr);
327
328 if (rc != TEST_SUCCESS)
329 break;
330 }
331 }
332
333 if (next->post && world.runner->post)
334 {
335 (void) world.runner->post(next->post, world_ptr);
336 }
337
338 if (! failed && ! skipped)
339 {
340 stats.collection_success++;
341 }
342 cleanup:
343
344 world.collection.shutdown(world_ptr);
345 }
346
347 if (stats.collection_failed || stats.collection_skipped)
348 {
349 fprintf(stderr, "Some test failures and/or skipped test occurred.\n\n");
350 #if 0
351 print_failed_test();
352 #endif
353 }
354 else
355 {
356 fprintf(stderr, "All tests completed successfully\n\n");
357 }
358
359 if (world.destroy)
360 {
361 test_return_t error;
362 error= world.destroy(world_ptr);
363
364 if (error != TEST_SUCCESS)
365 {
366 fprintf(stderr, "Failure during shutdown.\n");
367 stats.failed++; // We do this to make our exit code return EXIT_FAILURE
368 }
369 }
370
371 world_stats_print(&stats);
372
373 #ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
374 sasl_done();
375 #endif
376
377 return stats.failed == 0 ? 0 : 1;
378 }