xref: /memcached-1.4.29/testapp.c (revision dd11bde8)
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #undef NDEBUG
3 #include <pthread.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netdb.h>
7 #include <arpa/inet.h>
8 #include <netinet/in.h>
9 #include <netinet/tcp.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <assert.h>
15 #include <string.h>
16 #include <inttypes.h>
17 #include <stdbool.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 
21 #include "protocol_binary.h"
22 #include "config.h"
23 #include "cache.h"
24 #include "util.h"
25 
26 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
27 
28 enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
29 
30 static pid_t server_pid;
31 static in_port_t port;
32 static int sock;
33 static bool allow_closed_read = false;
34 
35 static enum test_return cache_create_test(void)
36 {
37     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
38                                   NULL, NULL);
39     assert(cache != NULL);
40     cache_destroy(cache);
41     return TEST_PASS;
42 }
43 
44 const uint64_t constructor_pattern = 0xdeadcafebabebeef;
45 
46 static int cache_constructor(void *buffer, void *notused1, int notused2) {
47     uint64_t *ptr = buffer;
48     *ptr = constructor_pattern;
49     return 0;
50 }
51 
52 static enum test_return cache_constructor_test(void)
53 {
54     cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
55                                   cache_constructor, NULL);
56     assert(cache != NULL);
57     uint64_t *ptr = cache_alloc(cache);
58     uint64_t pattern = *ptr;
59     cache_free(cache, ptr);
60     cache_destroy(cache);
61     return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
62 }
63 
64 static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
65     return 1;
66 }
67 
68 static enum test_return cache_fail_constructor_test(void)
69 {
70     enum test_return ret = TEST_PASS;
71 
72     cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
73                                   cache_fail_constructor, NULL);
74     assert(cache != NULL);
75     uint64_t *ptr = cache_alloc(cache);
76     if (ptr != NULL) {
77         ret = TEST_FAIL;
78     }
79     cache_destroy(cache);
80     return ret;
81 }
82 
83 static void *destruct_data = 0;
84 
85 static void cache_destructor(void *buffer, void *notused) {
86     destruct_data = buffer;
87 }
88 
89 static enum test_return cache_destructor_test(void)
90 {
91     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
92                                   NULL, cache_destructor);
93     assert(cache != NULL);
94     char *ptr = cache_alloc(cache);
95     cache_free(cache, ptr);
96     cache_destroy(cache);
97 
98     return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
99 }
100 
101 static enum test_return cache_reuse_test(void)
102 {
103     int ii;
104     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
105                                   NULL, NULL);
106     char *ptr = cache_alloc(cache);
107     cache_free(cache, ptr);
108     for (ii = 0; ii < 100; ++ii) {
109         char *p = cache_alloc(cache);
110         assert(p == ptr);
111         cache_free(cache, ptr);
112     }
113     cache_destroy(cache);
114     return TEST_PASS;
115 }
116 
117 static enum test_return cache_redzone_test(void)
118 {
119 #ifndef HAVE_UMEM_H
120     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
121                                   NULL, NULL);
122 
123     /* Ignore SIGABORT */
124     struct sigaction old_action;
125     struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
126     sigemptyset(&action.sa_mask);
127     sigaction(SIGABRT, &action, &old_action);
128 
129     /* check memory debug.. */
130     char *p = cache_alloc(cache);
131     char old = *(p - 1);
132     *(p - 1) = 0;
133     cache_free(cache, p);
134     assert(cache_error == -1);
135     *(p - 1) = old;
136 
137     p[sizeof(uint32_t)] = 0;
138     cache_free(cache, p);
139     assert(cache_error == 1);
140 
141     /* restore signal handler */
142     sigaction(SIGABRT, &old_action, NULL);
143 
144     cache_destroy(cache);
145 
146     return TEST_PASS;
147 #else
148     return TEST_SKIP;
149 #endif
150 }
151 
152 static enum test_return test_safe_strtoul(void) {
153     uint32_t val;
154     assert(safe_strtoul("123", &val));
155     assert(val == 123);
156     assert(safe_strtoul("+123", &val));
157     assert(val == 123);
158     assert(!safe_strtoul("", &val));  // empty
159     assert(!safe_strtoul("123BOGUS", &val));  // non-numeric
160     /* Not sure what it does, but this works with ICC :/
161        assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
162     */
163 
164     // extremes:
165     assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
166     assert(val == 4294967295L);
167     /* This actually works on 64-bit ubuntu
168        assert(!safe_strtoul("4294967296", &val)); // 2**32
169     */
170     assert(!safe_strtoul("-1", &val));  // negative
171     return TEST_PASS;
172 }
173 
174 
175 static enum test_return test_safe_strtoull(void) {
176     uint64_t val;
177     assert(safe_strtoull("123", &val));
178     assert(val == 123);
179     assert(safe_strtoull("+123", &val));
180     assert(val == 123);
181     assert(!safe_strtoull("", &val));  // empty
182     assert(!safe_strtoull("123BOGUS", &val));  // non-numeric
183     assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
184 
185     // extremes:
186     assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
187     assert(val == 18446744073709551615ULL);
188     assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
189     assert(!safe_strtoull("-1", &val));  // negative
190     return TEST_PASS;
191 }
192 
193 static enum test_return test_safe_strtoll(void) {
194     int64_t val;
195     assert(safe_strtoll("123", &val));
196     assert(val == 123);
197     assert(safe_strtoll("+123", &val));
198     assert(val == 123);
199     assert(safe_strtoll("-123", &val));
200     assert(val == -123);
201     assert(!safe_strtoll("", &val));  // empty
202     assert(!safe_strtoll("123BOGUS", &val));  // non-numeric
203     assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
204 
205     // extremes:
206     assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
207     assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
208     assert(val == 9223372036854775807LL);
209     /*
210       assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
211       assert(val == -9223372036854775808LL);
212     */
213     assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
214 
215     // We'll allow space to terminate the string.  And leading space.
216     assert(safe_strtoll(" 123 foo", &val));
217     assert(val == 123);
218     return TEST_PASS;
219 }
220 
221 static enum test_return test_safe_strtol(void) {
222     int32_t val;
223     assert(safe_strtol("123", &val));
224     assert(val == 123);
225     assert(safe_strtol("+123", &val));
226     assert(val == 123);
227     assert(safe_strtol("-123", &val));
228     assert(val == -123);
229     assert(!safe_strtol("", &val));  // empty
230     assert(!safe_strtol("123BOGUS", &val));  // non-numeric
231     assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
232 
233     // extremes:
234     /* This actually works on 64-bit ubuntu
235        assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
236     */
237     assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
238     assert(val == 2147483647L);
239     /* This actually works on 64-bit ubuntu
240        assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
241     */
242 
243     // We'll allow space to terminate the string.  And leading space.
244     assert(safe_strtol(" 123 foo", &val));
245     assert(val == 123);
246     return TEST_PASS;
247 }
248 
249 /**
250  * Function to start the server and let it listen on a random port
251  *
252  * @param port_out where to store the TCP port number the server is
253  *                 listening on
254  * @param daemon set to true if you want to run the memcached server
255  *               as a daemon process
256  * @return the pid of the memcached server
257  */
258 static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
259     char environment[80];
260     snprintf(environment, sizeof(environment),
261              "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
262     char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
263     char pid_file[80];
264     snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
265 
266     remove(filename);
267     remove(pid_file);
268 
269 #ifdef __sun
270     /* I want to name the corefiles differently so that they don't
271        overwrite each other
272     */
273     char coreadm[128];
274     sprintf(coreadm, "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
275     system(coreadm);
276 #endif
277 
278     pid_t pid = fork();
279     assert(pid != -1);
280 
281     if (pid == 0) {
282         /* Child */
283         char *argv[20];
284         int arg = 0;
285         char tmo[24];
286         snprintf(tmo, sizeof(tmo), "%u", timeout);
287 
288         putenv(environment);
289 #ifdef __sun
290         putenv("LD_PRELOAD=watchmalloc.so.1");
291         putenv("MALLOC_DEBUG=WATCH");
292 #endif
293 
294         if (!daemon) {
295             argv[arg++] = "./timedrun";
296             argv[arg++] = tmo;
297         }
298         argv[arg++] = "./memcached-debug";
299         argv[arg++] = "-p";
300         argv[arg++] = "-1";
301         argv[arg++] = "-U";
302         argv[arg++] = "0";
303         /* Handle rpmbuild and the like doing this as root */
304         if (getuid() == 0) {
305             argv[arg++] = "-u";
306             argv[arg++] = "root";
307         }
308         if (daemon) {
309             argv[arg++] = "-d";
310             argv[arg++] = "-P";
311             argv[arg++] = pid_file;
312         }
313 #ifdef MESSAGE_DEBUG
314          argv[arg++] = "-vvv";
315 #endif
316         argv[arg++] = NULL;
317         assert(execv(argv[0], argv) != -1);
318     }
319 
320     /* Yeah just let us "busy-wait" for the file to be created ;-) */
321     while (access(filename, F_OK) == -1) {
322         usleep(10);
323     }
324 
325     FILE *fp = fopen(filename, "r");
326     if (fp == NULL) {
327         fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
328                 strerror(errno));
329         assert(false);
330     }
331 
332     *port_out = (in_port_t)-1;
333     char buffer[80];
334     while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
335         if (strncmp(buffer, "TCP INET: ", 10) == 0) {
336             int32_t val;
337             assert(safe_strtol(buffer + 10, &val));
338             *port_out = (in_port_t)val;
339         }
340     }
341     fclose(fp);
342     assert(remove(filename) == 0);
343 
344     if (daemon) {
345         /* loop and wait for the pid file.. There is a potential race
346          * condition that the server just created the file but isn't
347          * finished writing the content, but I'll take the chance....
348          */
349         while (access(pid_file, F_OK) == -1) {
350             usleep(10);
351         }
352 
353         fp = fopen(pid_file, "r");
354         if (fp == NULL) {
355             fprintf(stderr, "Failed to open pid file: %s\n",
356                     strerror(errno));
357             assert(false);
358         }
359         assert(fgets(buffer, sizeof(buffer), fp) != NULL);
360         fclose(fp);
361 
362         int32_t val;
363         assert(safe_strtol(buffer, &val));
364         pid = (pid_t)val;
365     }
366 
367     return pid;
368 }
369 
370 static enum test_return test_issue_44(void) {
371     in_port_t port;
372     pid_t pid = start_server(&port, true, 15);
373     assert(kill(pid, SIGHUP) == 0);
374     sleep(1);
375     assert(kill(pid, SIGTERM) == 0);
376 
377     return TEST_PASS;
378 }
379 
380 static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
381 {
382     struct addrinfo *ai = 0;
383     struct addrinfo hints = { .ai_family = AF_UNSPEC,
384                               .ai_protocol = IPPROTO_TCP,
385                               .ai_socktype = SOCK_STREAM };
386     char service[NI_MAXSERV];
387     int error;
388 
389     (void)snprintf(service, NI_MAXSERV, "%d", port);
390     if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
391        if (error != EAI_SYSTEM) {
392           fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
393        } else {
394           perror("getaddrinfo()");
395        }
396     }
397 
398     return ai;
399 }
400 
401 static int connect_server(const char *hostname, in_port_t port)
402 {
403     struct addrinfo *ai = lookuphost(hostname, port);
404     int sock = -1;
405     if (ai != NULL) {
406        if ((sock = socket(ai->ai_family, ai->ai_socktype,
407                           ai->ai_protocol)) != -1) {
408           if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
409              fprintf(stderr, "Failed to connect socket: %s\n",
410                      strerror(errno));
411              close(sock);
412              sock = -1;
413           }
414        } else {
415           fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
416        }
417 
418        freeaddrinfo(ai);
419     }
420     return sock;
421 }
422 
423 static enum test_return test_vperror(void) {
424     int rv = 0;
425     int oldstderr = dup(STDERR_FILENO);
426     char tmpl[sizeof(TMP_TEMPLATE)+1];
427     strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
428 
429     int newfile = mkstemp(tmpl);
430     assert(newfile > 0);
431     rv = dup2(newfile, STDERR_FILENO);
432     assert(rv == STDERR_FILENO);
433     rv = close(newfile);
434     assert(rv == 0);
435 
436     errno = EIO;
437     vperror("Old McDonald had a farm.  %s", "EI EIO");
438 
439     /* Restore stderr */
440     rv = dup2(oldstderr, STDERR_FILENO);
441     assert(rv == STDERR_FILENO);
442 
443 
444     /* Go read the file */
445     char buf[80] = { 0 };
446     FILE *efile = fopen(tmpl, "r");
447     assert(efile);
448     char *prv = fgets(buf, sizeof(buf), efile);
449     assert(prv);
450     fclose(efile);
451 
452     unlink(tmpl);
453 
454     char expected[80] = { 0 };
455     snprintf(expected, sizeof(expected),
456              "Old McDonald had a farm.  EI EIO: %s\n", strerror(EIO));
457 
458     /*
459     fprintf(stderr,
460             "\nExpected:  ``%s''"
461             "\nGot:       ``%s''\n", expected, buf);
462     */
463 
464     return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
465 }
466 
467 static void send_ascii_command(const char *buf) {
468     off_t offset = 0;
469     const char* ptr = buf;
470     size_t len = strlen(buf);
471 
472     do {
473         ssize_t nw = write(sock, ptr + offset, len - offset);
474         if (nw == -1) {
475             if (errno != EINTR) {
476                 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
477                 abort();
478             }
479         } else {
480             offset += nw;
481         }
482     } while (offset < len);
483 }
484 
485 /*
486  * This is a dead slow single byte read, but it should only read out
487  * _one_ response and I don't have an input buffer... The current
488  * implementation only supports single-line responses, so if you want to use
489  * it for get commands you need to implement that first ;-)
490  */
491 static void read_ascii_response(char *buffer, size_t size) {
492     off_t offset = 0;
493     bool need_more = true;
494     do {
495         ssize_t nr = read(sock, buffer + offset, 1);
496         if (nr == -1) {
497             if (errno != EINTR) {
498                 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
499                 abort();
500             }
501         } else {
502             assert(nr == 1);
503             if (buffer[offset] == '\n') {
504                 need_more = false;
505                 buffer[offset + 1] = '\0';
506             }
507             offset += nr;
508             assert(offset + 1 < size);
509         }
510     } while (need_more);
511 }
512 
513 static enum test_return test_issue_92(void) {
514     char buffer[1024];
515 
516     close(sock);
517     sock = connect_server("127.0.0.1", port);
518 
519     send_ascii_command("stats cachedump 1 0 0\r\n");
520     read_ascii_response(buffer, sizeof(buffer));
521     assert(strncmp(buffer, "END", strlen("END")) == 0);
522 
523     send_ascii_command("stats cachedump 200 0 0\r\n");
524     read_ascii_response(buffer, sizeof(buffer));
525     assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
526 
527     close(sock);
528     sock = connect_server("127.0.0.1", port);
529     return TEST_PASS;
530 }
531 
532 static enum test_return start_memcached_server(void) {
533     server_pid = start_server(&port, false, 600);
534     sock = connect_server("127.0.0.1", port);
535     return TEST_PASS;
536 }
537 
538 static enum test_return stop_memcached_server(void) {
539     close(sock);
540     assert(kill(server_pid, SIGTERM) == 0);
541     return TEST_PASS;
542 }
543 
544 static void safe_send(const void* buf, size_t len, bool hickup)
545 {
546     off_t offset = 0;
547     const char* ptr = buf;
548 #ifdef MESSAGE_DEBUG
549     uint8_t val = *ptr;
550     assert(val == (uint8_t)0x80);
551     fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
552     for (int ii = 0; ii < len; ++ii) {
553         if (ii % 4 == 0) {
554             fprintf(stderr, "\n   ");
555         }
556         val = *(ptr + ii);
557         fprintf(stderr, " 0x%02x", val);
558     }
559     fprintf(stderr, "\n");
560     usleep(500);
561 #endif
562 
563     do {
564         size_t num_bytes = len - offset;
565         if (hickup) {
566             if (num_bytes > 1024) {
567                 num_bytes = (rand() % 1023) + 1;
568             }
569         }
570 
571         ssize_t nw = write(sock, ptr + offset, num_bytes);
572         if (nw == -1) {
573             if (errno != EINTR) {
574                 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
575                 abort();
576             }
577         } else {
578             if (hickup) {
579                 usleep(100);
580             }
581             offset += nw;
582         }
583     } while (offset < len);
584 }
585 
586 static bool safe_recv(void *buf, size_t len) {
587     if (len == 0) {
588         return true;
589     }
590     off_t offset = 0;
591     do {
592         ssize_t nr = read(sock, ((char*)buf) + offset, len - offset);
593         if (nr == -1) {
594             if (errno != EINTR) {
595                 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
596                 abort();
597             }
598         } else {
599             if (nr == 0 && allow_closed_read) {
600                 return false;
601             }
602             assert(nr != 0);
603             offset += nr;
604         }
605     } while (offset < len);
606 
607     return true;
608 }
609 
610 static bool safe_recv_packet(void *buf, size_t size) {
611     protocol_binary_response_no_extras *response = buf;
612     assert(size > sizeof(*response));
613     if (!safe_recv(response, sizeof(*response))) {
614         return false;
615     }
616     response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
617     response->message.header.response.status = ntohs(response->message.header.response.status);
618     response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
619 
620     size_t len = sizeof(*response);
621 
622     char *ptr = buf;
623     ptr += len;
624     if (!safe_recv(ptr, response->message.header.response.bodylen)) {
625         return false;
626     }
627 
628 #ifdef MESSAGE_DEBUG
629     usleep(500);
630     ptr = buf;
631     len += response->message.header.response.bodylen;
632     uint8_t val = *ptr;
633     assert(val == (uint8_t)0x81);
634     fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
635     for (int ii = 0; ii < len; ++ii) {
636         if (ii % 4 == 0) {
637             fprintf(stderr, "\n   ");
638         }
639         val = *(ptr + ii);
640         fprintf(stderr, " 0x%02x", val);
641     }
642     fprintf(stderr, "\n");
643 #endif
644     return true;
645 }
646 
647 static off_t storage_command(char*buf,
648                              size_t bufsz,
649                              uint8_t cmd,
650                              const void* key,
651                              size_t keylen,
652                              const void* dta,
653                              size_t dtalen,
654                              uint32_t flags,
655                              uint32_t exp) {
656     /* all of the storage commands use the same command layout */
657     protocol_binary_request_set *request = (void*)buf;
658     assert(bufsz > sizeof(*request) + keylen + dtalen);
659 
660     memset(request, 0, sizeof(*request));
661     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
662     request->message.header.request.opcode = cmd;
663     request->message.header.request.keylen = htons(keylen);
664     request->message.header.request.extlen = 8;
665     request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
666     request->message.header.request.opaque = 0xdeadbeef;
667     request->message.body.flags = flags;
668     request->message.body.expiration = exp;
669 
670     off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
671 
672     memcpy(buf + key_offset, key, keylen);
673     if (dta != NULL) {
674         memcpy(buf + key_offset + keylen, dta, dtalen);
675     }
676 
677     return key_offset + keylen + dtalen;
678 }
679 
680 static off_t raw_command(char* buf,
681                          size_t bufsz,
682                          uint8_t cmd,
683                          const void* key,
684                          size_t keylen,
685                          const void* dta,
686                          size_t dtalen) {
687     /* all of the storage commands use the same command layout */
688     protocol_binary_request_no_extras *request = (void*)buf;
689     assert(bufsz > sizeof(*request) + keylen + dtalen);
690 
691     memset(request, 0, sizeof(*request));
692     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
693     request->message.header.request.opcode = cmd;
694     request->message.header.request.keylen = htons(keylen);
695     request->message.header.request.bodylen = htonl(keylen + dtalen);
696     request->message.header.request.opaque = 0xdeadbeef;
697 
698     off_t key_offset = sizeof(protocol_binary_request_no_extras);
699 
700     if (key != NULL) {
701         memcpy(buf + key_offset, key, keylen);
702     }
703     if (dta != NULL) {
704         memcpy(buf + key_offset + keylen, dta, dtalen);
705     }
706 
707     return sizeof(*request) + keylen + dtalen;
708 }
709 
710 static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
711     protocol_binary_request_flush *request = (void*)buf;
712     assert(bufsz > sizeof(*request));
713 
714     memset(request, 0, sizeof(*request));
715     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
716     request->message.header.request.opcode = cmd;
717 
718     off_t size = sizeof(protocol_binary_request_no_extras);
719     if (use_extra) {
720         request->message.header.request.extlen = 4;
721         request->message.body.expiration = htonl(exptime);
722         request->message.header.request.bodylen = htonl(4);
723         size += 4;
724     }
725 
726     request->message.header.request.opaque = 0xdeadbeef;
727 
728     return size;
729 }
730 
731 static off_t arithmetic_command(char* buf,
732                                 size_t bufsz,
733                                 uint8_t cmd,
734                                 const void* key,
735                                 size_t keylen,
736                                 uint64_t delta,
737                                 uint64_t initial,
738                                 uint32_t exp) {
739     protocol_binary_request_incr *request = (void*)buf;
740     assert(bufsz > sizeof(*request) + keylen);
741 
742     memset(request, 0, sizeof(*request));
743     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
744     request->message.header.request.opcode = cmd;
745     request->message.header.request.keylen = htons(keylen);
746     request->message.header.request.extlen = 20;
747     request->message.header.request.bodylen = htonl(keylen + 20);
748     request->message.header.request.opaque = 0xdeadbeef;
749     request->message.body.delta = htonll(delta);
750     request->message.body.initial = htonll(initial);
751     request->message.body.expiration = htonl(exp);
752 
753     off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
754 
755     memcpy(buf + key_offset, key, keylen);
756     return key_offset + keylen;
757 }
758 
759 static void validate_response_header(protocol_binary_response_no_extras *response,
760                                      uint8_t cmd, uint16_t status)
761 {
762     assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
763     assert(response->message.header.response.opcode == cmd);
764     assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
765     assert(response->message.header.response.status == status);
766     assert(response->message.header.response.opaque == 0xdeadbeef);
767 
768     if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
769         switch (cmd) {
770         case PROTOCOL_BINARY_CMD_ADDQ:
771         case PROTOCOL_BINARY_CMD_APPENDQ:
772         case PROTOCOL_BINARY_CMD_DECREMENTQ:
773         case PROTOCOL_BINARY_CMD_DELETEQ:
774         case PROTOCOL_BINARY_CMD_FLUSHQ:
775         case PROTOCOL_BINARY_CMD_INCREMENTQ:
776         case PROTOCOL_BINARY_CMD_PREPENDQ:
777         case PROTOCOL_BINARY_CMD_QUITQ:
778         case PROTOCOL_BINARY_CMD_REPLACEQ:
779         case PROTOCOL_BINARY_CMD_SETQ:
780             assert("Quiet command shouldn't return on success" == NULL);
781         default:
782             break;
783         }
784 
785         switch (cmd) {
786         case PROTOCOL_BINARY_CMD_ADD:
787         case PROTOCOL_BINARY_CMD_REPLACE:
788         case PROTOCOL_BINARY_CMD_SET:
789         case PROTOCOL_BINARY_CMD_APPEND:
790         case PROTOCOL_BINARY_CMD_PREPEND:
791             assert(response->message.header.response.keylen == 0);
792             assert(response->message.header.response.extlen == 0);
793             assert(response->message.header.response.bodylen == 0);
794             assert(response->message.header.response.cas != 0);
795             break;
796         case PROTOCOL_BINARY_CMD_FLUSH:
797         case PROTOCOL_BINARY_CMD_NOOP:
798         case PROTOCOL_BINARY_CMD_QUIT:
799         case PROTOCOL_BINARY_CMD_DELETE:
800             assert(response->message.header.response.keylen == 0);
801             assert(response->message.header.response.extlen == 0);
802             assert(response->message.header.response.bodylen == 0);
803             assert(response->message.header.response.cas == 0);
804             break;
805 
806         case PROTOCOL_BINARY_CMD_DECREMENT:
807         case PROTOCOL_BINARY_CMD_INCREMENT:
808             assert(response->message.header.response.keylen == 0);
809             assert(response->message.header.response.extlen == 0);
810             assert(response->message.header.response.bodylen == 8);
811             assert(response->message.header.response.cas != 0);
812             break;
813 
814         case PROTOCOL_BINARY_CMD_STAT:
815             assert(response->message.header.response.extlen == 0);
816             /* key and value exists in all packets except in the terminating */
817             assert(response->message.header.response.cas == 0);
818             break;
819 
820         case PROTOCOL_BINARY_CMD_VERSION:
821             assert(response->message.header.response.keylen == 0);
822             assert(response->message.header.response.extlen == 0);
823             assert(response->message.header.response.bodylen != 0);
824             assert(response->message.header.response.cas == 0);
825             break;
826 
827         case PROTOCOL_BINARY_CMD_GET:
828         case PROTOCOL_BINARY_CMD_GETQ:
829             assert(response->message.header.response.keylen == 0);
830             assert(response->message.header.response.extlen == 4);
831             assert(response->message.header.response.cas != 0);
832             break;
833 
834         case PROTOCOL_BINARY_CMD_GETK:
835         case PROTOCOL_BINARY_CMD_GETKQ:
836             assert(response->message.header.response.keylen != 0);
837             assert(response->message.header.response.extlen == 4);
838             assert(response->message.header.response.cas != 0);
839             break;
840 
841         default:
842             /* Undefined command code */
843             break;
844         }
845     } else {
846         assert(response->message.header.response.cas == 0);
847         assert(response->message.header.response.extlen == 0);
848         if (cmd != PROTOCOL_BINARY_CMD_GETK) {
849             assert(response->message.header.response.keylen == 0);
850         }
851     }
852 }
853 
854 static enum test_return test_binary_noop(void) {
855     union {
856         protocol_binary_request_no_extras request;
857         protocol_binary_response_no_extras response;
858         char bytes[1024];
859     } buffer;
860 
861     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
862                              PROTOCOL_BINARY_CMD_NOOP,
863                              NULL, 0, NULL, 0);
864 
865     safe_send(buffer.bytes, len, false);
866     safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
867     validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
868                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
869 
870     return TEST_PASS;
871 }
872 
873 static enum test_return test_binary_quit_impl(uint8_t cmd) {
874     union {
875         protocol_binary_request_no_extras request;
876         protocol_binary_response_no_extras response;
877         char bytes[1024];
878     } buffer;
879     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
880                              cmd, NULL, 0, NULL, 0);
881 
882     safe_send(buffer.bytes, len, false);
883     if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
884         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
885         validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
886                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
887     }
888 
889     /* Socket should be closed now, read should return 0 */
890     assert(read(sock, buffer.bytes, sizeof(buffer.bytes)) == 0);
891     close(sock);
892     sock = connect_server("127.0.0.1", port);
893 
894     return TEST_PASS;
895 }
896 
897 static enum test_return test_binary_quit(void) {
898     return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
899 }
900 
901 static enum test_return test_binary_quitq(void) {
902     return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
903 }
904 
905 static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
906     union {
907         protocol_binary_request_no_extras request;
908         protocol_binary_response_no_extras response;
909         char bytes[1024];
910     } send, receive;
911     uint64_t value = 0xdeadbeefdeadcafe;
912     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
913                                  key, strlen(key), &value, sizeof(value),
914                                  0, 0);
915 
916     /* Set should work over and over again */
917     int ii;
918     for (ii = 0; ii < 10; ++ii) {
919         safe_send(send.bytes, len, false);
920         if (cmd == PROTOCOL_BINARY_CMD_SET) {
921             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
922             validate_response_header(&receive.response, cmd,
923                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
924         }
925     }
926 
927     if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
928         return test_binary_noop();
929     }
930 
931     send.request.message.header.request.cas = receive.response.message.header.response.cas;
932     safe_send(send.bytes, len, false);
933     if (cmd == PROTOCOL_BINARY_CMD_SET) {
934         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
935         validate_response_header(&receive.response, cmd,
936                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
937         assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
938     } else {
939         return test_binary_noop();
940     }
941 
942     return TEST_PASS;
943 }
944 
945 static enum test_return test_binary_set(void) {
946     return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
947 }
948 
949 static enum test_return test_binary_setq(void) {
950     return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
951 }
952 
953 
954 static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
955     uint64_t value = 0xdeadbeefdeadcafe;
956     union {
957         protocol_binary_request_no_extras request;
958         protocol_binary_response_no_extras response;
959         char bytes[1024];
960     } send, receive;
961     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
962                                  strlen(key), &value, sizeof(value),
963                                  0, 0);
964 
965     /* Add should only work the first time */
966     int ii;
967     for (ii = 0; ii < 10; ++ii) {
968         safe_send(send.bytes, len, false);
969         if (ii == 0) {
970             if (cmd == PROTOCOL_BINARY_CMD_ADD) {
971                 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
972                 validate_response_header(&receive.response, cmd,
973                                          PROTOCOL_BINARY_RESPONSE_SUCCESS);
974             }
975         } else {
976             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
977             validate_response_header(&receive.response, cmd,
978                                      PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
979         }
980     }
981 
982     return TEST_PASS;
983 }
984 
985 static enum test_return test_binary_add(void) {
986     return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
987 }
988 
989 static enum test_return test_binary_addq(void) {
990     return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
991 }
992 
993 static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
994     uint64_t value = 0xdeadbeefdeadcafe;
995     union {
996         protocol_binary_request_no_extras request;
997         protocol_binary_response_no_extras response;
998         char bytes[1024];
999     } send, receive;
1000     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1001                                  key, strlen(key), &value, sizeof(value),
1002                                  0, 0);
1003     safe_send(send.bytes, len, false);
1004     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1005     validate_response_header(&receive.response, cmd,
1006                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1007     len = storage_command(send.bytes, sizeof(send.bytes),
1008                           PROTOCOL_BINARY_CMD_ADD,
1009                           key, strlen(key), &value, sizeof(value), 0, 0);
1010     safe_send(send.bytes, len, false);
1011     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1012     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1013                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1014 
1015     len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1016                           key, strlen(key), &value, sizeof(value), 0, 0);
1017     int ii;
1018     for (ii = 0; ii < 10; ++ii) {
1019         safe_send(send.bytes, len, false);
1020         if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1021             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1022             validate_response_header(&receive.response,
1023                                      PROTOCOL_BINARY_CMD_REPLACE,
1024                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1025         }
1026     }
1027 
1028     if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1029         test_binary_noop();
1030     }
1031 
1032     return TEST_PASS;
1033 }
1034 
1035 static enum test_return test_binary_replace(void) {
1036     return test_binary_replace_impl("test_binary_replace",
1037                                     PROTOCOL_BINARY_CMD_REPLACE);
1038 }
1039 
1040 static enum test_return test_binary_replaceq(void) {
1041     return test_binary_replace_impl("test_binary_replaceq",
1042                                     PROTOCOL_BINARY_CMD_REPLACEQ);
1043 }
1044 
1045 static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1046     union {
1047         protocol_binary_request_no_extras request;
1048         protocol_binary_response_no_extras response;
1049         char bytes[1024];
1050     } send, receive;
1051     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1052                              key, strlen(key), NULL, 0);
1053 
1054     safe_send(send.bytes, len, false);
1055     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1056     validate_response_header(&receive.response, cmd,
1057                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1058     len = storage_command(send.bytes, sizeof(send.bytes),
1059                           PROTOCOL_BINARY_CMD_ADD,
1060                           key, strlen(key), NULL, 0, 0, 0);
1061     safe_send(send.bytes, len, false);
1062     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1063     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1064                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1065 
1066     len = raw_command(send.bytes, sizeof(send.bytes),
1067                       cmd, key, strlen(key), NULL, 0);
1068     safe_send(send.bytes, len, false);
1069 
1070     if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1071         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1072         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1073                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1074     }
1075 
1076     safe_send(send.bytes, len, false);
1077     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1078     validate_response_header(&receive.response, cmd,
1079                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1080 
1081     return TEST_PASS;
1082 }
1083 
1084 static enum test_return test_binary_delete(void) {
1085     return test_binary_delete_impl("test_binary_delete",
1086                                    PROTOCOL_BINARY_CMD_DELETE);
1087 }
1088 
1089 static enum test_return test_binary_deleteq(void) {
1090     return test_binary_delete_impl("test_binary_deleteq",
1091                                    PROTOCOL_BINARY_CMD_DELETEQ);
1092 }
1093 
1094 static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1095     union {
1096         protocol_binary_request_no_extras request;
1097         protocol_binary_response_no_extras response;
1098         char bytes[1024];
1099     } send, receive;
1100     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1101                              key, strlen(key), NULL, 0);
1102 
1103     safe_send(send.bytes, len, false);
1104     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1105     validate_response_header(&receive.response, cmd,
1106                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1107 
1108     len = storage_command(send.bytes, sizeof(send.bytes),
1109                           PROTOCOL_BINARY_CMD_ADD,
1110                           key, strlen(key), NULL, 0,
1111                           0, 0);
1112     safe_send(send.bytes, len, false);
1113     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1114     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1115                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1116 
1117     /* run a little pipeline test ;-) */
1118     len = 0;
1119     int ii;
1120     for (ii = 0; ii < 10; ++ii) {
1121         union {
1122             protocol_binary_request_no_extras request;
1123             char bytes[1024];
1124         } temp;
1125         size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1126                                cmd, key, strlen(key), NULL, 0);
1127         memcpy(send.bytes + len, temp.bytes, l);
1128         len += l;
1129     }
1130 
1131     safe_send(send.bytes, len, false);
1132     for (ii = 0; ii < 10; ++ii) {
1133         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1134         validate_response_header(&receive.response, cmd,
1135                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1136     }
1137 
1138     return TEST_PASS;
1139 }
1140 
1141 static enum test_return test_binary_get(void) {
1142     return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1143 }
1144 
1145 static enum test_return test_binary_getk(void) {
1146     return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1147 }
1148 
1149 static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1150     const char *missing = "test_binary_getq_missing";
1151     union {
1152         protocol_binary_request_no_extras request;
1153         protocol_binary_response_no_extras response;
1154         char bytes[1024];
1155     } send, temp, receive;
1156     size_t len = storage_command(send.bytes, sizeof(send.bytes),
1157                                  PROTOCOL_BINARY_CMD_ADD,
1158                                  key, strlen(key), NULL, 0,
1159                                  0, 0);
1160     size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1161                              missing, strlen(missing), NULL, 0);
1162     /* I need to change the first opaque so that I can separate the two
1163      * return packets */
1164     temp.request.message.header.request.opaque = 0xfeedface;
1165     memcpy(send.bytes + len, temp.bytes, len2);
1166     len += len2;
1167 
1168     len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1169                        key, strlen(key), NULL, 0);
1170     memcpy(send.bytes + len, temp.bytes, len2);
1171     len += len2;
1172 
1173     safe_send(send.bytes, len, false);
1174     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1175     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1176                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1177     /* The first GETQ shouldn't return anything */
1178     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1179     validate_response_header(&receive.response, cmd,
1180                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1181 
1182     return TEST_PASS;
1183 }
1184 
1185 static enum test_return test_binary_getq(void) {
1186     return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1187 }
1188 
1189 static enum test_return test_binary_getkq(void) {
1190     return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1191 }
1192 
1193 static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1194     union {
1195         protocol_binary_request_no_extras request;
1196         protocol_binary_response_no_extras response_header;
1197         protocol_binary_response_incr response;
1198         char bytes[1024];
1199     } send, receive;
1200     size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1201                                     key, strlen(key), 1, 0, 0);
1202 
1203     int ii;
1204     for (ii = 0; ii < 10; ++ii) {
1205         safe_send(send.bytes, len, false);
1206         if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1207             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1208             validate_response_header(&receive.response_header, cmd,
1209                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1210             assert(ntohll(receive.response.message.body.value) == ii);
1211         }
1212     }
1213 
1214     if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1215         test_binary_noop();
1216     }
1217     return TEST_PASS;
1218 }
1219 
1220 static enum test_return test_binary_incr(void) {
1221     return test_binary_incr_impl("test_binary_incr",
1222                                  PROTOCOL_BINARY_CMD_INCREMENT);
1223 }
1224 
1225 static enum test_return test_binary_incrq(void) {
1226     return test_binary_incr_impl("test_binary_incrq",
1227                                  PROTOCOL_BINARY_CMD_INCREMENTQ);
1228 }
1229 
1230 static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1231     union {
1232         protocol_binary_request_no_extras request;
1233         protocol_binary_response_no_extras response_header;
1234         protocol_binary_response_decr response;
1235         char bytes[1024];
1236     } send, receive;
1237     size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1238                                     key, strlen(key), 1, 9, 0);
1239 
1240     int ii;
1241     for (ii = 9; ii >= 0; --ii) {
1242         safe_send(send.bytes, len, false);
1243         if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1244             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1245             validate_response_header(&receive.response_header, cmd,
1246                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1247             assert(ntohll(receive.response.message.body.value) == ii);
1248         }
1249     }
1250 
1251     /* decr on 0 should not wrap */
1252     safe_send(send.bytes, len, false);
1253     if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1254         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1255         validate_response_header(&receive.response_header, cmd,
1256                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1257         assert(ntohll(receive.response.message.body.value) == 0);
1258     } else {
1259         test_binary_noop();
1260     }
1261 
1262     return TEST_PASS;
1263 }
1264 
1265 static enum test_return test_binary_decr(void) {
1266     return test_binary_decr_impl("test_binary_decr",
1267                                  PROTOCOL_BINARY_CMD_DECREMENT);
1268 }
1269 
1270 static enum test_return test_binary_decrq(void) {
1271     return test_binary_decr_impl("test_binary_decrq",
1272                                  PROTOCOL_BINARY_CMD_DECREMENTQ);
1273 }
1274 
1275 static enum test_return test_binary_version(void) {
1276     union {
1277         protocol_binary_request_no_extras request;
1278         protocol_binary_response_no_extras response;
1279         char bytes[1024];
1280     } buffer;
1281 
1282     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1283                              PROTOCOL_BINARY_CMD_VERSION,
1284                              NULL, 0, NULL, 0);
1285 
1286     safe_send(buffer.bytes, len, false);
1287     safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1288     validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1289                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1290 
1291     return TEST_PASS;
1292 }
1293 
1294 static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1295     union {
1296         protocol_binary_request_no_extras request;
1297         protocol_binary_response_no_extras response;
1298         char bytes[1024];
1299     } send, receive;
1300 
1301     size_t len = storage_command(send.bytes, sizeof(send.bytes),
1302                                  PROTOCOL_BINARY_CMD_ADD,
1303                                  key, strlen(key), NULL, 0, 0, 0);
1304     safe_send(send.bytes, len, false);
1305     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1306     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1307                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1308 
1309     len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1310     safe_send(send.bytes, len, false);
1311     if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1312         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1313         validate_response_header(&receive.response, cmd,
1314                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1315     }
1316 
1317     len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1318                       key, strlen(key), NULL, 0);
1319     safe_send(send.bytes, len, false);
1320     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1321     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1322                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1323 
1324     sleep(2);
1325     safe_send(send.bytes, len, false);
1326     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1327     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1328                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1329 
1330     int ii;
1331     for (ii = 0; ii < 2; ++ii) {
1332         len = storage_command(send.bytes, sizeof(send.bytes),
1333                               PROTOCOL_BINARY_CMD_ADD,
1334                               key, strlen(key), NULL, 0, 0, 0);
1335         safe_send(send.bytes, len, false);
1336         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1337         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1338                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1339 
1340         len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1341         safe_send(send.bytes, len, false);
1342         if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1343             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1344             validate_response_header(&receive.response, cmd,
1345                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1346         }
1347 
1348         len = raw_command(send.bytes, sizeof(send.bytes),
1349                           PROTOCOL_BINARY_CMD_GET,
1350                           key, strlen(key), NULL, 0);
1351         safe_send(send.bytes, len, false);
1352         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1353         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1354                                  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1355     }
1356 
1357     return TEST_PASS;
1358 }
1359 
1360 static enum test_return test_binary_flush(void) {
1361     return test_binary_flush_impl("test_binary_flush",
1362                                   PROTOCOL_BINARY_CMD_FLUSH);
1363 }
1364 
1365 static enum test_return test_binary_flushq(void) {
1366     return test_binary_flush_impl("test_binary_flushq",
1367                                   PROTOCOL_BINARY_CMD_FLUSHQ);
1368 }
1369 
1370 static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
1371     union {
1372         protocol_binary_request_no_extras request;
1373         protocol_binary_response_no_extras response;
1374         char bytes[1024];
1375     } send, receive;
1376     const char *value = "world";
1377 
1378     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1379                               key, strlen(key), value, strlen(value));
1380 
1381 
1382     safe_send(send.bytes, len, false);
1383     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1384     validate_response_header(&receive.response, cmd,
1385                              PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1386 
1387     len = storage_command(send.bytes, sizeof(send.bytes),
1388                           PROTOCOL_BINARY_CMD_ADD,
1389                           key, strlen(key), value, strlen(value), 0, 0);
1390     safe_send(send.bytes, len, false);
1391     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1392     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1393                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1394 
1395     len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1396                       key, strlen(key), value, strlen(value));
1397     safe_send(send.bytes, len, false);
1398 
1399     if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1400         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1401         validate_response_header(&receive.response, cmd,
1402                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1403     } else {
1404         len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
1405                           NULL, 0, NULL, 0);
1406         safe_send(send.bytes, len, false);
1407         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1408         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
1409                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1410     }
1411 
1412     len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
1413                       key, strlen(key), NULL, 0);
1414 
1415     safe_send(send.bytes, len, false);
1416     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1417     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
1418                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1419 
1420     assert(receive.response.message.header.response.keylen == strlen(key));
1421     assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
1422 
1423     char *ptr = receive.bytes;
1424     ptr += sizeof(receive.response);
1425     ptr += 4;
1426 
1427     assert(memcmp(ptr, key, strlen(key)) == 0);
1428     ptr += strlen(key);
1429     assert(memcmp(ptr, value, strlen(value)) == 0);
1430     ptr += strlen(value);
1431     assert(memcmp(ptr, value, strlen(value)) == 0);
1432 
1433     return TEST_PASS;
1434 }
1435 
1436 static enum test_return test_binary_append(void) {
1437     return test_binary_concat_impl("test_binary_append",
1438                                    PROTOCOL_BINARY_CMD_APPEND);
1439 }
1440 
1441 static enum test_return test_binary_prepend(void) {
1442     return test_binary_concat_impl("test_binary_prepend",
1443                                    PROTOCOL_BINARY_CMD_PREPEND);
1444 }
1445 
1446 static enum test_return test_binary_appendq(void) {
1447     return test_binary_concat_impl("test_binary_appendq",
1448                                    PROTOCOL_BINARY_CMD_APPENDQ);
1449 }
1450 
1451 static enum test_return test_binary_prependq(void) {
1452     return test_binary_concat_impl("test_binary_prependq",
1453                                    PROTOCOL_BINARY_CMD_PREPENDQ);
1454 }
1455 
1456 static enum test_return test_binary_stat(void) {
1457     union {
1458         protocol_binary_request_no_extras request;
1459         protocol_binary_response_no_extras response;
1460         char bytes[1024];
1461     } buffer;
1462 
1463     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1464                              PROTOCOL_BINARY_CMD_STAT,
1465                              NULL, 0, NULL, 0);
1466 
1467     safe_send(buffer.bytes, len, false);
1468     do {
1469         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1470         validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
1471                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1472     } while (buffer.response.message.header.response.keylen != 0);
1473 
1474     return TEST_PASS;
1475 }
1476 
1477 static enum test_return test_binary_illegal(void) {
1478     uint8_t cmd = 0x23;
1479     while (cmd != 0x00) {
1480         union {
1481             protocol_binary_request_no_extras request;
1482             protocol_binary_response_no_extras response;
1483             char bytes[1024];
1484         } buffer;
1485         size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1486                                  cmd, NULL, 0, NULL, 0);
1487         safe_send(buffer.bytes, len, false);
1488         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1489         validate_response_header(&buffer.response, cmd,
1490                                  PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND);
1491         ++cmd;
1492     }
1493 
1494     return TEST_PASS;
1495 }
1496 
1497 volatile bool hickup_thread_running;
1498 
1499 static void *binary_hickup_recv_verification_thread(void *arg) {
1500     protocol_binary_response_no_extras *response = malloc(65*1024);
1501     if (response != NULL) {
1502         while (safe_recv_packet(response, 65*1024)) {
1503             /* Just validate the packet format */
1504             validate_response_header(response,
1505                                      response->message.header.response.opcode,
1506                                      response->message.header.response.status);
1507         }
1508         free(response);
1509     }
1510     hickup_thread_running = false;
1511     allow_closed_read = false;
1512     return NULL;
1513 }
1514 
1515 static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
1516     off_t offset = 0;
1517     char *key[256];
1518     uint64_t value = 0xfeedfacedeadbeef;
1519 
1520     while (hickup_thread_running &&
1521            offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
1522         union {
1523             protocol_binary_request_no_extras request;
1524             char bytes[65 * 1024];
1525         } command;
1526         uint8_t cmd = (uint8_t)(rand() & 0xff);
1527         size_t len;
1528         size_t keylen = (rand() % 250) + 1;
1529 
1530         switch (cmd) {
1531         case PROTOCOL_BINARY_CMD_ADD:
1532         case PROTOCOL_BINARY_CMD_ADDQ:
1533         case PROTOCOL_BINARY_CMD_REPLACE:
1534         case PROTOCOL_BINARY_CMD_REPLACEQ:
1535         case PROTOCOL_BINARY_CMD_SET:
1536         case PROTOCOL_BINARY_CMD_SETQ:
1537             len = storage_command(command.bytes, sizeof(command.bytes), cmd,
1538                                   key, keylen , &value, sizeof(value),
1539                                   0, 0);
1540             break;
1541         case PROTOCOL_BINARY_CMD_APPEND:
1542         case PROTOCOL_BINARY_CMD_APPENDQ:
1543         case PROTOCOL_BINARY_CMD_PREPEND:
1544         case PROTOCOL_BINARY_CMD_PREPENDQ:
1545             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1546                               key, keylen, &value, sizeof(value));
1547             break;
1548         case PROTOCOL_BINARY_CMD_FLUSH:
1549         case PROTOCOL_BINARY_CMD_FLUSHQ:
1550             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1551                               NULL, 0, NULL, 0);
1552             break;
1553         case PROTOCOL_BINARY_CMD_NOOP:
1554             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1555                               NULL, 0, NULL, 0);
1556             break;
1557         case PROTOCOL_BINARY_CMD_DELETE:
1558         case PROTOCOL_BINARY_CMD_DELETEQ:
1559             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1560                              key, keylen, NULL, 0);
1561             break;
1562         case PROTOCOL_BINARY_CMD_DECREMENT:
1563         case PROTOCOL_BINARY_CMD_DECREMENTQ:
1564         case PROTOCOL_BINARY_CMD_INCREMENT:
1565         case PROTOCOL_BINARY_CMD_INCREMENTQ:
1566             len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
1567                                      key, keylen, 1, 0, 0);
1568             break;
1569         case PROTOCOL_BINARY_CMD_VERSION:
1570             len = raw_command(command.bytes, sizeof(command.bytes),
1571                              PROTOCOL_BINARY_CMD_VERSION,
1572                              NULL, 0, NULL, 0);
1573             break;
1574         case PROTOCOL_BINARY_CMD_GET:
1575         case PROTOCOL_BINARY_CMD_GETK:
1576         case PROTOCOL_BINARY_CMD_GETKQ:
1577         case PROTOCOL_BINARY_CMD_GETQ:
1578             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1579                              key, keylen, NULL, 0);
1580             break;
1581 
1582         case PROTOCOL_BINARY_CMD_STAT:
1583             len = raw_command(command.bytes, sizeof(command.bytes),
1584                               PROTOCOL_BINARY_CMD_STAT,
1585                               NULL, 0, NULL, 0);
1586             break;
1587 
1588         case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
1589         case PROTOCOL_BINARY_CMD_SASL_AUTH:
1590         case PROTOCOL_BINARY_CMD_SASL_STEP:
1591             /* Ignoring SASL */
1592         case PROTOCOL_BINARY_CMD_QUITQ:
1593         case PROTOCOL_BINARY_CMD_QUIT:
1594             /* I don't want to pass on the quit commands ;-) */
1595             cmd |= 0xf0;
1596             /* FALLTHROUGH */
1597         default:
1598             len = raw_command(command.bytes, sizeof(command.bytes),
1599                               cmd, NULL, 0, NULL, 0);
1600         }
1601 
1602         if ((len + offset) < buffersize) {
1603             memcpy(((char*)buffer) + offset, command.bytes, len);
1604             offset += len;
1605         } else {
1606             break;
1607         }
1608     }
1609     safe_send(buffer, offset, true);
1610 
1611     return TEST_PASS;
1612 }
1613 
1614 static enum test_return test_binary_pipeline_hickup(void)
1615 {
1616     size_t buffersize = 65 * 1024;
1617     void *buffer = malloc(buffersize);
1618     int ii;
1619 
1620     pthread_t tid;
1621     int ret;
1622     allow_closed_read = true;
1623     hickup_thread_running = true;
1624     if ((ret = pthread_create(&tid, NULL,
1625                               binary_hickup_recv_verification_thread, NULL)) != 0) {
1626         fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
1627         return TEST_FAIL;
1628     }
1629 
1630     /* Allow the thread to start */
1631     usleep(250);
1632 
1633     srand((int)time(NULL));
1634     for (ii = 0; ii < 2; ++ii) {
1635         test_binary_pipeline_hickup_chunk(buffer, buffersize);
1636     }
1637 
1638     /* send quitq to shut down the read thread ;-) */
1639     size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
1640                              NULL, 0, NULL, 0);
1641     safe_send(buffer, len, false);
1642 
1643     pthread_join(tid, NULL);
1644     free(buffer);
1645     return TEST_PASS;
1646 }
1647 
1648 typedef enum test_return (*TEST_FUNC)(void);
1649 struct testcase {
1650     const char *description;
1651     TEST_FUNC function;
1652 };
1653 
1654 struct testcase testcases[] = {
1655     { "cache_create", cache_create_test },
1656     { "cache_constructor", cache_constructor_test },
1657     { "cache_constructor_fail", cache_fail_constructor_test },
1658     { "cache_destructor", cache_destructor_test },
1659     { "cache_reuse", cache_reuse_test },
1660     { "cache_redzone", cache_redzone_test },
1661     { "strtol", test_safe_strtol },
1662     { "strtoll", test_safe_strtoll },
1663     { "strtoul", test_safe_strtoul },
1664     { "strtoull", test_safe_strtoull },
1665     { "issue_44", test_issue_44 },
1666     { "vperror", test_vperror },
1667     /* The following tests all run towards the same server */
1668     { "start_server", start_memcached_server },
1669     { "issue_92", test_issue_92 },
1670     { "binary_noop", test_binary_noop },
1671     { "binary_quit", test_binary_quit },
1672     { "binary_quitq", test_binary_quitq },
1673     { "binary_set", test_binary_set },
1674     { "binary_setq", test_binary_setq },
1675     { "binary_add", test_binary_add },
1676     { "binary_addq", test_binary_addq },
1677     { "binary_replace", test_binary_replace },
1678     { "binary_replaceq", test_binary_replaceq },
1679     { "binary_delete", test_binary_delete },
1680     { "binary_deleteq", test_binary_deleteq },
1681     { "binary_get", test_binary_get },
1682     { "binary_getq", test_binary_getq },
1683     { "binary_getk", test_binary_getk },
1684     { "binary_getkq", test_binary_getkq },
1685     { "binary_incr", test_binary_incr },
1686     { "binary_incrq", test_binary_incrq },
1687     { "binary_decr", test_binary_decr },
1688     { "binary_decrq", test_binary_decrq },
1689     { "binary_version", test_binary_version },
1690     { "binary_flush", test_binary_flush },
1691     { "binary_flushq", test_binary_flushq },
1692     { "binary_append", test_binary_append },
1693     { "binary_appendq", test_binary_appendq },
1694     { "binary_prepend", test_binary_prepend },
1695     { "binary_prependq", test_binary_prependq },
1696     { "binary_stat", test_binary_stat },
1697     { "binary_illegal", test_binary_illegal },
1698     { "binary_pipeline_hickup", test_binary_pipeline_hickup },
1699     { "stop_server", stop_memcached_server },
1700     { NULL, NULL }
1701 };
1702 
1703 int main(int argc, char **argv)
1704 {
1705     int exitcode = 0;
1706     int ii = 0, num_cases = 0;
1707 
1708     for (num_cases = 0; testcases[num_cases].description; num_cases++) {
1709         /* Just counting */
1710     }
1711 
1712     printf("1..%d\n", num_cases);
1713 
1714     for (ii = 0; testcases[ii].description != NULL; ++ii) {
1715         fflush(stdout);
1716 #ifndef DEBUG
1717         /* the test program shouldn't run longer than 10 minutes... */
1718         alarm(600);
1719 #endif
1720         enum test_return ret = testcases[ii].function();
1721         if (ret == TEST_SKIP) {
1722             fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
1723         } else if (ret == TEST_PASS) {
1724             fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
1725         } else {
1726             fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
1727             exitcode = 1;
1728         }
1729         fflush(stdout);
1730     }
1731 
1732     return exitcode;
1733 }
1734