testing: UDP test
authorMichael Wallner <mike@php.net>
Wed, 30 Sep 2020 10:00:57 +0000 (12:00 +0200)
committerMichael Wallner <mike@php.net>
Wed, 30 Sep 2020 10:00:57 +0000 (12:00 +0200)
TODO
test/lib/Cluster.cpp
test/lib/MemcachedCluster.cpp
test/lib/MemcachedCluster.hpp
test/lib/Server.cpp
test/lib/common.hpp
test/tests/memcached/udp.cpp [new file with mode: 0644]

diff --git a/TODO b/TODO
index 013aa85de2ed840426bcb6cfd8c4af2d60f86133..60a1d884ef57647cfdd582b74cf156883b4a51cf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,6 +3,11 @@
     - convert to proper C++ where applicable
 - Stats:
     - redo
+-Deprecations:
+    - UDP, disabled by default from memcached-1.5.6
+      soft (maybe only discourage in docs)
+    - API:
+        - memcached_delete(): expires param is obsolete
 
 ## Legacy:
 
index a4f8a3ae3c150fa4bbdcd3c40df313680941e53f..e1375bfde90ed50c65fcb52a3f0cff54c3be35fa 100644 (file)
@@ -8,7 +8,10 @@ Cluster::Cluster(Server serv, uint16_t cnt)
 , proto{move(serv)}
 {
   if (count < 4) {
-      count = 4;
+      count = stoi(getenv_else("MEMCACHED_CLUSTER", "4"));
+  }
+  if (!count) {
+    count = 1;
   }
   reset();
 }
index 63155e94aba6389c05ca1d6a1bf37b42a46445ea..573dddf384edd850b9c07723b4fa857b3ca5a84a 100644 (file)
@@ -15,6 +15,19 @@ void MemcachedCluster::init() {
     cluster.start();
   }
 
+  if (auto br = getenv_else("MEMCACHED_BREAK", "0")) {
+    if (*br && *br != '0') {
+      string in;
+
+      cout << "Started servers:\n";
+      for (const auto &server : cluster.getServers()) {
+        cout << server.getPid() << " ";
+      }
+      cout << "\nPress ENTER to continue... " << ::flush;
+      cin.get();
+    }
+  }
+
   REQUIRE(memcached_create(&memc));
   for (const auto &server : cluster.getServers()) {
     auto target = server.getSocketOrPort();
@@ -83,6 +96,16 @@ MemcachedCluster MemcachedCluster::socket() {
   }}};
 }
 
