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