Merge lp:~tangent-org/libmemcached/1.0-build/ Build: jenkins-Libmemcached-235
[awesomized/libmemcached] / libtest / main.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Data Differential YATL (i.e. libtest) library
4 *
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #include "libtest/yatlcon.h"
38 #include <libtest/common.h>
39
40 #include <cassert>
41 #include <cstdlib>
42 #include <cstring>
43 #include <ctime>
44 #include <fnmatch.h>
45 #include <iostream>
46 #include <fstream>
47 #include <memory>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 #include <sys/types.h>
51 #include <sys/wait.h>
52 #include <unistd.h>
53
54 #include <signal.h>
55
56 #ifndef __INTEL_COMPILER
57 #pragma GCC diagnostic ignored "-Wold-style-cast"
58 #endif
59
60 using namespace libtest;
61
62 static void stats_print(libtest::Framework *frame)
63 {
64 if (frame->failed() == 0 and frame->success() == 0)
65 {
66 return;
67 }
68
69 Outn();
70 Out << "Collections\t\t\t\t\t" << frame->total();
71 Out << "\tFailed\t\t\t\t\t" << frame->failed();
72 Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
73 Out << "\tSucceeded\t\t\t\t" << frame->success();
74 Outn();
75 Out << "Tests\t\t\t\t\t" << frame->sum_total();
76 Out << "\tFailed\t\t\t\t" << frame->sum_failed();
77 Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
78 Out << "\tSucceeded\t\t\t" << frame->sum_success();
79 }
80
81 #include <getopt.h>
82 #include <unistd.h>
83
84 int main(int argc, char *argv[])
85 {
86 bool opt_massive= false;
87 unsigned long int opt_repeat= 1; // Run all tests once
88 bool opt_quiet= false;
89 std::string collection_to_run;
90 std::string wildcard;
91 std::string binary_name;
92
93 const char *just_filename= rindex(argv[0], '/');
94 if (just_filename)
95 {
96 just_filename++;
97 }
98 else
99 {
100 just_filename= argv[0];
101 }
102
103 if (just_filename[0] == 'l' and just_filename[1] == 't' and just_filename[2] == '-')
104 {
105 just_filename+= 3;
106 }
107 binary_name.append(just_filename);
108
109 /*
110 Valgrind does not currently work reliably, or sometimes at all, on OSX
111 - Fri Jun 15 11:24:07 EDT 2012
112 */
113 #if defined(TARGET_OS_OSX) && TARGET_OS_OSX
114 if (valgrind_is_caller())
115 {
116 return EXIT_SKIP;
117 }
118 #endif
119
120 // Options parsing
121 {
122 enum long_option_t {
123 OPT_LIBYATL_VERSION,
124 OPT_LIBYATL_MATCH_COLLECTION,
125 OPT_LIBYATL_MASSIVE,
126 OPT_LIBYATL_QUIET,
127 OPT_LIBYATL_MATCH_WILDCARD,
128 OPT_LIBYATL_REPEAT
129 };
130
131 static struct option long_options[]=
132 {
133 { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
134 { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
135 { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT },
136 { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
137 { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
138 { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
139 { 0, 0, 0, 0 }
140 };
141
142 int option_index= 0;
143 while (1)
144 {
145 int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
146 if (option_rv == -1)
147 {
148 break;
149 }
150
151 switch (option_rv)
152 {
153 case OPT_LIBYATL_VERSION:
154 break;
155
156 case OPT_LIBYATL_QUIET:
157 opt_quiet= true;
158 break;
159
160 case OPT_LIBYATL_REPEAT:
161 errno= 0;
162 opt_repeat= strtoul(optarg, (char **) NULL, 10);
163 if (errno != 0)
164 {
165 Error << "unknown value passed to --repeat: `" << optarg << "`";
166 exit(EXIT_FAILURE);
167 }
168
169 break;
170
171 case OPT_LIBYATL_MATCH_COLLECTION:
172 collection_to_run= optarg;
173 break;
174
175 case OPT_LIBYATL_MATCH_WILDCARD:
176 wildcard= optarg;
177 break;
178
179 case OPT_LIBYATL_MASSIVE:
180 opt_massive= true;
181 break;
182
183 case '?':
184 /* getopt_long already printed an error message. */
185 Error << "unknown option to getopt_long()";
186 exit(EXIT_FAILURE);
187
188 default:
189 break;
190 }
191 }
192 }
193
194 srandom((unsigned int)time(NULL));
195
196 errno= 0;
197 if (bool(getenv("YATL_REPEAT")))
198 {
199 errno= 0;
200 opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
201 if (errno != 0)
202 {
203 Error << "ENV YATL_REPEAT passed an invalid value: `" << getenv("YATL_REPEAT") << "`";
204 exit(EXIT_FAILURE);
205 }
206 }
207
208 if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
209 {
210 opt_quiet= true;
211 }
212 else if (getenv("JENKINS_URL"))
213 {
214 if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
215 { }
216 else
217 {
218 opt_quiet= true;
219 }
220 }
221
222 if ((bool(getenv("YATL_RUN_MASSIVE_TESTS"))) or opt_massive)
223 {
224 opt_massive= true;
225 }
226
227 if (opt_quiet)
228 {
229 close(STDOUT_FILENO);
230 }
231
232 if (opt_massive)
233 {
234 is_massive(opt_massive);
235 }
236
237 libtest::vchar_t tmp_directory;
238 tmp_directory.resize(1024);
239 if (getenv("LIBTEST_TMP"))
240 {
241 snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP"));
242 }
243 else
244 {
245 snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP);
246 }
247
248 if (chdir(&tmp_directory[0]) == -1)
249 {
250 libtest::vchar_t getcwd_buffer;
251 getcwd_buffer.resize(1024);
252 char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size());
253
254 Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno);
255 return EXIT_FAILURE;
256 }
257
258 if (libtest::libtool() == NULL)
259 {
260 Error << "Failed to locate libtool";
261 return EXIT_FAILURE;
262 }
263
264 if (getenv("YATL_COLLECTION_TO_RUN"))
265 {
266 if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
267 {
268 collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
269 }
270 }
271
272 if (collection_to_run.compare("none") == 0)
273 {
274 return EXIT_SUCCESS;
275 }
276
277 if (collection_to_run.empty() == false)
278 {
279 Out << "Only testing " << collection_to_run;
280 }
281
282 int exit_code;
283
284 try
285 {
286 do
287 {
288 exit_code= EXIT_SUCCESS;
289 fatal_assert(sigignore(SIGPIPE) == 0);
290
291 libtest::SignalThread signal;
292 if (signal.setup() == false)
293 {
294 Error << "Failed to setup signals";
295 return EXIT_FAILURE;
296 }
297
298 std::auto_ptr<libtest::Framework> frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard));
299
300 // Run create(), bail on error.
301 try
302 {
303 switch (frame->create())
304 {
305 case TEST_SUCCESS:
306 break;
307
308 case TEST_SKIPPED:
309 return EXIT_SKIP;
310
311 case TEST_FAILURE:
312 std::cerr << "Could not call frame->create()" << std::endl;
313 return EXIT_FAILURE;
314 }
315 }
316 catch (const libtest::__skipped& e)
317 {
318 return EXIT_SKIP;
319 }
320
321 frame->exec();
322
323 if (signal.is_shutdown() == false)
324 {
325 signal.set_shutdown(SHUTDOWN_GRACEFUL);
326 }
327
328 shutdown_t status= signal.get_shutdown();
329 if (status == SHUTDOWN_FORCED)
330 {
331 Out << "Tests were aborted.";
332 exit_code= EXIT_FAILURE;
333 }
334 else if (frame->failed())
335 {
336 Out << "Some test failed.";
337 exit_code= EXIT_FAILURE;
338 }
339 else if (frame->skipped() and frame->failed() and frame->success())
340 {
341 Out << "Some tests were skipped.";
342 }
343 else if (frame->success() and (frame->failed() == 0))
344 {
345 Out;
346 Out << "All tests completed successfully.";
347 }
348
349 stats_print(frame.get());
350
351 std::ofstream xml_file;
352 std::string file_name;
353 file_name.append(&tmp_directory[0]);
354 file_name.append(frame->name());
355 file_name.append(".xml");
356 xml_file.open(file_name.c_str(), std::ios::trunc);
357 libtest::Formatter::xml(*frame, xml_file);
358
359 Outn(); // Generate a blank to break up the messages if make check/test has been run
360 } while (exit_code == EXIT_SUCCESS and --opt_repeat);
361 }
362 catch (const libtest::__skipped& e)
363 {
364 return EXIT_SKIP;
365 }
366 catch (const libtest::__failure& e)
367 {
368 libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
369 exit_code= EXIT_FAILURE;
370 }
371 catch (const libtest::fatal& e)
372 {
373 std::cerr << "FATAL:" << e.what() << std::endl;
374 exit_code= EXIT_FAILURE;
375 }
376 catch (const libtest::disconnected& e)
377 {
378 std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
379 exit_code= EXIT_FAILURE;
380 }
381 catch (const std::exception& e)
382 {
383 std::cerr << "std::exception:" << e.what() << std::endl;
384 exit_code= EXIT_FAILURE;
385 }
386 catch (char const*)
387 {
388 std::cerr << "Exception:" << std::endl;
389 exit_code= EXIT_FAILURE;
390 }
391 catch (...)
392 {
393 std::cerr << "Unknown exception halted execution." << std::endl;
394 exit_code= EXIT_FAILURE;
395 }
396
397 return exit_code;
398 }