xref: /3.0.2-MP2/memcached/tests/testapp.c (revision f4b802c8)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#include "config.h"
3#include <sys/types.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <errno.h>
7#include <string.h>
8#include <fcntl.h>
9#include <ctype.h>
10#include <time.h>
11#include <evutil.h>
12#include <snappy-c.h>
13#include <cJSON.h>
14
15
16#include "daemon/cache.h"
17#include <memcached/util.h>
18#include <memcached/protocol_binary.h>
19#include <memcached/config_parser.h>
20#include "extensions/protocol/fragment_rw.h"
21#include "extensions/protocol/testapp_extension.h"
22#include "platform/platform.h"
23#include "memcached/openssl.h"
24#include "programs/utilities.h"
25
26/* Set the read/write commands differently than the default values
27 * so that we can verify that the override works
28 */
29static uint8_t read_command = 0xe1;
30static uint8_t write_command = 0xe2;
31
32const char config_file[] = "memcached_testapp.json";
33
34#define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
35
36enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
37
38/* test phases */
39#define phase_plain 1
40#define phase_ssl 2
41#define phase_cleanup 4
42#define phase_max 3
43static int current_phase = 0;
44
45static pid_t server_pid;
46static in_port_t port = -1;
47static in_port_t ssl_port = -1;
48static SOCKET sock;
49static bool allow_closed_read = false;
50static time_t server_start_time = 0;
51static SSL_CTX *ssl_ctx = NULL;
52static BIO *ssl_bio = NULL;
53
54static enum test_return cache_create_test(void)
55{
56    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
57                                  NULL, NULL);
58    cb_assert(cache != NULL);
59    cache_destroy(cache);
60    return TEST_PASS;
61}
62
63const uint64_t constructor_pattern = 0xdeadcafebabebeef;
64
65static int cache_constructor(void *buffer, void *notused1, int notused2) {
66    uint64_t *ptr = buffer;
67    *ptr = constructor_pattern;
68    return 0;
69}
70
71static enum test_return cache_constructor_test(void)
72{
73    uint64_t *ptr;
74    uint64_t pattern;
75    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
76                                  cache_constructor, NULL);
77
78
79    cb_assert(cache != NULL);
80    ptr = cache_alloc(cache);
81    pattern = *ptr;
82    cache_free(cache, ptr);
83    cache_destroy(cache);
84    return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
85}
86
87static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
88    return 1;
89}
90
91static enum test_return cache_fail_constructor_test(void)
92{
93    enum test_return ret = TEST_PASS;
94    uint64_t *ptr;
95    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
96                                  cache_fail_constructor, NULL);
97    cb_assert(cache != NULL);
98    ptr = cache_alloc(cache);
99    if (ptr != NULL) {
100        ret = TEST_FAIL;
101    }
102    cache_destroy(cache);
103    return ret;
104}
105
106static void *destruct_data = 0;
107
108static void cache_destructor(void *buffer, void *notused) {
109    destruct_data = buffer;
110}
111
112static enum test_return cache_destructor_test(void)
113{
114    char *ptr;
115    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
116                                  NULL, cache_destructor);
117    cb_assert(cache != NULL);
118    ptr = cache_alloc(cache);
119    cache_free(cache, ptr);
120    cache_destroy(cache);
121
122    return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
123}
124
125static enum test_return cache_reuse_test(void)
126{
127    int ii;
128    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
129                                  NULL, NULL);
130    char *ptr = cache_alloc(cache);
131    cache_free(cache, ptr);
132    for (ii = 0; ii < 100; ++ii) {
133        char *p = cache_alloc(cache);
134        cb_assert(p == ptr);
135        cache_free(cache, ptr);
136    }
137    cache_destroy(cache);
138    return TEST_PASS;
139}
140
141
142static enum test_return cache_bulkalloc(size_t datasize)
143{
144    cache_t *cache = cache_create("test", datasize, sizeof(char*),
145                                  NULL, NULL);
146#define ITERATIONS 1024
147    void *ptr[ITERATIONS];
148    int ii;
149    for (ii = 0; ii < ITERATIONS; ++ii) {
150        ptr[ii] = cache_alloc(cache);
151        cb_assert(ptr[ii] != 0);
152        memset(ptr[ii], 0xff, datasize);
153    }
154
155    for (ii = 0; ii < ITERATIONS; ++ii) {
156        cache_free(cache, ptr[ii]);
157    }
158
159#undef ITERATIONS
160    cache_destroy(cache);
161    return TEST_PASS;
162}
163
164static enum test_return test_issue_161(void)
165{
166    enum test_return ret = cache_bulkalloc(1);
167    if (ret == TEST_PASS) {
168        ret = cache_bulkalloc(512);
169    }
170
171    return ret;
172}
173
174static enum test_return cache_redzone_test(void)
175{
176#if !defined(HAVE_UMEM_H) && !defined(NDEBUG) && !defined(WIN32)
177    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
178                                  NULL, NULL);
179
180    /* Ignore SIGABORT */
181    struct sigaction old_action;
182    struct sigaction action;
183    char *p;
184    char old;
185
186    memset(&action, 0, sizeof(action));
187    action.sa_handler = SIG_IGN;
188    sigemptyset(&action.sa_mask);
189    sigaction(SIGABRT, &action, &old_action);
190
191    /* check memory debug.. */
192    p = cache_alloc(cache);
193    old = *(p - 1);
194    *(p - 1) = 0;
195    cache_free(cache, p);
196    cb_assert(cache_error == -1);
197    *(p - 1) = old;
198
199    p[sizeof(uint32_t)] = 0;
200    cache_free(cache, p);
201    cb_assert(cache_error == 1);
202
203    /* restore signal handler */
204    sigaction(SIGABRT, &old_action, NULL);
205
206    cache_destroy(cache);
207
208    return TEST_PASS;
209#else
210    return TEST_SKIP;
211#endif
212}
213
214static enum test_return test_safe_strtoul(void) {
215    uint32_t val;
216    cb_assert(safe_strtoul("123", &val));
217    cb_assert(val == 123);
218    cb_assert(safe_strtoul("+123", &val));
219    cb_assert(val == 123);
220    cb_assert(!safe_strtoul("", &val));  /* empty */
221    cb_assert(!safe_strtoul("123BOGUS", &val));  /* non-numeric */
222    /* Not sure what it does, but this works with ICC :/
223       cb_assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
224    */
225
226    /* extremes: */
227    cb_assert(safe_strtoul("4294967295", &val)); /* 2**32 - 1 */
228    cb_assert(val == 4294967295L);
229    /* This actually works on 64-bit ubuntu
230       cb_assert(!safe_strtoul("4294967296", &val)); 2**32
231    */
232    cb_assert(!safe_strtoul("-1", &val));  /* negative */
233    return TEST_PASS;
234}
235
236
237static enum test_return test_safe_strtoull(void) {
238    uint64_t val;
239    uint64_t exp = -1;
240    cb_assert(safe_strtoull("123", &val));
241    cb_assert(val == 123);
242    cb_assert(safe_strtoull("+123", &val));
243    cb_assert(val == 123);
244    cb_assert(!safe_strtoull("", &val));  /* empty */
245    cb_assert(!safe_strtoull("123BOGUS", &val));  /* non-numeric */
246    cb_assert(!safe_strtoull("92837498237498237498029383", &val)); /* out of range */
247
248    /* extremes: */
249    cb_assert(safe_strtoull("18446744073709551615", &val)); /* 2**64 - 1 */
250    cb_assert(val == exp);
251    cb_assert(!safe_strtoull("18446744073709551616", &val)); /* 2**64 */
252    cb_assert(!safe_strtoull("-1", &val));  /* negative */
253    return TEST_PASS;
254}
255
256static enum test_return test_safe_strtoll(void) {
257    int64_t val;
258    int64_t exp = 1;
259    exp <<= 63;
260    exp -= 1;
261    cb_assert(safe_strtoll("123", &val));
262    cb_assert(val == 123);
263    cb_assert(safe_strtoll("+123", &val));
264    cb_assert(val == 123);
265    cb_assert(safe_strtoll("-123", &val));
266    cb_assert(val == -123);
267    cb_assert(!safe_strtoll("", &val));  /* empty */
268    cb_assert(!safe_strtoll("123BOGUS", &val));  /* non-numeric */
269    cb_assert(!safe_strtoll("92837498237498237498029383", &val)); /* out of range */
270
271    /* extremes: */
272    cb_assert(!safe_strtoll("18446744073709551615", &val)); /* 2**64 - 1 */
273    cb_assert(safe_strtoll("9223372036854775807", &val)); /* 2**63 - 1 */
274
275    cb_assert(val == exp); /* 9223372036854775807LL); */
276    /*
277      cb_assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
278      cb_assert(val == -9223372036854775808LL);
279    */
280    cb_assert(!safe_strtoll("-9223372036854775809", &val)); /* -2**63 - 1 */
281
282    /* We'll allow space to terminate the string.  And leading space. */
283    cb_assert(safe_strtoll(" 123 foo", &val));
284    cb_assert(val == 123);
285    return TEST_PASS;
286}
287
288static enum test_return test_safe_strtol(void) {
289    int32_t val;
290    cb_assert(safe_strtol("123", &val));
291    cb_assert(val == 123);
292    cb_assert(safe_strtol("+123", &val));
293    cb_assert(val == 123);
294    cb_assert(safe_strtol("-123", &val));
295    cb_assert(val == -123);
296    cb_assert(!safe_strtol("", &val));  /* empty */
297    cb_assert(!safe_strtol("123BOGUS", &val));  /* non-numeric */
298    cb_assert(!safe_strtol("92837498237498237498029383", &val)); /* out of range */
299
300    /* extremes: */
301    /* This actually works on 64-bit ubuntu
302       cb_assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
303    */
304    cb_assert(safe_strtol("2147483647", &val)); /* (- (expt 2.0 31) 1) */
305    cb_assert(val == 2147483647L);
306    /* This actually works on 64-bit ubuntu
307       cb_assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
308    */
309
310    /* We'll allow space to terminate the string.  And leading space. */
311    cb_assert(safe_strtol(" 123 foo", &val));
312    cb_assert(val == 123);
313    return TEST_PASS;
314}
315
316static enum test_return test_safe_strtof(void) {
317    float val;
318    cb_assert(safe_strtof("123", &val));
319    cb_assert(val == 123.00f);
320    cb_assert(safe_strtof("+123", &val));
321    cb_assert(val == 123.00f);
322    cb_assert(safe_strtof("-123", &val));
323    cb_assert(val == -123.00f);
324    cb_assert(!safe_strtof("", &val));  /* empty */
325    cb_assert(!safe_strtof("123BOGUS", &val));  /* non-numeric */
326
327    /* We'll allow space to terminate the string.  And leading space. */
328    cb_assert(safe_strtof(" 123 foo", &val));
329    cb_assert(val == 123.00f);
330
331    cb_assert(safe_strtof("123.23", &val));
332    cb_assert(val == 123.23f);
333
334    cb_assert(safe_strtof("123.00", &val));
335    cb_assert(val == 123.00f);
336
337    return TEST_PASS;
338}
339
340#ifdef WIN32
341static void log_network_error(const char* prefix) {
342    LPVOID error_msg;
343    DWORD err = WSAGetLastError();
344
345    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
346                      FORMAT_MESSAGE_FROM_SYSTEM |
347                      FORMAT_MESSAGE_IGNORE_INSERTS,
348                      NULL, err, 0,
349                      (LPTSTR)&error_msg, 0, NULL) != 0) {
350        fprintf(stderr, prefix, error_msg);
351        LocalFree(error_msg);
352    } else {
353        fprintf(stderr, prefix, "unknown error");
354    }
355}
356#else
357static void log_network_error(const char* prefix) {
358    fprintf(stderr, prefix, strerror(errno));
359}
360#endif
361
362#ifdef WIN32
363#define CERTIFICATE_PATH(file) ("\\tests\\cert\\"#file)
364#else
365#define CERTIFICATE_PATH(file) ("/tests/cert/"#file)
366#endif
367
368static void get_working_current_directory(char* out_buf, int out_buf_len) {
369    bool ok = false;
370#ifdef WIN32
371    ok = GetCurrentDirectory(out_buf_len, out_buf) != 0;
372#else
373    ok = getcwd(out_buf, out_buf_len) != NULL;
374#endif
375    /* memcached may throw a warning, but let's push through */
376    if (!ok) {
377        fprintf(stderr, "Failed to determine current working directory");
378        strncpy(out_buf, ".", out_buf_len);
379    }
380}
381
382static int generate_config(const char *fname)
383{
384    FILE *fp;
385    cJSON *root = cJSON_CreateObject();
386    cJSON *array = cJSON_CreateArray();
387    cJSON *obj = cJSON_CreateObject();
388    cJSON *obj_ssl = NULL;
389    char pem_path[256];
390    char cert_path[256];
391
392    get_working_current_directory(pem_path, 256);
393    strncpy(cert_path, pem_path, 256);
394    strncat(pem_path, CERTIFICATE_PATH(testapp.pem), 256);
395    strncat(cert_path, CERTIFICATE_PATH(testapp.cert), 256);
396
397    cJSON_AddStringToObject(obj, "module", "default_engine.so");
398    cJSON_AddItemReferenceToObject(root, "engine", obj);
399
400    obj = cJSON_CreateObject();
401    cJSON_AddStringToObject(obj, "module", "blackhole_logger.so");
402    cJSON_AddItemToArray(array, obj);
403    obj = cJSON_CreateObject();
404    cJSON_AddStringToObject(obj, "module", "fragment_rw_ops.so");
405    cJSON_AddStringToObject(obj, "config", "r=225;w=226");
406    cJSON_AddItemToArray(array, obj);
407    obj = cJSON_CreateObject();
408    cJSON_AddStringToObject(obj, "module", "testapp_extension.so");
409    cJSON_AddItemToArray(array, obj);
410
411    cJSON_AddItemReferenceToObject(root, "extensions", array);
412
413    array = cJSON_CreateArray();
414    obj = cJSON_CreateObject();
415    obj_ssl = cJSON_CreateObject();
416
417#ifdef WIN32
418    cJSON_AddNumberToObject(obj, "port", 11211);
419#else
420    cJSON_AddNumberToObject(obj, "port", 0);
421#endif
422    cJSON_AddNumberToObject(obj, "maxconn", 1000);
423    cJSON_AddNumberToObject(obj, "backlog", 1024);
424    cJSON_AddStringToObject(obj, "host", "*");
425    cJSON_AddItemToArray(array, obj);
426
427    obj = cJSON_CreateObject();
428    cJSON_AddNumberToObject(obj, "port", 11996);
429    cJSON_AddNumberToObject(obj, "maxconn", 1000);
430    cJSON_AddNumberToObject(obj, "backlog", 1024);
431    cJSON_AddStringToObject(obj, "host", "*");
432    cJSON_AddItemToObject(obj, "ssl", obj_ssl = cJSON_CreateObject());
433    cJSON_AddStringToObject(obj_ssl, "key", pem_path);
434    cJSON_AddStringToObject(obj_ssl, "cert", cert_path);
435    cJSON_AddItemToArray(array, obj);
436    cJSON_AddItemReferenceToObject(root, "interfaces", array);
437
438    cJSON_AddStringToObject(root, "admin", "");
439    cJSON_AddTrueToObject(root, "datatype_support");
440
441    if ((fp = fopen(fname, "w")) == NULL) {
442        return -1;
443    } else {
444        fprintf(fp, "%s", cJSON_Print(root));
445        fclose(fp);
446    }
447
448    return 0;
449}
450
451#ifdef WIN32
452static HANDLE start_server(in_port_t *port_out, in_port_t *ssl_port_out, bool daemon, int timeout) {
453    STARTUPINFO sinfo;
454    PROCESS_INFORMATION pinfo;
455    char *commandline = malloc(1024);
456    char env[80];
457    sprintf_s(env, sizeof(env), "MEMCACHED_PARENT_MONITOR=%u", GetCurrentProcessId());
458    putenv(env);
459
460    memset(&sinfo, 0, sizeof(sinfo));
461    memset(&pinfo, 0, sizeof(pinfo));
462    sinfo.cb = sizeof(sinfo);
463
464    sprintf(commandline, "memcached.exe -C %s", config_file);
465
466    if (!CreateProcess("memcached.exe",
467                       commandline,
468                       NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, NULL, NULL, &sinfo, &pinfo)) {
469        LPVOID error_msg;
470        DWORD err = GetLastError();
471
472        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
473                          FORMAT_MESSAGE_FROM_SYSTEM |
474                          FORMAT_MESSAGE_IGNORE_INSERTS,
475                          NULL, err, 0,
476                          (LPTSTR)&error_msg, 0, NULL) != 0) {
477            fprintf(stderr, "Failed to start process: %s\n", error_msg);
478            LocalFree(error_msg);
479        } else {
480            fprintf(stderr, "Failed to start process: unknown error\n");
481        }
482        exit(EXIT_FAILURE);
483    }
484    /* Do a short sleep to let the other process to start */
485    Sleep(1);
486    CloseHandle(pinfo.hThread);
487
488    *port_out = 11211;
489    *ssl_port_out = 11996;
490    return pinfo.hProcess;
491}
492#else
493/**
494 * Function to start the server and let it listen on a random port
495 *
496 * @param port_out where to store the TCP port number the server is
497 *                 listening on
498 * @param daemon set to true if you want to run the memcached server
499 *               as a daemon process
500 * @return the pid of the memcached server
501 */
502
503static pid_t start_server(in_port_t *port_out, in_port_t *ssl_port_out, bool daemon, int timeout) {
504    char environment[80];
505    char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
506#ifdef __sun
507    char coreadm[128];
508#endif
509    pid_t pid;
510    FILE *fp;
511    char buffer[80];
512
513    char env[80];
514    snprintf(env, sizeof(env), "MEMCACHED_PARENT_MONITOR=%lu", (unsigned long)getpid());
515    putenv(env);
516
517    snprintf(environment, sizeof(environment),
518             "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
519    remove(filename);
520
521#ifdef __sun
522    /* I want to name the corefiles differently so that they don't
523       overwrite each other
524    */
525    snprintf(coreadm, sizeof(coreadm),
526             "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
527    system(coreadm);
528#endif
529
530    pid = fork();
531    cb_assert(pid != -1);
532
533    if (pid == 0) {
534        /* Child */
535        char *argv[20];
536        int arg = 0;
537        char tmo[24];
538
539        snprintf(tmo, sizeof(tmo), "%u", timeout);
540        putenv(environment);
541
542        argv[arg++] = "./memcached";
543        argv[arg++] = "-C";
544        argv[arg++] = (char*)config_file;
545
546        argv[arg++] = NULL;
547        cb_assert(execv(argv[0], argv) != -1);
548    }
549
550    /* Yeah just let us "busy-wait" for the file to be created ;-) */
551    while (access(filename, F_OK) == -1) {
552        usleep(10);
553    }
554
555    fp = fopen(filename, "r");
556    if (fp == NULL) {
557        fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
558                strerror(errno));
559        cb_assert(false);
560    }
561
562    *port_out = (in_port_t)-1;
563    *ssl_port_out = (in_port_t)-1;
564
565    while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
566        if (strncmp(buffer, "TCP INET: ", 10) == 0) {
567            int32_t val;
568            cb_assert(safe_strtol(buffer + 10, &val));
569            if (*port_out == (in_port_t)-1) {
570                *port_out = (in_port_t)val;
571            } else {
572                *ssl_port_out = (in_port_t)val;
573            }
574        }
575    }
576    fclose(fp);
577    cb_assert(remove(filename) == 0);
578
579    return pid;
580}
581#endif
582
583static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
584{
585    struct addrinfo *ai = 0;
586    struct addrinfo hints;
587    char service[NI_MAXSERV];
588    int error;
589
590    memset(&hints, 0, sizeof(hints));
591    hints.ai_family = AF_UNSPEC;
592    hints.ai_protocol = IPPROTO_TCP;
593    hints.ai_socktype = SOCK_STREAM;
594
595    (void)snprintf(service, NI_MAXSERV, "%d", port);
596    if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
597#ifdef WIN32
598        log_network_error("getaddrinfo(): %s\r\n");
599#else
600       if (error != EAI_SYSTEM) {
601          fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
602       } else {
603          perror("getaddrinfo()");
604       }
605#endif
606    }
607
608    return ai;
609}
610
611static SOCKET connect_server(const char *hostname, in_port_t port, bool nonblock)
612{
613    struct addrinfo *ai = lookuphost(hostname, port);
614    SOCKET sock = INVALID_SOCKET;
615    if (ai != NULL) {
616       if ((sock = socket(ai->ai_family, ai->ai_socktype,
617                          ai->ai_protocol)) != INVALID_SOCKET) {
618          if (connect(sock, ai->ai_addr, (socklen_t)ai->ai_addrlen) == SOCKET_ERROR) {
619             log_network_error("Failed to connect socket: %s\n");
620             closesocket(sock);
621             sock = INVALID_SOCKET;
622          } else if (nonblock) {
623#ifdef WIN32
624              if (evutil_make_socket_nonblocking(sock) == -1) {
625                abort();
626              }
627#else
628              int flags = fcntl(sock, F_GETFL, 0);
629              if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
630                  fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
631                          strerror(errno));
632                  close(sock);
633                  sock = -1;
634              }
635#endif
636          }
637       } else {
638          fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
639       }
640
641       freeaddrinfo(ai);
642    }
643    return sock;
644}
645
646static void connect_ssl_server(const char *hostname, in_port_t port, bool nonblocking) {
647    char port_str[32];
648    snprintf(port_str, 32, "%d", port);
649    create_ssl_connection(&ssl_ctx, &ssl_bio, hostname, port_str, NULL, NULL, 1);
650    BIO_set_nbio(ssl_bio, nonblocking?1:0);
651}
652
653/*
654    re-connect to server on hostname.
655    Uses global port and ssl_port values.
656    New socket-fd written to global "sock" and "ssl_bio"
657*/
658static void reconnect_to_server(const char *hostname, bool nonblocking) {
659#ifdef WIN32
660    closesocket(sock);
661#else
662    close(sock);
663#endif
664    BIO_reset(ssl_bio);
665    sock = connect_server("127.0.0.1", port, nonblocking);
666    connect_ssl_server("127.0.0.1", ssl_port, nonblocking);
667}
668
669static enum test_return test_vperror(void) {
670#ifdef WIN32
671    return TEST_SKIP;
672#else
673    int rv = 0;
674    int oldstderr = dup(STDERR_FILENO);
675    char tmpl[sizeof(TMP_TEMPLATE)+1];
676    int newfile;
677    char buf[80] = {0};
678    FILE *efile;
679    char *prv;
680    char expected[80] = {0};
681
682    strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
683
684    newfile = mkstemp(tmpl);
685    cb_assert(newfile > 0);
686    rv = dup2(newfile, STDERR_FILENO);
687    cb_assert(rv == STDERR_FILENO);
688    rv = close(newfile);
689    cb_assert(rv == 0);
690
691    errno = EIO;
692    vperror("Old McDonald had a farm.  %s", "EI EIO");
693
694    /* Restore stderr */
695    rv = dup2(oldstderr, STDERR_FILENO);
696    cb_assert(rv == STDERR_FILENO);
697
698
699    /* Go read the file */
700    efile = fopen(tmpl, "r");
701    cb_assert(efile);
702    prv = fgets(buf, sizeof(buf), efile);
703    cb_assert(prv);
704    fclose(efile);
705
706    unlink(tmpl);
707
708    snprintf(expected, sizeof(expected),
709             "Old McDonald had a farm.  EI EIO: %s\n", strerror(EIO));
710
711    /*
712    fprintf(stderr,
713            "\nExpected:  ``%s''"
714            "\nGot:       ``%s''\n", expected, buf);
715    */
716
717    return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
718#endif
719}
720
721static char* trim(char* ptr) {
722    char *start = ptr;
723    char *end;
724
725    while (isspace(*start)) {
726        ++start;
727    }
728    end = start + strlen(start) - 1;
729    if (end != start) {
730        while (isspace(*end)) {
731            *end = '\0';
732            --end;
733        }
734    }
735    return start;
736}
737
738static enum test_return test_config_parser(void) {
739#ifndef WIN32
740    bool bool_val = false;
741    size_t size_val = 0;
742    ssize_t ssize_val = 0;
743    float float_val = 0;
744    char *string_val = 0;
745    int ii;
746    char buffer[1024];
747    FILE *cfg;
748    char outfile[sizeof(TMP_TEMPLATE)+1];
749    char cfgfile[sizeof(TMP_TEMPLATE)+1];
750    int newfile;
751    FILE *error;
752
753    /* Set up the different items I can handle */
754    struct config_item items[7];
755    memset(&items, 0, sizeof(items));
756    ii = 0;
757    items[ii].key = "bool";
758    items[ii].datatype = DT_BOOL;
759    items[ii].value.dt_bool = &bool_val;
760    ++ii;
761
762    items[ii].key = "size_t";
763    items[ii].datatype = DT_SIZE;
764    items[ii].value.dt_size = &size_val;
765    ++ii;
766
767    items[ii].key = "ssize_t";
768    items[ii].datatype = DT_SSIZE;
769    items[ii].value.dt_ssize = &ssize_val;
770    ++ii;
771
772    items[ii].key = "float";
773    items[ii].datatype = DT_FLOAT;
774    items[ii].value.dt_float = &float_val;
775    ++ii;
776
777    items[ii].key = "string";
778    items[ii].datatype = DT_STRING;
779    items[ii].value.dt_string = &string_val;
780    ++ii;
781
782    items[ii].key = "config_file";
783    items[ii].datatype = DT_CONFIGFILE;
784    ++ii;
785
786    items[ii].key = NULL;
787    ++ii;
788
789    cb_assert(ii == 7);
790    strncpy(outfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
791    strncpy(cfgfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
792
793    newfile = mkstemp(outfile);
794    cb_assert(newfile > 0);
795    error = fdopen(newfile, "w");
796
797    cb_assert(error != NULL);
798    cb_assert(parse_config("", items, error) == 0);
799    /* Nothing should be found */
800    for (ii = 0; ii < 5; ++ii) {
801        cb_assert(!items[0].found);
802    }
803
804    cb_assert(parse_config("bool=true", items, error) == 0);
805    cb_assert(bool_val);
806    /* only bool should be found */
807    cb_assert(items[0].found);
808    items[0].found = false;
809    for (ii = 0; ii < 5; ++ii) {
810        cb_assert(!items[0].found);
811    }
812
813    /* It should allow illegal keywords */
814    cb_assert(parse_config("pacman=dead", items, error) == 1);
815    /* and illegal values */
816    cb_assert(parse_config("bool=12", items, error) == -1);
817    cb_assert(!items[0].found);
818    /* and multiple occurences of the same value */
819    cb_assert(parse_config("size_t=1; size_t=1024", items, error) == 0);
820    cb_assert(items[1].found);
821    cb_assert(size_val == 1024);
822    items[1].found = false;
823
824    /* Empty string */
825    /* XXX:  This test fails on Linux, but works on OS X.
826    cb_assert(parse_config("string=", items, error) == 0);
827    cb_assert(items[4].found);
828    cb_assert(strcmp(string_val, "") == 0);
829    items[4].found = false;
830    */
831    /* Plain string */
832    cb_assert(parse_config("string=sval", items, error) == 0);
833    cb_assert(items[4].found);
834    cb_assert(strcmp(string_val, "sval") == 0);
835    items[4].found = false;
836    /* Leading space */
837    cb_assert(parse_config("string= sval", items, error) == 0);
838    cb_assert(items[4].found);
839    cb_assert(strcmp(string_val, "sval") == 0);
840    items[4].found = false;
841    /* Escaped leading space */
842    cb_assert(parse_config("string=\\ sval", items, error) == 0);
843    cb_assert(items[4].found);
844    cb_assert(strcmp(string_val, " sval") == 0);
845    items[4].found = false;
846    /* trailing space */
847    cb_assert(parse_config("string=sval ", items, error) == 0);
848    cb_assert(items[4].found);
849    cb_assert(strcmp(string_val, "sval") == 0);
850    items[4].found = false;
851    /* escaped trailing space */
852    cb_assert(parse_config("string=sval\\ ", items, error) == 0);
853    cb_assert(items[4].found);
854    cb_assert(strcmp(string_val, "sval ") == 0);
855    items[4].found = false;
856    /* escaped stop char */
857    cb_assert(parse_config("string=sval\\;blah=x", items, error) == 0);
858    cb_assert(items[4].found);
859    cb_assert(strcmp(string_val, "sval;blah=x") == 0);
860    items[4].found = false;
861    /* middle space */
862    cb_assert(parse_config("string=s val", items, error) == 0);
863    cb_assert(items[4].found);
864    cb_assert(strcmp(string_val, "s val") == 0);
865    items[4].found = false;
866
867    /* And all of the variables */
868    cb_assert(parse_config("bool=true;size_t=1024;float=12.5;string=somestr",
869                        items, error) == 0);
870    cb_assert(bool_val);
871    cb_assert(size_val == 1024);
872    cb_assert(float_val == 12.5f);
873    cb_assert(strcmp(string_val, "somestr") == 0);
874    for (ii = 0; ii < 5; ++ii) {
875        items[ii].found = false;
876    }
877
878    cb_assert(parse_config("size_t=1k", items, error) == 0);
879    cb_assert(items[1].found);
880    cb_assert(size_val == 1024);
881    items[1].found = false;
882    cb_assert(parse_config("size_t=1m", items, error) == 0);
883    cb_assert(items[1].found);
884    cb_assert(size_val == 1024*1024);
885    items[1].found = false;
886    cb_assert(parse_config("size_t=1g", items, error) == 0);
887    cb_assert(items[1].found);
888    cb_assert(size_val == 1024*1024*1024);
889    items[1].found = false;
890    cb_assert(parse_config("size_t=1K", items, error) == 0);
891    cb_assert(items[1].found);
892    cb_assert(size_val == 1024);
893    items[1].found = false;
894    cb_assert(parse_config("size_t=1M", items, error) == 0);
895    cb_assert(items[1].found);
896    cb_assert(size_val == 1024*1024);
897    items[1].found = false;
898    cb_assert(parse_config("size_t=1G", items, error) == 0);
899    cb_assert(items[1].found);
900    cb_assert(size_val == 1024*1024*1024);
901    items[1].found = false;
902
903    newfile = mkstemp(cfgfile);
904    cb_assert(newfile > 0);
905    cfg = fdopen(newfile, "w");
906    cb_assert(cfg != NULL);
907    fprintf(cfg, "# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
908    fclose(cfg);
909    sprintf(buffer, "config_file=%s", cfgfile);
910    cb_assert(parse_config(buffer, items, error) == 0);
911    cb_assert(bool_val);
912    cb_assert(size_val == 1023);
913    cb_assert(float_val == 12.4f);
914    fclose(error);
915
916    remove(cfgfile);
917    /* Verify that I received the error messages ;-) */
918    error = fopen(outfile, "r");
919    cb_assert(error);
920
921    cb_assert(fgets(buffer, sizeof(buffer), error));
922    cb_assert(strcmp("Unsupported key: <pacman>", trim(buffer)) == 0);
923    cb_assert(fgets(buffer, sizeof(buffer), error));
924    cb_assert(strcmp("Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
925    cb_assert(fgets(buffer, sizeof(buffer), error));
926    cb_assert(strcmp("WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
927    cb_assert(fgets(buffer, sizeof(buffer), error) == NULL);
928
929    remove(outfile);
930    return TEST_PASS;
931#else
932    return TEST_SKIP;
933#endif
934}
935
936static enum test_return start_memcached_server(void) {
937    if (generate_config(config_file) == -1) {
938        return TEST_FAIL;
939    }
940
941    server_start_time = time(0);
942    server_pid = start_server(&port, &ssl_port, false, 600);
943    sock = connect_server("127.0.0.1", port, false);
944
945    /* connect ssl sets the global ssl_ctx/ssl_bio structures up, no raw FD returned*/
946    connect_ssl_server("127.0.0.1", ssl_port, false);
947
948    return TEST_PASS;
949}
950
951static enum test_return stop_memcached_server(void) {
952    closesocket(sock);
953    sock = INVALID_SOCKET;
954#ifdef WIN32
955    TerminateProcess(server_pid, 0);
956#else
957    if (kill(server_pid, SIGTERM) == 0) {
958        /* Wait for the process to be gone... */
959        while (kill(server_pid, 0) == 0) {
960            sleep(1);
961            waitpid(server_pid, NULL, WNOHANG);
962        }
963    }
964#endif
965
966    remove(config_file);
967    return TEST_PASS;
968}
969
970static ssize_t phase_send(const void *buf, size_t len) {
971
972    ssize_t rv = 0;
973    if (current_phase == phase_ssl) {
974        rv = (ssize_t)BIO_write(ssl_bio, (const char*)buf, len);
975    } else {
976#ifdef WIN32
977        rv = send(sock, buf, (int)len, 0);
978#else
979        rv = send(sock, buf, len, 0);
980#endif
981    }
982    return rv;
983}
984
985static ssize_t phase_recv(void *buf, size_t len) {
986
987    ssize_t rv = 0;
988    if (current_phase == phase_ssl) {
989        rv = (ssize_t)BIO_read(ssl_bio, (char*)buf, len);
990    } else {
991#ifdef WIN32
992        rv = recv(sock, buf, (int)len, 0);
993#else
994        rv = recv(sock, buf, len, 0);
995#endif
996    }
997    return rv;
998}
999
1000char ssl_error_string[256];
1001int ssl_error_string_len = 256;
1002
1003static char* phase_get_errno() {
1004    char * rv = 0;
1005    if (current_phase == phase_ssl) {
1006        /* could do with more work here, but so far this has sufficed */
1007        snprintf(ssl_error_string, ssl_error_string_len, "SSL error\n");
1008        rv = ssl_error_string;
1009    } else {
1010        rv = strerror(errno);
1011    }
1012    return rv;
1013}
1014
1015static void safe_send(const void* buf, size_t len, bool hickup)
1016{
1017    off_t offset = 0;
1018    const char* ptr = buf;
1019    do {
1020        size_t num_bytes = len - offset;
1021        ssize_t nw;
1022        if (hickup) {
1023            if (num_bytes > 1024) {
1024                num_bytes = (rand() % 1023) + 1;
1025            }
1026        }
1027
1028        nw = phase_send(ptr + offset, num_bytes);
1029
1030        if (nw == -1) {
1031            if (errno != EINTR) {
1032                fprintf(stderr, "Failed to write: %s\n", phase_get_errno());
1033                abort();
1034            }
1035        } else {
1036            if (hickup) {
1037#ifndef WIN32
1038                usleep(100);
1039#endif
1040            }
1041            offset += nw;
1042        }
1043    } while (offset < len);
1044}
1045
1046static bool safe_recv(void *buf, size_t len) {
1047    off_t offset = 0;
1048    if (len == 0) {
1049        return true;
1050    }
1051    do {
1052
1053        ssize_t nr = phase_recv(((char*)buf) + offset, len - offset);
1054
1055        if (nr == -1) {
1056            if (errno != EINTR) {
1057                fprintf(stderr, "Failed to read: %s\n", phase_get_errno());
1058                abort();
1059            }
1060        } else {
1061            if (nr == 0 && allow_closed_read) {
1062                return false;
1063            }
1064            cb_assert(nr != 0);
1065            offset += nr;
1066        }
1067    } while (offset < len);
1068
1069    return true;
1070}
1071
1072static bool safe_recv_packet(void *buf, size_t size) {
1073    protocol_binary_response_no_extras *response = buf;
1074    char *ptr;
1075    size_t len;
1076
1077    cb_assert(size >= sizeof(*response));
1078    if (!safe_recv(response, sizeof(*response))) {
1079        return false;
1080    }
1081    response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
1082    response->message.header.response.status = ntohs(response->message.header.response.status);
1083    response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
1084
1085    len = sizeof(*response);
1086    ptr = buf;
1087    ptr += len;
1088    cb_assert(size >= (sizeof(*response) + response->message.header.response.bodylen));
1089    if (!safe_recv(ptr, response->message.header.response.bodylen)) {
1090        return false;
1091    }
1092
1093    return true;
1094}
1095
1096static off_t storage_command(char*buf,
1097                             size_t bufsz,
1098                             uint8_t cmd,
1099                             const void* key,
1100                             size_t keylen,
1101                             const void* dta,
1102                             size_t dtalen,
1103                             uint32_t flags,
1104                             uint32_t exp) {
1105    /* all of the storage commands use the same command layout */
1106    off_t key_offset;
1107    protocol_binary_request_set *request = (void*)buf;
1108    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1109
1110    memset(request, 0, sizeof(*request));
1111    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1112    request->message.header.request.opcode = cmd;
1113    request->message.header.request.keylen = htons((uint16_t)keylen);
1114    request->message.header.request.extlen = 8;
1115    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 8 + dtalen));
1116    request->message.header.request.opaque = 0xdeadbeef;
1117    request->message.body.flags = htonl(flags);
1118    request->message.body.expiration = htonl(exp);
1119
1120    key_offset = sizeof(protocol_binary_request_no_extras) + 8;
1121
1122    memcpy(buf + key_offset, key, keylen);
1123    if (dta != NULL) {
1124        memcpy(buf + key_offset + keylen, dta, dtalen);
1125    }
1126
1127    return (off_t)(key_offset + keylen + dtalen);
1128}
1129
1130static off_t raw_command(char* buf,
1131                         size_t bufsz,
1132                         uint8_t cmd,
1133                         const void* key,
1134                         size_t keylen,
1135                         const void* dta,
1136                         size_t dtalen) {
1137    /* all of the storage commands use the same command layout */
1138    off_t key_offset;
1139    protocol_binary_request_no_extras *request = (void*)buf;
1140    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1141
1142    memset(request, 0, sizeof(*request));
1143    if (cmd == read_command || cmd == write_command) {
1144        request->message.header.request.extlen = 8;
1145    }
1146    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1147    request->message.header.request.opcode = cmd;
1148    request->message.header.request.keylen = htons((uint16_t)keylen);
1149    request->message.header.request.bodylen = htonl((uint32_t)(keylen + dtalen + request->message.header.request.extlen));
1150    request->message.header.request.opaque = 0xdeadbeef;
1151
1152    key_offset = sizeof(protocol_binary_request_no_extras) +
1153        request->message.header.request.extlen;
1154
1155    if (key != NULL) {
1156        memcpy(buf + key_offset, key, keylen);
1157    }
1158    if (dta != NULL) {
1159        memcpy(buf + key_offset + keylen, dta, dtalen);
1160    }
1161
1162    return (off_t)(sizeof(*request) + keylen + dtalen + request->message.header.request.extlen);
1163}
1164
1165static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1166    off_t size;
1167    protocol_binary_request_flush *request = (void*)buf;
1168    cb_assert(bufsz > sizeof(*request));
1169
1170    memset(request, 0, sizeof(*request));
1171    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1172    request->message.header.request.opcode = cmd;
1173
1174    size = sizeof(protocol_binary_request_no_extras);
1175    if (use_extra) {
1176        request->message.header.request.extlen = 4;
1177        request->message.body.expiration = htonl(exptime);
1178        request->message.header.request.bodylen = htonl(4);
1179        size += 4;
1180    }
1181
1182    request->message.header.request.opaque = 0xdeadbeef;
1183
1184    return size;
1185}
1186
1187static off_t arithmetic_command(char* buf,
1188                                size_t bufsz,
1189                                uint8_t cmd,
1190                                const void* key,
1191                                size_t keylen,
1192                                uint64_t delta,
1193                                uint64_t initial,
1194                                uint32_t exp) {
1195    off_t key_offset;
1196    protocol_binary_request_incr *request = (void*)buf;
1197    cb_assert(bufsz > sizeof(*request) + keylen);
1198
1199    memset(request, 0, sizeof(*request));
1200    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1201    request->message.header.request.opcode = cmd;
1202    request->message.header.request.keylen = htons((uint16_t)keylen);
1203    request->message.header.request.extlen = 20;
1204    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 20));
1205    request->message.header.request.opaque = 0xdeadbeef;
1206    request->message.body.delta = htonll(delta);
1207    request->message.body.initial = htonll(initial);
1208    request->message.body.expiration = htonl(exp);
1209
1210    key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1211
1212    memcpy(buf + key_offset, key, keylen);
1213    return (off_t)(key_offset + keylen);
1214}
1215
1216static void validate_response_header(protocol_binary_response_no_extras *response,
1217                                     uint8_t cmd, uint16_t status)
1218{
1219    cb_assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1220    cb_assert(response->message.header.response.opcode == cmd);
1221    cb_assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1222    if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1223        if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1224            response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1225        }
1226    }
1227    cb_assert(response->message.header.response.status == status);
1228    cb_assert(response->message.header.response.opaque == 0xdeadbeef);
1229
1230    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1231        switch (cmd) {
1232        case PROTOCOL_BINARY_CMD_ADDQ:
1233        case PROTOCOL_BINARY_CMD_APPENDQ:
1234        case PROTOCOL_BINARY_CMD_DECREMENTQ:
1235        case PROTOCOL_BINARY_CMD_DELETEQ:
1236        case PROTOCOL_BINARY_CMD_FLUSHQ:
1237        case PROTOCOL_BINARY_CMD_INCREMENTQ:
1238        case PROTOCOL_BINARY_CMD_PREPENDQ:
1239        case PROTOCOL_BINARY_CMD_QUITQ:
1240        case PROTOCOL_BINARY_CMD_REPLACEQ:
1241        case PROTOCOL_BINARY_CMD_SETQ:
1242            cb_assert("Quiet command shouldn't return on success" == NULL);
1243        default:
1244            break;
1245        }
1246
1247        switch (cmd) {
1248        case PROTOCOL_BINARY_CMD_ADD:
1249        case PROTOCOL_BINARY_CMD_REPLACE:
1250        case PROTOCOL_BINARY_CMD_SET:
1251        case PROTOCOL_BINARY_CMD_APPEND:
1252        case PROTOCOL_BINARY_CMD_PREPEND:
1253            cb_assert(response->message.header.response.keylen == 0);
1254            cb_assert(response->message.header.response.extlen == 0);
1255            cb_assert(response->message.header.response.bodylen == 0);
1256            cb_assert(response->message.header.response.cas != 0);
1257            break;
1258        case PROTOCOL_BINARY_CMD_FLUSH:
1259        case PROTOCOL_BINARY_CMD_NOOP:
1260        case PROTOCOL_BINARY_CMD_QUIT:
1261        case PROTOCOL_BINARY_CMD_DELETE:
1262            cb_assert(response->message.header.response.keylen == 0);
1263            cb_assert(response->message.header.response.extlen == 0);
1264            cb_assert(response->message.header.response.bodylen == 0);
1265            break;
1266
1267        case PROTOCOL_BINARY_CMD_DECREMENT:
1268        case PROTOCOL_BINARY_CMD_INCREMENT:
1269            cb_assert(response->message.header.response.keylen == 0);
1270            cb_assert(response->message.header.response.extlen == 0);
1271            cb_assert(response->message.header.response.bodylen == 8);
1272            cb_assert(response->message.header.response.cas != 0);
1273            break;
1274
1275        case PROTOCOL_BINARY_CMD_STAT:
1276            cb_assert(response->message.header.response.extlen == 0);
1277            /* key and value exists in all packets except in the terminating */
1278            cb_assert(response->message.header.response.cas == 0);
1279            break;
1280
1281        case PROTOCOL_BINARY_CMD_VERSION:
1282            cb_assert(response->message.header.response.keylen == 0);
1283            cb_assert(response->message.header.response.extlen == 0);
1284            cb_assert(response->message.header.response.bodylen != 0);
1285            cb_assert(response->message.header.response.cas == 0);
1286            break;
1287
1288        case PROTOCOL_BINARY_CMD_GET:
1289        case PROTOCOL_BINARY_CMD_GETQ:
1290            cb_assert(response->message.header.response.keylen == 0);
1291            cb_assert(response->message.header.response.extlen == 4);
1292            cb_assert(response->message.header.response.cas != 0);
1293            break;
1294
1295        case PROTOCOL_BINARY_CMD_GETK:
1296        case PROTOCOL_BINARY_CMD_GETKQ:
1297            cb_assert(response->message.header.response.keylen != 0);
1298            cb_assert(response->message.header.response.extlen == 4);
1299            cb_assert(response->message.header.response.cas != 0);
1300            break;
1301
1302        default:
1303            /* Undefined command code */
1304            break;
1305        }
1306    } else {
1307        cb_assert(response->message.header.response.cas == 0);
1308        cb_assert(response->message.header.response.extlen == 0);
1309        if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1310            cb_assert(response->message.header.response.keylen == 0);
1311        }
1312    }
1313}
1314
1315static enum test_return test_binary_noop(void) {
1316    union {
1317        protocol_binary_request_no_extras request;
1318        protocol_binary_response_no_extras response;
1319        char bytes[1024];
1320    } buffer;
1321
1322    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1323                             PROTOCOL_BINARY_CMD_NOOP,
1324                             NULL, 0, NULL, 0);
1325
1326    safe_send(buffer.bytes, len, false);
1327    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1328    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1329                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1330
1331    return TEST_PASS;
1332}
1333
1334static enum test_return test_binary_quit_impl(uint8_t cmd) {
1335    union {
1336        protocol_binary_request_no_extras request;
1337        protocol_binary_response_no_extras response;
1338        char bytes[1024];
1339    } buffer;
1340    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1341                             cmd, NULL, 0, NULL, 0);
1342
1343    safe_send(buffer.bytes, len, false);
1344    if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1345        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1346        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1347                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1348    }
1349
1350    /* Socket should be closed now, read should return 0 */
1351    cb_assert(phase_recv(buffer.bytes, sizeof(buffer.bytes)) == 0);
1352
1353    reconnect_to_server("127.0.0.1", false);
1354
1355    return TEST_PASS;
1356}
1357
1358static enum test_return test_binary_quit(void) {
1359    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1360}
1361
1362static enum test_return test_binary_quitq(void) {
1363    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1364}
1365
1366static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1367    union {
1368        protocol_binary_request_no_extras request;
1369        protocol_binary_response_no_extras response;
1370        char bytes[1024];
1371    } send, receive;
1372    uint64_t value = 0xdeadbeefdeadcafe;
1373    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1374                                 key, strlen(key), &value, sizeof(value),
1375                                 0, 0);
1376
1377    /* Set should work over and over again */
1378    int ii;
1379    for (ii = 0; ii < 10; ++ii) {
1380        safe_send(send.bytes, len, false);
1381        if (cmd == PROTOCOL_BINARY_CMD_SET) {
1382            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1383            validate_response_header(&receive.response, cmd,
1384                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1385        }
1386    }
1387
1388    if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1389        return test_binary_noop();
1390    }
1391
1392    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1393    safe_send(send.bytes, len, false);
1394    if (cmd == PROTOCOL_BINARY_CMD_SET) {
1395        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1396        validate_response_header(&receive.response, cmd,
1397                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1398        cb_assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1399    } else {
1400        return test_binary_noop();
1401    }
1402
1403    return TEST_PASS;
1404}
1405
1406static enum test_return test_binary_set(void) {
1407    return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1408}
1409
1410static enum test_return test_binary_setq(void) {
1411    return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1412}
1413
1414static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1415    uint64_t value = 0xdeadbeefdeadcafe;
1416    union {
1417        protocol_binary_request_no_extras request;
1418        protocol_binary_response_no_extras response;
1419        char bytes[1024];
1420    } send, receive;
1421    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1422                                 strlen(key), &value, sizeof(value),
1423                                 0, 0);
1424
1425    /* Add should only work the first time */
1426    int ii;
1427    for (ii = 0; ii < 10; ++ii) {
1428        safe_send(send.bytes, len, false);
1429        if (ii == 0) {
1430            if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1431                safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1432                validate_response_header(&receive.response, cmd,
1433                                         PROTOCOL_BINARY_RESPONSE_SUCCESS);
1434            }
1435        } else {
1436            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1437            validate_response_header(&receive.response, cmd,
1438                                     PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1439        }
1440    }
1441
1442    /* And verify that it doesn't work with the "correct" CAS */
1443    /* value */
1444    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1445    safe_send(send.bytes, len, false);
1446    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1447    validate_response_header(&receive.response, cmd,
1448                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1449    return TEST_PASS;
1450}
1451
1452static enum test_return test_binary_add(void) {
1453    return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1454}
1455
1456static enum test_return test_binary_addq(void) {
1457    return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1458}
1459
1460static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1461    uint64_t value = 0xdeadbeefdeadcafe;
1462    union {
1463        protocol_binary_request_no_extras request;
1464        protocol_binary_response_no_extras response;
1465        char bytes[1024];
1466    } send, receive;
1467    int ii;
1468    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1469                                 key, strlen(key), &value, sizeof(value),
1470                                 0, 0);
1471    safe_send(send.bytes, len, false);
1472    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1473    validate_response_header(&receive.response, cmd,
1474                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1475    len = storage_command(send.bytes, sizeof(send.bytes),
1476                          PROTOCOL_BINARY_CMD_ADD,
1477                          key, strlen(key), &value, sizeof(value), 0, 0);
1478    safe_send(send.bytes, len, false);
1479    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1480    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1481                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1482
1483    len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1484                          key, strlen(key), &value, sizeof(value), 0, 0);
1485    for (ii = 0; ii < 10; ++ii) {
1486        safe_send(send.bytes, len, false);
1487        if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1488            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1489            validate_response_header(&receive.response,
1490                                     PROTOCOL_BINARY_CMD_REPLACE,
1491                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1492        }
1493    }
1494
1495    if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1496        test_binary_noop();
1497    }
1498
1499    return TEST_PASS;
1500}
1501
1502static enum test_return test_binary_replace(void) {
1503    return test_binary_replace_impl("test_binary_replace",
1504                                    PROTOCOL_BINARY_CMD_REPLACE);
1505}
1506
1507static enum test_return test_binary_replaceq(void) {
1508    return test_binary_replace_impl("test_binary_replaceq",
1509                                    PROTOCOL_BINARY_CMD_REPLACEQ);
1510}
1511
1512static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1513    union {
1514        protocol_binary_request_no_extras request;
1515        protocol_binary_response_no_extras response;
1516        char bytes[1024];
1517    } send, receive;
1518    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1519                             key, strlen(key), NULL, 0);
1520
1521    safe_send(send.bytes, len, false);
1522    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1523    validate_response_header(&receive.response, cmd,
1524                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1525    len = storage_command(send.bytes, sizeof(send.bytes),
1526                          PROTOCOL_BINARY_CMD_ADD,
1527                          key, strlen(key), NULL, 0, 0, 0);
1528    safe_send(send.bytes, len, false);
1529    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1530    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1531                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1532
1533    len = raw_command(send.bytes, sizeof(send.bytes),
1534                      cmd, key, strlen(key), NULL, 0);
1535    safe_send(send.bytes, len, false);
1536
1537    if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1538        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1539        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1540                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1541    }
1542
1543    safe_send(send.bytes, len, false);
1544    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1545    validate_response_header(&receive.response, cmd,
1546                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1547
1548    return TEST_PASS;
1549}
1550
1551static enum test_return test_binary_delete(void) {
1552    return test_binary_delete_impl("test_binary_delete",
1553                                   PROTOCOL_BINARY_CMD_DELETE);
1554}
1555
1556static enum test_return test_binary_deleteq(void) {
1557    return test_binary_delete_impl("test_binary_deleteq",
1558                                   PROTOCOL_BINARY_CMD_DELETEQ);
1559}
1560
1561static enum test_return test_binary_delete_cas_impl(const char *key, bool bad) {
1562    union {
1563        protocol_binary_request_no_extras request;
1564        protocol_binary_response_no_extras response;
1565        char bytes[1024];
1566    } send, receive;
1567    size_t len;
1568    len = storage_command(send.bytes, sizeof(send.bytes),
1569                          PROTOCOL_BINARY_CMD_SET,
1570                          key, strlen(key), NULL, 0, 0, 0);
1571    safe_send(send.bytes, len, false);
1572    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1573    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1574                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1575    len = raw_command(send.bytes, sizeof(send.bytes),
1576                       PROTOCOL_BINARY_CMD_DELETE, key, strlen(key), NULL, 0);
1577
1578    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1579    if (bad) {
1580        ++send.request.message.header.request.cas;
1581    }
1582    safe_send(send.bytes, len, false);
1583    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1584    if (bad) {
1585        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1586                                 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1587    } else {
1588        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1589                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1590    }
1591
1592    return TEST_PASS;
1593}
1594
1595
1596static enum test_return test_binary_delete_cas(void) {
1597    return test_binary_delete_cas_impl("test_binary_delete_cas", false);
1598}
1599
1600static enum test_return test_binary_delete_bad_cas(void) {
1601    return test_binary_delete_cas_impl("test_binary_delete_bad_cas", true);
1602}
1603
1604static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1605    union {
1606        protocol_binary_request_no_extras request;
1607        protocol_binary_response_no_extras response;
1608        char bytes[1024];
1609    } send, receive;
1610    int ii;
1611    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1612                             key, strlen(key), NULL, 0);
1613
1614    safe_send(send.bytes, len, false);
1615    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1616    validate_response_header(&receive.response, cmd,
1617                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1618
1619    len = storage_command(send.bytes, sizeof(send.bytes),
1620                          PROTOCOL_BINARY_CMD_ADD,
1621                          key, strlen(key), NULL, 0,
1622                          0, 0);
1623    safe_send(send.bytes, len, false);
1624    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1625    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1626                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1627
1628    /* run a little pipeline test ;-) */
1629    len = 0;
1630    for (ii = 0; ii < 10; ++ii) {
1631        union {
1632            protocol_binary_request_no_extras request;
1633            char bytes[1024];
1634        } temp;
1635        size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1636                               cmd, key, strlen(key), NULL, 0);
1637        memcpy(send.bytes + len, temp.bytes, l);
1638        len += l;
1639    }
1640
1641    safe_send(send.bytes, len, false);
1642    for (ii = 0; ii < 10; ++ii) {
1643        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1644        validate_response_header(&receive.response, cmd,
1645                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1646    }
1647
1648    return TEST_PASS;
1649}
1650
1651static enum test_return test_binary_get(void) {
1652    return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1653}
1654
1655static enum test_return test_binary_getk(void) {
1656    return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1657}
1658
1659static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1660    const char *missing = "test_binary_getq_missing";
1661    union {
1662        protocol_binary_request_no_extras request;
1663        protocol_binary_response_no_extras response;
1664        char bytes[1024];
1665    } send, temp, receive;
1666    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1667                                 PROTOCOL_BINARY_CMD_ADD,
1668                                 key, strlen(key), NULL, 0,
1669                                 0, 0);
1670    size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1671                             missing, strlen(missing), NULL, 0);
1672    /* I need to change the first opaque so that I can separate the two
1673     * return packets */
1674    temp.request.message.header.request.opaque = 0xfeedface;
1675    memcpy(send.bytes + len, temp.bytes, len2);
1676    len += len2;
1677
1678    len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1679                       key, strlen(key), NULL, 0);
1680    memcpy(send.bytes + len, temp.bytes, len2);
1681    len += len2;
1682
1683    safe_send(send.bytes, len, false);
1684    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1685    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1686                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1687    /* The first GETQ shouldn't return anything */
1688    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1689    validate_response_header(&receive.response, cmd,
1690                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1691
1692    return TEST_PASS;
1693}
1694
1695static enum test_return test_binary_getq(void) {
1696    return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1697}
1698
1699static enum test_return test_binary_getkq(void) {
1700    return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1701}
1702
1703static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1704    union {
1705        protocol_binary_request_no_extras request;
1706        protocol_binary_response_no_extras response_header;
1707        protocol_binary_response_incr response;
1708        char bytes[1024];
1709    } send, receive;
1710    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1711                                    key, strlen(key), 1, 0, 0);
1712
1713    int ii;
1714    for (ii = 0; ii < 10; ++ii) {
1715        safe_send(send.bytes, len, false);
1716        if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1717            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1718            validate_response_header(&receive.response_header, cmd,
1719                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1720            cb_assert(ntohll(receive.response.message.body.value) == ii);
1721        }
1722    }
1723
1724    if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1725        test_binary_noop();
1726    }
1727    return TEST_PASS;
1728}
1729
1730static enum test_return test_binary_incr(void) {
1731    return test_binary_incr_impl("test_binary_incr",
1732                                 PROTOCOL_BINARY_CMD_INCREMENT);
1733}
1734
1735static enum test_return test_binary_incrq(void) {
1736    return test_binary_incr_impl("test_binary_incrq",
1737                                 PROTOCOL_BINARY_CMD_INCREMENTQ);
1738}
1739
1740static enum test_return test_binary_incr_invalid_cas_impl(const char* key, uint8_t cmd) {
1741    union {
1742        protocol_binary_request_no_extras request;
1743        protocol_binary_response_no_extras response_header;
1744        protocol_binary_response_incr response;
1745        char bytes[1024];
1746    } send, receive;
1747    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1748                                    key, strlen(key), 1, 0, 0);
1749
1750    send.request.message.header.request.cas = 5;
1751    safe_send(send.bytes, len, false);
1752    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1753    validate_response_header(&receive.response_header, cmd,
1754                             PROTOCOL_BINARY_RESPONSE_EINVAL);
1755    return TEST_PASS;
1756}
1757
1758static enum test_return test_binary_invalid_cas_incr(void) {
1759    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1760                                             PROTOCOL_BINARY_CMD_INCREMENT);
1761}
1762
1763static enum test_return test_binary_invalid_cas_incrq(void) {
1764    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1765                                             PROTOCOL_BINARY_CMD_INCREMENTQ);
1766}
1767
1768static enum test_return test_binary_invalid_cas_decr(void) {
1769    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1770                                             PROTOCOL_BINARY_CMD_DECREMENT);
1771}
1772
1773static enum test_return test_binary_invalid_cas_decrq(void) {
1774    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1775                                             PROTOCOL_BINARY_CMD_DECREMENTQ);
1776}
1777
1778static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1779    union {
1780        protocol_binary_request_no_extras request;
1781        protocol_binary_response_no_extras response_header;
1782        protocol_binary_response_decr response;
1783        char bytes[1024];
1784    } send, receive;
1785    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1786                                    key, strlen(key), 1, 9, 0);
1787
1788    int ii;
1789    for (ii = 9; ii >= 0; --ii) {
1790        safe_send(send.bytes, len, false);
1791        if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1792            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1793            validate_response_header(&receive.response_header, cmd,
1794                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1795            cb_assert(ntohll(receive.response.message.body.value) == ii);
1796        }
1797    }
1798
1799    /* decr on 0 should not wrap */
1800    safe_send(send.bytes, len, false);
1801    if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1802        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1803        validate_response_header(&receive.response_header, cmd,
1804                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1805        cb_assert(ntohll(receive.response.message.body.value) == 0);
1806    } else {
1807        test_binary_noop();
1808    }
1809
1810    return TEST_PASS;
1811}
1812
1813static enum test_return test_binary_decr(void) {
1814    return test_binary_decr_impl("test_binary_decr",
1815                                 PROTOCOL_BINARY_CMD_DECREMENT);
1816}
1817
1818static enum test_return test_binary_decrq(void) {
1819    return test_binary_decr_impl("test_binary_decrq",
1820                                 PROTOCOL_BINARY_CMD_DECREMENTQ);
1821}
1822
1823static enum test_return test_binary_version(void) {
1824    union {
1825        protocol_binary_request_no_extras request;
1826        protocol_binary_response_no_extras response;
1827        char bytes[1024];
1828    } buffer;
1829
1830    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1831                             PROTOCOL_BINARY_CMD_VERSION,
1832                             NULL, 0, NULL, 0);
1833
1834    safe_send(buffer.bytes, len, false);
1835    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1836    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1837                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1838
1839    return TEST_PASS;
1840}
1841
1842static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1843    union {
1844        protocol_binary_request_no_extras request;
1845        protocol_binary_response_no_extras response;
1846        char bytes[1024];
1847    } send, receive;
1848    int ii;
1849
1850    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1851                                 PROTOCOL_BINARY_CMD_ADD,
1852                                 key, strlen(key), NULL, 0, 0, 0);
1853    safe_send(send.bytes, len, false);
1854    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1855    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1856                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1857
1858    len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1859    safe_send(send.bytes, len, false);
1860    if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1861        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1862        validate_response_header(&receive.response, cmd,
1863                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1864    }
1865
1866    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1867                      key, strlen(key), NULL, 0);
1868    safe_send(send.bytes, len, false);
1869    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1870    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1871                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1872
1873#ifdef WIN32
1874    Sleep(2000);
1875#else
1876    sleep(2);
1877#endif
1878    safe_send(send.bytes, len, false);
1879    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1880    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1881                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1882
1883    for (ii = 0; ii < 2; ++ii) {
1884        len = storage_command(send.bytes, sizeof(send.bytes),
1885                              PROTOCOL_BINARY_CMD_ADD,
1886                              key, strlen(key), NULL, 0, 0, 0);
1887        safe_send(send.bytes, len, false);
1888        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1889        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1890                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1891
1892        len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1893        safe_send(send.bytes, len, false);
1894        if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1895            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1896            validate_response_header(&receive.response, cmd,
1897                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1898        }
1899
1900        len = raw_command(send.bytes, sizeof(send.bytes),
1901                          PROTOCOL_BINARY_CMD_GET,
1902                          key, strlen(key), NULL, 0);
1903        safe_send(send.bytes, len, false);
1904        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1905        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1906                                 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1907    }
1908
1909    return TEST_PASS;
1910}
1911
1912static enum test_return test_binary_flush(void) {
1913    return test_binary_flush_impl("test_binary_flush",
1914                                  PROTOCOL_BINARY_CMD_FLUSH);
1915}
1916
1917static enum test_return test_binary_flushq(void) {
1918    return test_binary_flush_impl("test_binary_flushq",
1919                                  PROTOCOL_BINARY_CMD_FLUSHQ);
1920}
1921
1922static enum test_return test_binary_cas(void) {
1923    union {
1924        protocol_binary_request_no_extras request;
1925        protocol_binary_response_no_extras response;
1926        char bytes[1024];
1927    } send, receive;
1928    uint64_t value = 0xdeadbeefdeadcafe;
1929    size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1930                               0, false);
1931    safe_send(send.bytes, len, false);
1932    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1933    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1934                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1935
1936    len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1937                          "FOO", 3, &value, sizeof(value), 0, 0);
1938
1939    send.request.message.header.request.cas = 0x7ffffff;
1940    safe_send(send.bytes, len, false);
1941    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1942    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1943                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1944
1945    send.request.message.header.request.cas = 0x0;
1946    safe_send(send.bytes, len, false);
1947    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1948    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1949                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1950
1951    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1952    safe_send(send.bytes, len, false);
1953    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1954    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1955                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1956
1957    send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
1958    safe_send(send.bytes, len, false);
1959    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1960    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1961                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1962    return TEST_PASS;
1963}
1964
1965static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
1966    union {
1967        protocol_binary_request_no_extras request;
1968        protocol_binary_response_no_extras response;
1969        char bytes[1024];
1970    } send, receive;
1971    const char *value = "world";
1972    char *ptr;
1973    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1974                              key, strlen(key), value, strlen(value));
1975
1976
1977    safe_send(send.bytes, len, false);
1978    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1979    validate_response_header(&receive.response, cmd,
1980                             PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1981
1982    len = storage_command(send.bytes, sizeof(send.bytes),
1983                          PROTOCOL_BINARY_CMD_ADD,
1984                          key, strlen(key), value, strlen(value), 0, 0);
1985    safe_send(send.bytes, len, false);
1986    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1987    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1988                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1989
1990    len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1991                      key, strlen(key), value, strlen(value));
1992    safe_send(send.bytes, len, false);
1993
1994    if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1995        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1996        validate_response_header(&receive.response, cmd,
1997                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1998    } else {
1999        len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
2000                          NULL, 0, NULL, 0);
2001        safe_send(send.bytes, len, false);
2002        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2003        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
2004                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2005    }
2006
2007    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
2008                      key, strlen(key), NULL, 0);
2009
2010    safe_send(send.bytes, len, false);
2011    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2012    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
2013                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2014
2015    cb_assert(receive.response.message.header.response.keylen == strlen(key));
2016    cb_assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
2017
2018    ptr = receive.bytes;
2019    ptr += sizeof(receive.response);
2020    ptr += 4;
2021
2022    cb_assert(memcmp(ptr, key, strlen(key)) == 0);
2023    ptr += strlen(key);
2024    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2025    ptr += strlen(value);
2026    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2027
2028    return TEST_PASS;
2029}
2030
2031static enum test_return test_binary_append(void) {
2032    return test_binary_concat_impl("test_binary_append",
2033                                   PROTOCOL_BINARY_CMD_APPEND);
2034}
2035
2036static enum test_return test_binary_prepend(void) {
2037    return test_binary_concat_impl("test_binary_prepend",
2038                                   PROTOCOL_BINARY_CMD_PREPEND);
2039}
2040
2041static enum test_return test_binary_appendq(void) {
2042    return test_binary_concat_impl("test_binary_appendq",
2043                                   PROTOCOL_BINARY_CMD_APPENDQ);
2044}
2045
2046static enum test_return test_binary_prependq(void) {
2047    return test_binary_concat_impl("test_binary_prependq",
2048                                   PROTOCOL_BINARY_CMD_PREPENDQ);
2049}
2050
2051static enum test_return test_binary_stat(void) {
2052    union {
2053        protocol_binary_request_no_extras request;
2054        protocol_binary_response_no_extras response;
2055        char bytes[1024];
2056    } buffer;
2057
2058    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2059                             PROTOCOL_BINARY_CMD_STAT,
2060                             NULL, 0, NULL, 0);
2061
2062    safe_send(buffer.bytes, len, false);
2063    do {
2064        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2065        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
2066                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2067    } while (buffer.response.message.header.response.keylen != 0);
2068
2069    return TEST_PASS;
2070}
2071
2072static enum test_return test_binary_scrub(void) {
2073    union {
2074        protocol_binary_request_no_extras request;
2075        protocol_binary_response_no_extras response;
2076        char bytes[1024];
2077    } buffer;
2078
2079    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2080                             PROTOCOL_BINARY_CMD_SCRUB,
2081                             NULL, 0, NULL, 0);
2082
2083    safe_send(buffer.bytes, len, false);
2084    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2085    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
2086                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2087
2088    return TEST_PASS;
2089}
2090
2091
2092volatile bool hickup_thread_running;
2093
2094static void binary_hickup_recv_verification_thread(void *arg) {
2095    protocol_binary_response_no_extras *response = malloc(65*1024);
2096    if (response != NULL) {
2097        while (safe_recv_packet(response, 65*1024)) {
2098            /* Just validate the packet format */
2099            validate_response_header(response,
2100                                     response->message.header.response.opcode,
2101                                     response->message.header.response.status);
2102        }
2103        free(response);
2104    }
2105    hickup_thread_running = false;
2106    allow_closed_read = false;
2107}
2108
2109static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
2110    off_t offset = 0;
2111    char *key[256];
2112    uint64_t value = 0xfeedfacedeadbeef;
2113
2114    while (hickup_thread_running &&
2115           offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
2116        union {
2117            protocol_binary_request_no_extras request;
2118            char bytes[65 * 1024];
2119        } command;
2120        uint8_t cmd = (uint8_t)(rand() & 0xff);
2121        size_t len;
2122        size_t keylen = (rand() % 250) + 1;
2123
2124        switch (cmd) {
2125        case PROTOCOL_BINARY_CMD_ADD:
2126        case PROTOCOL_BINARY_CMD_ADDQ:
2127        case PROTOCOL_BINARY_CMD_REPLACE:
2128        case PROTOCOL_BINARY_CMD_REPLACEQ:
2129        case PROTOCOL_BINARY_CMD_SET:
2130        case PROTOCOL_BINARY_CMD_SETQ:
2131            len = storage_command(command.bytes, sizeof(command.bytes), cmd,
2132                                  key, keylen , &value, sizeof(value),
2133                                  0, 0);
2134            break;
2135        case PROTOCOL_BINARY_CMD_APPEND:
2136        case PROTOCOL_BINARY_CMD_APPENDQ:
2137        case PROTOCOL_BINARY_CMD_PREPEND:
2138        case PROTOCOL_BINARY_CMD_PREPENDQ:
2139            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2140                              key, keylen, &value, sizeof(value));
2141            break;
2142        case PROTOCOL_BINARY_CMD_FLUSH:
2143        case PROTOCOL_BINARY_CMD_FLUSHQ:
2144            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2145                              NULL, 0, NULL, 0);
2146            break;
2147        case PROTOCOL_BINARY_CMD_NOOP:
2148            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2149                              NULL, 0, NULL, 0);
2150            break;
2151        case PROTOCOL_BINARY_CMD_DELETE:
2152        case PROTOCOL_BINARY_CMD_DELETEQ:
2153            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2154                             key, keylen, NULL, 0);
2155            break;
2156        case PROTOCOL_BINARY_CMD_DECREMENT:
2157        case PROTOCOL_BINARY_CMD_DECREMENTQ:
2158        case PROTOCOL_BINARY_CMD_INCREMENT:
2159        case PROTOCOL_BINARY_CMD_INCREMENTQ:
2160            len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
2161                                     key, keylen, 1, 0, 0);
2162            break;
2163        case PROTOCOL_BINARY_CMD_VERSION:
2164            len = raw_command(command.bytes, sizeof(command.bytes),
2165                             PROTOCOL_BINARY_CMD_VERSION,
2166                             NULL, 0, NULL, 0);
2167            break;
2168        case PROTOCOL_BINARY_CMD_GET:
2169        case PROTOCOL_BINARY_CMD_GETK:
2170        case PROTOCOL_BINARY_CMD_GETKQ:
2171        case PROTOCOL_BINARY_CMD_GETQ:
2172            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2173                             key, keylen, NULL, 0);
2174            break;
2175
2176        case PROTOCOL_BINARY_CMD_STAT:
2177            len = raw_command(command.bytes, sizeof(command.bytes),
2178                              PROTOCOL_BINARY_CMD_STAT,
2179                              NULL, 0, NULL, 0);
2180            break;
2181
2182        default:
2183            /* don't run commands we don't know */
2184            continue;
2185        }
2186
2187        if ((len + offset) < buffersize) {
2188            memcpy(((char*)buffer) + offset, command.bytes, len);
2189            offset += (off_t)len;
2190        } else {
2191            break;
2192        }
2193    }
2194    safe_send(buffer, offset, true);
2195
2196    return TEST_PASS;
2197}
2198
2199static enum test_return test_binary_pipeline_hickup(void)
2200{
2201    size_t buffersize = 65 * 1024;
2202    void *buffer = malloc(buffersize);
2203    int ii;
2204    cb_thread_t tid;
2205    int ret;
2206    size_t len;
2207
2208    allow_closed_read = true;
2209    hickup_thread_running = true;
2210    if ((ret = cb_create_thread(&tid, binary_hickup_recv_verification_thread, NULL, 0)) != 0) {
2211        fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
2212        free(buffer);
2213        return TEST_FAIL;
2214    }
2215
2216    /* Allow the thread to start */
2217#ifdef WIN32
2218    Sleep(1);
2219#else
2220    usleep(250);
2221#endif
2222
2223    srand((int)time(NULL));
2224    for (ii = 0; ii < 2; ++ii) {
2225        test_binary_pipeline_hickup_chunk(buffer, buffersize);
2226    }
2227
2228    /* send quitq to shut down the read thread ;-) */
2229    len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
2230                      NULL, 0, NULL, 0);
2231    safe_send(buffer, len, false);
2232
2233    cb_join_thread(tid);
2234    free(buffer);
2235
2236    reconnect_to_server("127.0.0.1", false);
2237    return TEST_PASS;
2238}
2239
2240static enum test_return test_binary_ioctl(void) {
2241    union {
2242        protocol_binary_request_no_extras request;
2243        protocol_binary_response_no_extras response;
2244        char bytes[1024];
2245    } buffer;
2246
2247    /* NULL key is invalid. */
2248    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2249                             PROTOCOL_BINARY_CMD_IOCTL_SET, NULL, 0, NULL, 0);
2250
2251    safe_send(buffer.bytes, len, false);
2252    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2253    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2254                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2255
2256    /* release_free_memory always returns OK, regardless of how much was freed.*/
2257    {
2258        char cmd[] = "release_free_memory";
2259        len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2260                          PROTOCOL_BINARY_CMD_IOCTL_SET, cmd, strlen(cmd),
2261                          NULL, 0);
2262
2263        safe_send(buffer.bytes, len, false);
2264        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2265        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2266                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2267    }
2268
2269    return TEST_PASS;
2270}
2271
2272static enum test_return test_binary_verbosity(void) {
2273    union {
2274        protocol_binary_request_verbosity request;
2275        protocol_binary_response_no_extras response;
2276        char bytes[1024];
2277    } buffer;
2278
2279    int ii;
2280    for (ii = 10; ii > -1; --ii) {
2281        size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2282                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2283                                 NULL, 0, NULL, 0);
2284        buffer.request.message.header.request.extlen = 4;
2285        buffer.request.message.header.request.bodylen = ntohl(4);
2286        buffer.request.message.body.level = (uint32_t)ntohl(ii);
2287        safe_send(buffer.bytes, len + sizeof(4), false);
2288        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2289        validate_response_header(&buffer.response,
2290                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2291                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2292    }
2293
2294    return TEST_PASS;
2295}
2296
2297static enum test_return validate_object(const char *key, const char *value) {
2298    union {
2299        protocol_binary_request_no_extras request;
2300        protocol_binary_response_no_extras response;
2301        char bytes[1024];
2302    } send, receive;
2303    char *ptr;
2304    size_t len = raw_command(send.bytes, sizeof(send.bytes),
2305                             PROTOCOL_BINARY_CMD_GET,
2306                             key, strlen(key), NULL, 0);
2307    safe_send(send.bytes, len, false);
2308    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2309    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
2310                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2311    cb_assert(receive.response.message.header.response.bodylen - 4 == strlen(value));
2312    ptr = receive.bytes + sizeof(receive.response) + 4;
2313    cb_assert(memcmp(value, ptr, strlen(value)) == 0);
2314
2315    return TEST_PASS;
2316}
2317
2318static enum test_return store_object(const char *key, char *value) {
2319    union {
2320        protocol_binary_request_no_extras request;
2321        protocol_binary_response_no_extras response;
2322        char bytes[1024];
2323    } send, receive;
2324    size_t len = storage_command(send.bytes, sizeof(send.bytes),
2325                                 PROTOCOL_BINARY_CMD_SET,
2326                                 key, strlen(key), value, strlen(value),
2327                                 0, 0);
2328
2329    safe_send(send.bytes, len, false);
2330    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2331    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2332                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2333
2334    validate_object(key, value);
2335    return TEST_PASS;
2336}
2337
2338static enum test_return test_binary_read(void) {
2339    union {
2340        protocol_binary_request_read request;
2341        protocol_binary_response_read response;
2342        char bytes[1024];
2343    } buffer;
2344    size_t len;
2345    char *ptr;
2346
2347    store_object("hello", "world");
2348
2349    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2350                      read_command, "hello",
2351                      strlen("hello"), NULL, 0);
2352    buffer.request.message.body.offset = htonl(1);
2353    buffer.request.message.body.length = htonl(3);
2354
2355    safe_send(buffer.bytes, len, false);
2356    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2357    validate_response_header(&buffer.response, read_command,
2358                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2359    cb_assert(buffer.response.message.header.response.bodylen == 3);
2360    ptr = buffer.bytes + sizeof(buffer.response);
2361    cb_assert(memcmp(ptr, "orl", 3) == 0);
2362
2363
2364    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2365                      read_command, "hello",
2366                      strlen("hello"), NULL, 0);
2367    buffer.request.message.body.offset = htonl(7);
2368    buffer.request.message.body.length = htonl(2);
2369    safe_send(buffer.bytes, len, false);
2370    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2371    validate_response_header(&buffer.response, read_command,
2372                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2373
2374    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2375                      read_command, "myhello",
2376                      strlen("myhello"), NULL, 0);
2377    buffer.request.message.body.offset = htonl(0);
2378    buffer.request.message.body.length = htonl(5);
2379
2380    safe_send(buffer.bytes, len, false);
2381    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2382    validate_response_header(&buffer.response, read_command,
2383                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2384    return TEST_PASS;
2385}
2386
2387static enum test_return test_binary_write(void) {
2388    union {
2389        protocol_binary_request_read request;
2390        protocol_binary_response_read response;
2391        char bytes[1024];
2392    } buffer;
2393    size_t len;
2394
2395    store_object("hello", "world");
2396
2397    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2398                             write_command, "hello",
2399                             strlen("hello"), "bubba", 5);
2400    buffer.request.message.body.offset = htonl(0);
2401    buffer.request.message.body.length = htonl(5);
2402
2403    safe_send(buffer.bytes, len, false);
2404    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2405    validate_response_header(&buffer.response, write_command,
2406                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2407    validate_object("hello", "bubba");
2408
2409    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2410                             write_command, "hello",
2411                             strlen("hello"), "zz", 2);
2412    buffer.request.message.body.offset = htonl(2);
2413    buffer.request.message.body.length = htonl(2);
2414
2415    safe_send(buffer.bytes, len, false);
2416    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2417    validate_response_header(&buffer.response, write_command,
2418                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2419    validate_object("hello", "buzza");
2420
2421    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2422                             write_command, "hello",
2423                             strlen("hello"), "zz", 2);
2424    buffer.request.message.body.offset = htonl(7);
2425    buffer.request.message.body.length = htonl(2);
2426
2427    safe_send(buffer.bytes, len, false);
2428    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2429    validate_response_header(&buffer.response, write_command,
2430                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2431
2432    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2433                             write_command, "hello",
2434                             strlen("hello"), "bb", 2);
2435    buffer.request.message.body.offset = htonl(2);
2436    buffer.request.message.body.length = htonl(2);
2437    buffer.request.message.header.request.cas = 1;
2438
2439    safe_send(buffer.bytes, len, false);
2440    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2441    validate_response_header(&buffer.response, write_command,
2442                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2443
2444    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2445                      write_command, "myhello",
2446                      strlen("myhello"), "bubba", 5);
2447    buffer.request.message.body.offset = htonl(0);
2448    buffer.request.message.body.length = htonl(5);
2449
2450    safe_send(buffer.bytes, len, false);
2451    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2452    validate_response_header(&buffer.response, write_command,
2453                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2454    return TEST_PASS;
2455}
2456
2457static enum test_return test_binary_bad_tap_ttl(void) {
2458    union {
2459        protocol_binary_request_tap_flush request;
2460        protocol_binary_response_no_extras response;
2461        char bytes[1024];
2462    } buffer;
2463
2464    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2465                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2466                             NULL, 0, NULL, 0);
2467
2468    buffer.request.message.header.request.extlen = 8;
2469    buffer.request.message.header.request.bodylen = ntohl(8);
2470    buffer.request.message.body.tap.enginespecific_length = 0;
2471    buffer.request.message.body.tap.flags = 0;
2472    buffer.request.message.body.tap.ttl = 0;
2473    buffer.request.message.body.tap.res1 = 0;
2474    buffer.request.message.body.tap.res2 = 0;
2475    buffer.request.message.body.tap.res3 = 0;
2476    len += 8;
2477
2478    safe_send(buffer.bytes, len, false);
2479    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2480    validate_response_header(&buffer.response,
2481                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2482                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2483    return TEST_PASS;
2484}
2485
2486static enum test_return test_binary_hello(void) {
2487    union {
2488        protocol_binary_request_hello request;
2489        protocol_binary_response_hello response;
2490        char bytes[1024];
2491    } buffer;
2492    const char *useragent = "hello world";
2493    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2494    uint16_t *ptr;
2495    size_t len;
2496
2497    memset(buffer.bytes, 0, sizeof(buffer.bytes));
2498
2499    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2500                      PROTOCOL_BINARY_CMD_HELLO,
2501                      useragent, strlen(useragent), &feature,
2502                      sizeof(feature));
2503
2504    safe_send(buffer.bytes, len, false);
2505    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2506    validate_response_header(&buffer.response,
2507                             PROTOCOL_BINARY_CMD_HELLO,
2508                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2509
2510    cb_assert(buffer.response.message.header.response.bodylen == 2);
2511    ptr = (uint16_t*)(buffer.bytes + sizeof(buffer.response));
2512    cb_assert(ntohs(*ptr) == PROTOCOL_BINARY_FEATURE_DATATYPE);
2513
2514    feature = 0xffff;
2515    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2516                             PROTOCOL_BINARY_CMD_HELLO,
2517                             useragent, strlen(useragent), &feature,
2518                             sizeof(feature));
2519
2520    safe_send(buffer.bytes, len, false);
2521    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2522    validate_response_header(&buffer.response,
2523                             PROTOCOL_BINARY_CMD_HELLO,
2524                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2525    cb_assert(buffer.response.message.header.response.bodylen == 0);
2526
2527
2528    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2529                             PROTOCOL_BINARY_CMD_HELLO,
2530                             useragent, strlen(useragent), &feature,
2531                             sizeof(feature) - 1);
2532
2533    safe_send(buffer.bytes, len, false);
2534    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2535    validate_response_header(&buffer.response,
2536                             PROTOCOL_BINARY_CMD_HELLO,
2537                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2538
2539    return TEST_PASS;
2540}
2541
2542static void set_datatype_feature(bool enable) {
2543    union {
2544        protocol_binary_request_hello request;
2545        protocol_binary_response_hello response;
2546        char bytes[1024];
2547    } buffer;
2548    const char *useragent = "testapp";
2549    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2550    size_t len = strlen(useragent);
2551
2552    memset(buffer.bytes, 0, sizeof(buffer));
2553    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2554    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_HELLO;
2555    buffer.request.message.header.request.keylen = htons((uint16_t)len);
2556    if (enable) {
2557        buffer.request.message.header.request.bodylen = htonl((uint32_t)len + 2);
2558    } else {
2559        buffer.request.message.header.request.bodylen = htonl((uint32_t)len);
2560    }
2561    memcpy(buffer.bytes + 24, useragent, len);
2562    memcpy(buffer.bytes + 24 + len, &feature, 2);
2563
2564    safe_send(buffer.bytes,
2565              sizeof(buffer.request) + ntohl(buffer.request.message.header.request.bodylen), false);
2566
2567    safe_recv(&buffer.response, sizeof(buffer.response));
2568    len = ntohl(buffer.response.message.header.response.bodylen);
2569    if (enable) {
2570        cb_assert(len == 2);
2571        safe_recv(&feature, sizeof(feature));
2572        cb_assert(feature == htons(PROTOCOL_BINARY_FEATURE_DATATYPE));
2573    } else {
2574        cb_assert(len == 0);
2575    }
2576}
2577
2578static void store_object_w_datatype(const char *key,
2579                                    const void *data, size_t datalen,
2580                                    bool deflate, bool json)
2581{
2582    protocol_binary_request_no_extras request;
2583    int keylen = (int)strlen(key);
2584    char extra[8] = { 0 };
2585    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2586    if (deflate) {
2587        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2588    }
2589
2590    if (json) {
2591        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2592    }
2593
2594    memset(request.bytes, 0, sizeof(request));
2595    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2596    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_SETQ;
2597    request.message.header.request.datatype = datatype;
2598    request.message.header.request.extlen = 8;
2599    request.message.header.request.keylen = htons((uint16_t)keylen);
2600    request.message.header.request.bodylen = htonl((uint32_t)(keylen + datalen + 8));
2601
2602    safe_send(&request.bytes, sizeof(request.bytes), false);
2603    safe_send(extra, sizeof(extra), false);
2604    safe_send(key, strlen(key), false);
2605    safe_send(data, datalen, false);
2606}
2607
2608static void get_object_w_datatype(const char *key,
2609                                  const void *data, size_t datalen,
2610                                  bool deflate, bool json,
2611                                  bool conversion)
2612{
2613    protocol_binary_response_no_extras response;
2614    protocol_binary_request_no_extras request;
2615    char *body;
2616    int keylen = (int)strlen(key);
2617    uint32_t flags;
2618    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2619    uint32_t len;
2620
2621    if (deflate) {
2622        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2623    }
2624
2625    if (json) {
2626        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2627    }
2628
2629    memset(request.bytes, 0, sizeof(request));
2630    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2631    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET;
2632    request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
2633    request.message.header.request.keylen = htons((uint16_t)keylen);
2634    request.message.header.request.bodylen = htonl(keylen);
2635
2636    safe_send(&request.bytes, sizeof(request.bytes), false);
2637    safe_send(key, strlen(key), false);
2638
2639    safe_recv(&response.bytes, sizeof(response.bytes));
2640    if (ntohs(response.message.header.response.status != PROTOCOL_BINARY_RESPONSE_SUCCESS)) {
2641        fprintf(stderr, "Failed to retrieve object!: %d\n",
2642                (int)ntohs(response.message.header.response.status));
2643        abort();
2644    }
2645
2646    len = ntohl(response.message.header.response.bodylen);
2647    cb_assert(len > 4);
2648    safe_recv(&flags, sizeof(flags));
2649    len -= 4;
2650    cb_assert((body = malloc(len)) != NULL);
2651    safe_recv(body, len);
2652
2653    if (conversion) {
2654        cb_assert(response.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
2655    } else {
2656        cb_assert(response.message.header.response.datatype == datatype);
2657    }
2658
2659    cb_assert(len == datalen);
2660    cb_assert(memcmp(data, body, len) == 0);
2661    free(body);
2662}
2663
2664static enum test_return test_binary_datatype_json(void) {
2665    const char body[] = "{ \"value\" : 1234123412 }";
2666    set_datatype_feature(true);
2667    store_object_w_datatype("myjson", body, strlen(body), false, true);
2668
2669    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2670
2671    set_datatype_feature(false);
2672    get_object_w_datatype("myjson", body, strlen(body), false, true, true);
2673
2674    return TEST_PASS;
2675}
2676
2677static enum test_return test_binary_datatype_json_without_support(void) {
2678    const char body[] = "{ \"value\" : 1234123412 }";
2679    set_datatype_feature(false);
2680    store_object_w_datatype("myjson", body, strlen(body), false, false);
2681
2682    get_object_w_datatype("myjson", body, strlen(body), false, false, false);
2683
2684    set_datatype_feature(true);
2685    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2686
2687    return TEST_PASS;
2688}
2689
2690static enum test_return test_binary_datatype_compressed(void) {
2691    const char inflated[] = "aaaaaaaaabbbbbbbccccccdddddd";
2692    size_t inflated_len = strlen(inflated);
2693    char deflated[256];
2694    size_t deflated_len = 256;
2695    snappy_status status;
2696
2697    status = snappy_compress(inflated, inflated_len,
2698                             deflated, &deflated_len);
2699
2700    if (status != SNAPPY_OK) {
2701        fprintf(stderr, "Failed to compress data\n");
2702        abort();
2703    }
2704
2705    set_datatype_feature(true);
2706    store_object_w_datatype("mycompressed", deflated, deflated_len,
2707                            true, false);
2708
2709    get_object_w_datatype("mycompressed", deflated, deflated_len,
2710                          true, false, false);
2711
2712    set_datatype_feature(false);
2713    get_object_w_datatype("mycompressed", inflated, inflated_len,
2714                          true, false, true);
2715
2716    return TEST_PASS;
2717}
2718
2719static enum test_return test_binary_datatype_compressed_json(void) {
2720    const char inflated[] = "{ \"value\" : \"aaaaaaaaabbbbbbbccccccdddddd\" }";
2721    size_t inflated_len = strlen(inflated);
2722    char deflated[256];
2723    size_t deflated_len = 256;
2724    snappy_status status;
2725
2726    status = snappy_compress(inflated, inflated_len,
2727                             deflated, &deflated_len);
2728
2729    if (status != SNAPPY_OK) {
2730        fprintf(stderr, "Failed to compress data\n");
2731        abort();
2732    }
2733
2734    set_datatype_feature(true);
2735    store_object_w_datatype("mycompressedjson", deflated, deflated_len,
2736                            true, true);
2737
2738    get_object_w_datatype("mycompressedjson", deflated, deflated_len,
2739                          true, true, false);
2740
2741    set_datatype_feature(false);
2742    get_object_w_datatype("mycompressedjson", inflated, inflated_len,
2743                          true, true, true);
2744
2745    return TEST_PASS;
2746}
2747
2748static enum test_return test_binary_invalid_datatype(void) {
2749    protocol_binary_request_no_extras request;
2750    union {
2751        protocol_binary_response_no_extras response;
2752        char buffer[1024];
2753    } res;
2754    uint16_t code;
2755
2756    set_datatype_feature(false);
2757
2758    memset(request.bytes, 0, sizeof(request));
2759    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2760    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_NOOP;
2761    request.message.header.request.datatype = 1;
2762
2763    safe_send(&request.bytes, sizeof(request.bytes), false);
2764    safe_recv_packet(res.buffer, sizeof(res.buffer));
2765
2766    code = res.response.message.header.response.status;
2767    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2768
2769    reconnect_to_server("127.0.0.1", false);
2770
2771    set_datatype_feature(false);
2772    request.message.header.request.datatype = 4;
2773    safe_send(&request.bytes, sizeof(request.bytes), false);
2774    safe_recv_packet(res.buffer, sizeof(res.buffer));
2775    code = res.response.message.header.response.status;
2776    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2777
2778    reconnect_to_server("127.0.0.1", false);
2779
2780    return TEST_PASS;
2781}
2782
2783static uint64_t get_session_ctrl_token(void) {
2784    union {
2785        protocol_binary_request_get_ctrl_token request;
2786        protocol_binary_response_get_ctrl_token response;
2787        char bytes[1024];
2788    } buffer;
2789    uint64_t ret;
2790
2791    memset(buffer.bytes, 0, sizeof(buffer));
2792    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2793    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET_CTRL_TOKEN;
2794
2795    safe_send(buffer.bytes, sizeof(buffer.request), false);
2796    safe_recv_packet(&buffer.response, sizeof(buffer.bytes));
2797
2798    cb_assert(htons(buffer.response.message.header.response.status) ==
2799                PROTOCOL_BINARY_RESPONSE_SUCCESS);
2800
2801    ret = ntohll(buffer.response.message.header.response.cas);
2802    cb_assert(ret != 0);
2803
2804    return ret;
2805}
2806
2807static void prepare_set_session_ctrl_token(protocol_binary_request_set_ctrl_token *req,
2808                                           uint64_t old, uint64_t new)
2809{
2810    memset(req, 0, sizeof(*req));
2811    req->message.header.request.magic = PROTOCOL_BINARY_REQ;
2812    req->message.header.request.opcode = PROTOCOL_BINARY_CMD_SET_CTRL_TOKEN;
2813    req->message.header.request.extlen = sizeof(uint64_t);
2814    req->message.header.request.bodylen = htonl(sizeof(uint64_t));
2815    req->message.header.request.cas = htonll(old);
2816    req->message.body.new_cas = htonll(new);
2817}
2818
2819static enum test_return test_session_ctrl_token(void) {
2820    union {
2821        protocol_binary_request_set_ctrl_token request;
2822        protocol_binary_response_set_ctrl_token response;
2823        char bytes[1024];
2824    } buffer;
2825
2826    uint64_t old_token = get_session_ctrl_token();
2827    uint64_t new_token = 0x0102030405060708;
2828
2829    /* Validate that you may successfully set the token to a legal value */
2830    prepare_set_session_ctrl_token(&buffer.request, old_token, new_token);
2831    safe_send(buffer.bytes, sizeof(buffer.request), false);
2832    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2833
2834    cb_assert(buffer.response.message.header.response.status ==
2835              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2836    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2837    old_token = new_token;
2838
2839    /* Validate that you can't set it to 0 */
2840    prepare_set_session_ctrl_token(&buffer.request, old_token, 0);
2841    safe_send(buffer.bytes, sizeof(buffer.request), false);
2842    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2843    cb_assert(buffer.response.message.header.response.status ==
2844              PROTOCOL_BINARY_RESPONSE_EINVAL);
2845    cb_assert(old_token == get_session_ctrl_token());
2846
2847    /* Validate that you can't set it by providing an incorrect cas */
2848    prepare_set_session_ctrl_token(&buffer.request, old_token + 1, new_token - 1);
2849    safe_send(buffer.bytes, sizeof(buffer.request), false);
2850    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2851
2852    cb_assert(buffer.response.message.header.response.status ==
2853              PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2854    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2855    cb_assert(new_token == get_session_ctrl_token());
2856
2857    /* Validate that you may set it by overriding the cas with 0 */
2858    prepare_set_session_ctrl_token(&buffer.request, 0, 0xdeadbeef);
2859    safe_send(buffer.bytes, sizeof(buffer.request), false);
2860    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2861    cb_assert(buffer.response.message.header.response.status ==
2862              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2863    cb_assert(0xdeadbeef == ntohll(buffer.response.message.header.response.cas));
2864    cb_assert(0xdeadbeef == get_session_ctrl_token());
2865
2866    return TEST_PASS;
2867}
2868
2869static enum test_return test_mb_10114(void) {
2870    char buffer[512];
2871    const char *key = "mb-10114";
2872    union {
2873        protocol_binary_request_no_extras request;
2874        protocol_binary_response_no_extras response;
2875        char bytes[1024];
2876    } send, receive;
2877    size_t len;
2878
2879    store_object(key, "world");
2880    do {
2881        len = raw_command(send.bytes, sizeof(send.bytes),
2882                          PROTOCOL_BINARY_CMD_APPEND,
2883                          key, strlen(key), buffer, sizeof(buffer));
2884        safe_send(send.bytes, len, false);
2885        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2886    } while (receive.response.message.header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS);
2887
2888    cb_assert(receive.response.message.header.response.status == PROTOCOL_BINARY_RESPONSE_E2BIG);
2889
2890    /* We should be able to delete it */
2891    len = raw_command(send.bytes, sizeof(send.bytes),
2892                      PROTOCOL_BINARY_CMD_DELETE,
2893                      key, strlen(key), NULL, 0);
2894    safe_send(send.bytes, len, false);
2895    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2896    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
2897                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2898
2899    return TEST_PASS;
2900}
2901
2902static enum test_return test_binary_dcp_noop(void) {
2903    union {
2904        protocol_binary_request_dcp_noop request;
2905        protocol_binary_response_dcp_noop response;
2906        char bytes[1024];
2907    } buffer;
2908
2909    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2910                             PROTOCOL_BINARY_CMD_DCP_NOOP,
2911                             NULL, 0, NULL, 0);
2912
2913    /*
2914     * Default engine don't support DCP, so just check that
2915     * it detects that and if the packet