MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
testapp.c
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "config.h"
3 #undef NDEBUG
4 #include <pthread.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/wait.h>
8 #include <netdb.h>
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include <netinet/tcp.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 
23 #include "cache.h"
24 #include <memcached/util.h>
25 #include <memcached/protocol_binary.h>
26 #include <memcached/config_parser.h>
27 
28 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
29 
30 enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
31 
32 static pid_t server_pid;
33 static in_port_t port;
34 static int sock;
35 static bool allow_closed_read = false;
36 
37 static enum test_return cache_create_test(void)
38 {
39  cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
40  NULL, NULL);
41  assert(cache != NULL);
42  cache_destroy(cache);
43  return TEST_PASS;
44 }
45 
46 const uint64_t constructor_pattern = 0xdeadcafebabebeef;
47 
48 static int cache_constructor(void *buffer, void *notused1, int notused2) {
49  uint64_t *ptr = buffer;
50  *ptr = constructor_pattern;
51  return 0;
52 }
53 
54 static enum test_return cache_constructor_test(void)
55 {
56  cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
57  cache_constructor, NULL);
58  assert(cache != NULL);
59  uint64_t *ptr = cache_alloc(cache);
60  uint64_t pattern = *ptr;
61  cache_free(cache, ptr);
62  cache_destroy(cache);
63  return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
64 }
65 
66 static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
67  return 1;
68 }
69 
70 static enum test_return cache_fail_constructor_test(void)
71 {
72  enum test_return ret = TEST_PASS;
73 
74  cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
75  cache_fail_constructor, NULL);
76  assert(cache != NULL);
77  uint64_t *ptr = cache_alloc(cache);
78  if (ptr != NULL) {
79  ret = TEST_FAIL;
80  }
81  cache_destroy(cache);
82  return ret;
83 }
84 
85 static void *destruct_data = 0;
86 
87 static void cache_destructor(void *buffer, void *notused) {
88  destruct_data = buffer;
89 }
90 
91 static enum test_return cache_destructor_test(void)
92 {
93  cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
94  NULL, cache_destructor);
95  assert(cache != NULL);
96  char *ptr = cache_alloc(cache);
97  cache_free(cache, ptr);
98  cache_destroy(cache);
99 
100  return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
101 }
102 
103 static enum test_return cache_reuse_test(void)
104 {
105  int ii;
106  cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
107  NULL, NULL);
108  char *ptr = cache_alloc(cache);
109  cache_free(cache, ptr);
110  for (ii = 0; ii < 100; ++ii) {
111  char *p = cache_alloc(cache);
112  assert(p == ptr);
113  cache_free(cache, ptr);
114  }
115  cache_destroy(cache);
116  return TEST_PASS;
117 }
118 
119 
120 static enum test_return cache_bulkalloc(size_t datasize)
121 {
122  cache_t *cache = cache_create("test", datasize, sizeof(char*),
123  NULL, NULL);
124 #define ITERATIONS 1024
125  void *ptr[ITERATIONS];
126 
127  for (int ii = 0; ii < ITERATIONS; ++ii) {
128  ptr[ii] = cache_alloc(cache);
129  assert(ptr[ii] != 0);
130  memset(ptr[ii], 0xff, datasize);
131  }
132 
133  for (int ii = 0; ii < ITERATIONS; ++ii) {
134  cache_free(cache, ptr[ii]);
135  }
136 
137 #undef ITERATIONS
138  cache_destroy(cache);
139  return TEST_PASS;
140 }
141 
142 static enum test_return test_issue_161(void)
143 {
144  enum test_return ret = cache_bulkalloc(1);
145  if (ret == TEST_PASS) {
146  ret = cache_bulkalloc(512);
147  }
148 
149  return ret;
150 }
151 
152 static enum test_return cache_redzone_test(void)
153 {
154 #ifndef HAVE_UMEM_H
155  cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
156  NULL, NULL);
157 
158  /* Ignore SIGABORT */
159  struct sigaction old_action;
160  struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
161  sigemptyset(&action.sa_mask);
162  sigaction(SIGABRT, &action, &old_action);
163 
164  /* check memory debug.. */
165  char *p = cache_alloc(cache);
166  char old = *(p - 1);
167  *(p - 1) = 0;
168  cache_free(cache, p);
169  assert(cache_error == -1);
170  *(p - 1) = old;
171 
172  p[sizeof(uint32_t)] = 0;
173  cache_free(cache, p);
174  assert(cache_error == 1);
175 
176  /* restore signal handler */
177  sigaction(SIGABRT, &old_action, NULL);
178 
179  cache_destroy(cache);
180 
181  return TEST_PASS;
182 #else
183  return TEST_SKIP;
184 #endif
185 }
186 
187 static enum test_return test_safe_strtoul(void) {
188  uint32_t val;
189  assert(safe_strtoul("123", &val));
190  assert(val == 123);
191  assert(safe_strtoul("+123", &val));
192  assert(val == 123);
193  assert(!safe_strtoul("", &val)); // empty
194  assert(!safe_strtoul("123BOGUS", &val)); // non-numeric
195  /* Not sure what it does, but this works with ICC :/
196  assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
197  */
198 
199  // extremes:
200  assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
201  assert(val == 4294967295L);
202  /* This actually works on 64-bit ubuntu
203  assert(!safe_strtoul("4294967296", &val)); // 2**32
204  */
205  assert(!safe_strtoul("-1", &val)); // negative
206  return TEST_PASS;
207 }
208 
209 
210 static enum test_return test_safe_strtoull(void) {
211  uint64_t val;
212  assert(safe_strtoull("123", &val));
213  assert(val == 123);
214  assert(safe_strtoull("+123", &val));
215  assert(val == 123);
216  assert(!safe_strtoull("", &val)); // empty
217  assert(!safe_strtoull("123BOGUS", &val)); // non-numeric
218  assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
219 
220  // extremes:
221  assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
222  assert(val == 18446744073709551615ULL);
223  assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
224  assert(!safe_strtoull("-1", &val)); // negative
225  return TEST_PASS;
226 }
227 
228 static enum test_return test_safe_strtoll(void) {
229  int64_t val;
230  assert(safe_strtoll("123", &val));
231  assert(val == 123);
232  assert(safe_strtoll("+123", &val));
233  assert(val == 123);
234  assert(safe_strtoll("-123", &val));
235  assert(val == -123);
236  assert(!safe_strtoll("", &val)); // empty
237  assert(!safe_strtoll("123BOGUS", &val)); // non-numeric
238  assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
239 
240  // extremes:
241  assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
242  assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
243  assert(val == 9223372036854775807LL);
244  /*
245  assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
246  assert(val == -9223372036854775808LL);
247  */
248  assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
249 
250  // We'll allow space to terminate the string. And leading space.
251  assert(safe_strtoll(" 123 foo", &val));
252  assert(val == 123);
253  return TEST_PASS;
254 }
255 
256 static enum test_return test_safe_strtol(void) {
257  int32_t val;
258  assert(safe_strtol("123", &val));
259  assert(val == 123);
260  assert(safe_strtol("+123", &val));
261  assert(val == 123);
262  assert(safe_strtol("-123", &val));
263  assert(val == -123);
264  assert(!safe_strtol("", &val)); // empty
265  assert(!safe_strtol("123BOGUS", &val)); // non-numeric
266  assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
267 
268  // extremes:
269  /* This actually works on 64-bit ubuntu
270  assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
271  */
272  assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
273  assert(val == 2147483647L);
274  /* This actually works on 64-bit ubuntu
275  assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
276  */
277 
278  // We'll allow space to terminate the string. And leading space.
279  assert(safe_strtol(" 123 foo", &val));
280  assert(val == 123);
281  return TEST_PASS;
282 }
283 
284 static enum test_return test_safe_strtof(void) {
285  float val;
286  assert(safe_strtof("123", &val));
287  assert(val == 123.00f);
288  assert(safe_strtof("+123", &val));
289  assert(val == 123.00f);
290  assert(safe_strtof("-123", &val));
291  assert(val == -123.00f);
292  assert(!safe_strtof("", &val)); // empty
293  assert(!safe_strtof("123BOGUS", &val)); // non-numeric
294 
295  // We'll allow space to terminate the string. And leading space.
296  assert(safe_strtof(" 123 foo", &val));
297  assert(val == 123.00f);
298 
299  assert(safe_strtof("123.23", &val));
300  assert(val == 123.23f);
301 
302  assert(safe_strtof("123.00", &val));
303  assert(val == 123.00f);
304 
305  return TEST_PASS;
306 }
307 
317 static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
318  char environment[80];
319  snprintf(environment, sizeof(environment),
320  "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
321  char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
322  char pid_file[80];
323  snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
324 
325  remove(filename);
326  remove(pid_file);
327 
328  char engine[1024];
329  assert(getcwd(engine, sizeof(engine)));
330  strcat(engine, "/.libs/default_engine.so");
331  assert(strlen(engine) < sizeof(engine));
332 
333  char blackhole[1024];
334  assert(getcwd(blackhole, sizeof(blackhole)));
335  strcat(blackhole, "/.libs/blackhole_logger.so");
336 
337 
338 #ifdef __sun
339  /* I want to name the corefiles differently so that they don't
340  overwrite each other
341  */
342  char coreadm[128];
343  snprintf(coreadm, sizeof(coreadm),
344  "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
345  system(coreadm);
346 #endif
347 
348  pid_t pid = fork();
349  assert(pid != -1);
350 
351  if (pid == 0) {
352  /* Child */
353  char *argv[20];
354  int arg = 0;
355  char tmo[24];
356  snprintf(tmo, sizeof(tmo), "%u", timeout);
357 
358  putenv(environment);
359 
360  if (!daemon) {
361  argv[arg++] = "./timedrun";
362  argv[arg++] = tmo;
363  }
364  argv[arg++] = "./memcached";
365  argv[arg++] = "-E";
366  argv[arg++] = engine;
367  argv[arg++] = "-X";
368  argv[arg++] = blackhole;
369  argv[arg++] = "-p";
370  argv[arg++] = "-1";
371  argv[arg++] = "-U";
372  argv[arg++] = "0";
373  /* Handle rpmbuild and the like doing this as root */
374  if (getuid() == 0) {
375  argv[arg++] = "-u";
376  argv[arg++] = "root";
377  }
378  if (daemon) {
379  argv[arg++] = "-d";
380  argv[arg++] = "-P";
381  argv[arg++] = pid_file;
382  }
383 #ifdef MESSAGE_DEBUG
384  argv[arg++] = "-vvv";
385 #endif
386  argv[arg++] = NULL;
387  assert(execv(argv[0], argv) != -1);
388  }
389 
390  /* Yeah just let us "busy-wait" for the file to be created ;-) */
391  while (access(filename, F_OK) == -1) {
392  usleep(10);
393  }
394 
395  FILE *fp = fopen(filename, "r");
396  if (fp == NULL) {
397  fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
398  strerror(errno));
399  assert(false);
400  }
401 
402  *port_out = (in_port_t)-1;
403  char buffer[80];
404  while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
405  if (strncmp(buffer, "TCP INET: ", 10) == 0) {
406  int32_t val;
407  assert(safe_strtol(buffer + 10, &val));
408  *port_out = (in_port_t)val;
409  }
410  }
411  fclose(fp);
412  assert(remove(filename) == 0);
413 
414  if (daemon) {
415  /* loop and wait for the pid file.. There is a potential race
416  * condition that the server just created the file but isn't
417  * finished writing the content, but I'll take the chance....
418  */
419  while (access(pid_file, F_OK) == -1) {
420  usleep(10);
421  }
422 
423  fp = fopen(pid_file, "r");
424  if (fp == NULL) {
425  fprintf(stderr, "Failed to open pid file: %s\n",
426  strerror(errno));
427  assert(false);
428  }
429  assert(fgets(buffer, sizeof(buffer), fp) != NULL);
430  fclose(fp);
431 
432  int32_t val;
433  assert(safe_strtol(buffer, &val));
434  pid = (pid_t)val;
435  }
436 
437  return pid;
438 }
439 
440 static enum test_return test_issue_44(void) {
441  in_port_t port;
442  pid_t pid = start_server(&port, true, 15);
443  assert(kill(pid, SIGHUP) == 0);
444  sleep(1);
445  assert(kill(pid, SIGTERM) == 0);
446 
447  return TEST_PASS;
448 }
449 
450 static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
451 {
452  struct addrinfo *ai = 0;
453  struct addrinfo hints = { .ai_family = AF_UNSPEC,
454  .ai_protocol = IPPROTO_TCP,
455  .ai_socktype = SOCK_STREAM };
456  char service[NI_MAXSERV];
457  int error;
458 
459  (void)snprintf(service, NI_MAXSERV, "%d", port);
460  if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
461  if (error != EAI_SYSTEM) {
462  fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
463  } else {
464  perror("getaddrinfo()");
465  }
466  }
467 
468  return ai;
469 }
470 
471 static int connect_server(const char *hostname, in_port_t port, bool nonblock)
472 {
473  struct addrinfo *ai = lookuphost(hostname, port);
474  int sock = -1;
475  if (ai != NULL) {
476  if ((sock = socket(ai->ai_family, ai->ai_socktype,
477  ai->ai_protocol)) != -1) {
478  if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
479  fprintf(stderr, "Failed to connect socket: %s\n",
480  strerror(errno));
481  close(sock);
482  sock = -1;
483  } else if (nonblock) {
484  int flags = fcntl(sock, F_GETFL, 0);
485  if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
486  fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
487  strerror(errno));
488  close(sock);
489  sock = -1;
490  }
491  }
492  } else {
493  fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
494  }
495 
496  freeaddrinfo(ai);
497  }
498  return sock;
499 }
500 
501 static enum test_return test_vperror(void) {
502  int rv = 0;
503  int oldstderr = dup(STDERR_FILENO);
504  char tmpl[sizeof(TMP_TEMPLATE)+1];
505  strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
506 
507  int newfile = mkstemp(tmpl);
508  assert(newfile > 0);
509  rv = dup2(newfile, STDERR_FILENO);
510  assert(rv == STDERR_FILENO);
511  rv = close(newfile);
512  assert(rv == 0);
513 
514  errno = EIO;
515  vperror("Old McDonald had a farm. %s", "EI EIO");
516 
517  /* Restore stderr */
518  rv = dup2(oldstderr, STDERR_FILENO);
519  assert(rv == STDERR_FILENO);
520 
521 
522  /* Go read the file */
523  char buf[80] = { 0 };
524  FILE *efile = fopen(tmpl, "r");
525  assert(efile);
526  char *prv = fgets(buf, sizeof(buf), efile);
527  assert(prv);
528  fclose(efile);
529 
530  unlink(tmpl);
531 
532  char expected[80] = { 0 };
533  snprintf(expected, sizeof(expected),
534  "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO));
535 
536  /*
537  fprintf(stderr,
538  "\nExpected: ``%s''"
539  "\nGot: ``%s''\n", expected, buf);
540  */
541 
542  return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
543 }
544 
545 static char* trim(char* ptr) {
546  char *start = ptr;
547  while (isspace(*start)) {
548  ++start;
549  }
550  char *end = start + strlen(start) - 1;
551  if (end != start) {
552  while (isspace(*end)) {
553  *end = '\0';
554  --end;
555  }
556  }
557  return start;
558 }
559 
560 static enum test_return test_config_parser(void) {
561  bool bool_val = false;
562  size_t size_val = 0;
563  float float_val = 0;
564  char *string_val = 0;
565 
566  /* Set up the different items I can handle */
567  struct config_item items[] = {
568  { .key = "bool",
569  .datatype = DT_BOOL,
570  .value.dt_bool = &bool_val },
571  { .key = "size_t",
572  .datatype = DT_SIZE,
573  .value.dt_size = &size_val },
574  { .key = "float",
575  .datatype = DT_FLOAT,
576  .value.dt_float = &float_val},
577  { .key = "string",
578  .datatype = DT_STRING,
579  .value.dt_string = &string_val},
580  { .key = "config_file",
581  .datatype = DT_CONFIGFILE },
582  { .key = NULL}
583  };
584 
585  char outfile[sizeof(TMP_TEMPLATE)+1];
586  strncpy(outfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
587  char cfgfile[sizeof(TMP_TEMPLATE)+1];
588  strncpy(cfgfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
589 
590  int newfile = mkstemp(outfile);
591  assert(newfile > 0);
592  FILE *error = fdopen(newfile, "w");
593 
594  assert(error != NULL);
595  assert(parse_config("", items, error) == 0);
596  /* Nothing should be found */
597  for (int ii = 0; ii < 5; ++ii) {
598  assert(!items[0].found);
599  }
600 
601  assert(parse_config("bool=true", items, error) == 0);
602  assert(bool_val);
603  /* only bool should be found */
604  assert(items[0].found);
605  items[0].found = false;
606  for (int ii = 0; ii < 5; ++ii) {
607  assert(!items[0].found);
608  }
609 
610  /* It should allow illegal keywords */
611  assert(parse_config("pacman=dead", items, error) == 1);
612  /* and illegal values */
613  assert(parse_config("bool=12", items, error) == -1);
614  assert(!items[0].found);
615  /* and multiple occurences of the same value */
616  assert(parse_config("size_t=1; size_t=1024", items, error) == 0);
617  assert(items[1].found);
618  assert(size_val == 1024);
619  items[1].found = false;
620 
621  /* Empty string */
622  /* XXX: This test fails on Linux, but works on OS X.
623  assert(parse_config("string=", items, error) == 0);
624  assert(items[3].found);
625  assert(strcmp(string_val, "") == 0);
626  items[3].found = false;
627  */
628  /* Plain string */
629  assert(parse_config("string=sval", items, error) == 0);
630  assert(items[3].found);
631  assert(strcmp(string_val, "sval") == 0);
632  items[3].found = false;
633  /* Leading space */
634  assert(parse_config("string= sval", items, error) == 0);
635  assert(items[3].found);
636  assert(strcmp(string_val, "sval") == 0);
637  items[3].found = false;
638  /* Escaped leading space */
639  assert(parse_config("string=\\ sval", items, error) == 0);
640  assert(items[3].found);
641  assert(strcmp(string_val, " sval") == 0);
642  items[3].found = false;
643  /* trailing space */
644  assert(parse_config("string=sval ", items, error) == 0);
645  assert(items[3].found);
646  assert(strcmp(string_val, "sval") == 0);
647  items[3].found = false;
648  /* escaped trailing space */
649  assert(parse_config("string=sval\\ ", items, error) == 0);
650  assert(items[3].found);
651  assert(strcmp(string_val, "sval ") == 0);
652  items[3].found = false;
653  /* escaped stop char */
654  assert(parse_config("string=sval\\;blah=x", items, error) == 0);
655  assert(items[3].found);
656  assert(strcmp(string_val, "sval;blah=x") == 0);
657  items[3].found = false;
658  /* middle space */
659  assert(parse_config("string=s val", items, error) == 0);
660  assert(items[3].found);
661  assert(strcmp(string_val, "s val") == 0);
662  items[3].found = false;
663 
664  /* And all of the variables */
665  assert(parse_config("bool=true;size_t=1024;float=12.5;string=somestr",
666  items, error) == 0);
667  assert(bool_val);
668  assert(size_val == 1024);
669  assert(float_val == 12.5f);
670  assert(strcmp(string_val, "somestr") == 0);
671  for (int ii = 0; ii < 5; ++ii) {
672  items[ii].found = false;
673  }
674 
675  assert(parse_config("size_t=1k", items, error) == 0);
676  assert(items[1].found);
677  assert(size_val == 1024);
678  items[1].found = false;
679  assert(parse_config("size_t=1m", items, error) == 0);
680  assert(items[1].found);
681  assert(size_val == 1024*1024);
682  items[1].found = false;
683  assert(parse_config("size_t=1g", items, error) == 0);
684  assert(items[1].found);
685  assert(size_val == 1024*1024*1024);
686  items[1].found = false;
687  assert(parse_config("size_t=1K", items, error) == 0);
688  assert(items[1].found);
689  assert(size_val == 1024);
690  items[1].found = false;
691  assert(parse_config("size_t=1M", items, error) == 0);
692  assert(items[1].found);
693  assert(size_val == 1024*1024);
694  items[1].found = false;
695  assert(parse_config("size_t=1G", items, error) == 0);
696  assert(items[1].found);
697  assert(size_val == 1024*1024*1024);
698  items[1].found = false;
699 
700  newfile = mkstemp(cfgfile);
701  assert(newfile > 0);
702  FILE *cfg = fdopen(newfile, "w");
703  assert(cfg != NULL);
704  fprintf(cfg, "# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
705  fclose(cfg);
706  char buffer[1024];
707  sprintf(buffer, "config_file=%s", cfgfile);
708  assert(parse_config(buffer, items, error) == 0);
709  assert(bool_val);
710  assert(size_val == 1023);
711  assert(float_val == 12.4f);
712  fclose(error);
713 
714  remove(cfgfile);
715  /* Verify that I received the error messages ;-) */
716  error = fopen(outfile, "r");
717  assert(error);
718 
719  assert(fgets(buffer, sizeof(buffer), error));
720  assert(strcmp("Unsupported key: <pacman>", trim(buffer)) == 0);
721  assert(fgets(buffer, sizeof(buffer), error));
722  assert(strcmp("Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
723  assert(fgets(buffer, sizeof(buffer), error));
724  assert(strcmp("WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
725  assert(fgets(buffer, sizeof(buffer), error) == NULL);
726 
727  remove(outfile);
728  return TEST_PASS;
729 }
730 
731 static void send_ascii_command(const char *buf) {
732  off_t offset = 0;
733  const char* ptr = buf;
734  size_t len = strlen(buf);
735 
736  do {
737  ssize_t nw = send(sock, ptr + offset, len - offset, 0);
738  if (nw == -1) {
739  if (errno != EINTR) {
740  fprintf(stderr, "Failed to write: %s\n", strerror(errno));
741  abort();
742  }
743  } else {
744  offset += nw;
745  }
746  } while (offset < len);
747 }
748 
749 /*
750  * This is a dead slow single byte read, but it should only read out
751  * _one_ response and I don't have an input buffer... The current
752  * implementation only supports single-line responses, so if you want to use
753  * it for get commands you need to implement that first ;-)
754  */
755 static void read_ascii_response(char *buffer, size_t size) {
756  off_t offset = 0;
757  bool need_more = true;
758  do {
759  ssize_t nr = recv(sock, buffer + offset, 1, 0);
760  if (nr == -1) {
761  if (errno != EINTR) {
762  fprintf(stderr, "Failed to read: %s\n", strerror(errno));
763  abort();
764  }
765  } else {
766  assert(nr == 1);
767  if (buffer[offset] == '\n') {
768  need_more = false;
769  buffer[offset + 1] = '\0';
770  }
771  offset += nr;
772  assert(offset + 1 < size);
773  }
774  } while (need_more);
775 }
776 
777 static enum test_return test_issue_92(void) {
778 #ifdef FUTURE
779  char buffer[1024];
780 
781  close(sock);
782  sock = connect_server("127.0.0.1", port, false);
783 
784  send_ascii_command("stats cachedump 1 0 0\r\n");
785  read_ascii_response(buffer, sizeof(buffer));
786  assert(strncmp(buffer, "END", strlen("END")) == 0);
787 
788  send_ascii_command("stats cachedump 200 0 0\r\n");
789  read_ascii_response(buffer, sizeof(buffer));
790  assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
791 
792  close(sock);
793  sock = connect_server("127.0.0.1", port, false);
794 #endif
795 
796  return TEST_PASS;
797 }
798 
799 static enum test_return test_issue_102(void) {
800  char buffer[4096];
801  memset(buffer, ' ', sizeof(buffer));
802  buffer[sizeof(buffer) - 1] = '\0';
803 
804  close(sock);
805  sock = connect_server("127.0.0.1", port, false);
806 
807  send_ascii_command(buffer);
808  /* verify that the server closed the connection */
809  assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
810  close(sock);
811  sock = connect_server("127.0.0.1", port, false);
812 
813  snprintf(buffer, sizeof(buffer), "gets ");
814  size_t offset = 5;
815  while (offset < 4000) {
816  offset += snprintf(buffer + offset, sizeof(buffer) - offset,
817  "%010u ", (unsigned int)offset);
818  }
819 
820  send_ascii_command(buffer);
821  usleep(250);
822 
823  send_ascii_command("\r\n");
824  char rsp[80];
825  read_ascii_response(rsp, sizeof(rsp));
826  assert(strncmp(rsp, "END", strlen("END")) == 0);
827  buffer[3]= ' ';
828  send_ascii_command(buffer);
829  usleep(250);
830  send_ascii_command("\r\n");
831  read_ascii_response(rsp, sizeof(rsp));
832  assert(strncmp(rsp, "END", strlen("END")) == 0);
833 
834  memset(buffer, ' ', sizeof(buffer));
835  int len = snprintf(buffer + 101, sizeof(buffer) - 101, "gets foo");
836  buffer[101 + len] = ' ';
837  buffer[sizeof(buffer) - 1] = '\0';
838  send_ascii_command(buffer);
839  /* verify that the server closed the connection */
840  assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
841 
842  close(sock);
843  sock = connect_server("127.0.0.1", port, false);
844 
845  return TEST_PASS;
846 }
847 
848 static enum test_return start_memcached_server(void) {
849  server_pid = start_server(&port, false, 600);
850  sock = connect_server("127.0.0.1", port, false);
851 
852  return TEST_PASS;
853 }
854 
855 static enum test_return stop_memcached_server(void) {
856  close(sock);
857  assert(kill(server_pid, SIGTERM) == 0);
858  return TEST_PASS;
859 }
860 
861 static void safe_send(const void* buf, size_t len, bool hickup)
862 {
863  off_t offset = 0;
864  const char* ptr = buf;
865 #ifdef MESSAGE_DEBUG
866  uint8_t val = *ptr;
867  assert(val == (uint8_t)0x80);
868  fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
869  for (int ii = 0; ii < len; ++ii) {
870  if (ii % 4 == 0) {
871  fprintf(stderr, "\n ");
872  }
873  val = *(ptr + ii);
874  fprintf(stderr, " 0x%02x", val);
875  }
876  fprintf(stderr, "\n");
877  usleep(500);
878 #endif
879 
880  do {
881  size_t num_bytes = len - offset;
882  if (hickup) {
883  if (num_bytes > 1024) {
884  num_bytes = (rand() % 1023) + 1;
885  }
886  }
887 
888  ssize_t nw = send(sock, ptr + offset, num_bytes, 0);
889  if (nw == -1) {
890  if (errno != EINTR) {
891  fprintf(stderr, "Failed to write: %s\n", strerror(errno));
892  abort();
893  }
894  } else {
895  if (hickup) {
896  usleep(100);
897  }
898  offset += nw;
899  }
900  } while (offset < len);
901 }
902 
903 static bool safe_recv(void *buf, size_t len) {
904  if (len == 0) {
905  return true;
906  }
907  off_t offset = 0;
908  do {
909  ssize_t nr = recv(sock, ((char*)buf) + offset, len - offset, 0);
910  if (nr == -1) {
911  if (errno != EINTR) {
912  fprintf(stderr, "Failed to read: %s\n", strerror(errno));
913  abort();
914  }
915  } else {
916  if (nr == 0 && allow_closed_read) {
917  return false;
918  }
919  assert(nr != 0);
920  offset += nr;
921  }
922  } while (offset < len);
923 
924  return true;
925 }
926 
927 static bool safe_recv_packet(void *buf, size_t size) {
929  assert(size > sizeof(*response));
930  if (!safe_recv(response, sizeof(*response))) {
931  return false;
932  }
933  response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
934  response->message.header.response.status = ntohs(response->message.header.response.status);
935  response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
936 
937  size_t len = sizeof(*response);
938 
939  char *ptr = buf;
940  ptr += len;
941  if (!safe_recv(ptr, response->message.header.response.bodylen)) {
942  return false;
943  }
944 
945 #ifdef MESSAGE_DEBUG
946  usleep(500);
947  ptr = buf;
948  len += response->message.header.response.bodylen;
949  uint8_t val = *ptr;
950  assert(val == (uint8_t)0x81);
951  fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
952  for (int ii = 0; ii < len; ++ii) {
953  if (ii % 4 == 0) {
954  fprintf(stderr, "\n ");
955  }
956  val = *(ptr + ii);
957  fprintf(stderr, " 0x%02x", val);
958  }
959  fprintf(stderr, "\n");
960 #endif
961  return true;
962 }
963 
964 static off_t storage_command(char*buf,
965  size_t bufsz,
966  uint8_t cmd,
967  const void* key,
968  size_t keylen,
969  const void* dta,
970  size_t dtalen,
971  uint32_t flags,
972  uint32_t exp) {
973  /* all of the storage commands use the same command layout */
974  protocol_binary_request_set *request = (void*)buf;
975  assert(bufsz > sizeof(*request) + keylen + dtalen);
976 
977  memset(request, 0, sizeof(*request));
978  request->message.header.request.magic = PROTOCOL_BINARY_REQ;
979  request->message.header.request.opcode = cmd;
980  request->message.header.request.keylen = htons(keylen);
981  request->message.header.request.extlen = 8;
982  request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
983  request->message.header.request.opaque = 0xdeadbeef;
984  request->message.body.flags = flags;
985  request->message.body.expiration = exp;
986 
987  off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
988 
989  memcpy(buf + key_offset, key, keylen);
990  if (dta != NULL) {
991  memcpy(buf + key_offset + keylen, dta, dtalen);
992  }
993 
994  return key_offset + keylen + dtalen;
995 }
996 
997 static off_t raw_command(char* buf,
998  size_t bufsz,
999  uint8_t cmd,
1000  const void* key,
1001  size_t keylen,
1002  const void* dta,
1003  size_t dtalen) {
1004  /* all of the storage commands use the same command layout */
1005  protocol_binary_request_no_extras *request = (void*)buf;
1006  assert(bufsz > sizeof(*request) + keylen + dtalen);
1007 
1008  memset(request, 0, sizeof(*request));
1009  request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1010  request->message.header.request.opcode = cmd;
1011  request->message.header.request.keylen = htons(keylen);
1012  request->message.header.request.bodylen = htonl(keylen + dtalen);
1013  request->message.header.request.opaque = 0xdeadbeef;
1014 
1015  off_t key_offset = sizeof(protocol_binary_request_no_extras);
1016 
1017  if (key != NULL) {
1018  memcpy(buf + key_offset, key, keylen);
1019  }
1020  if (dta != NULL) {
1021  memcpy(buf + key_offset + keylen, dta, dtalen);
1022  }
1023 
1024  return sizeof(*request) + keylen + dtalen;
1025 }
1026 
1027 static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1028  protocol_binary_request_flush *request = (void*)buf;
1029  assert(bufsz > sizeof(*request));
1030 
1031  memset(request, 0, sizeof(*request));
1032  request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1033  request->message.header.request.opcode = cmd;
1034 
1035  off_t size = sizeof(protocol_binary_request_no_extras);
1036  if (use_extra) {
1037  request->message.header.request.extlen = 4;
1038  request->message.body.expiration = htonl(exptime);
1039  request->message.header.request.bodylen = htonl(4);
1040  size += 4;
1041  }
1042 
1043  request->message.header.request.opaque = 0xdeadbeef;
1044 
1045  return size;
1046 }
1047 
1048 static off_t arithmetic_command(char* buf,
1049  size_t bufsz,
1050  uint8_t cmd,
1051  const void* key,
1052  size_t keylen,
1053  uint64_t delta,
1054  uint64_t initial,
1055  uint32_t exp) {
1056  protocol_binary_request_incr *request = (void*)buf;
1057  assert(bufsz > sizeof(*request) + keylen);
1058 
1059  memset(request, 0, sizeof(*request));
1060  request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1061  request->message.header.request.opcode = cmd;
1062  request->message.header.request.keylen = htons(keylen);
1063  request->message.header.request.extlen = 20;
1064  request->message.header.request.bodylen = htonl(keylen + 20);
1065  request->message.header.request.opaque = 0xdeadbeef;
1066  request->message.body.delta = htonll(delta);
1067  request->message.body.initial = htonll(initial);
1068  request->message.body.expiration = htonl(exp);
1069 
1070  off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1071 
1072  memcpy(buf + key_offset, key, keylen);
1073  return key_offset + keylen;
1074 }
1075 
1076 static void validate_response_header(protocol_binary_response_no_extras *response,
1077  uint8_t cmd, uint16_t status)
1078 {
1079  assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1080  assert(response->message.header.response.opcode == cmd);
1081  assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1082  if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1083  if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1084  response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1085  }
1086  }
1087  assert(response->message.header.response.status == status);
1088  assert(response->message.header.response.opaque == 0xdeadbeef);
1089 
1090  if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1091  switch (cmd) {
1092  case PROTOCOL_BINARY_CMD_ADDQ:
1093  case PROTOCOL_BINARY_CMD_APPENDQ:
1094  case PROTOCOL_BINARY_CMD_DECREMENTQ:
1095  case PROTOCOL_BINARY_CMD_DELETEQ:
1096  case PROTOCOL_BINARY_CMD_FLUSHQ:
1097  case PROTOCOL_BINARY_CMD_INCREMENTQ:
1098  case PROTOCOL_BINARY_CMD_PREPENDQ:
1099  case PROTOCOL_BINARY_CMD_QUITQ:
1100  case PROTOCOL_BINARY_CMD_REPLACEQ:
1101  case PROTOCOL_BINARY_CMD_SETQ:
1102  assert("Quiet command shouldn't return on success" == NULL);
1103  default:
1104  break;
1105  }
1106 
1107  switch (cmd) {
1108  case PROTOCOL_BINARY_CMD_ADD:
1109  case PROTOCOL_BINARY_CMD_REPLACE:
1110  case PROTOCOL_BINARY_CMD_SET:
1111  case PROTOCOL_BINARY_CMD_APPEND:
1112  case PROTOCOL_BINARY_CMD_PREPEND:
1113  assert(response->message.header.response.keylen == 0);
1114  assert(response->message.header.response.extlen == 0);
1115  assert(response->message.header.response.bodylen == 0);
1116  assert(response->message.header.response.cas != 0);
1117  break;
1118  case PROTOCOL_BINARY_CMD_FLUSH:
1119  case PROTOCOL_BINARY_CMD_NOOP:
1120  case PROTOCOL_BINARY_CMD_QUIT:
1121  case PROTOCOL_BINARY_CMD_DELETE:
1122  assert(response->message.header.response.keylen == 0);
1123  assert(response->message.header.response.extlen == 0);
1124  assert(response->message.header.response.bodylen == 0);
1125  assert(response->message.header.response.cas == 0);
1126  break;
1127 
1128  case PROTOCOL_BINARY_CMD_DECREMENT:
1129  case PROTOCOL_BINARY_CMD_INCREMENT:
1130  assert(response->message.header.response.keylen == 0);
1131  assert(response->message.header.response.extlen == 0);
1132  assert(response->message.header.response.bodylen == 8);
1133  assert(response->message.header.response.cas != 0);
1134  break;
1135 
1136  case PROTOCOL_BINARY_CMD_STAT:
1137  assert(response->message.header.response.extlen == 0);
1138  /* key and value exists in all packets except in the terminating */
1139  assert(response->message.header.response.cas == 0);
1140  break;
1141 
1142  case PROTOCOL_BINARY_CMD_VERSION:
1143  assert(response->message.header.response.keylen == 0);
1144  assert(response->message.header.response.extlen == 0);
1145  assert(response->message.header.response.bodylen != 0);
1146  assert(response->message.header.response.cas == 0);
1147  break;
1148 
1149  case PROTOCOL_BINARY_CMD_GET:
1150  case PROTOCOL_BINARY_CMD_GETQ:
1151  assert(response->message.header.response.keylen == 0);
1152  assert(response->message.header.response.extlen == 4);
1153  assert(response->message.header.response.cas != 0);
1154  break;
1155 
1156  case PROTOCOL_BINARY_CMD_GETK:
1157  case PROTOCOL_BINARY_CMD_GETKQ:
1158  assert(response->message.header.response.keylen != 0);
1159  assert(response->message.header.response.extlen == 4);
1160  assert(response->message.header.response.cas != 0);
1161  break;
1162 
1163  default:
1164  /* Undefined command code */
1165  break;
1166  }
1167  } else {
1168  assert(response->message.header.response.cas == 0);
1169  assert(response->message.header.response.extlen == 0);
1170  if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1171  assert(response->message.header.response.keylen == 0);
1172  }
1173  }
1174 }
1175 
1176 static enum test_return test_binary_noop(void) {
1177  union {
1180  char bytes[1024];
1181  } buffer;
1182 
1183  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1184  PROTOCOL_BINARY_CMD_NOOP,
1185  NULL, 0, NULL, 0);
1186 
1187  safe_send(buffer.bytes, len, false);
1188  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1189  validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1190  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1191 
1192  return TEST_PASS;
1193 }
1194 
1195 static enum test_return test_binary_quit_impl(uint8_t cmd) {
1196  union {
1199  char bytes[1024];
1200  } buffer;
1201  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1202  cmd, NULL, 0, NULL, 0);
1203 
1204  safe_send(buffer.bytes, len, false);
1205  if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1206  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1207  validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1208  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1209  }
1210 
1211  /* Socket should be closed now, read should return 0 */
1212  assert(recv(sock, buffer.bytes, sizeof(buffer.bytes), 0) == 0);
1213  close(sock);
1214  sock = connect_server("127.0.0.1", port, false);
1215 
1216  return TEST_PASS;
1217 }
1218 
1219 static enum test_return test_binary_quit(void) {
1220  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1221 }
1222 
1223 static enum test_return test_binary_quitq(void) {
1224  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1225 }
1226 
1227 static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1228  union {
1231  char bytes[1024];
1232  } send, receive;
1233  uint64_t value = 0xdeadbeefdeadcafe;
1234  size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1235  key, strlen(key), &value, sizeof(value),
1236  0, 0);
1237 
1238  /* Set should work over and over again */
1239  int ii;
1240  for (ii = 0; ii < 10; ++ii) {
1241  safe_send(send.bytes, len, false);
1242  if (cmd == PROTOCOL_BINARY_CMD_SET) {
1243  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1244  validate_response_header(&receive.response, cmd,
1245  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1246  }
1247  }
1248 
1249  if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1250  return test_binary_noop();
1251  }
1252 
1253  send.request.message.header.request.cas = receive.response.message.header.response.cas;
1254  safe_send(send.bytes, len, false);
1255  if (cmd == PROTOCOL_BINARY_CMD_SET) {
1256  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1257  validate_response_header(&receive.response, cmd,
1258  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1259  assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1260  } else {
1261  return test_binary_noop();
1262  }
1263 
1264  return TEST_PASS;
1265 }
1266 
1267 static enum test_return test_binary_set(void) {
1268  return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1269 }
1270 
1271 static enum test_return test_binary_setq(void) {
1272  return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1273 }
1274 
1275 static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1276  uint64_t value = 0xdeadbeefdeadcafe;
1277  union {
1280  char bytes[1024];
1281  } send, receive;
1282  size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1283  strlen(key), &value, sizeof(value),
1284  0, 0);
1285 
1286  /* Add should only work the first time */
1287  int ii;
1288  for (ii = 0; ii < 10; ++ii) {
1289  safe_send(send.bytes, len, false);
1290  if (ii == 0) {
1291  if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1292  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1293  validate_response_header(&receive.response, cmd,
1294  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1295  }
1296  } else {
1297  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1298  validate_response_header(&receive.response, cmd,
1299  PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1300  }
1301  }
1302 
1303  return TEST_PASS;
1304 }
1305 
1306 static enum test_return test_binary_add(void) {
1307  return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1308 }
1309 
1310 static enum test_return test_binary_addq(void) {
1311  return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1312 }
1313 
1314 static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1315  uint64_t value = 0xdeadbeefdeadcafe;
1316  union {
1319  char bytes[1024];
1320  } send, receive;
1321  size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1322  key, strlen(key), &value, sizeof(value),
1323  0, 0);
1324  safe_send(send.bytes, len, false);
1325  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1326  validate_response_header(&receive.response, cmd,
1327  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1328  len = storage_command(send.bytes, sizeof(send.bytes),
1329  PROTOCOL_BINARY_CMD_ADD,
1330  key, strlen(key), &value, sizeof(value), 0, 0);
1331  safe_send(send.bytes, len, false);
1332  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1333  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1334  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1335 
1336  len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1337  key, strlen(key), &value, sizeof(value), 0, 0);
1338  int ii;
1339  for (ii = 0; ii < 10; ++ii) {
1340  safe_send(send.bytes, len, false);
1341  if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1342  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1343  validate_response_header(&receive.response,
1344  PROTOCOL_BINARY_CMD_REPLACE,
1345  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1346  }
1347  }
1348 
1349  if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1350  test_binary_noop();
1351  }
1352 
1353  return TEST_PASS;
1354 }
1355 
1356 static enum test_return test_binary_replace(void) {
1357  return test_binary_replace_impl("test_binary_replace",
1358  PROTOCOL_BINARY_CMD_REPLACE);
1359 }
1360 
1361 static enum test_return test_binary_replaceq(void) {
1362  return test_binary_replace_impl("test_binary_replaceq",
1363  PROTOCOL_BINARY_CMD_REPLACEQ);
1364 }
1365 
1366 static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1367  union {
1370  char bytes[1024];
1371  } send, receive;
1372  size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1373  key, strlen(key), NULL, 0);
1374 
1375  safe_send(send.bytes, len, false);
1376  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1377  validate_response_header(&receive.response, cmd,
1378  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1379  len = storage_command(send.bytes, sizeof(send.bytes),
1380  PROTOCOL_BINARY_CMD_ADD,
1381  key, strlen(key), NULL, 0, 0, 0);
1382  safe_send(send.bytes, len, false);
1383  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1384  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1385  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1386 
1387  len = raw_command(send.bytes, sizeof(send.bytes),
1388  cmd, key, strlen(key), NULL, 0);
1389  safe_send(send.bytes, len, false);
1390 
1391  if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1392  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1393  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1394  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1395  }
1396 
1397  safe_send(send.bytes, len, false);
1398  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1399  validate_response_header(&receive.response, cmd,
1400  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1401 
1402  return TEST_PASS;
1403 }
1404 
1405 static enum test_return test_binary_delete(void) {
1406  return test_binary_delete_impl("test_binary_delete",
1407  PROTOCOL_BINARY_CMD_DELETE);
1408 }
1409 
1410 static enum test_return test_binary_deleteq(void) {
1411  return test_binary_delete_impl("test_binary_deleteq",
1412  PROTOCOL_BINARY_CMD_DELETEQ);
1413 }
1414 
1415 static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1416  union {
1419  char bytes[1024];
1420  } send, receive;
1421  size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1422  key, strlen(key), NULL, 0);
1423 
1424  safe_send(send.bytes, len, false);
1425  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1426  validate_response_header(&receive.response, cmd,
1427  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1428 
1429  len = storage_command(send.bytes, sizeof(send.bytes),
1430  PROTOCOL_BINARY_CMD_ADD,
1431  key, strlen(key), NULL, 0,
1432  0, 0);
1433  safe_send(send.bytes, len, false);
1434  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1435  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1436  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1437 
1438  /* run a little pipeline test ;-) */
1439  len = 0;
1440  int ii;
1441  for (ii = 0; ii < 10; ++ii) {
1442  union {
1444  char bytes[1024];
1445  } temp;
1446  size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1447  cmd, key, strlen(key), NULL, 0);
1448  memcpy(send.bytes + len, temp.bytes, l);
1449  len += l;
1450  }
1451 
1452  safe_send(send.bytes, len, false);
1453  for (ii = 0; ii < 10; ++ii) {
1454  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1455  validate_response_header(&receive.response, cmd,
1456  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1457  }
1458 
1459  return TEST_PASS;
1460 }
1461 
1462 static enum test_return test_binary_get(void) {
1463  return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1464 }
1465 
1466 static enum test_return test_binary_getk(void) {
1467  return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1468 }
1469 
1470 static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1471  const char *missing = "test_binary_getq_missing";
1472  union {
1475  char bytes[1024];
1476  } send, temp, receive;
1477  size_t len = storage_command(send.bytes, sizeof(send.bytes),
1478  PROTOCOL_BINARY_CMD_ADD,
1479  key, strlen(key), NULL, 0,
1480  0, 0);
1481  size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1482  missing, strlen(missing), NULL, 0);
1483  /* I need to change the first opaque so that I can separate the two
1484  * return packets */
1485  temp.request.message.header.request.opaque = 0xfeedface;
1486  memcpy(send.bytes + len, temp.bytes, len2);
1487  len += len2;
1488 
1489  len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1490  key, strlen(key), NULL, 0);
1491  memcpy(send.bytes + len, temp.bytes, len2);
1492  len += len2;
1493 
1494  safe_send(send.bytes, len, false);
1495  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1496  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1497  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1498  /* The first GETQ shouldn't return anything */
1499  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1500  validate_response_header(&receive.response, cmd,
1501  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1502 
1503  return TEST_PASS;
1504 }
1505 
1506 static enum test_return test_binary_getq(void) {
1507  return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1508 }
1509 
1510 static enum test_return test_binary_getkq(void) {
1511  return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1512 }
1513 
1514 static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1515  union {
1517  protocol_binary_response_no_extras response_header;
1519  char bytes[1024];
1520  } send, receive;
1521  size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1522  key, strlen(key), 1, 0, 0);
1523 
1524  int ii;
1525  for (ii = 0; ii < 10; ++ii) {
1526  safe_send(send.bytes, len, false);
1527  if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1528  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1529  validate_response_header(&receive.response_header, cmd,
1530  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1531  assert(ntohll(receive.response.message.body.value) == ii);
1532  }
1533  }
1534 
1535  if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1536  test_binary_noop();
1537  }
1538  return TEST_PASS;
1539 }
1540 
1541 static enum test_return test_binary_incr(void) {
1542  return test_binary_incr_impl("test_binary_incr",
1543  PROTOCOL_BINARY_CMD_INCREMENT);
1544 }
1545 
1546 static enum test_return test_binary_incrq(void) {
1547  return test_binary_incr_impl("test_binary_incrq",
1548  PROTOCOL_BINARY_CMD_INCREMENTQ);
1549 }
1550 
1551 static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1552  union {
1554  protocol_binary_response_no_extras response_header;
1556  char bytes[1024];
1557  } send, receive;
1558  size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1559  key, strlen(key), 1, 9, 0);
1560 
1561  int ii;
1562  for (ii = 9; ii >= 0; --ii) {
1563  safe_send(send.bytes, len, false);
1564  if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1565  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1566  validate_response_header(&receive.response_header, cmd,
1567  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1568  assert(ntohll(receive.response.message.body.value) == ii);
1569  }
1570  }
1571 
1572  /* decr on 0 should not wrap */
1573  safe_send(send.bytes, len, false);
1574  if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1575  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1576  validate_response_header(&receive.response_header, cmd,
1577  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1578  assert(ntohll(receive.response.message.body.value) == 0);
1579  } else {
1580  test_binary_noop();
1581  }
1582 
1583  return TEST_PASS;
1584 }
1585 
1586 static enum test_return test_binary_decr(void) {
1587  return test_binary_decr_impl("test_binary_decr",
1588  PROTOCOL_BINARY_CMD_DECREMENT);
1589 }
1590 
1591 static enum test_return test_binary_decrq(void) {
1592  return test_binary_decr_impl("test_binary_decrq",
1593  PROTOCOL_BINARY_CMD_DECREMENTQ);
1594 }
1595 
1596 static enum test_return test_binary_version(void) {
1597  union {
1600  char bytes[1024];
1601  } buffer;
1602 
1603  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1604  PROTOCOL_BINARY_CMD_VERSION,
1605  NULL, 0, NULL, 0);
1606 
1607  safe_send(buffer.bytes, len, false);
1608  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1609  validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1610  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1611 
1612  return TEST_PASS;
1613 }
1614 
1615 static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1616  union {
1619  char bytes[1024];
1620  } send, receive;
1621 
1622  size_t len = storage_command(send.bytes, sizeof(send.bytes),
1623  PROTOCOL_BINARY_CMD_ADD,
1624  key, strlen(key), NULL, 0, 0, 0);
1625  safe_send(send.bytes, len, false);
1626  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1627  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1628  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1629 
1630  len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1631  safe_send(send.bytes, len, false);
1632  if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1633  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1634  validate_response_header(&receive.response, cmd,
1635  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1636  }
1637 
1638  len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1639  key, strlen(key), NULL, 0);
1640  safe_send(send.bytes, len, false);
1641  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1642  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1643  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1644 
1645  sleep(2);
1646  safe_send(send.bytes, len, false);
1647  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1648  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1649  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1650 
1651  int ii;
1652  for (ii = 0; ii < 2; ++ii) {
1653  len = storage_command(send.bytes, sizeof(send.bytes),
1654  PROTOCOL_BINARY_CMD_ADD,
1655  key, strlen(key), NULL, 0, 0, 0);
1656  safe_send(send.bytes, len, false);
1657  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1658  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1659  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1660 
1661  len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1662  safe_send(send.bytes, len, false);
1663  if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1664  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1665  validate_response_header(&receive.response, cmd,
1666  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1667  }
1668 
1669  len = raw_command(send.bytes, sizeof(send.bytes),
1670  PROTOCOL_BINARY_CMD_GET,
1671  key, strlen(key), NULL, 0);
1672  safe_send(send.bytes, len, false);
1673  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1674  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1675  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1676  }
1677 
1678  return TEST_PASS;
1679 }
1680 
1681 static enum test_return test_binary_flush(void) {
1682  return test_binary_flush_impl("test_binary_flush",
1683  PROTOCOL_BINARY_CMD_FLUSH);
1684 }
1685 
1686 static enum test_return test_binary_flushq(void) {
1687  return test_binary_flush_impl("test_binary_flushq",
1688  PROTOCOL_BINARY_CMD_FLUSHQ);
1689 }
1690 
1691 static enum test_return test_binary_cas(void) {
1692  union {
1695  char bytes[1024];
1696  } send, receive;
1697 
1698  size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1699  0, false);
1700  safe_send(send.bytes, len, false);
1701  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1702  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1703  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1704 
1705  uint64_t value = 0xdeadbeefdeadcafe;
1706  len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1707  "FOO", 3, &value, sizeof(value), 0, 0);
1708 
1709  send.request.message.header.request.cas = 0x7ffffff;
1710  safe_send(send.bytes, len, false);
1711  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1712  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1713  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1714 
1715  send.request.message.header.request.cas = 0x0;
1716  safe_send(send.bytes, len, false);
1717  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1718  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1719  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1720 
1721  send.request.message.header.request.cas = receive.response.message.header.response.cas;
1722  safe_send(send.bytes, len, false);
1723  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1724  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1725  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1726 
1727  send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
1728  safe_send(send.bytes, len, false);
1729  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1730  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1731  PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1732  return TEST_PASS;
1733 }
1734 
1735 static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
1736  union {
1739  char bytes[1024];
1740  } send, receive;
1741  const char *value = "world";
1742 
1743  size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1744  key, strlen(key), value, strlen(value));
1745 
1746 
1747  safe_send(send.bytes, len, false);
1748  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1749  validate_response_header(&receive.response, cmd,
1750  PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1751 
1752  len = storage_command(send.bytes, sizeof(send.bytes),
1753  PROTOCOL_BINARY_CMD_ADD,
1754  key, strlen(key), value, strlen(value), 0, 0);
1755  safe_send(send.bytes, len, false);
1756  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1757  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1758  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1759 
1760  len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1761  key, strlen(key), value, strlen(value));
1762  safe_send(send.bytes, len, false);
1763 
1764  if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1765  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1766  validate_response_header(&receive.response, cmd,
1767  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1768  } else {
1769  len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
1770  NULL, 0, NULL, 0);
1771  safe_send(send.bytes, len, false);
1772  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1773  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
1774  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1775  }
1776 
1777  len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
1778  key, strlen(key), NULL, 0);
1779 
1780  safe_send(send.bytes, len, false);
1781  safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1782  validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
1783  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1784 
1785  assert(receive.response.message.header.response.keylen == strlen(key));
1786  assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
1787 
1788  char *ptr = receive.bytes;
1789  ptr += sizeof(receive.response);
1790  ptr += 4;
1791 
1792  assert(memcmp(ptr, key, strlen(key)) == 0);
1793  ptr += strlen(key);
1794  assert(memcmp(ptr, value, strlen(value)) == 0);
1795  ptr += strlen(value);
1796  assert(memcmp(ptr, value, strlen(value)) == 0);
1797 
1798  return TEST_PASS;
1799 }
1800 
1801 static enum test_return test_binary_append(void) {
1802  return test_binary_concat_impl("test_binary_append",
1803  PROTOCOL_BINARY_CMD_APPEND);
1804 }
1805 
1806 static enum test_return test_binary_prepend(void) {
1807  return test_binary_concat_impl("test_binary_prepend",
1808  PROTOCOL_BINARY_CMD_PREPEND);
1809 }
1810 
1811 static enum test_return test_binary_appendq(void) {
1812  return test_binary_concat_impl("test_binary_appendq",
1813  PROTOCOL_BINARY_CMD_APPENDQ);
1814 }
1815 
1816 static enum test_return test_binary_prependq(void) {
1817  return test_binary_concat_impl("test_binary_prependq",
1818  PROTOCOL_BINARY_CMD_PREPENDQ);
1819 }
1820 
1821 static enum test_return test_binary_stat(void) {
1822  union {
1825  char bytes[1024];
1826  } buffer;
1827 
1828  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1829  PROTOCOL_BINARY_CMD_STAT,
1830  NULL, 0, NULL, 0);
1831 
1832  safe_send(buffer.bytes, len, false);
1833  do {
1834  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1835  validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
1836  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1837  } while (buffer.response.message.header.response.keylen != 0);
1838 
1839  return TEST_PASS;
1840 }
1841 
1842 static enum test_return test_binary_scrub(void) {
1843  union {
1846  char bytes[1024];
1847  } buffer;
1848 
1849  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1850  PROTOCOL_BINARY_CMD_SCRUB,
1851  NULL, 0, NULL, 0);
1852 
1853  safe_send(buffer.bytes, len, false);
1854  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1855  validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
1856  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1857 
1858  return TEST_PASS;
1859 }
1860 
1861 
1862 volatile bool hickup_thread_running;
1863 
1864 static void *binary_hickup_recv_verification_thread(void *arg) {
1865  protocol_binary_response_no_extras *response = malloc(65*1024);
1866  if (response != NULL) {
1867  while (safe_recv_packet(response, 65*1024)) {
1868  /* Just validate the packet format */
1869  validate_response_header(response,
1870  response->message.header.response.opcode,
1871  response->message.header.response.status);
1872  }
1873  free(response);
1874  }
1875  hickup_thread_running = false;
1876  allow_closed_read = false;
1877  return NULL;
1878 }
1879 
1880 static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
1881  off_t offset = 0;
1882  char *key[256];
1883  uint64_t value = 0xfeedfacedeadbeef;
1884 
1885  while (hickup_thread_running &&
1886  offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
1887  union {
1889  char bytes[65 * 1024];
1890  } command;
1891  uint8_t cmd = (uint8_t)(rand() & 0xff);
1892  size_t len;
1893  size_t keylen = (rand() % 250) + 1;
1894 
1895  switch (cmd) {
1896  case PROTOCOL_BINARY_CMD_ADD:
1897  case PROTOCOL_BINARY_CMD_ADDQ:
1898  case PROTOCOL_BINARY_CMD_REPLACE:
1899  case PROTOCOL_BINARY_CMD_REPLACEQ:
1900  case PROTOCOL_BINARY_CMD_SET:
1901  case PROTOCOL_BINARY_CMD_SETQ:
1902  len = storage_command(command.bytes, sizeof(command.bytes), cmd,
1903  key, keylen , &value, sizeof(value),
1904  0, 0);
1905  break;
1906  case PROTOCOL_BINARY_CMD_APPEND:
1907  case PROTOCOL_BINARY_CMD_APPENDQ:
1908  case PROTOCOL_BINARY_CMD_PREPEND:
1909  case PROTOCOL_BINARY_CMD_PREPENDQ:
1910  len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1911  key, keylen, &value, sizeof(value));
1912  break;
1913  case PROTOCOL_BINARY_CMD_FLUSH:
1914  case PROTOCOL_BINARY_CMD_FLUSHQ:
1915  len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1916  NULL, 0, NULL, 0);
1917  break;
1918  case PROTOCOL_BINARY_CMD_NOOP:
1919  len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1920  NULL, 0, NULL, 0);
1921  break;
1922  case PROTOCOL_BINARY_CMD_DELETE:
1923  case PROTOCOL_BINARY_CMD_DELETEQ:
1924  len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1925  key, keylen, NULL, 0);
1926  break;
1927  case PROTOCOL_BINARY_CMD_DECREMENT:
1928  case PROTOCOL_BINARY_CMD_DECREMENTQ:
1929  case PROTOCOL_BINARY_CMD_INCREMENT:
1930  case PROTOCOL_BINARY_CMD_INCREMENTQ:
1931  len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
1932  key, keylen, 1, 0, 0);
1933  break;
1934  case PROTOCOL_BINARY_CMD_VERSION:
1935  len = raw_command(command.bytes, sizeof(command.bytes),
1936  PROTOCOL_BINARY_CMD_VERSION,
1937  NULL, 0, NULL, 0);
1938  break;
1939  case PROTOCOL_BINARY_CMD_GET:
1940  case PROTOCOL_BINARY_CMD_GETK:
1941  case PROTOCOL_BINARY_CMD_GETKQ:
1942  case PROTOCOL_BINARY_CMD_GETQ:
1943  len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1944  key, keylen, NULL, 0);
1945  break;
1946 
1947  case PROTOCOL_BINARY_CMD_STAT:
1948  len = raw_command(command.bytes, sizeof(command.bytes),
1949  PROTOCOL_BINARY_CMD_STAT,
1950  NULL, 0, NULL, 0);
1951  break;
1952 
1953  default:
1954  // don't run commands we don't know
1955  continue;
1956  }
1957 
1958  if ((len + offset) < buffersize) {
1959  memcpy(((char*)buffer) + offset, command.bytes, len);
1960  offset += len;
1961  } else {
1962  break;
1963  }
1964  }
1965  safe_send(buffer, offset, true);
1966 
1967  return TEST_PASS;
1968 }
1969 
1970 static enum test_return test_binary_pipeline_hickup(void)
1971 {
1972  size_t buffersize = 65 * 1024;
1973  void *buffer = malloc(buffersize);
1974  int ii;
1975 
1976  pthread_t tid;
1977  int ret;
1978  allow_closed_read = true;
1979  hickup_thread_running = true;
1980  if ((ret = pthread_create(&tid, NULL,
1981  binary_hickup_recv_verification_thread, NULL)) != 0) {
1982  fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
1983  return TEST_FAIL;
1984  }
1985 
1986  /* Allow the thread to start */
1987  usleep(250);
1988 
1989  srand((int)time(NULL));
1990  for (ii = 0; ii < 2; ++ii) {
1991  test_binary_pipeline_hickup_chunk(buffer, buffersize);
1992  }
1993 
1994  /* send quitq to shut down the read thread ;-) */
1995  size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
1996  NULL, 0, NULL, 0);
1997  safe_send(buffer, len, false);
1998 
1999  pthread_join(tid, NULL);
2000  free(buffer);
2001  return TEST_PASS;
2002 }
2003 
2004 static enum test_return test_binary_verbosity(void) {
2005  union {
2008  char bytes[1024];
2009  } buffer;
2010 
2011  for (int ii = 10; ii > -1; --ii) {
2012  size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2013  PROTOCOL_BINARY_CMD_VERBOSITY,
2014  NULL, 0, NULL, 0);
2015  buffer.request.message.header.request.extlen = 4;
2016  buffer.request.message.header.request.bodylen = ntohl(4);
2017  buffer.request.message.body.level = (uint32_t)ntohl(ii);
2018  safe_send(buffer.bytes, len + sizeof(4), false);
2019  safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2020  validate_response_header(&buffer.response,
2021  PROTOCOL_BINARY_CMD_VERBOSITY,
2022  PROTOCOL_BINARY_RESPONSE_SUCCESS);
2023  }
2024 
2025  return TEST_PASS;
2026 }
2027 
2028 static enum test_return test_issue_101(void) {
2029  const int max = 2;
2030  enum test_return ret = TEST_PASS;
2031  int fds[max];
2032  int ii = 0;
2033  pid_t child = 0;
2034 
2035  if (getenv("DONT_SKIP_TEST_101") == NULL) {
2036  return TEST_SKIP;
2037  }
2038 
2039  const char *command = "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
2040  size_t cmdlen = strlen(command);
2041 
2042  server_pid = start_server(&port, false, 1000);
2043 
2044  for (ii = 0; ii < max; ++ii) {
2045  fds[ii] = connect_server("127.0.0.1", port, true);
2046  assert(fds[ii] > 0);
2047  }
2048 
2049  /* Send command on the connection until it blocks */
2050  for (ii = 0; ii < max; ++ii) {
2051  bool more = true;
2052  do {
2053  ssize_t err = send(fds[ii], command, cmdlen, 0);
2054  if (err == -1) {
2055  switch (errno) {
2056  case EINTR:
2057  break;
2058  case ENOMEM:
2059  case EWOULDBLOCK:
2060  more = false;
2061  break;
2062  default:
2063  ret = TEST_FAIL;
2064  goto cleanup;
2065  }
2066  }
2067  } while (more);
2068  }
2069 
2070  child = fork();
2071  if (child == (pid_t)-1) {
2072  abort();
2073  } else if (child > 0) {
2074  int stat;
2075  pid_t c;
2076  while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
2077  assert(c == child);
2078  assert(stat == 0);
2079  } else {
2080  sock = connect_server("127.0.0.1", port, false);
2081  ret = test_binary_noop();
2082  close(sock);
2083  exit(0);
2084  }
2085 
2086  cleanup:
2087  /* close all connections */
2088  for (ii = 0; ii < max; ++ii) {
2089  close(fds[ii]);
2090  }
2091 
2092  assert(kill(server_pid, SIGTERM) == 0);
2093 
2094  return ret;
2095 }
2096 
2097 typedef enum test_return (*TEST_FUNC)(void);
2098 struct testcase {
2099  const char *description;
2100  TEST_FUNC function;
2101 };
2102 
2103 struct testcase testcases[] = {
2104  { "cache_create", cache_create_test },
2105  { "cache_constructor", cache_constructor_test },
2106  { "cache_constructor_fail", cache_fail_constructor_test },
2107  { "cache_destructor", cache_destructor_test },
2108  { "cache_reuse", cache_reuse_test },
2109  { "cache_redzone", cache_redzone_test },
2110  { "issue_161", test_issue_161 },
2111  { "strtof", test_safe_strtof },
2112  { "strtol", test_safe_strtol },
2113  { "strtoll", test_safe_strtoll },
2114  { "strtoul", test_safe_strtoul },
2115  { "strtoull", test_safe_strtoull },
2116  { "issue_44", test_issue_44 },
2117  { "vperror", test_vperror },
2118  { "issue_101", test_issue_101 },
2119  { "config_parser", test_config_parser },
2120  /* The following tests all run towards the same server */
2121  { "start_server", start_memcached_server },
2122  { "issue_92", test_issue_92 },
2123  { "issue_102", test_issue_102 },
2124  { "binary_noop", test_binary_noop },
2125  { "binary_quit", test_binary_quit },
2126  { "binary_quitq", test_binary_quitq },
2127  { "binary_set", test_binary_set },
2128  { "binary_setq", test_binary_setq },
2129  { "binary_add", test_binary_add },
2130  { "binary_addq", test_binary_addq },
2131  { "binary_replace", test_binary_replace },
2132  { "binary_replaceq", test_binary_replaceq },
2133  { "binary_delete", test_binary_delete },
2134  { "binary_deleteq", test_binary_deleteq },
2135  { "binary_get", test_binary_get },
2136  { "binary_getq", test_binary_getq },
2137  { "binary_getk", test_binary_getk },
2138  { "binary_getkq", test_binary_getkq },
2139  { "binary_incr", test_binary_incr },
2140  { "binary_incrq", test_binary_incrq },
2141  { "binary_decr", test_binary_decr },
2142  { "binary_decrq", test_binary_decrq },
2143  { "binary_version", test_binary_version },
2144  { "binary_flush", test_binary_flush },
2145  { "binary_flushq", test_binary_flushq },
2146  { "binary_cas", test_binary_cas },
2147  { "binary_append", test_binary_append },
2148  { "binary_appendq", test_binary_appendq },
2149  { "binary_prepend", test_binary_prepend },
2150  { "binary_prependq", test_binary_prependq },
2151  { "binary_stat", test_binary_stat },
2152  { "binary_scrub", test_binary_scrub },
2153  { "binary_verbosity", test_binary_verbosity },
2154  { "binary_pipeline_hickup", test_binary_pipeline_hickup },
2155  { "stop_server", stop_memcached_server },
2156  { NULL, NULL }
2157 };
2158 
2159 int main(int argc, char **argv)
2160 {
2161  int exitcode = 0;
2162  int ii = 0, num_cases = 0;
2163 
2164  /* Use unbuffered stdio */
2165  setbuf(stdout, NULL);
2166  setbuf(stderr, NULL);
2167 
2168  for (num_cases = 0; testcases[num_cases].description; num_cases++) {
2169  /* Just counting */
2170  }
2171 
2172  printf("1..%d\n", num_cases);
2173 
2174  for (ii = 0; testcases[ii].description != NULL; ++ii) {
2175  fflush(stdout);
2176 #if 0
2177  /* the test program shouldn't run longer than 10 minutes... */
2178  alarm(600);
2179 #endif
2180  enum test_return ret = testcases[ii].function();
2181  if (ret == TEST_SKIP) {
2182  fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
2183  } else if (ret == TEST_PASS) {
2184  fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
2185  } else {
2186  fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
2187  exitcode = 1;
2188  }
2189  fflush(stdout);
2190  }
2191 
2192  return exitcode;
2193 }