+MemcachedCluster MemcachedCluster::udp() {
+  return MemcachedCluster{Cluster{Server{
+    MEMCACHED_BINARY,
+    {
+      Server::arg_pair_t{"-U", random_socket_or_port_string},
+      Server::arg_t{"-v"}
+    }
+  }}};
+}
+
 #if LIBMEMCACHED_WITH_SASL_SUPPORT
 MemcachedCluster MemcachedCluster::sasl() {
   auto mc = MemcachedCluster{Cluster{Server{
@@ -114,3 +137,7 @@ void MemcachedCluster::enableReplication() {
       MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, memcached_server_count(&memc)));
 }
 
+void MemcachedCluster::enableUdp(bool enable) {
+  REQUIRE(MEMCACHED_SUCCESS == memcached_behavior_set(&memc,
+      MEMCACHED_BEHAVIOR_USE_UDP, enable));
+}
index 39859b7d90aee4e9bd162ba305a84210a10abf42..8e4385808a766ac32533650a0fdf7fe077127217 100644 (file)
@@ -25,11 +25,13 @@ public:
   void enableBinaryProto(bool enable = true);
   void enableBuffering(bool enable = true);
   void enableReplication();
+  void enableUdp(bool enable = true);
   void flush();
 
   static MemcachedCluster mixed();
   static MemcachedCluster network();
   static MemcachedCluster socket();
+  static MemcachedCluster udp();
 
 #if LIBMEMCACHED_WITH_SASL_SUPPORT
   static MemcachedCluster sasl();
index 8666b690ee602d5eb54a9ec8c843cbe24748f7f5..af6e41ba63d5a1f010f3c9ca0de0aef13bd2d989 100644 (file)
@@ -39,11 +39,16 @@ static inline void pushArg(vector<char *> &arr, const string &arg) {
 
 optional<string> Server::handleArg(vector<char *> &arr, const string &arg, const arg_func_t &next_arg) {
   pushArg(arr, arg);
-  if (arg == "-p" || arg == "--port") {
+  if (arg == "-U" || arg == "--udp-port") {
+    auto port = next_arg(arg);
+    pushArg(arr, port);
+    pushArg(arr, "-p");
+    pushArg(arr, port);
+    socket_or_port = stoi(port);
+    return port;
+  } else if (arg == "-p" || arg == "--port") {
     auto port = next_arg(arg);
     pushArg(arr, port);
-//    pushArg(arr, "-U");
-//    pushArg(arr, port);
     socket_or_port = stoi(port);
     return port;
   } else if (arg == "-s" || arg == "--unix-socket") {
@@ -180,8 +185,19 @@ bool Server::check() {
 
 bool Server::wait(int flags) {
   if (pid && pid == waitpid(pid, &status, flags)) {
-    if (drain().length()) {
-      cerr << "Ouput of " << *this << ":\n" << output << endl;
+    if (drain().length() && output != "Signal handled: Terminated.\n") {
+      cerr << "Output of " << *this << ":\n";
+
+      istringstream iss{output};
+      string line;
+
+      while (getline(iss, line)) {
+        cerr << "  " << line << "\n";
+      }
+
+      if (output.back() != '\n') {
+        cerr << endl;
+      }
       output.clear();
     }
     pid = 0;
index 24ec3a485fc01af85ef101421fa5c2ca2a6a7106..ecfa07d413535b8aab9ed83650729320d7d3670b 100644 (file)
@@ -97,15 +97,15 @@ public:
   ~MemcachedPtr() {
     memcached_free(memc);
   }
-  memcached_st *operator * () {
+  memcached_st *operator * () const {
     return memc;
   }
-  auto operator ->() {
+  auto operator ->() const{
     return memc;
   }
 };
 
-template<class T>
+template<class T, void (*F)(void*) = free>
 class Malloced {
   T *ptr;
 public:
@@ -115,7 +115,7 @@ public:
   {}
   ~Malloced() {
     if(ptr)
-      free(ptr);
+      F(ptr);
   }
   auto operator *() {
     return ptr;
diff --git a/test/tests/memcached/udp.cpp b/test/tests/memcached/udp.cpp
new file mode 100644 (file)
index 0000000..0c76f53
--- /dev/null
@@ -0,0 +1,92 @@
+#include "test/lib/common.hpp"
+#include "test/lib/MemcachedCluster.hpp"
+
+TEST_CASE("memcached_udp") {
+  auto test = MemcachedCluster::udp();
+  auto memc = &test.memc;
+
+  SECTION("sets reply flag") {
+    // FIXME: bad internals test
+    REQUIRE(memc->flags.reply);
+    REQUIRE_FALSE(memc->flags.use_udp);
+    REQUIRE_FALSE(memc->flags.use_udp == memc->flags.reply);
+    test.enableUdp();
+    REQUIRE_FALSE(memc->flags.reply);
+    REQUIRE(memc->flags.use_udp);
+    REQUIRE_FALSE(memc->flags.use_udp == memc->flags.reply);
+    test.enableUdp(false);
+    REQUIRE(memc->flags.reply);
+    REQUIRE_FALSE(memc->flags.use_udp);
+    REQUIRE_FALSE(memc->flags.use_udp == memc->flags.reply);
+  }
+
+  test.enableUdp();
+
+  SECTION("compat") {
+    memcached_return_t rc;
+    REQUIRE_RC(MEMCACHED_INVALID_ARGUMENTS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true));
+    REQUIRE_RC(MEMCACHED_NOT_SUPPORTED, memcached_version(memc));
+    REQUIRE_SUCCESS(memcached_verbosity(memc, 0));
+    REQUIRE(nullptr == memcached_get(memc, S(__func__), 0, 0, &rc));
+    REQUIRE_RC(MEMCACHED_NOT_SUPPORTED, rc);
+    REQUIRE_RC(MEMCACHED_NOT_SUPPORTED, memcached_mget_execute_by_key(memc, S(__func__), nullptr, nullptr, 0, nullptr, nullptr, 0));
+    REQUIRE(nullptr == memcached_stat(memc, nullptr, &rc));
+    REQUIRE_RC(MEMCACHED_NOT_SUPPORTED, rc);
+  }
+
+  SECTION("io") {
+    const auto max = 1025; // request id rolls over at 1024
+    auto binary = GENERATE(0,1);
+
+    test.enableBinaryProto(binary);
+
+    DYNAMIC_SECTION("binary=" << binary) {
+      SECTION("set") {
+        for (auto i = 0; i < max; ++i) {
+          auto s = to_string(i);
+          INFO("i=" << i);
+          REQUIRE_SUCCESS(memcached_set(memc, s.c_str(), s.length(), s.c_str(), s.length(), 0, 0));
+        }
+        // FIXME: check request id
+        memcached_quit(memc);
+        REQUIRE_SUCCESS(memcached_last_error(memc));
+      }
+
+      SECTION("set too big") {
+        const auto len = 1'234'567;
+        auto blob = make_unique<char>(len);
+        REQUIRE_RC(MEMCACHED_WRITE_FAILURE, memcached_set(memc, S(__func__), blob.get(), len, 0, 0));
+        memcached_quit(memc);
+        REQUIRE_SUCCESS(memcached_last_error(memc));
+      }
+
+      SECTION("delete") {
+        for (auto i = 0; i < max; ++i) {
+          auto s = to_string(i);
+          INFO("i=" << i);
+          REQUIRE_SUCCESS(memcached_delete(memc, s.c_str(), s.length(), 0));
+        }
+        memcached_quit(memc);
+        REQUIRE_SUCCESS(memcached_last_error(memc));
+      }
+
+      SECTION("verbosity") {
+        for (auto i = 0; i < max; ++i) {
+          INFO("i=" << i);
+          REQUIRE_SUCCESS(memcached_verbosity(memc, 0));
+        }
+        memcached_quit(memc);
+        REQUIRE_SUCCESS(memcached_last_error(memc));
+      }
+
+      SECTION("flush") {
+        for (auto i = 0; i < max; ++i) {
+          INFO("i=" << i);
+          REQUIRE_SUCCESS(memcached_flush(memc, 0));
+        }
+        memcached_quit(memc);
+        REQUIRE_SUCCESS(memcached_last_error(memc));
+      }
+    }
+  }
+}