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