Merge in code such that we are much closer to running the same test
[m6w6/libmemcached] / libtest / test.cc
1 /* uTest
2 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
3 * Copyright (C) 2006-2009 Brian Aker
4 * All rights reserved.
5 *
6 * Use and distribution licensed under the BSD license. See
7 * the COPYING file in the parent directory for full text.
8 */
9
10
11 #include <config.h>
12
13 #include <stdint.h>
14 #include <assert.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <time.h>
23 #include <fnmatch.h>
24 #include <iostream>
25
26 #include <libtest/test.h>
27
28 #ifndef __INTEL_COMPILER
29 #pragma GCC diagnostic ignored "-Wold-style-cast"
30 #endif
31
32 static void world_stats_print(world_stats_st *stats)
33 {
34 std::cout << "\tTotal Collections\t\t\t\t" << stats->collection_total << std::endl;
35 std::cout << "\tFailed Collections\t\t\t\t" << stats->collection_failed << std::endl;
36 std::cout << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped << std::endl;
37 std::cout << "\tSucceeded Collections\t\t\t\t" << stats->collection_success << std::endl;
38 std::cout << std::endl;
39 std::cout << "Total\t\t\t\t" << stats->total << std::endl;
40 std::cout << "\tFailed\t\t\t" << stats->failed << std::endl;
41 std::cout << "\tSkipped\t\t\t" << stats->skipped << std::endl;
42 std::cout << "\tSucceeded\t\t" << stats->success << std::endl;
43 }
44
45 static long int timedif(struct timeval a, struct timeval b)
46 {
47 long us, s;
48
49 us = (long)(a.tv_usec - b.tv_usec);
50 us /= 1000;
51 s = (long)(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_FATAL:
64 return "failed";
65 case TEST_MEMORY_ALLOCATION_FAILURE:
66 return "memory allocation";
67 case TEST_SKIPPED:
68 return "skipped";
69 case TEST_MAXIMUM_RETURN:
70 default:
71 std::cerr << "Unknown return value." << std::endl;
72 abort();
73 }
74 }
75
76 void create_core(void)
77 {
78 if (getenv("LIBMEMCACHED_NO_COREDUMP") == NULL)
79 {
80 pid_t pid= fork();
81
82 if (pid == 0)
83 {
84 abort();
85 }
86 else
87 {
88 while (waitpid(pid, NULL, 0) != pid) {};
89 }
90 }
91 }
92
93
94 static test_return_t _runner_default(test_callback_fn func, void *p)
95 {
96 if (func)
97 return func(p);
98
99 return TEST_SUCCESS;
100 }
101
102 static world_runner_st defualt_runners= {
103 _runner_default,
104 _runner_default,
105 _runner_default
106 };
107
108 static test_return_t _default_callback(void *p)
109 {
110 (void)p;
111
112 return TEST_SUCCESS;
113 }
114
115 static collection_st *init_world(world_st *world)
116 {
117 if (world->runner == NULL)
118 {
119 world->runner= &defualt_runners;
120 }
121
122 if (world->collection_startup == NULL)
123 world->collection_startup= _default_callback;
124
125 if (world->collection_shutdown == NULL)
126 world->collection_shutdown= _default_callback;
127
128 return world->collections;
129 }
130
131
132 int main(int argc, char *argv[])
133 {
134 world_st world;
135 void *world_ptr;
136
137 world_stats_st stats;
138
139 get_world(&world);
140
141 if (not world.runner)
142 {
143 world.runner= &defualt_runners;
144 }
145
146 collection_st *collection= init_world(&world);
147
148 if (world.create)
149 {
150 test_return_t error;
151 world_ptr= world.create(&error);
152 if (error != TEST_SUCCESS)
153 {
154 return EXIT_FAILURE;
155 }
156 }
157 else
158 {
159 world_ptr= NULL;
160 }
161
162 char *collection_to_run= NULL;
163 if (argc > 1)
164 {
165 collection_to_run= argv[1];
166 }
167 else if (getenv("TEST_COLLECTION"))
168 {
169 collection_to_run= getenv("TEST_COLLECTION");
170 }
171
172 if (collection_to_run)
173 {
174 std::cout << "Only testing " << collection_to_run << std::endl;
175 }
176
177 char *wildcard= NULL;
178 if (argc == 3)
179 {
180 wildcard= argv[2];
181 }
182
183 for (collection_st *next= collection; next->name; next++)
184 {
185 test_return_t collection_rc= TEST_SUCCESS;
186 bool failed= false;
187 bool skipped= false;
188
189 if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
190 continue;
191
192 stats.collection_total++;
193
194 collection_rc= world.collection_startup(world_ptr);
195
196 if (collection_rc == TEST_SUCCESS and next->pre)
197 {
198 collection_rc= world.runner->pre(next->pre, world_ptr);
199 }
200
201 switch (collection_rc)
202 {
203 case TEST_SUCCESS:
204 std::cerr << std::endl << next->name << std::endl << std::endl;
205 break;
206
207 case TEST_FATAL:
208 case TEST_FAILURE:
209 std::cerr << std::endl << next->name << " [ failed ]" << std::endl << std::endl;
210 stats.collection_failed++;
211 goto cleanup;
212
213 case TEST_SKIPPED:
214 std::cerr << std::endl << next->name << " [ skipping ]" << std::endl << std::endl;
215 stats.collection_skipped++;
216 goto cleanup;
217
218 case TEST_MEMORY_ALLOCATION_FAILURE:
219 case TEST_MAXIMUM_RETURN:
220 default:
221 assert(0);
222 break;
223 }
224
225 for (test_st *run= next->tests; run->name; run++)
226 {
227 struct timeval start_time, end_time;
228 long int load_time= 0;
229
230 if (wildcard && fnmatch(wildcard, run->name, 0))
231 {
232 continue;
233 }
234
235 std::cerr << "\tTesting " << run->name;
236
237 if (world.run_startup)
238 {
239 world.run_startup(world_ptr);
240 }
241
242 if (run->requires_flush && world.flush)
243 {
244 world.flush(world_ptr);
245 }
246
247 if (world.pre_run)
248 {
249 world.pre_run(world_ptr);
250 }
251
252
253 test_return_t return_code;
254 { // Runner Code
255 #if 0
256 if (next->pre and world.runner->pre)
257 {
258 return_code= world.runner->pre(next->pre, world_ptr);
259
260 if (return_code != TEST_SUCCESS)
261 {
262 goto error;
263 }
264 }
265 #endif
266
267 gettimeofday(&start_time, NULL);
268 return_code= world.runner->run(run->test_fn, world_ptr);
269 gettimeofday(&end_time, NULL);
270 load_time= timedif(end_time, start_time);
271
272 #if 0
273 if (next->post && world.runner->post)
274 {
275 (void) world.runner->post(next->post, world_ptr);
276 }
277 #endif
278 }
279
280 if (world.post_run)
281 {
282 world.post_run(world_ptr);
283 }
284
285 stats.total++;
286
287 std::cerr << "\t\t\t\t\t";
288
289 switch (return_code)
290 {
291 case TEST_SUCCESS:
292 std::cerr << load_time / 1000 << "." << load_time % 1000;
293 stats.success++;
294 break;
295
296 case TEST_FATAL:
297 case TEST_FAILURE:
298 stats.failed++;
299 failed= true;
300 break;
301
302 case TEST_SKIPPED:
303 stats.skipped++;
304 skipped= true;
305 break;
306
307 case TEST_MEMORY_ALLOCATION_FAILURE:
308 case TEST_MAXIMUM_RETURN:
309 default:
310 break;
311 abort();
312 }
313
314 std::cerr << "[ " << test_strerror(return_code) << " ]" << std::endl;
315
316 if (world.on_error)
317 {
318 test_return_t rc= world.on_error(return_code, world_ptr);
319
320 if (rc != TEST_SUCCESS)
321 break;
322 }
323
324 }
325
326 if (next->post && world.runner->post)
327 {
328 (void) world.runner->post(next->post, world_ptr);
329 }
330
331 if (failed == 0 and skipped == 0)
332 {
333 stats.collection_success++;
334 }
335 cleanup:
336
337 if (world.collection_shutdown)
338 {
339 world.collection_shutdown(world_ptr);
340 }
341 }
342
343 if (stats.collection_failed || stats.collection_skipped)
344 {
345 std::cerr << std::endl << std::endl << "Some test failures and/or skipped test occurred." << std::endl << std::endl;
346 #if 0
347 print_failed_test();
348 #endif
349 }
350 else
351 {
352 std::cout << std::endl << std::endl << "All tests completed successfully." << std::endl << std::endl;
353 }
354
355 if (world.destroy)
356 {
357 test_return_t error= world.destroy(world_ptr);
358
359 if (error != TEST_SUCCESS)
360 {
361 std::cerr << "Failure during shutdown." << std::endl;
362 stats.failed++; // We do this to make our exit code return EXIT_FAILURE
363 }
364 }
365
366 world_stats_print(&stats);
367
368 return stats.failed == 0 ? 0 : 1;
369 }