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