Merge in fixes for deprecated bits in behavior.
[m6w6/libmemcached] / clients / memcapable.c
index 6ef5bc69285028a3787ae14a98caf98418c54110..69d2557ea959608a0702a2494971595cd17cb313 100644 (file)
@@ -623,7 +623,7 @@ static enum test_return test_binary_quit_impl(uint8_t cc)
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS));
   }
 
-  /* Socket should be closed now, read should return 0 */
+  /* Socket should be closed now, read should return EXIT_SUCCESS */
   verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
 
   return TEST_PASS_RECONNECT;
@@ -1211,7 +1211,7 @@ static enum test_return test_ascii_quit(void)
   /* Verify that quit works */
   execute(send_string("quit\r\n"));
 
-  /* Socket should be closed now, read should return 0 */
+  /* Socket should be closed now, read should return EXIT_SUCCESS */
   char buffer[80];
   verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
   return TEST_PASS_RECONNECT;
@@ -1267,8 +1267,7 @@ static enum test_return test_ascii_set_impl(const char* key, bool noreply)
 {
   /* @todo add tests for bogus format! */
   char buffer[1024];
-  sprintf(buffer, "set %s 0 0 5%s\r\nvalue\r\n", key,
-          noreply ? " noreply" : "");
+  snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
   execute(send_string(buffer));
 
   if (!noreply)
@@ -1291,8 +1290,7 @@ static enum test_return test_ascii_add_impl(const char* key, bool noreply)
 {
   /* @todo add tests for bogus format! */
   char buffer[1024];
-  sprintf(buffer, "add %s 0 0 5%s\r\nvalue\r\n", key,
-          noreply ? " noreply" : "");
+  snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
   execute(send_string(buffer));
 
   if (!noreply)
@@ -1316,6 +1314,41 @@ static enum test_return test_ascii_add_noreply(void)
   return test_ascii_add_impl("test_ascii_add_noreply", true);
 }
 
+static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
+{
+  char buffer[1024];
+
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "VALUE ", 6) == 0);
+  char *end= strchr(buffer + 6, ' ');
+  verify(end != NULL);
+  *end= '\0';
+  *key= strdup(buffer + 6);
+  verify(*key != NULL);
+  char *ptr= end + 1;
+
+  unsigned long val= strtoul(ptr, &end, 10); /* flags */
+  verify(ptr != end);
+  verify(val == 0);
+  verify(end != NULL);
+  *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
+  verify(ptr != end);
+  verify(end != NULL);
+  while (*end != '\n' && isspace(*end))
+    ++end;
+  verify(*end == '\n');
+
+  *value= malloc((size_t)*ndata);
+  verify(*value != NULL);
+
+  execute(retry_read(*value, (size_t)*ndata));
+
+  execute(retry_read(buffer, 2));
+  verify(memcmp(buffer, "\r\n", 2) == 0);
+
+  return TEST_PASS;
+}
+
 static enum test_return ascii_get_value(const char *key, const char *value)
 {
 
@@ -1359,7 +1392,7 @@ static enum test_return ascii_get_item(const char *key, const char *value,
     datasize= strlen(value);
 
   verify(datasize < sizeof(buffer));
-  sprintf(buffer, "get %s\r\n", key);
+  snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
   execute(send_string(buffer));
 
   if (exist)
@@ -1420,7 +1453,7 @@ static enum test_return ascii_gets_item(const char *key, const char *value,
     datasize= strlen(value);
 
   verify(datasize < sizeof(buffer));
-  sprintf(buffer, "gets %s\r\n", key);
+  snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
   execute(send_string(buffer));
 
   if (exist)
@@ -1436,7 +1469,7 @@ static enum test_return ascii_set_item(const char *key, const char *value)
 {
   char buffer[300];
   size_t len= strlen(value);
-  sprintf(buffer, "set %s 0 0 %u\r\n", key, (unsigned int)len);
+  snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
   execute(send_string(buffer));
   execute(retry_write(value, len));
   execute(send_string("\r\n"));
@@ -1447,8 +1480,7 @@ static enum test_return ascii_set_item(const char *key, const char *value)
 static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
 {
   char buffer[1024];
-  sprintf(buffer, "replace %s 0 0 5%s\r\nvalue\r\n", key,
-          noreply ? " noreply" : "");
+  snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
   execute(send_string(buffer));
 
   if (noreply)
@@ -1488,8 +1520,7 @@ static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
   execute(ascii_set_item(key, "value"));
   execute(ascii_gets_item(key, "value", true, &cas));
 
-  sprintf(buffer, "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas,
-          noreply ? " noreply" : "");
+  snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
   execute(send_string(buffer));
 
   if (noreply)
@@ -1529,7 +1560,7 @@ static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
   execute(receive_error_response());
 
   char buffer[1024];
-  sprintf(buffer, "delete %s%s\r\n", key, noreply ? " noreply" : "");
+  snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
   execute(send_string(buffer));
 
   if (noreply)
@@ -1584,31 +1615,65 @@ static enum test_return test_ascii_gets(void)
 
 static enum test_return test_ascii_mget(void)
 {
-  execute(ascii_set_item("test_ascii_mget1", "value"));
-  execute(ascii_set_item("test_ascii_mget2", "value"));
-  execute(ascii_set_item("test_ascii_mget3", "value"));
-  execute(ascii_set_item("test_ascii_mget4", "value"));
-  execute(ascii_set_item("test_ascii_mget5", "value"));
+  const uint32_t nkeys= 5;
+  const char * const keys[]= {
+    "test_ascii_mget1",
+    "test_ascii_mget2",
+    /* test_ascii_mget_3 does not exist :) */
+    "test_ascii_mget4",
+    "test_ascii_mget5",
+    "test_ascii_mget6"
+  };
 
+  for (uint32_t x= 0; x < nkeys; ++x)
+    execute(ascii_set_item(keys[x], "value"));
+
+  /* Ask for a key that doesn't exist as well */
   execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
                       "test_ascii_mget4 test_ascii_mget5 "
                       "test_ascii_mget6\r\n"));
-  execute(ascii_get_value("test_ascii_mget1", "value"));
-  execute(ascii_get_value("test_ascii_mget2", "value"));
-  execute(ascii_get_value("test_ascii_mget3", "value"));
-  execute(ascii_get_value("test_ascii_mget4", "value"));
-  execute(ascii_get_value("test_ascii_mget5", "value"));
+
+  char *returned[nkeys];
+
+  for (uint32_t x= 0; x < nkeys; ++x)
+  {
+    ssize_t nbytes = 0;
+    char *v= NULL;
+    execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
+    verify(nbytes == 5);
+    verify(memcmp(v, "value", 5) == 0);
+    free(v);
+  }
 
   char buffer[5];
   execute(retry_read(buffer, 5));
   verify(memcmp(buffer, "END\r\n", 5) == 0);
- return TEST_PASS;
+
+  /* verify that we got all the keys we expected */
+  for (uint32_t x= 0; x < nkeys; ++x)
+  {
+    bool found= false;
+    for (uint32_t y= 0; y < nkeys; ++y)
+    {
+      if (strcmp(keys[x], returned[y]) == 0)
+      {
+        found = true;
+        break;
+      }
+    }
+    verify(found);
+  }
+
+  for (uint32_t x= 0; x < nkeys; ++x)
+    free(returned[x]);
+
+  return TEST_PASS;
 }
 
 static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
 {
   char cmd[300];
-  sprintf(cmd, "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
+  snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
 
   execute(ascii_set_item(key, "0"));
   for (int x= 1; x < 11; ++x)
@@ -1644,7 +1709,7 @@ static enum test_return test_ascii_incr_noreply(void)
 static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
 {
   char cmd[300];
-  sprintf(cmd, "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
+  snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
 
   execute(ascii_set_item(key, "9"));
   for (int x= 8; x > -1; --x)
@@ -1746,10 +1811,10 @@ static enum test_return test_ascii_concat_impl(const char *key,
     value="hello";
 
   char cmd[400];
-  sprintf(cmd, "%s %s 0 0 %u%s\r\n%s\r\n",
-          append ? "append" : "prepend",
-          key, (unsigned int)strlen(value), noreply ? " noreply" : "",
-          value);
+  snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
+           append ? "append" : "prepend",
+           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+           value);
   execute(send_string(cmd));
 
   if (noreply)
@@ -1759,10 +1824,10 @@ static enum test_return test_ascii_concat_impl(const char *key,
 
   execute(ascii_get_item(key, "hello world", true));
 
-  sprintf(cmd, "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
-          append ? "append" : "prepend",
-          key, (unsigned int)strlen(value), noreply ? " noreply" : "",
-          value);
+  snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
+           append ? "append" : "prepend",
+           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+           value);
   execute(send_string(cmd));
 
   if (noreply)
@@ -1872,9 +1937,19 @@ struct testcase testcases[]= {
   { NULL, NULL}
 };
 
+const int ascii_tests = 1;
+const int binary_tests = 2;
+
+struct test_type_st
+{
+  bool ascii;
+  bool binary;
+};
+
 int main(int argc, char **argv)
 {
   static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
+  struct test_type_st tests= { true, true };
   int total= 0;
   int failed= 0;
   const char *hostname= "localhost";
@@ -1883,15 +1958,25 @@ int main(int argc, char **argv)
   bool prompt= false;
   const char *testname= NULL;
 
-  while ((cmd= getopt(argc, argv, "t:vch:p:PT:?")) != EOF)
+
+
+  while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
   {
     switch (cmd) {
+    case 'a':
+      tests.ascii= true;
+      tests.binary= false;
+      break;
+    case 'b':
+      tests.ascii= false;
+      tests.binary= true;
+      break;
     case 't':
       timeout= atoi(optarg);
       if (timeout == 0)
       {
         fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
-        return 1;
+        return EXIT_FAILURE;
       }
       break;
     case 'v': verbose= true;
@@ -1907,8 +1992,7 @@ int main(int argc, char **argv)
     case 'T': testname= optarg;
        break;
     default:
-      fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n]"
-              " [-P] [-T testname]'\n"
+      fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
               "\t-c\tGenerate coredump if a test fails\n"
               "\t-v\tVerbose test output (print out the assertion)\n"
               "\t-t n\tSet the timeout for io-operations to n seconds\n"
@@ -1916,9 +2000,11 @@ int main(int argc, char **argv)
               "\t\t\t\"skip\" will skip the test\n"
               "\t\t\t\"quit\" will terminate memcapable\n"
               "\t\t\tEverything else will start the test\n"
-              "\t-T n\tJust run the test named n\n",
+              "\t-T n\tJust run the test named n\n"
+              "\t-a\tOnly test the ascii protocol\n"
+              "\t-b\tOnly test the binary protocol\n",
               argv[0]);
-      return 1;
+      return EXIT_FAILURE;
     }
   }
 
@@ -1928,7 +2014,7 @@ int main(int argc, char **argv)
   {
     fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
             hostname, port, strerror(get_socket_errno()));
-    return 1;
+    return EXIT_FAILURE;
   }
 
   for (int ii= 0; testcases[ii].description != NULL; ++ii)
@@ -1936,6 +2022,11 @@ int main(int argc, char **argv)
     if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
        continue;
 
+    if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
+        (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
+    {
+      continue;
+    }
     ++total;
     fprintf(stdout, "%-40s", testcases[ii].description);
     fflush(stdout);
@@ -1981,7 +2072,7 @@ int main(int argc, char **argv)
         fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
                 hostname, port, strerror(get_socket_errno()));
         fprintf(stderr, "%d of %d tests failed\n", failed, total);
-        return 1;
+        return EXIT_FAILURE;
       }
     }
   }