testing: errors
[awesomized/libmemcached] / test / tests / memcached / errors.cpp
index 16ac61a7e62eb815d453c8a51942b4dab84c039a..75ba019aba085c1adf457a64a715b3e29aa97888 100644 (file)
@@ -1,4 +1,6 @@
 #include "test/lib/common.hpp"
+#include "test/lib/MemcachedCluster.hpp"
+#include "test/lib/Retry.hpp"
 
 TEST_CASE("memcached_errors") {
   SECTION("NO_SERVERS") {
@@ -13,4 +15,64 @@ TEST_CASE("memcached_errors") {
     REQUIRE(MEMCACHED_NO_SERVERS == rc);
     REQUIRE(MEMCACHED_NO_SERVERS == memcached_mget(*memc, &key, &len, 1));
   }
+
+  SECTION("dead servers") {
+    MemcachedCluster test{Cluster{vector<Server>{Server{MEMCACHED_BINARY, {"-p", random_port_string("-p")}}}}};
+    auto memc = &test.memc;
+
+    REQUIRE_SUCCESS(memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+    memcached_quit(memc);
+
+    test.cluster.stop();
+    Retry cluster_is_stopped{[&cluster = test.cluster]{
+      return cluster.isStopped();
+    }};
+    REQUIRE(cluster_is_stopped());
+
+    SECTION("TEMPORARILY_DISABLED") {
+      REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 3));
+      REQUIRE_RC(MEMCACHED_CONNECTION_FAILURE, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+      REQUIRE_RC(MEMCACHED_SERVER_TEMPORARILY_DISABLED, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+    }
+
+    SECTION("recovers from TEMPORARILY_DISABLED") {
+      REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 1));
+      REQUIRE_RC(MEMCACHED_CONNECTION_FAILURE, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+      REQUIRE_RC(MEMCACHED_SERVER_TEMPORARILY_DISABLED, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+
+      REQUIRE(test.cluster.start());
+      Retry cluster_is_listening{[&cluster = test.cluster] {
+        return cluster.isListening();
+      }};
+      REQUIRE(cluster_is_listening());
+
+      Retry recovers{[memc]{
+        return MEMCACHED_SUCCESS == memcached_set(memc, S("foo"), nullptr, 0, 0, 0);
+      }, 50, 100ms};
+      REQUIRE(recovers());
+    }
+
+    SECTION("MARKED_DEAD") {
+      SECTION("immediately") {
+        REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, true));
+        REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 1));
+
+        REQUIRE_RC(MEMCACHED_CONNECTION_FAILURE, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+        REQUIRE_RC(MEMCACHED_SERVER_MARKED_DEAD, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+      }
+      SECTION("with retry") {
+        REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, true));
+        REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 2));
+        REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 1));
+
+        REQUIRE_RC(MEMCACHED_CONNECTION_FAILURE, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+        REQUIRE_RC(MEMCACHED_SERVER_TEMPORARILY_DISABLED, memcached_set(memc, S("foo"), nullptr, 0, 0, 0));
+
+        Retry server_is_marked_dead{[memc] {
+          return MEMCACHED_SERVER_MARKED_DEAD == memcached_set(memc, S("foo"), nullptr, 0, 0, 0);
+        },50, 100ms};
+        REQUIRE(server_is_marked_dead());
+      }
+    }
+  }
 }