Merge in ability for memcapable to handle ascii/binary as flags to the
authorBrian Aker <brian@tangent.org>
Tue, 22 Feb 2011 02:02:11 +0000 (18:02 -0800)
committerBrian Aker <brian@tangent.org>
Tue, 22 Feb 2011 02:02:11 +0000 (18:02 -0800)
command.

1  2 
clients/memcapable.c

diff --combined clients/memcapable.c
index 3de6baf18205837c32738e1c95bc112df283a790,7f5d51ee94e5144571eb320e7783f2b39f54cb45..fdbc35c8d4bb33624c0c72b37735f2da0b9ac188
@@@ -303,7 -303,6 +303,7 @@@ static enum test_return retry_read(voi
      ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
      switch (nr) {
      case -1 :
 +       fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
        verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
        break;
      case 0:
   */
  static enum test_return recv_packet(response *rsp)
  {
 -  execute(retry_read(rsp, sizeof (protocol_binary_response_no_extras)));
 +  execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
  
    /* Fix the byte order in the packet header */
    rsp->plain.message.header.response.keylen=
@@@ -694,12 -693,10 +694,12 @@@ static enum test_return test_binary_set
    cmd.plain.message.header.request.cas=
            htonll(rsp.plain.message.header.response.cas - 1);
    execute(resend_packet(&cmd));
 +  execute(send_binary_noop());
    execute(recv_packet(&rsp));
    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
 +  execute(receive_binary_noop());
  
 -  return test_binary_noop();
 +  return TEST_PASS;
  }
  
  static enum test_return test_binary_set(void)
@@@ -736,9 -733,7 +736,9 @@@ static enum test_return test_binary_add
        else
          expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
  
 +      execute(send_binary_noop());
        execute(recv_packet(&rsp));
 +      execute(receive_binary_noop());
        verify(validate_response_header(&rsp, cc, expected_result));
      }
      else
@@@ -795,9 -790,7 +795,9 @@@ static enum test_return test_binary_rep
        else
          expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
  
 +      execute(send_binary_noop());
        execute(recv_packet(&rsp));
 +      execute(receive_binary_noop());
        verify(validate_response_header(&rsp, cc, expected_result));
  
        if (ii == 0)
    cmd.plain.message.header.request.cas=
            htonll(rsp.plain.message.header.response.cas - 1);
    execute(resend_packet(&cmd));
 +  execute(send_binary_noop());
    execute(recv_packet(&rsp));
 +  execute(receive_binary_noop());
    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
  
    return TEST_PASS;
@@@ -850,10 -841,8 +850,10 @@@ static enum test_return test_binary_del
  
    /* The delete shouldn't work the first time, because the item isn't there */
    execute(send_packet(&cmd));
 +  execute(send_binary_noop());
    execute(recv_packet(&rsp));
    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
 +  execute(receive_binary_noop());
    execute(binary_set_item(key, key));
  
    /* The item should be present now, resend*/
@@@ -1267,7 -1256,8 +1267,7 @@@ static enum test_return test_ascii_set_
  {
    /* @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)
@@@ -1290,7 -1280,8 +1290,7 @@@ static enum test_return test_ascii_add_
  {
    /* @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)
@@@ -1314,41 -1305,6 +1314,41 @@@ static enum test_return test_ascii_add_
    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)
  {
  
@@@ -1392,7 -1348,7 +1392,7 @@@ static enum test_return ascii_get_item(
      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)
@@@ -1453,7 -1409,7 +1453,7 @@@ static enum test_return ascii_gets_item
      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)
@@@ -1469,7 -1425,7 +1469,7 @@@ static enum test_return ascii_set_item(
  {
    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"));
  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)
@@@ -1520,7 -1477,8 +1520,7 @@@ static enum test_return test_ascii_cas_
    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)
@@@ -1560,7 -1518,7 +1560,7 @@@ static enum test_return test_ascii_dele
    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)
@@@ -1615,65 -1573,31 +1615,65 @@@ static enum test_return test_ascii_gets
  
  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)
@@@ -1709,7 -1633,7 +1709,7 @@@ static enum test_return test_ascii_incr
  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)
@@@ -1811,10 -1735,10 +1811,10 @@@ static enum test_return test_ascii_conc
      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)
  
    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)
@@@ -1937,20 -1861,29 +1937,40 @@@ 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";
    const char *port= "11211";
    int cmd;
 -  int tests = ascii_tests | binary_tests;
 +  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:?ab")) != EOF)
++  while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
    {
      switch (cmd) {
 -      tests = ascii_tests;
+     case 'a':
 -      tests = binary_tests;
++      tests.ascii= true;
++      tests.binary= false;
+       break;
+     case 'b':
++      tests.ascii= false;
++      tests.binary= true;
+       break;
      case 't':
        timeout= atoi(optarg);
        if (timeout == 0)
        break;
      case 'p': port= optarg;
        break;
 +    case 'P': prompt= true;
 +      break;
 +    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] [-a] [-b]\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"
-               "\t-T n\tJust run the test named n\n",
 +              "\t-P\tPrompt the user before starting a test.\n"
 +              "\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-a\tOnly test the ascii protocol\n"
+               "\t-b\tOnly test the binary protocol\n",
                argv[0]);
        return 1;
      }
  
    for (int ii= 0; testcases[ii].description != NULL; ++ii)
    {
 -    if ((testcases[ii].description[0] == 'a' && (tests & ascii_tests) == 0) ||
 -        (testcases[ii].description[0] == 'b' && (tests & binary_tests) == 0))
 +    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);
  
 +    if (prompt)
 +    {
 +      fprintf(stdout, "\nPress <return> when you are ready? ");
 +      char buffer[80] = {0};
 +      if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
 +        if (strncmp(buffer, "skip", 4) == 0)
 +        {
 +          fprintf(stdout, "%-40s%s\n", testcases[ii].description,
 +                  status_msg[TEST_SKIP]);
 +          fflush(stdout);
 +          continue;
 +        }
 +        if (strncmp(buffer, "quit", 4) == 0)
 +          exit(0);
 +      }
 +
 +      fprintf(stdout, "%-40s", testcases[ii].description);
 +      fflush(stdout);
 +    }
 +
      bool reconnect= false;
      enum test_return ret= testcases[ii].function();
      if (ret == TEST_FAIL)