Merge from build
[m6w6/libmemcached] / libtest / test.cc
index b7f584421276443b9f8b9a2d206b029ffb6df232..52dd03e7b4e60263b744b42e68df826fe9faa545 100644 (file)
 
 #include <signal.h>
 
+#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H
+#include <curl/curl.h>
+#endif
+
 #ifndef __INTEL_COMPILER
 #pragma GCC diagnostic ignored "-Wold-style-cast"
 #endif
@@ -70,276 +74,371 @@ static long int timedif(struct timeval a, struct timeval b)
   return s + us;
 }
 
-static Framework *world= NULL;
-int main(int argc, char *argv[])
+static void cleanup_curl(void)
 {
-  srandom((unsigned int)time(NULL));
-
-  if (getenv("LIBTEST_QUIET"))
-  {
-    close(STDOUT_FILENO);
-  }
+#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H
+  curl_global_cleanup();
+#endif
+}
 
-  char buffer[1024];
-  if (getenv("LIBTEST_TMP"))
-  {
-    snprintf(buffer, sizeof(buffer), "%s", getenv("LIBTEST_TMP"));
-  }
-  else
-  {
-    snprintf(buffer, sizeof(buffer), "%s", LIBTEST_TEMP);
-  }
+#include <getopt.h>
+#include <unistd.h>
 
