runtests
authorMichael Wallner <mike@php.net>
Fri, 30 Oct 2020 18:42:31 +0000 (19:42 +0100)
committerMichael Wallner <mike@php.net>
Fri, 30 Oct 2020 18:42:31 +0000 (19:42 +0100)
test/CMakeLists.txt
test/conf.h.in
test/lib/Cluster.cpp
test/lib/Cluster.hpp
test/lib/MemcachedCluster.cpp
test/lib/MemcachedCluster.hpp
test/lib/Server.cpp
test/lib/Server.hpp
test/setup.cpp
test/tests/lib.cpp
test/tests/memcached/errors.cpp

index d364ac313b4d07ebf14f8a7aaa25984e7e762b5c..bd865f36d51a0c850dbfc4d364e8122d83d43693 100644 (file)
@@ -9,10 +9,10 @@ if(NOT MEMCACHED_BINARY)
     set(ENV{INVALID_CONFIGURATION} 1)
 endif()
 
-
 check_decl(pipe2 unistd.h)
 check_decl(SOCK_NONBLOCK sys/socket.h)
 check_decl(SOCK_CLOEXEC sys/socket.h)
+check_header(execution)
 
 file(GLOB_RECURSE TESTING_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
 set(TESTING_ROOT ${CMAKE_CURRENT_BINARY_DIR})
index 22193bfb6fd2a13bdc4f00fb736a18cb60b17714..b34f03a9adab3f6174cd5d585cf81e5969a5d8e7 100644 (file)
@@ -19,6 +19,7 @@
 #cmakedefine HAVE_PIPE2 1
 #cmakedefine HAVE_SOCK_NONBLOCK 1
 #cmakedefine HAVE_SOCK_CLOEXEC 1
+#cmakedefine HAVE_EXECUTION 1
 
 #cmakedefine TESTING_ROOT "@TESTING_ROOT@"
 #cmakedefine MEMCACHED_BINARY getenv_else("MEMCACHED_BINARY", "@MEMCACHED_BINARY@")
index 3ecc6e9abea2d629009e3a54cf05e610bdef2e7c..1186077b2b945187a4042041b00b211e399789b2 100644 (file)
@@ -1,16 +1,17 @@
 #include "Cluster.hpp"
 #include "Retry.hpp"
 
+#include <algorithm>
 #include <sys/wait.h>
 
-Cluster::Cluster(Server serv, uint16_t cnt)
+Cluster::Cluster(Server serv, size_t cnt)
 : count{cnt}
 , proto{move(serv)}
 {
   if (!count) {
     count = 1;
   }
-  for (int i = 0; i < count; ++i) {
+  for (size_t i = 0; i < count; ++i) {
     cluster.push_back(proto);
   }
 }
@@ -28,9 +29,11 @@ bool Cluster::start() {
   bool started = true;
 
   for (auto &server : cluster) {
-    if (!startServer(server)) {
+    if (!server.start()) {
       started = false;
+      continue;
     }
+    pids[server.getPid()] = &server;
   }
 
   return started;
@@ -49,46 +52,43 @@ void Cluster::stop(bool graceful) {
 }
 
 bool Cluster::isStopped() {
-  for (auto &server : cluster) {
-    if (server.getPid() && !server.tryWait()) {
-      return false;
-    }
-  }
-  return true;
+  return none_of(
+#if HAVE_EXECUTION
+    execution::par,
+#endif
+      cluster.begin(), cluster.end(), [](Server &s) {
+    return s.getPid() && !s.tryWait();
+  });
 }
 
-bool Cluster::isListening() {
-  for (auto &server : cluster) {
-    Retry server_is_listening{[&] {
-      if (!server.isListening()) {
-        // zombie?
-        auto old_pid = server.getPid();
-        if (server.tryWait()) {
-          cerr << "Collected zombie " << server << "(old pid=" << old_pid << ")\n";
-          pids.erase(old_pid);
-          // restart
-          startServer(server);
-        }
-        if (!server.isListening()) {
-          return false;
-        }
-      }
-      return true;
-    }};
-    if (!server_is_listening()) {
-      return false;
-    }
-  }
-
-  return true;
+bool Cluster::isListening() const {
+  return all_of(
+#if HAVE_EXECUTION
+    execution::par,
+#endif
+      cluster.cbegin(), cluster.cend(), [](const Server &s) {
+    return s.isListening();
+  });
 }
 
-bool Cluster::startServer(Server &server) {
-  if (server.start().has_value()) {
+bool Cluster::ensureListening() {
+  if (!start()) {
+    return false;
+  }
+  auto listening = all_of(
+#if HAVE_EXECUTION
+    execution::par,
+#endif
+  cluster.begin(), cluster.end(), [](Server &s) {
+    return s.ensureListening();
+  });
+
+  pids.clear();
+  for (auto &server : cluster) {
     pids[server.getPid()] = &server;
-    return true;
   }
-  return false;
+
+  return listening;
 }
 
 void Cluster::wait() {
index d2b93b9cd7a31806a51622768e236371b0a180f1..ab20108c17d447a50532209c53a4b22fa2e75043 100644 (file)
@@ -20,7 +20,7 @@
 
 class Cluster {
 public:
-  explicit Cluster(Server serv, uint16_t cnt = 3);
+  explicit Cluster(Server serv, size_t cnt = 3);
   ~Cluster();
 
   Cluster(const Cluster &c) = delete;
@@ -43,7 +43,8 @@ public:
   bool start();
   void stop(bool graceful = false);
   bool isStopped();
-  bool isListening();
+  bool isListening() const;
+  bool ensureListening();
   void wait();
   bool restart();
 
@@ -52,6 +53,4 @@ private:
   Server proto;
   vector<Server> cluster;
   map<pid_t, Server *> pids;
-
-  bool startServer(Server &server);
 };
index 521ff12cde1d81332995802ade4eeff18ab3cd9b..a443360b52b9b3082dcfb1d102e39098098bd048 100644 (file)
@@ -6,7 +6,7 @@ const memcached_st MemcachedCluster::empty_memc{};
 void MemcachedCluster::init() {
   REQUIRE(cluster.start());
 
-  while (!isListening()) {
+  while (!cluster.ensureListening()) {
     cluster.restart();
   }
 
@@ -146,7 +146,3 @@ void MemcachedCluster::killOneServer() const {
   const auto &victim = servers[random_num(0UL, servers.size() - 1)];
   ::kill(victim.getPid(), SIGKILL);
 }
-
-bool MemcachedCluster::isListening() {
-  return Retry{[this]() {return cluster.isListening();}}();
-}
index b2a692cd697ea8b873a1b00a9e7454cd1c18b347..dcda9ddd72afb30744ac70acd939ac0bad4b84b6 100644 (file)
@@ -42,7 +42,6 @@ public:
   void enableBuffering(bool enable = true);
   void enableReplication();
   void flush();
-  bool isListening();
 
   static MemcachedCluster mixed();
   static MemcachedCluster network();
index 2744f3e1b9c1876b895cb056d6905518cfb534c4..dddb68d9f733ceecf98da9ae9f3e5bca83bce323 100644 (file)
@@ -117,7 +117,7 @@ optional<Server::ChildProc> Server::start() {
   return ChildProc{pid, pipe};
 }
 
-bool Server::isListening() {
+bool Server::isListening() const {
   MemcachedPtr memc;
 
   if (holds_alternative<string>(socket_or_port)) {
@@ -149,11 +149,16 @@ bool Server::isListening() {
 }
 
 bool Server::ensureListening() {
+  if (!start()) {
+    return false;
+  }
   return Retry{[this] {
     again:
     start();
     if (!isListening()) {
-      if (tryWait()){
+      auto old = pid;
+      if (tryWait()) {
+        cerr << "Collected zombie " << *this << "(old pid=" << old << ")\n";
         goto again;
       }
     }
@@ -186,7 +191,8 @@ bool Server::check() {
 
 bool Server::wait(int flags) {
   if (pid && pid == waitpid(pid, &status, flags)) {
-    if (drain().length() && output != "Signal handled: Terminated.\n") {
+    if (drain().length() &&
+        output.rfind("Signal handled: Terminated", 0) != 0) {
       cerr << "Output of " << *this << ":\n";
 
       istringstream iss{output};
index 9b1d4a7324c2334800cc075597e237b455e1f494..26acdc4468b2f89ff0b4524e28ea3251a273a923 100644 (file)
@@ -69,7 +69,7 @@ public:
 
   bool signal(int signo = SIGTERM);
   bool check();
-  bool isListening();
+  bool isListening() const;
   bool ensureListening();
 
   bool wait(int flags = 0);
index a0325af52530637fb1b95058e7e6e3e41d72d862..9e23ce2be14cb242cc9b36f3fd091df670b755e2 100644 (file)
@@ -31,14 +31,17 @@ static void sigchld(int, siginfo_t *si, void *) {
 }
 
 static inline void setup_signals() {
-  struct sigaction sa;
+  cout << " - Setting up signals ... ";
 
+  struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO | SA_NODEFER;
 
   sa.sa_sigaction = sigchld;
   if (0 > sigaction(SIGCHLD, &sa, nullptr)) {
     perror("sigaction(CHLD)");
+  } else {
+    cout << "done\n";
   }
 }
 
@@ -59,11 +62,15 @@ static inline void setup_signals() {
 static inline void setup_asan(char **argv) {
   const auto set = getenv("ASAN_OPTIONS");
 
+  cout << " - Setting up ASAN ... ";
+
   if (!set || !*set) {
     SET_ENV_EX(asan, "ASAN_OPTIONS", ASAN_OPTIONS, 0);
+    cout << "re-exec\n";
     execvp(argv[0], argv);
     perror("exec()");
   }
+  cout << "done\n";
 }
 #else
 # define setup_asan(a) (void) a
@@ -71,17 +78,30 @@ static inline void setup_asan(char **argv) {
 
 #if LIBMEMCACHED_WITH_SASL_SUPPORT
 static inline void setup_sasl() {
+  cout << " - Setting up SASL ... ";
+
   SET_ENV_EX(sasl_pwdb, "MEMCACHED_SASL_PWDB", LIBMEMCACHED_WITH_SASL_PWDB, 0);
   SET_ENV_EX(sasl_conf, "SASL_CONF_PATH", LIBMEMCACHED_WITH_SASL_CONF, 0);
+
+  cout << "done\n";
 }
 #else
 # define setup_sasl()
 #endif
 
-int setup(int &, char ***argv) {
+static inline void setup_random() {
+  cout << " - Setting up RNG ... ";
+
   random_setup();
 
+  cout << "done\n";
+}
+
+int setup(int &, char ***argv) {
+  cout << "Starting " << **argv << " (pid=" << getpid() << ") ... \n";
+
   setup_signals();
+  setup_random();
   setup_asan(*argv);
   setup_sasl();
 
index 76e6516eb5f8d00eb33cb9a18ec7b1975f828952..2c3e0bd0e918bf5140c49865b8d4a1987673543a 100644 (file)
@@ -13,11 +13,9 @@ TEST_CASE("lib/Server") {
   SECTION("starts and listens") {
 
     REQUIRE(server.start().has_value());
-
-    Retry server_is_listening{[&server] {
-      return server.isListening();
-    }};
-    REQUIRE(server_is_listening());
+    REQUIRE(server.ensureListening());
+    REQUIRE(server.isListening());
+    REQUIRE(server.check());
 
     SECTION("stops") {
 
@@ -30,6 +28,7 @@ TEST_CASE("lib/Server") {
         SECTION("stopped") {
 
           REQUIRE_FALSE(server.check());
+          REQUIRE_FALSE(server.isListening());
         }
       }
     }
@@ -44,11 +43,8 @@ TEST_CASE("lib/Cluster") {
   SECTION("starts and listens") {
 
     REQUIRE(cluster.start());
-
-    Retry cluster_is_listening{[&cluster] {
-      return cluster.isListening();
-    }};
-    REQUIRE(cluster_is_listening());
+    REQUIRE(cluster.ensureListening());
+    REQUIRE(cluster.isListening());
 
     SECTION("stops") {
 
@@ -58,6 +54,7 @@ TEST_CASE("lib/Cluster") {
       SECTION("stopped") {
 
         REQUIRE(cluster.isStopped());
+        REQUIRE_FALSE(cluster.isListening());
       }
     }
   }
index db557431e29d178b9266378c067b21025672888c..377e14d1ba837f15c14a95cd799bc7341cc8160d 100644 (file)
@@ -41,7 +41,7 @@ TEST_CASE("memcached_errors") {
       REQUIRE_RC(MEMCACHED_SERVER_TEMPORARILY_DISABLED, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
 
       REQUIRE(test.cluster.start());
-      REQUIRE(test.isListening());
+      REQUIRE(test.cluster.ensureListening());
 
       Retry recovers{[memc]{
         return MEMCACHED_SUCCESS == memcached_set(memc, S("foo"), nullptr, 0, 0, 0);