/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: * * Data Differential YATL (i.e. libtest) library * * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * * The names of its contributors may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "libtest/yatlcon.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __INTEL_COMPILER #pragma GCC diagnostic ignored "-Wold-style-cast" #endif using namespace libtest; #include #include #if __GNUC__ >= 7 #pragma GCC diagnostic warning "-Wimplicit-fallthrough" #endif int main(int argc, char *argv[], char* environ_[]) { bool opt_massive= false; bool opt_ssl= false; unsigned long int opt_repeat= 1; // Run all tests once bool opt_verbose= false; bool opt_quiet= false; bool opt_list_collection= false; bool opt_list_tests= false; std::string collection_to_run; std::string wildcard; std::string binary_name; const char *just_filename= rindex(argv[0], '/'); if (just_filename) { just_filename++; } else { just_filename= argv[0]; } if (just_filename[0] == 'l' and just_filename[1] == 't' and just_filename[2] == '-') { just_filename+= 3; } binary_name.append(just_filename); /* Valgrind does not currently work reliably, or sometimes at all, on OSX - Fri Jun 15 11:24:07 EDT 2012 */ #if defined(__APPLE__) && __APPLE__ if (valgrind_is_caller()) { return EXIT_SKIP; } #endif // Options parsing { enum long_option_t { OPT_LIBYATL_HELP, OPT_LIBYATL_VERBOSE, OPT_LIBYATL_VERSION, OPT_LIBYATL_MATCH_COLLECTION, OPT_LIBYATL_LIST_COLLECTIONS, OPT_LIBYATL_LIST_TESTS, OPT_LIBYATL_MASSIVE, OPT_LIBYATL_QUIET, OPT_LIBYATL_MATCH_WILDCARD, OPT_LIBYATL_REPEAT, OPT_LIBYATL_SSL, OPT_LIBYATL_MAX }; static struct option long_options[]= { { "help", no_argument, NULL, OPT_LIBYATL_HELP }, { "verbose", no_argument, NULL, OPT_LIBYATL_VERBOSE }, { "version", no_argument, NULL, OPT_LIBYATL_VERSION }, { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET }, { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT }, { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION }, { "list-collections", no_argument, NULL, OPT_LIBYATL_LIST_COLLECTIONS }, { "list-tests", no_argument, NULL, OPT_LIBYATL_LIST_TESTS }, { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD }, { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE }, { "ssl", no_argument, NULL, OPT_LIBYATL_SSL }, { 0, 0, 0, 0 } }; int option_index= 0; while (1) { int option_rv= getopt_long(argc, argv, "", long_options, &option_index); if (option_rv == -1) { break; } switch (option_rv) { case OPT_LIBYATL_HELP: for (struct option *opt= long_options; opt->name; ++opt) { Out << "--" << opt->name; } exit(EXIT_SUCCESS); case OPT_LIBYATL_VERBOSE: opt_verbose= true; break; case OPT_LIBYATL_VERSION: break; case OPT_LIBYATL_QUIET: opt_quiet= true; break; case OPT_LIBYATL_REPEAT: errno= 0; opt_repeat= strtoul(optarg, (char **) NULL, 10); if (errno != 0) { Error << "unknown value passed to --repeat: `" << optarg << "`"; exit(EXIT_FAILURE); } break; case OPT_LIBYATL_LIST_TESTS: opt_list_tests= true; opt_list_collection= true; break; case OPT_LIBYATL_LIST_COLLECTIONS: opt_list_collection= true; break; case OPT_LIBYATL_MATCH_COLLECTION: collection_to_run= optarg; break; case OPT_LIBYATL_MATCH_WILDCARD: wildcard= optarg; break; case OPT_LIBYATL_SSL: opt_ssl= true; break; case OPT_LIBYATL_MASSIVE: opt_massive= true; break; case '?': /* getopt_long already printed an error message. */ Error << "unknown option to getopt_long()"; exit(EXIT_FAILURE); default: break; } } } if (opt_verbose) { for (char** ptr= environ_; *ptr; ptr++) { Out << *ptr; } } srandom((unsigned int)time(NULL)); errno= 0; if (bool(getenv("YATL_REPEAT"))) { errno= 0; opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10); if (errno != 0) { Error << "ENV YATL_REPEAT passed an invalid value: `" << getenv("YATL_REPEAT") << "`"; exit(EXIT_FAILURE); } } if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet) { opt_quiet= true; } else if (getenv("JENKINS_URL")) { if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0)) { } else { opt_quiet= true; } } if (getenv("YATL_WILDCARD")) { wildcard= getenv("YATL_WILDCARD"); } if (getenv("YATL_RUN_MASSIVE_TESTS")) { opt_massive= true; } if (getenv("YATL_SSL")) { opt_ssl= true; } if (opt_quiet) { close(STDOUT_FILENO); } if (opt_ssl) { is_ssl(opt_ssl); } if (opt_massive) { is_massive(opt_massive); } libtest::vchar_t tmp_directory; tmp_directory.resize(1024); if (getenv("LIBTEST_TMP")) { snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP")); } else { snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP); } if (chdir(&tmp_directory[0]) == -1) { libtest::vchar_t getcwd_buffer; getcwd_buffer.resize(1024); char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size()); Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno); return EXIT_FAILURE; } if (libtest::libtool() == NULL) { Error << "Failed to locate libtool"; return EXIT_FAILURE; } if (getenv("YATL_COLLECTION_TO_RUN")) { if (strlen(getenv("YATL_COLLECTION_TO_RUN"))) { collection_to_run= getenv("YATL_COLLECTION_TO_RUN"); } } if (collection_to_run.compare("none") == 0) { return EXIT_SUCCESS; } if (collection_to_run.empty() == false) { Out << "Only testing " << collection_to_run; } int exit_code; try { do { exit_code= EXIT_SUCCESS; struct sigaction sa; sa.sa_handler= SIG_IGN; fatal_assert(sigaction(SIGPIPE, &sa, NULL) == 0); libtest::SignalThread signal; if (signal.setup() == false) { Error << "Failed to setup signals"; return EXIT_FAILURE; } std::unique_ptr frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard)); if (opt_list_collection) { for (Suites::iterator iter= frame->suites().begin(); iter != frame->suites().end(); ++iter) { if (opt_list_tests) { for (TestCases::iterator test_iter= (*iter)->tests().begin(); test_iter != (*iter)->tests().end(); ++test_iter) { Out << (*iter)->name() << "." << (*test_iter)->name(); } } else { Out << (*iter)->name(); } } continue; } // Run create(), bail on error. { switch (frame->create()) { case TEST_SUCCESS: break; case TEST_SKIPPED: SKIP("SKIP was returned from framework create()"); break; case TEST_FAILURE: std::cerr << "Could not call frame->create()" << std::endl; return EXIT_FAILURE; } } frame->exec(); if (signal.is_shutdown() == false) { signal.set_shutdown(SHUTDOWN_GRACEFUL); } shutdown_t status= signal.get_shutdown(); if (status == SHUTDOWN_FORCED) { // Tests were aborted exit_code= EXIT_FAILURE; } else if (frame->failed()) { // Some test failed exit_code= EXIT_FAILURE; } else if (frame->skipped() and frame->failed() and frame->success()) { // Some tests were skipped } else if (frame->success() and (frame->failed() == 0)) { // Success } #if 0 { std::ofstream xml_file; std::string file_name; if (getenv("WORKSPACE")) { file_name.append(getenv("WORKSPACE")); file_name.append("/"); } file_name.append(frame->name()); file_name.append(".xml"); xml_file.open(file_name.c_str(), std::ios::trunc); libtest::Formatter::xml(*frame, xml_file); } #endif #if 0 { std::ofstream tap_file; std::string file_name; if (getenv("WORKSPACE")) { file_name.append(getenv("WORKSPACE")); file_name.append("/"); } file_name.append(frame->name()); file_name.append(".tap"); tap_file.open(file_name.c_str(), std::ios::trunc); libtest::Formatter::tap(*frame, tap_file); } #endif } while (exit_code == EXIT_SUCCESS and --opt_repeat); } catch (const libtest::__skipped& e) { exit_code= EXIT_SKIP; } catch (const libtest::__failure& e) { libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what(); exit_code= EXIT_FAILURE; } catch (const libtest::fatal& e) { std::cerr << "FATAL:" << e.what() << std::endl; exit_code= EXIT_FAILURE; } catch (const libtest::disconnected& e) { std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl; exit_code= EXIT_FAILURE; } catch (const std::exception& e) { std::cerr << "std::exception:" << e.what() << std::endl; exit_code= EXIT_FAILURE; } catch (char const* s) { std::cerr << "Exception:" << s << std::endl; exit_code= EXIT_FAILURE; } catch (...) { std::cerr << "Unknown exception halted execution." << std::endl; exit_code= EXIT_FAILURE; } return exit_code; }