-  if (chdir(buffer) == -1)
+int main(int argc, char *argv[])
+{
+#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H
+  if (curl_global_init(CURL_GLOBAL_ALL))
   {
-    char getcwd_buffer[1024];
-    char *dir= getcwd(getcwd_buffer, sizeof(getcwd_buffer));
-
-    Error << "Unable to chdir() from " << dir << " to " << buffer << " errno:" << strerror(errno);
+    Error << "curl_global_init(CURL_GLOBAL_ALL) failed";
     return EXIT_FAILURE;
   }
+#endif
 
-  if (libtest::libtool() == NULL)
+  if (atexit(cleanup_curl))
   {
-    Error << "Failed to locate libtool";
+    Error << "atexit() failed";
     return EXIT_FAILURE;
   }
 
-  world= new Framework();
+  bool opt_repeat= false;
+  std::string collection_to_run;
 
-  if (world == NULL)
+  // Options parsing
   {
-    Error << "Failed to create Framework()";
-    return EXIT_FAILURE;
-  }
+    enum long_option_t {
+      OPT_LIBYATL_VERSION,
+      OPT_LIBYATL_MATCH_COLLECTION,
+      OPT_LIBYATL_REPEAT
+    };
 
-  libtest::SignalThread signal;
-  if (not signal.setup())
-  {
-    return EXIT_FAILURE;
-  }
+    static struct option long_options[]=
+    {
+      {"repeat", no_argument, NULL, OPT_LIBYATL_REPEAT},
+      {"collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION},
+      {0, 0, 0, 0}
+    };
 
-  Stats stats;
+    int option_index= 0;
+    while (1)
+    {
+      int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
+      if (option_rv == -1)
+      {
+        break;
+      }
 
-  get_world(world);
+      switch (option_rv)
+      {
+      case OPT_LIBYATL_VERSION:
+        break;
 
-  test_return_t error;
-  void *creators_ptr= world->create(error);
+      case OPT_LIBYATL_REPEAT:
+        opt_repeat= true;
+        break;
 
-  switch (error)
-  {
-  case TEST_SUCCESS:
-    break;
+      case OPT_LIBYATL_MATCH_COLLECTION:
+        collection_to_run= optarg;
+        break;
 
-  case TEST_SKIPPED:
-    Out << "SKIP " << argv[0];
-    delete world;
-    return EXIT_SUCCESS;
+      case '?':
+        /* getopt_long already printed an error message. */
+        Error << "unknown option to getopt_long()";
+        exit(EXIT_FAILURE);
 
-  case TEST_FATAL:
-  case TEST_FAILURE:
-  case TEST_MEMORY_ALLOCATION_FAILURE:
-    Error << argv[0] << " failed in Framework::create()";
-    delete world;
-    return EXIT_FAILURE;
+      default:
+        break;
+      }
+    }
   }
 
-  char *collection_to_run= NULL;
-  if (argc > 1)
+  srandom((unsigned int)time(NULL));
+
+  if (getenv("LIBTEST_QUIET") and strcmp(getenv("LIBTEST_QUIET"), "0") == 0)
   {
-    collection_to_run= argv[1];
+    close(STDOUT_FILENO);
   }
-  else if (getenv("TEST_COLLECTION"))
+  else if (getenv("JENKINS_URL"))
   {
-    collection_to_run= getenv("TEST_COLLECTION");
+    close(STDOUT_FILENO);
   }
 
-  if (collection_to_run)
+  char buffer[1024];
+  if (getenv("LIBTEST_TMP"))
+  {
+    snprintf(buffer, sizeof(buffer), "%s", getenv("LIBTEST_TMP"));
+  }
+  else
   {
-    Out << "Only testing " <<  collection_to_run;
+    snprintf(buffer, sizeof(buffer), "%s", LIBTEST_TEMP);
   }
 
-  char *wildcard= NULL;
-  if (argc == 3)
+  if (chdir(buffer) == -1)
   {
-    wildcard= argv[2];
+    char getcwd_buffer[1024];
+    char *dir= getcwd(getcwd_buffer, sizeof(getcwd_buffer));
+
+    Error << "Unable to chdir() from " << dir << " to " << buffer << " errno:" << strerror(errno);
+    return EXIT_FAILURE;
   }
 
-  for (collection_st *next= world->collections; next->name and (not signal.is_shutdown()); next++)
+  if (libtest::libtool() == NULL)
   {
-    test_return_t collection_rc= TEST_SUCCESS;
-    bool failed= false;
-    bool skipped= false;
+    Error << "Failed to locate libtool";
+    return EXIT_FAILURE;
+  }
 
-    if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
-      continue;
+  int exit_code;
+  do {
+    exit_code= EXIT_SUCCESS;
+    Framework *world= new Framework();
 
-    stats.collection_total++;
+    if (world == NULL)
+    {
+      Error << "Failed to create Framework()";
+      return EXIT_FAILURE;
+    }
 
-    collection_rc= world->startup(creators_ptr);
+    assert(sigignore(SIGPIPE) == 0);
 
-    if (collection_rc == TEST_SUCCESS and next->pre)
+    libtest::SignalThread signal;
+    if (not signal.setup())
     {
-      collection_rc= world->runner()->pre(next->pre, creators_ptr);
+      Error << "Failed to setup signals";
+      return EXIT_FAILURE;
     }
 
-    switch (collection_rc)
+    Stats stats;
+
+    get_world(world);
+
+    test_return_t error;
+    void *creators_ptr= world->create(error);
+
+    switch (error)
     {
     case TEST_SUCCESS:
       break;
 
+    case TEST_SKIPPED:
+      Out << "SKIP " << argv[0];
+      delete world;
+      return EXIT_SUCCESS;
+
     case TEST_FATAL:
     case TEST_FAILURE:
-      Out << next->name << " [ failed ]";
-      failed= true;
-      signal.set_shutdown(SHUTDOWN_GRACEFUL);
-      goto cleanup;
+    case TEST_MEMORY_ALLOCATION_FAILURE:
+      delete world;
+      return EXIT_FAILURE;
+    }
 
-    case TEST_SKIPPED:
-      Out << next->name << " [ skipping ]";
-      skipped= true;
-      goto cleanup;
+    if (getenv("TEST_COLLECTION"))
+    {
+      if (strlen(getenv("TEST_COLLECTION")))
+      {
+        collection_to_run= getenv("TEST_COLLECTION");
+      }
+    }
 
-    case TEST_MEMORY_ALLOCATION_FAILURE:
-      test_assert(0, "Allocation failure, or unknown return");
+    if (collection_to_run.empty() == false)
+    {
+      Out << "Only testing " <<  collection_to_run;
     }
 
-    Out << "Collection: " << next->name;
+    char *wildcard= NULL;
+    if (argc == 3)
+    {
+      wildcard= argv[2];
+    }
 
-    for (test_st *run= next->tests; run->name; run++)
+    for (collection_st *next= world->collections; next and next->name and (not signal.is_shutdown()); next++)
     {
-      struct timeval start_time, end_time;
-      long int load_time= 0;
+      bool failed= false;
+      bool skipped= false;
 
-      if (wildcard && fnmatch(wildcard, run->name, 0))
+      if (collection_to_run.empty() == false and fnmatch(collection_to_run.c_str(), next->name, 0))
       {
         continue;
       }
 
-      test_return_t return_code;
-      if (test_success(return_code= world->item.startup(creators_ptr)))
-      {
-        if (test_success(return_code= world->item.flush(creators_ptr, run)))
-        {
-          // @note pre will fail is SKIPPED is returned
-          if (test_success(return_code= world->item.pre(creators_ptr)))
-          {
-            { // Runner Code
-              gettimeofday(&start_time, NULL);
-              assert(world->runner());
-              assert(run->test_fn);
-              return_code= world->runner()->run(run->test_fn, creators_ptr);
-              gettimeofday(&end_time, NULL);
-              load_time= timedif(end_time, start_time);
-            }
-          }
+      stats.collection_total++;
 
-          // @todo do something if post fails
-          (void)world->item.post(creators_ptr);
-        }
-        else if (return_code == TEST_SKIPPED)
-        { }
-        else if (return_code == TEST_FAILURE)
-        {
-          Error << " item.flush(failure)";
-          signal.set_shutdown(SHUTDOWN_GRACEFUL);
-        }
-      }
-      else if (return_code == TEST_SKIPPED)
-      { }
-      else if (return_code == TEST_FAILURE)
+      test_return_t collection_rc= world->startup(creators_ptr);
+
+      if (collection_rc == TEST_SUCCESS and next->pre)
       {
-        Error << " item.startup(failure)";
-        signal.set_shutdown(SHUTDOWN_GRACEFUL);
+        collection_rc= world->runner()->pre(next->pre, creators_ptr);
       }
 
-      stats.total++;
-
-      switch (return_code)
+      switch (collection_rc)
       {
       case TEST_SUCCESS:
-        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
-        stats.success++;
         break;
 
       case TEST_FATAL:
       case TEST_FAILURE:
-        stats.failed++;
+        Out << next->name << " [ failed ]";
         failed= true;
-        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
-        break;
+        signal.set_shutdown(SHUTDOWN_GRACEFUL);
+        goto cleanup;
 
       case TEST_SKIPPED:
-        stats.skipped++;
+        Out << next->name << " [ skipping ]";
         skipped= true;
-        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
-        break;
+        goto cleanup;
 
       case TEST_MEMORY_ALLOCATION_FAILURE:
-        test_assert(0, "Memory Allocation Error");
+        test_assert(0, "Allocation failure, or unknown return");
       }
 
-      if (test_failed(world->on_error(return_code, creators_ptr)))
+      Out << "Collection: " << next->name;
+
+      for (test_st *run= next->tests; run->name; run++)
       {
-        Error << "Failed while running on_error()";
-        signal.set_shutdown(SHUTDOWN_GRACEFUL);
-        break;
+        struct timeval start_time, end_time;
+        long int load_time= 0;
+
+        if (wildcard && fnmatch(wildcard, run->name, 0))
+        {
+          continue;
+        }
+
+        test_return_t return_code;
+        try {
+          if (test_success(return_code= world->item.startup(creators_ptr)))
+          {
+            if (test_success(return_code= world->item.flush(creators_ptr, run)))
+            {
+              // @note pre will fail is SKIPPED is returned
+              if (test_success(return_code= world->item.pre(creators_ptr)))
+              {
+                { // Runner Code
+                  gettimeofday(&start_time, NULL);
+                  assert(world->runner());
+                  assert(run->test_fn);
+                  return_code= world->runner()->run(run->test_fn, creators_ptr);
+                  gettimeofday(&end_time, NULL);
+                  load_time= timedif(end_time, start_time);
+                }
+              }
+
+              // @todo do something if post fails
+              (void)world->item.post(creators_ptr);
+            }
+            else if (return_code == TEST_SKIPPED)
+            { }
+            else if (return_code == TEST_FAILURE)
+            {
+              Error << " item.flush(failure)";
+              signal.set_shutdown(SHUTDOWN_GRACEFUL);
+            }
+          }
+          else if (return_code == TEST_SKIPPED)
+          { }
+          else if (return_code == TEST_FAILURE)
+          {
+            Error << " item.startup(failure)";
+            signal.set_shutdown(SHUTDOWN_GRACEFUL);
+          }
+        }
+
+        catch (std::exception &e)
+        {
+          Error << "Exception was thrown: " << e.what();
+          return_code= TEST_FAILURE;
+        }
+        catch (...)
+        {
+          Error << "Unknown exception occurred";
+          return_code= TEST_FAILURE;
+        }
+
+        stats.total++;
+
+        switch (return_code)
+        {
+        case TEST_SUCCESS:
+          Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
+          stats.success++;
+          break;
+
+        case TEST_FATAL:
+        case TEST_FAILURE:
+          stats.failed++;
+          failed= true;
+          Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+          break;
+
+        case TEST_SKIPPED:
+          stats.skipped++;
+          skipped= true;
+          Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+          break;
+
+        case TEST_MEMORY_ALLOCATION_FAILURE:
+          test_assert(0, "Memory Allocation Error");
+        }
+
+        if (test_failed(world->on_error(return_code, creators_ptr)))
+        {
+          Error << "Failed while running on_error()";
+          signal.set_shutdown(SHUTDOWN_GRACEFUL);
+          break;
+        }
       }
-    }
 
-    (void) world->runner()->post(next->post, creators_ptr);
+      (void) world->runner()->post(next->post, creators_ptr);
 
 cleanup:
-    if (failed == false and skipped == false)
-    {
-      stats.collection_success++;
+      if (failed == false and skipped == false)
+      {
+        stats.collection_success++;
+      }
+
+      if (failed)
+      {
+        stats.collection_failed++;
+      }
+
+      if (skipped)
+      {
+        stats.collection_skipped++;
+      }
+
+      world->shutdown(creators_ptr);
+      Outn();
     }
 
-    if (failed)
+    if (not signal.is_shutdown())
     {
-      stats.collection_failed++;
+      signal.set_shutdown(SHUTDOWN_GRACEFUL);
     }
 
-    if (skipped)
+    shutdown_t status= signal.get_shutdown();
+    if (status == SHUTDOWN_FORCED)
     {
-      stats.collection_skipped++;
+      Out << "Tests were aborted.";
+      exit_code= EXIT_FAILURE;
+    }
+    else if (stats.collection_failed)
+    {
+      Out << "Some test failed.";
+      exit_code= EXIT_FAILURE;
+    }
+    else if (stats.collection_skipped and stats.collection_failed and stats.collection_success)
+    {
+      Out << "Some tests were skipped.";
+    }
+    else if (stats.collection_success and stats.collection_failed == 0)
+    {
+      Out << "All tests completed successfully.";
     }
 
-    world->shutdown(creators_ptr);
-    Outn();
-  }
-
-  if (not signal.is_shutdown())
-  {
-    signal.set_shutdown(SHUTDOWN_GRACEFUL);
-  }
-
-  int exit_code= EXIT_SUCCESS;
-  shutdown_t status= signal.get_shutdown();
-  if (status == SHUTDOWN_FORCED)
-  {
-    Out << "Tests were aborted.";
-    exit_code= EXIT_FAILURE;
-  }
-  else if (stats.collection_failed)
-  {
-    Out << "Some test failed.";
-    exit_code= EXIT_FAILURE;
-  }
-  else if (stats.collection_skipped and stats.collection_failed and stats.collection_success)
-  {
-    Out << "Some tests were skipped.";
-  }
-  else if (stats.collection_success and stats.collection_failed == 0)
-  {
-    Out << "All tests completed successfully.";
-  }
-
-  stats_print(&stats);
+    stats_print(&stats);
 
-  delete world;
+    delete world;
 
-  Outn(); // Generate a blank to break up the messages if make check/test has been run
+    Outn(); // Generate a blank to break up the messages if make check/test has been run
+  } while (exit_code == EXIT_SUCCESS and opt_repeat);
 
   return exit_code;
 }