New stats output for collection information.
[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.test_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.flush)
205 {
206 world.flush(world_ptr);
207 }
208
209 if (world.pre_run)
210 {
211 world.pre_run(world_ptr);
212 }
213
214
215 if (next->pre && world.runner->pre)
216 {
217 return_code= world.runner->pre(next->pre, world_ptr);
218
219 if (return_code != TEST_SUCCESS)
220 {
221 goto error;
222 }
223 }
224
225 gettimeofday(&start_time, NULL);
226 return_code= world.runner->run(run->test_fn, world_ptr);
227 gettimeofday(&end_time, NULL);
228 load_time= timedif(end_time, start_time);
229
230 if (next->post && world.runner->post)
231 {
232 (void) world.runner->post(next->post, world_ptr);
233 }
234
235 if (world.post_run)
236 {
237 world.post_run(world_ptr);
238 }
239
240 error:
241 stats.total++;
242
243 fprintf(stderr, "\t\t\t\t\t");
244
245 switch (return_code)
246 {
247 case TEST_SUCCESS:
248 fprintf(stderr, "%ld.%03ld ", load_time / 1000, load_time % 1000);
249 stats.success++;
250 break;
251 case TEST_FAILURE:
252 stats.failed++;
253 failed= true;
254 break;
255 case TEST_SKIPPED:
256 stats.skipped++;
257 skipped= true;
258 break;
259 case TEST_MEMORY_ALLOCATION_FAILURE:
260 fprintf(stderr, "Exhausted memory, quitting\n");
261 abort();
262 case TEST_MAXIMUM_RETURN:
263 default:
264 assert(0); // Coding error.
265 break;
266 }
267
268 fprintf(stderr, "[ %s ]\n", test_strerror(return_code));
269
270 if (world.on_error)
271 {
272 test_return_t rc;
273 rc= world.on_error(return_code, world_ptr);
274
275 if (rc != TEST_SUCCESS)
276 break;
277 }
278 }
279
280 if (failed)
281 {
282 stats.collection_failed++;
283 }
284
285 if (skipped)
286 {
287 stats.collection_skipped++;
288 }
289
290 if (! failed && ! skipped)
291 {
292 stats.collection_success++;
293 }
294
295 if (world.collection_shutdown)
296 {
297 world.collection_shutdown(world_ptr);
298 }
299 }
300
301 if (stats.collection_failed || stats.collection_skipped)
302 {
303 fprintf(stderr, "Some test failures and/or skipped test occurred.\n\n");
304 }
305 else
306 {
307 fprintf(stderr, "All tests completed successfully\n\n");
308 }
309
310 if (world.destroy)
311 {
312 test_return_t error;
313 error= world.destroy(world_ptr);
314
315 if (error != TEST_SUCCESS)
316 {
317 fprintf(stderr, "Failure during shutdown.\n");
318 stats.failed++; // We do this to make our exit code return 1
319 }
320 }
321
322 world_stats_print(&stats);
323
324 return stats.failed == 0 ? 0 : 1;
325 }