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