14c86fa59STrond Norbye /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
24c86fa59STrond Norbye #undef NDEBUG
36ae66c84STrond Norbye #include <pthread.h>
47bb82191STrond Norbye #include <sys/types.h>
57bb82191STrond Norbye #include <sys/socket.h>
6d8cc25b0STrond Norbye #include <sys/wait.h>
77bb82191STrond Norbye #include <netdb.h>
87bb82191STrond Norbye #include <arpa/inet.h>
97bb82191STrond Norbye #include <netinet/in.h>
107bb82191STrond Norbye #include <netinet/tcp.h>
114c86fa59STrond Norbye #include <signal.h>
124c86fa59STrond Norbye #include <stdio.h>
134c86fa59STrond Norbye #include <stdlib.h>
144c86fa59STrond Norbye #include <errno.h>
154c86fa59STrond Norbye #include <assert.h>
164c86fa59STrond Norbye #include <string.h>
174c86fa59STrond Norbye #include <unistd.h>
18e337faf6STrond Norbye #include <netinet/in.h>
190731dc82STrond Norbye #include <fcntl.h>
204c86fa59STrond Norbye
214c86fa59STrond Norbye #include "config.h"
224c86fa59STrond Norbye #include "cache.h"
234c86fa59STrond Norbye #include "util.h"
2424869322STrond Norbye #include "protocol_binary.h"
254c86fa59STrond Norbye
26891082f3SDustin Sallings #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
27891082f3SDustin Sallings
284c86fa59STrond Norbye enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
294c86fa59STrond Norbye
306ae66c84STrond Norbye static pid_t server_pid;
316ae66c84STrond Norbye static in_port_t port;
326ae66c84STrond Norbye static int sock;
336ae66c84STrond Norbye static bool allow_closed_read = false;
346ae66c84STrond Norbye
cache_create_test(void)354c86fa59STrond Norbye static enum test_return cache_create_test(void)
364c86fa59STrond Norbye {
374c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
384c86fa59STrond Norbye NULL, NULL);
394c86fa59STrond Norbye assert(cache != NULL);
404c86fa59STrond Norbye cache_destroy(cache);
414c86fa59STrond Norbye return TEST_PASS;
424c86fa59STrond Norbye }
434c86fa59STrond Norbye
444c86fa59STrond Norbye const uint64_t constructor_pattern = 0xdeadcafebabebeef;
454c86fa59STrond Norbye
cache_constructor(void * buffer,void * notused1,int notused2)464c86fa59STrond Norbye static int cache_constructor(void *buffer, void *notused1, int notused2) {
474c86fa59STrond Norbye uint64_t *ptr = buffer;
484c86fa59STrond Norbye *ptr = constructor_pattern;
494c86fa59STrond Norbye return 0;
504c86fa59STrond Norbye }
514c86fa59STrond Norbye
cache_constructor_test(void)524c86fa59STrond Norbye static enum test_return cache_constructor_test(void)
534c86fa59STrond Norbye {
544c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
554c86fa59STrond Norbye cache_constructor, NULL);
564c86fa59STrond Norbye assert(cache != NULL);
574c86fa59STrond Norbye uint64_t *ptr = cache_alloc(cache);
584c86fa59STrond Norbye uint64_t pattern = *ptr;
594c86fa59STrond Norbye cache_free(cache, ptr);
604c86fa59STrond Norbye cache_destroy(cache);
614c86fa59STrond Norbye return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
624c86fa59STrond Norbye }
634c86fa59STrond Norbye
cache_fail_constructor(void * buffer,void * notused1,int notused2)644c86fa59STrond Norbye static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
654c86fa59STrond Norbye return 1;
664c86fa59STrond Norbye }
674c86fa59STrond Norbye
cache_fail_constructor_test(void)684c86fa59STrond Norbye static enum test_return cache_fail_constructor_test(void)
694c86fa59STrond Norbye {
704c86fa59STrond Norbye enum test_return ret = TEST_PASS;
714c86fa59STrond Norbye
724c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
734c86fa59STrond Norbye cache_fail_constructor, NULL);
744c86fa59STrond Norbye assert(cache != NULL);
754c86fa59STrond Norbye uint64_t *ptr = cache_alloc(cache);
764c86fa59STrond Norbye if (ptr != NULL) {
774c86fa59STrond Norbye ret = TEST_FAIL;
784c86fa59STrond Norbye }
794c86fa59STrond Norbye cache_destroy(cache);
804c86fa59STrond Norbye return ret;
814c86fa59STrond Norbye }
824c86fa59STrond Norbye
834c86fa59STrond Norbye static void *destruct_data = 0;
844c86fa59STrond Norbye
cache_destructor(void * buffer,void * notused)854c86fa59STrond Norbye static void cache_destructor(void *buffer, void *notused) {
864c86fa59STrond Norbye destruct_data = buffer;
874c86fa59STrond Norbye }
884c86fa59STrond Norbye
cache_destructor_test(void)894c86fa59STrond Norbye static enum test_return cache_destructor_test(void)
904c86fa59STrond Norbye {
914c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
924c86fa59STrond Norbye NULL, cache_destructor);
934c86fa59STrond Norbye assert(cache != NULL);
944c86fa59STrond Norbye char *ptr = cache_alloc(cache);
954c86fa59STrond Norbye cache_free(cache, ptr);
964c86fa59STrond Norbye cache_destroy(cache);
974c86fa59STrond Norbye
984c86fa59STrond Norbye return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
994c86fa59STrond Norbye }
1004c86fa59STrond Norbye
cache_reuse_test(void)1014c86fa59STrond Norbye static enum test_return cache_reuse_test(void)
1024c86fa59STrond Norbye {
1034c86fa59STrond Norbye int ii;
1044c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
1054c86fa59STrond Norbye NULL, NULL);
1064c86fa59STrond Norbye char *ptr = cache_alloc(cache);
1074c86fa59STrond Norbye cache_free(cache, ptr);
1084c86fa59STrond Norbye for (ii = 0; ii < 100; ++ii) {
1094c86fa59STrond Norbye char *p = cache_alloc(cache);
1104c86fa59STrond Norbye assert(p == ptr);
1114c86fa59STrond Norbye cache_free(cache, ptr);
1124c86fa59STrond Norbye }
1134c86fa59STrond Norbye cache_destroy(cache);
1144c86fa59STrond Norbye return TEST_PASS;
1154c86fa59STrond Norbye }
1164c86fa59STrond Norbye
11716a809e2STrond Norbye
cache_bulkalloc(size_t datasize)11816a809e2STrond Norbye static enum test_return cache_bulkalloc(size_t datasize)
11916a809e2STrond Norbye {
12016a809e2STrond Norbye cache_t *cache = cache_create("test", datasize, sizeof(char*),
12116a809e2STrond Norbye NULL, NULL);
12216a809e2STrond Norbye #define ITERATIONS 1024
12316a809e2STrond Norbye void *ptr[ITERATIONS];
12416a809e2STrond Norbye
12516a809e2STrond Norbye for (int ii = 0; ii < ITERATIONS; ++ii) {
12616a809e2STrond Norbye ptr[ii] = cache_alloc(cache);
12716a809e2STrond Norbye assert(ptr[ii] != 0);
12816a809e2STrond Norbye memset(ptr[ii], 0xff, datasize);
12916a809e2STrond Norbye }
13016a809e2STrond Norbye
13116a809e2STrond Norbye for (int ii = 0; ii < ITERATIONS; ++ii) {
13216a809e2STrond Norbye cache_free(cache, ptr[ii]);
13316a809e2STrond Norbye }
13416a809e2STrond Norbye
13516a809e2STrond Norbye #undef ITERATIONS
13616a809e2STrond Norbye cache_destroy(cache);
13716a809e2STrond Norbye return TEST_PASS;
13816a809e2STrond Norbye }
13916a809e2STrond Norbye
test_issue_161(void)14016a809e2STrond Norbye static enum test_return test_issue_161(void)
14116a809e2STrond Norbye {
14216a809e2STrond Norbye enum test_return ret = cache_bulkalloc(1);
14316a809e2STrond Norbye if (ret == TEST_PASS) {
14416a809e2STrond Norbye ret = cache_bulkalloc(512);
14516a809e2STrond Norbye }
14616a809e2STrond Norbye
14716a809e2STrond Norbye return ret;
14816a809e2STrond Norbye }
14916a809e2STrond Norbye
cache_redzone_test(void)1504c86fa59STrond Norbye static enum test_return cache_redzone_test(void)
1514c86fa59STrond Norbye {
1524c86fa59STrond Norbye #ifndef HAVE_UMEM_H
1534c86fa59STrond Norbye cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
1544c86fa59STrond Norbye NULL, NULL);
1554c86fa59STrond Norbye
1564c86fa59STrond Norbye /* Ignore SIGABORT */
1574c86fa59STrond Norbye struct sigaction old_action;
1584c86fa59STrond Norbye struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
1594c86fa59STrond Norbye sigemptyset(&action.sa_mask);
1604c86fa59STrond Norbye sigaction(SIGABRT, &action, &old_action);
1614c86fa59STrond Norbye
1624c86fa59STrond Norbye /* check memory debug.. */
1634c86fa59STrond Norbye char *p = cache_alloc(cache);
1644c86fa59STrond Norbye char old = *(p - 1);
1654c86fa59STrond Norbye *(p - 1) = 0;
1664c86fa59STrond Norbye cache_free(cache, p);
1674c86fa59STrond Norbye assert(cache_error == -1);
1684c86fa59STrond Norbye *(p - 1) = old;
1694c86fa59STrond Norbye
1704c86fa59STrond Norbye p[sizeof(uint32_t)] = 0;
1714c86fa59STrond Norbye cache_free(cache, p);
1724c86fa59STrond Norbye assert(cache_error == 1);
1734c86fa59STrond Norbye
1744c86fa59STrond Norbye /* restore signal handler */
1754c86fa59STrond Norbye sigaction(SIGABRT, &old_action, NULL);
1764c86fa59STrond Norbye
1774c86fa59STrond Norbye cache_destroy(cache);
1784c86fa59STrond Norbye
1794c86fa59STrond Norbye return TEST_PASS;
1804c86fa59STrond Norbye #else
1814c86fa59STrond Norbye return TEST_SKIP;
1824c86fa59STrond Norbye #endif
1834c86fa59STrond Norbye }
1844c86fa59STrond Norbye
test_safe_strtoul(void)1854c86fa59STrond Norbye static enum test_return test_safe_strtoul(void) {
1864c86fa59STrond Norbye uint32_t val;
1874c86fa59STrond Norbye assert(safe_strtoul("123", &val));
1884c86fa59STrond Norbye assert(val == 123);
1894c86fa59STrond Norbye assert(safe_strtoul("+123", &val));
1904c86fa59STrond Norbye assert(val == 123);
1914c86fa59STrond Norbye assert(!safe_strtoul("", &val)); // empty
1924c86fa59STrond Norbye assert(!safe_strtoul("123BOGUS", &val)); // non-numeric
19351c8f31fSTrond Norbye assert(!safe_strtoul(" issue221", &val)); // non-numeric
1944c86fa59STrond Norbye /* Not sure what it does, but this works with ICC :/
1954c86fa59STrond Norbye assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
1964c86fa59STrond Norbye */
1974c86fa59STrond Norbye
1984c86fa59STrond Norbye // extremes:
1994c86fa59STrond Norbye assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
2004c86fa59STrond Norbye assert(val == 4294967295L);
2014c86fa59STrond Norbye /* This actually works on 64-bit ubuntu
2024c86fa59STrond Norbye assert(!safe_strtoul("4294967296", &val)); // 2**32
2034c86fa59STrond Norbye */
2044c86fa59STrond Norbye assert(!safe_strtoul("-1", &val)); // negative
2054c86fa59STrond Norbye return TEST_PASS;
2064c86fa59STrond Norbye }
2074c86fa59STrond Norbye
2084c86fa59STrond Norbye
test_safe_strtoull(void)2094c86fa59STrond Norbye static enum test_return test_safe_strtoull(void) {
2104c86fa59STrond Norbye uint64_t val;
2114c86fa59STrond Norbye assert(safe_strtoull("123", &val));
2124c86fa59STrond Norbye assert(val == 123);
2134c86fa59STrond Norbye assert(safe_strtoull("+123", &val));
2144c86fa59STrond Norbye assert(val == 123);
2154c86fa59STrond Norbye assert(!safe_strtoull("", &val)); // empty
2164c86fa59STrond Norbye assert(!safe_strtoull("123BOGUS", &val)); // non-numeric
2174c86fa59STrond Norbye assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
21851c8f31fSTrond Norbye assert(!safe_strtoull(" issue221", &val)); // non-numeric
2194c86fa59STrond Norbye
2204c86fa59STrond Norbye // extremes:
2214c86fa59STrond Norbye assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
2224c86fa59STrond Norbye assert(val == 18446744073709551615ULL);
2234c86fa59STrond Norbye assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
2244c86fa59STrond Norbye assert(!safe_strtoull("-1", &val)); // negative
2254c86fa59STrond Norbye return TEST_PASS;
2264c86fa59STrond Norbye }
2274c86fa59STrond Norbye
test_safe_strtoll(void)2284c86fa59STrond Norbye static enum test_return test_safe_strtoll(void) {
2294c86fa59STrond Norbye int64_t val;
2304c86fa59STrond Norbye assert(safe_strtoll("123", &val));
2314c86fa59STrond Norbye assert(val == 123);
2324c86fa59STrond Norbye assert(safe_strtoll("+123", &val));
2334c86fa59STrond Norbye assert(val == 123);
2344c86fa59STrond Norbye assert(safe_strtoll("-123", &val));
2354c86fa59STrond Norbye assert(val == -123);
2364c86fa59STrond Norbye assert(!safe_strtoll("", &val)); // empty
2374c86fa59STrond Norbye assert(!safe_strtoll("123BOGUS", &val)); // non-numeric
2384c86fa59STrond Norbye assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
23951c8f31fSTrond Norbye assert(!safe_strtoll(" issue221", &val)); // non-numeric
2404c86fa59STrond Norbye
2414c86fa59STrond Norbye // extremes:
2424c86fa59STrond Norbye assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
2434c86fa59STrond Norbye assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
2444c86fa59STrond Norbye assert(val == 9223372036854775807LL);
2454c86fa59STrond Norbye /*
2464c86fa59STrond Norbye assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
2474c86fa59STrond Norbye assert(val == -9223372036854775808LL);
2484c86fa59STrond Norbye */
2494c86fa59STrond Norbye assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
2504c86fa59STrond Norbye
2514c86fa59STrond Norbye // We'll allow space to terminate the string. And leading space.
2524c86fa59STrond Norbye assert(safe_strtoll(" 123 foo", &val));
2534c86fa59STrond Norbye assert(val == 123);
2544c86fa59STrond Norbye return TEST_PASS;
2554c86fa59STrond Norbye }
2564c86fa59STrond Norbye
test_safe_strtol(void)2574c86fa59STrond Norbye static enum test_return test_safe_strtol(void) {
2584c86fa59STrond Norbye int32_t val;
2594c86fa59STrond Norbye assert(safe_strtol("123", &val));
2604c86fa59STrond Norbye assert(val == 123);
2614c86fa59STrond Norbye assert(safe_strtol("+123", &val));
2624c86fa59STrond Norbye assert(val == 123);
2634c86fa59STrond Norbye assert(safe_strtol("-123", &val));
2644c86fa59STrond Norbye assert(val == -123);
2654c86fa59STrond Norbye assert(!safe_strtol("", &val)); // empty
2664c86fa59STrond Norbye assert(!safe_strtol("123BOGUS", &val)); // non-numeric
2674c86fa59STrond Norbye assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
26851c8f31fSTrond Norbye assert(!safe_strtol(" issue221", &val)); // non-numeric
2694c86fa59STrond Norbye
2704c86fa59STrond Norbye // extremes:
2714c86fa59STrond Norbye /* This actually works on 64-bit ubuntu
2724c86fa59STrond Norbye assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
2734c86fa59STrond Norbye */
2744c86fa59STrond Norbye assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
2754c86fa59STrond Norbye assert(val == 2147483647L);
2764c86fa59STrond Norbye /* This actually works on 64-bit ubuntu
2774c86fa59STrond Norbye assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
2784c86fa59STrond Norbye */
2794c86fa59STrond Norbye
2804c86fa59STrond Norbye // We'll allow space to terminate the string. And leading space.
2814c86fa59STrond Norbye assert(safe_strtol(" 123 foo", &val));
2824c86fa59STrond Norbye assert(val == 123);
2834c86fa59STrond Norbye return TEST_PASS;
2844c86fa59STrond Norbye }
2854c86fa59STrond Norbye
286e337faf6STrond Norbye /**
287e337faf6STrond Norbye * Function to start the server and let it listen on a random port
288e337faf6STrond Norbye *
289e337faf6STrond Norbye * @param port_out where to store the TCP port number the server is
290e337faf6STrond Norbye * listening on
291e337faf6STrond Norbye * @param daemon set to true if you want to run the memcached server
292e337faf6STrond Norbye * as a daemon process
293e337faf6STrond Norbye * @return the pid of the memcached server
294e337faf6STrond Norbye */
start_server(in_port_t * port_out,bool daemon,int timeout)2956ae66c84STrond Norbye static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
296e337faf6STrond Norbye char environment[80];
297e337faf6STrond Norbye snprintf(environment, sizeof(environment),
2983fa31371STrond Norbye "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
299e337faf6STrond Norbye char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
300e337faf6STrond Norbye char pid_file[80];
3013fa31371STrond Norbye snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
302e337faf6STrond Norbye
303e337faf6STrond Norbye remove(filename);
304e337faf6STrond Norbye remove(pid_file);
305e337faf6STrond Norbye
3066ae66c84STrond Norbye #ifdef __sun
3076ae66c84STrond Norbye /* I want to name the corefiles differently so that they don't
3086ae66c84STrond Norbye overwrite each other
3096ae66c84STrond Norbye */
3106ae66c84STrond Norbye char coreadm[128];
311cb10b041STrond Norbye snprintf(coreadm, sizeof(coreadm),
312cb10b041STrond Norbye "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
3136ae66c84STrond Norbye system(coreadm);
3146ae66c84STrond Norbye #endif
3156ae66c84STrond Norbye
316e337faf6STrond Norbye pid_t pid = fork();
317e337faf6STrond Norbye assert(pid != -1);
318e337faf6STrond Norbye
319e337faf6STrond Norbye if (pid == 0) {
320e337faf6STrond Norbye /* Child */
321fba0a891SDustin Sallings char *argv[20];
322e337faf6STrond Norbye int arg = 0;
3236ae66c84STrond Norbye char tmo[24];
3246ae66c84STrond Norbye snprintf(tmo, sizeof(tmo), "%u", timeout);
3256ae66c84STrond Norbye
326e337faf6STrond Norbye putenv(environment);
32789d5126bSTrond Norbye #ifdef __sun
32889d5126bSTrond Norbye putenv("LD_PRELOAD=watchmalloc.so.1");
32989d5126bSTrond Norbye putenv("MALLOC_DEBUG=WATCH");
33089d5126bSTrond Norbye #endif
33189d5126bSTrond Norbye
332fba0a891SDustin Sallings if (!daemon) {
333fba0a891SDustin Sallings argv[arg++] = "./timedrun";
3346ae66c84STrond Norbye argv[arg++] = tmo;
335fba0a891SDustin Sallings }
336e337faf6STrond Norbye argv[arg++] = "./memcached-debug";
337d11dc0eaSBrian Aker argv[arg++] = "-A";
338e337faf6STrond Norbye argv[arg++] = "-p";
339e337faf6STrond Norbye argv[arg++] = "-1";
340e337faf6STrond Norbye argv[arg++] = "-U";
341e337faf6STrond Norbye argv[arg++] = "0";
3429a0357e9SDustin Sallings /* Handle rpmbuild and the like doing this as root */
3439a0357e9SDustin Sallings if (getuid() == 0) {
3449a0357e9SDustin Sallings argv[arg++] = "-u";
3459a0357e9SDustin Sallings argv[arg++] = "root";
3469a0357e9SDustin Sallings }
347e337faf6STrond Norbye if (daemon) {
348e337faf6STrond Norbye argv[arg++] = "-d";
349e337faf6STrond Norbye argv[arg++] = "-P";
350e337faf6STrond Norbye argv[arg++] = pid_file;
351e337faf6STrond Norbye }
3526ae66c84STrond Norbye #ifdef MESSAGE_DEBUG
3536ae66c84STrond Norbye argv[arg++] = "-vvv";
3546ae66c84STrond Norbye #endif
355e337faf6STrond Norbye argv[arg++] = NULL;
356fba0a891SDustin Sallings assert(execv(argv[0], argv) != -1);
357e337faf6STrond Norbye }
358e337faf6STrond Norbye
359e337faf6STrond Norbye /* Yeah just let us "busy-wait" for the file to be created ;-) */
360e337faf6STrond Norbye while (access(filename, F_OK) == -1) {
361e337faf6STrond Norbye usleep(10);
362e337faf6STrond Norbye }
363e337faf6STrond Norbye
364e337faf6STrond Norbye FILE *fp = fopen(filename, "r");
365e337faf6STrond Norbye if (fp == NULL) {
366e337faf6STrond Norbye fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
367e337faf6STrond Norbye strerror(errno));
368e337faf6STrond Norbye assert(false);
369e337faf6STrond Norbye }
370e337faf6STrond Norbye
371e337faf6STrond Norbye *port_out = (in_port_t)-1;
372e337faf6STrond Norbye char buffer[80];
373e337faf6STrond Norbye while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
374e337faf6STrond Norbye if (strncmp(buffer, "TCP INET: ", 10) == 0) {
375e337faf6STrond Norbye int32_t val;
376e337faf6STrond Norbye assert(safe_strtol(buffer + 10, &val));
377e337faf6STrond Norbye *port_out = (in_port_t)val;
378e337faf6STrond Norbye }
379e337faf6STrond Norbye }
3804c86fa59STrond Norbye fclose(fp);
381e337faf6STrond Norbye assert(remove(filename) == 0);
382e337faf6STrond Norbye
383e337faf6STrond Norbye if (daemon) {
384e337faf6STrond Norbye /* loop and wait for the pid file.. There is a potential race
385e337faf6STrond Norbye * condition that the server just created the file but isn't
386d707b99dSClint Byrum * finished writing the content, so we loop a few times
387d707b99dSClint Byrum * reading as well */
388e337faf6STrond Norbye while (access(pid_file, F_OK) == -1) {
389e337faf6STrond Norbye usleep(10);
390e337faf6STrond Norbye }
391e337faf6STrond Norbye
392e337faf6STrond Norbye fp = fopen(pid_file, "r");
393e337faf6STrond Norbye if (fp == NULL) {
394e337faf6STrond Norbye fprintf(stderr, "Failed to open pid file: %s\n",
395e337faf6STrond Norbye strerror(errno));
396e337faf6STrond Norbye assert(false);
397e337faf6STrond Norbye }
398d707b99dSClint Byrum
399d707b99dSClint Byrum /* Avoid race by retrying 20 times */
400d707b99dSClint Byrum for (int x = 0; x < 20 && fgets(buffer, sizeof(buffer), fp) == NULL; x++) {
401d707b99dSClint Byrum usleep(10);
402d707b99dSClint Byrum }
403e337faf6STrond Norbye fclose(fp);
404e337faf6STrond Norbye
405e337faf6STrond Norbye int32_t val;
406e337faf6STrond Norbye assert(safe_strtol(buffer, &val));
407e337faf6STrond Norbye pid = (pid_t)val;
408e337faf6STrond Norbye }
409e337faf6STrond Norbye
410e337faf6STrond Norbye return pid;
411e337faf6STrond Norbye }
412e337faf6STrond Norbye
test_issue_44(void)413e337faf6STrond Norbye static enum test_return test_issue_44(void) {
414e337faf6STrond Norbye in_port_t port;
4156ae66c84STrond Norbye pid_t pid = start_server(&port, true, 15);
4164c86fa59STrond Norbye assert(kill(pid, SIGHUP) == 0);
4174c86fa59STrond Norbye sleep(1);
4184c86fa59STrond Norbye assert(kill(pid, SIGTERM) == 0);
4194c86fa59STrond Norbye
4204c86fa59STrond Norbye return TEST_PASS;
4214c86fa59STrond Norbye }
4224c86fa59STrond Norbye
lookuphost(const char * hostname,in_port_t port)4237bb82191STrond Norbye static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
4247bb82191STrond Norbye {
4257bb82191STrond Norbye struct addrinfo *ai = 0;
4267bb82191STrond Norbye struct addrinfo hints = { .ai_family = AF_UNSPEC,
4277bb82191STrond Norbye .ai_protocol = IPPROTO_TCP,
4287bb82191STrond Norbye .ai_socktype = SOCK_STREAM };
4297bb82191STrond Norbye char service[NI_MAXSERV];
4307bb82191STrond Norbye int error;
4317bb82191STrond Norbye
4327bb82191STrond Norbye (void)snprintf(service, NI_MAXSERV, "%d", port);
4337bb82191STrond Norbye if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
4347bb82191STrond Norbye if (error != EAI_SYSTEM) {
4357bb82191STrond Norbye fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
4367bb82191STrond Norbye } else {
4377bb82191STrond Norbye perror("getaddrinfo()");
4387bb82191STrond Norbye }
4397bb82191STrond Norbye }
4407bb82191STrond Norbye
4417bb82191STrond Norbye return ai;
4427bb82191STrond Norbye }
4437bb82191STrond Norbye
connect_server(const char * hostname,in_port_t port,bool nonblock)4440731dc82STrond Norbye static int connect_server(const char *hostname, in_port_t port, bool nonblock)
4457bb82191STrond Norbye {
4467bb82191STrond Norbye struct addrinfo *ai = lookuphost(hostname, port);
4477bb82191STrond Norbye int sock = -1;
4487bb82191STrond Norbye if (ai != NULL) {
4497bb82191STrond Norbye if ((sock = socket(ai->ai_family, ai->ai_socktype,
4507bb82191STrond Norbye ai->ai_protocol)) != -1) {
4517bb82191STrond Norbye if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
4527bb82191STrond Norbye fprintf(stderr, "Failed to connect socket: %s\n",
4537bb82191STrond Norbye strerror(errno));
4547bb82191STrond Norbye close(sock);
4557bb82191STrond Norbye sock = -1;
4560731dc82STrond Norbye } else if (nonblock) {
4570731dc82STrond Norbye int flags = fcntl(sock, F_GETFL, 0);
4580731dc82STrond Norbye if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
4590731dc82STrond Norbye fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
4600731dc82STrond Norbye strerror(errno));
4610731dc82STrond Norbye close(sock);
4620731dc82STrond Norbye sock = -1;
4630731dc82STrond Norbye }
4647bb82191STrond Norbye }
4657bb82191STrond Norbye } else {
4667bb82191STrond Norbye fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
4677bb82191STrond Norbye }
4687bb82191STrond Norbye
4697bb82191STrond Norbye freeaddrinfo(ai);
4707bb82191STrond Norbye }
4717bb82191STrond Norbye return sock;
4727bb82191STrond Norbye }
4737bb82191STrond Norbye
test_vperror(void)474891082f3SDustin Sallings static enum test_return test_vperror(void) {
475891082f3SDustin Sallings int rv = 0;
476891082f3SDustin Sallings int oldstderr = dup(STDERR_FILENO);
477891082f3SDustin Sallings char tmpl[sizeof(TMP_TEMPLATE)+1];
478891082f3SDustin Sallings strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
479891082f3SDustin Sallings
480891082f3SDustin Sallings int newfile = mkstemp(tmpl);
481891082f3SDustin Sallings assert(newfile > 0);
482891082f3SDustin Sallings rv = dup2(newfile, STDERR_FILENO);
483891082f3SDustin Sallings assert(rv == STDERR_FILENO);
484891082f3SDustin Sallings rv = close(newfile);
485891082f3SDustin Sallings assert(rv == 0);
486891082f3SDustin Sallings
487891082f3SDustin Sallings errno = EIO;
488891082f3SDustin Sallings vperror("Old McDonald had a farm. %s", "EI EIO");
489891082f3SDustin Sallings
490891082f3SDustin Sallings /* Restore stderr */
491891082f3SDustin Sallings rv = dup2(oldstderr, STDERR_FILENO);
492891082f3SDustin Sallings assert(rv == STDERR_FILENO);
493891082f3SDustin Sallings
494891082f3SDustin Sallings
495891082f3SDustin Sallings /* Go read the file */
496891082f3SDustin Sallings char buf[80] = { 0 };
497891082f3SDustin Sallings FILE *efile = fopen(tmpl, "r");
498891082f3SDustin Sallings assert(efile);
499891082f3SDustin Sallings char *prv = fgets(buf, sizeof(buf), efile);
500891082f3SDustin Sallings assert(prv);
501891082f3SDustin Sallings fclose(efile);
502891082f3SDustin Sallings
503891082f3SDustin Sallings unlink(tmpl);
504891082f3SDustin Sallings
505891082f3SDustin Sallings char expected[80] = { 0 };
506891082f3SDustin Sallings snprintf(expected, sizeof(expected),
507891082f3SDustin Sallings "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO));
508891082f3SDustin Sallings
509891082f3SDustin Sallings /*
510891082f3SDustin Sallings fprintf(stderr,
511891082f3SDustin Sallings "\nExpected: ``%s''"
512891082f3SDustin Sallings "\nGot: ``%s''\n", expected, buf);
513891082f3SDustin Sallings */
514891082f3SDustin Sallings
515891082f3SDustin Sallings return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
516891082f3SDustin Sallings }
517891082f3SDustin Sallings
send_ascii_command(const char * buf)5182c7bfeb8STrond Norbye static void send_ascii_command(const char *buf) {
5192c7bfeb8STrond Norbye off_t offset = 0;
5202c7bfeb8STrond Norbye const char* ptr = buf;
5212c7bfeb8STrond Norbye size_t len = strlen(buf);
5222c7bfeb8STrond Norbye
5232c7bfeb8STrond Norbye do {
5242c7bfeb8STrond Norbye ssize_t nw = write(sock, ptr + offset, len - offset);
5252c7bfeb8STrond Norbye if (nw == -1) {
5262c7bfeb8STrond Norbye if (errno != EINTR) {
5272c7bfeb8STrond Norbye fprintf(stderr, "Failed to write: %s\n", strerror(errno));
5282c7bfeb8STrond Norbye abort();
5292c7bfeb8STrond Norbye }
5302c7bfeb8STrond Norbye } else {
5312c7bfeb8STrond Norbye offset += nw;
5322c7bfeb8STrond Norbye }
5332c7bfeb8STrond Norbye } while (offset < len);
5342c7bfeb8STrond Norbye }
5352c7bfeb8STrond Norbye
5362c7bfeb8STrond Norbye /*
5372c7bfeb8STrond Norbye * This is a dead slow single byte read, but it should only read out
5382c7bfeb8STrond Norbye * _one_ response and I don't have an input buffer... The current
5392c7bfeb8STrond Norbye * implementation only supports single-line responses, so if you want to use
5402c7bfeb8STrond Norbye * it for get commands you need to implement that first ;-)
5412c7bfeb8STrond Norbye */
read_ascii_response(char * buffer,size_t size)5422c7bfeb8STrond Norbye static void read_ascii_response(char *buffer, size_t size) {
5432c7bfeb8STrond Norbye off_t offset = 0;
5442c7bfeb8STrond Norbye bool need_more = true;
5452c7bfeb8STrond Norbye do {
5462c7bfeb8STrond Norbye ssize_t nr = read(sock, buffer + offset, 1);
5472c7bfeb8STrond Norbye if (nr == -1) {
5482c7bfeb8STrond Norbye if (errno != EINTR) {
5492c7bfeb8STrond Norbye fprintf(stderr, "Failed to read: %s\n", strerror(errno));
5502c7bfeb8STrond Norbye abort();
5512c7bfeb8STrond Norbye }
5522c7bfeb8STrond Norbye } else {
5532c7bfeb8STrond Norbye assert(nr == 1);
5542c7bfeb8STrond Norbye if (buffer[offset] == '\n') {
5552c7bfeb8STrond Norbye need_more = false;
5562c7bfeb8STrond Norbye buffer[offset + 1] = '\0';
5572c7bfeb8STrond Norbye }
5582c7bfeb8STrond Norbye offset += nr;
5592c7bfeb8STrond Norbye assert(offset + 1 < size);
5602c7bfeb8STrond Norbye }
5612c7bfeb8STrond Norbye } while (need_more);
5622c7bfeb8STrond Norbye }
5632c7bfeb8STrond Norbye
test_issue_92(void)5642c7bfeb8STrond Norbye static enum test_return test_issue_92(void) {
5652c7bfeb8STrond Norbye char buffer[1024];
5662c7bfeb8STrond Norbye
5672c7bfeb8STrond Norbye close(sock);
5680731dc82STrond Norbye sock = connect_server("127.0.0.1", port, false);
5692c7bfeb8STrond Norbye
5702c7bfeb8STrond Norbye send_ascii_command("stats cachedump 1 0 0\r\n");
5712c7bfeb8STrond Norbye read_ascii_response(buffer, sizeof(buffer));
5722c7bfeb8STrond Norbye assert(strncmp(buffer, "END", strlen("END")) == 0);
5732c7bfeb8STrond Norbye
5742c7bfeb8STrond Norbye send_ascii_command("stats cachedump 200 0 0\r\n");
5752c7bfeb8STrond Norbye read_ascii_response(buffer, sizeof(buffer));
5762c7bfeb8STrond Norbye assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
5772c7bfeb8STrond Norbye
5782c7bfeb8STrond Norbye close(sock);
5790731dc82STrond Norbye sock = connect_server("127.0.0.1", port, false);
5802c7bfeb8STrond Norbye return TEST_PASS;
5812c7bfeb8STrond Norbye }
5822c7bfeb8STrond Norbye
test_issue_102(void)58375cc8368STrond Norbye static enum test_return test_issue_102(void) {
58475cc8368STrond Norbye char buffer[4096];
58575cc8368STrond Norbye memset(buffer, ' ', sizeof(buffer));
58675cc8368STrond Norbye buffer[sizeof(buffer) - 1] = '\0';
58775cc8368STrond Norbye
58875cc8368STrond Norbye close(sock);
58975cc8368STrond Norbye sock = connect_server("127.0.0.1", port, false);
59075cc8368STrond Norbye
59175cc8368STrond Norbye send_ascii_command(buffer);
59275cc8368STrond Norbye /* verify that the server closed the connection */
59375cc8368STrond Norbye assert(read(sock, buffer, sizeof(buffer)) == 0);
59475cc8368STrond Norbye close(sock);
59575cc8368STrond Norbye sock = connect_server("127.0.0.1", port, false);
596e24110a4STrond Norbye
597cb10b041STrond Norbye snprintf(buffer, sizeof(buffer), "gets ");
598e24110a4STrond Norbye size_t offset = 5;
599e24110a4STrond Norbye while (offset < 4000) {
600cb10b041STrond Norbye offset += snprintf(buffer + offset, sizeof(buffer) - offset,
601cb10b041STrond Norbye "%010u ", (unsigned int)offset);
602e24110a4STrond Norbye }
603e24110a4STrond Norbye
604e24110a4STrond Norbye send_ascii_command(buffer);
605e24110a4STrond Norbye usleep(250);
606e24110a4STrond Norbye
607e24110a4STrond Norbye send_ascii_command("\r\n");
608e24110a4STrond Norbye char rsp[80];
609e24110a4STrond Norbye read_ascii_response(rsp, sizeof(rsp));
610e24110a4STrond Norbye assert(strncmp(rsp, "END", strlen("END")) == 0);
611e24110a4STrond Norbye buffer[3]= ' ';
612e24110a4STrond Norbye send_ascii_command(buffer);
613e24110a4STrond Norbye usleep(250);
614e24110a4STrond Norbye send_ascii_command("\r\n");
615e24110a4STrond Norbye read_ascii_response(rsp, sizeof(rsp));
616e24110a4STrond Norbye assert(strncmp(rsp, "END", strlen("END")) == 0);
617e24110a4STrond Norbye
618cb10b041STrond Norbye memset(buffer, ' ', sizeof(buffer));
619cb10b041STrond Norbye int len = snprintf(buffer + 101, sizeof(buffer) - 101, "gets foo");
620cb10b041STrond Norbye buffer[101 + len] = ' ';
621cb10b041STrond Norbye buffer[sizeof(buffer) - 1] = '\0';
622e24110a4STrond Norbye send_ascii_command(buffer);
623e24110a4STrond Norbye /* verify that the server closed the connection */
624e24110a4STrond Norbye assert(read(sock, buffer, sizeof(buffer)) == 0);
625e24110a4STrond Norbye
626e24110a4STrond Norbye close(sock);
627e24110a4STrond Norbye sock = connect_server("127.0.0.1", port, false);
628e24110a4STrond Norbye
62975cc8368STrond Norbye return TEST_PASS;
63075cc8368STrond Norbye }
63175cc8368STrond Norbye
start_memcached_server(void)6326ae66c84STrond Norbye static enum test_return start_memcached_server(void) {
6336ae66c84STrond Norbye server_pid = start_server(&port, false, 600);
6340731dc82STrond Norbye sock = connect_server("127.0.0.1", port, false);
6356ae66c84STrond Norbye return TEST_PASS;
6366ae66c84STrond Norbye }
6376ae66c84STrond Norbye
stop_memcached_server(void)6386ae66c84STrond Norbye static enum test_return stop_memcached_server(void) {
6396ae66c84STrond Norbye close(sock);
640d11dc0eaSBrian Aker if (server_pid != -1) {
6416ae66c84STrond Norbye assert(kill(server_pid, SIGTERM) == 0);
642d11dc0eaSBrian Aker }
643d11dc0eaSBrian Aker
644d11dc0eaSBrian Aker return TEST_PASS;
645d11dc0eaSBrian Aker }
646d11dc0eaSBrian Aker
shutdown_memcached_server(void)647d11dc0eaSBrian Aker static enum test_return shutdown_memcached_server(void) {
648d11dc0eaSBrian Aker char buffer[1024];
649d11dc0eaSBrian Aker
650d11dc0eaSBrian Aker close(sock);
651d11dc0eaSBrian Aker sock = connect_server("127.0.0.1", port, false);
652d11dc0eaSBrian Aker
653d11dc0eaSBrian Aker send_ascii_command("shutdown\r\n");
654d11dc0eaSBrian Aker /* verify that the server closed the connection */
655d11dc0eaSBrian Aker assert(read(sock, buffer, sizeof(buffer)) == 0);
656d11dc0eaSBrian Aker
657d11dc0eaSBrian Aker close(sock);
658d11dc0eaSBrian Aker
659d11dc0eaSBrian Aker /* We set server_pid to -1 so that we don't later call kill() */
660d11dc0eaSBrian Aker if (kill(server_pid, 0) == 0) {
661d11dc0eaSBrian Aker server_pid = -1;
662d11dc0eaSBrian Aker }
663d11dc0eaSBrian Aker
6646ae66c84STrond Norbye return TEST_PASS;
6656ae66c84STrond Norbye }
6666ae66c84STrond Norbye
safe_send(const void * buf,size_t len,bool hickup)6676ae66c84STrond Norbye static void safe_send(const void* buf, size_t len, bool hickup)
6686ae66c84STrond Norbye {
6696ae66c84STrond Norbye off_t offset = 0;
6706ae66c84STrond Norbye const char* ptr = buf;
6716ae66c84STrond Norbye #ifdef MESSAGE_DEBUG
6726ae66c84STrond Norbye uint8_t val = *ptr;
6736ae66c84STrond Norbye assert(val == (uint8_t)0x80);
6746ae66c84STrond Norbye fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
6756ae66c84STrond Norbye for (int ii = 0; ii < len; ++ii) {
6766ae66c84STrond Norbye if (ii % 4 == 0) {
6776ae66c84STrond Norbye fprintf(stderr, "\n ");
6786ae66c84STrond Norbye }
6796ae66c84STrond Norbye val = *(ptr + ii);
6806ae66c84STrond Norbye fprintf(stderr, " 0x%02x", val);
6816ae66c84STrond Norbye }
6826ae66c84STrond Norbye fprintf(stderr, "\n");
6836ae66c84STrond Norbye usleep(500);
6846ae66c84STrond Norbye #endif
6856ae66c84STrond Norbye
6866ae66c84STrond Norbye do {
6876ae66c84STrond Norbye size_t num_bytes = len - offset;
6886ae66c84STrond Norbye if (hickup) {
6896ae66c84STrond Norbye if (num_bytes > 1024) {
6906ae66c84STrond Norbye num_bytes = (rand() % 1023) + 1;
6916ae66c84STrond Norbye }
6926ae66c84STrond Norbye }
6936ae66c84STrond Norbye
6946ae66c84STrond Norbye ssize_t nw = write(sock, ptr + offset, num_bytes);
6956ae66c84STrond Norbye if (nw == -1) {
6966ae66c84STrond Norbye if (errno != EINTR) {
6976ae66c84STrond Norbye fprintf(stderr, "Failed to write: %s\n", strerror(errno));
6986ae66c84STrond Norbye abort();
6996ae66c84STrond Norbye }
7006ae66c84STrond Norbye } else {
7016ae66c84STrond Norbye if (hickup) {
7026ae66c84STrond Norbye usleep(100);
7036ae66c84STrond Norbye }
7046ae66c84STrond Norbye offset += nw;
7056ae66c84STrond Norbye }
7066ae66c84STrond Norbye } while (offset < len);
7076ae66c84STrond Norbye }
7086ae66c84STrond Norbye
safe_recv(void * buf,size_t len)7096ae66c84STrond Norbye static bool safe_recv(void *buf, size_t len) {
7106ae66c84STrond Norbye if (len == 0) {
7116ae66c84STrond Norbye return true;
7126ae66c84STrond Norbye }
7136ae66c84STrond Norbye off_t offset = 0;
7146ae66c84STrond Norbye do {
7156ae66c84STrond Norbye ssize_t nr = read(sock, ((char*)buf) + offset, len - offset);
7166ae66c84STrond Norbye if (nr == -1) {
7176ae66c84STrond Norbye if (errno != EINTR) {
7186ae66c84STrond Norbye fprintf(stderr, "Failed to read: %s\n", strerror(errno));
7196ae66c84STrond Norbye abort();
7206ae66c84STrond Norbye }
7216ae66c84STrond Norbye } else {
7226ae66c84STrond Norbye if (nr == 0 && allow_closed_read) {
7236ae66c84STrond Norbye return false;
7246ae66c84STrond Norbye }
7256ae66c84STrond Norbye assert(nr != 0);
7266ae66c84STrond Norbye offset += nr;
7276ae66c84STrond Norbye }
7286ae66c84STrond Norbye } while (offset < len);
7296ae66c84STrond Norbye
7306ae66c84STrond Norbye return true;
7316ae66c84STrond Norbye }
7326ae66c84STrond Norbye
safe_recv_packet(void * buf,size_t size)7336ae66c84STrond Norbye static bool safe_recv_packet(void *buf, size_t size) {
7346ae66c84STrond Norbye protocol_binary_response_no_extras *response = buf;
7356ae66c84STrond Norbye assert(size > sizeof(*response));
7366ae66c84STrond Norbye if (!safe_recv(response, sizeof(*response))) {
7376ae66c84STrond Norbye return false;
7386ae66c84STrond Norbye }
7396ae66c84STrond Norbye response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
7406ae66c84STrond Norbye response->message.header.response.status = ntohs(response->message.header.response.status);
7416ae66c84STrond Norbye response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
7426ae66c84STrond Norbye
7436ae66c84STrond Norbye size_t len = sizeof(*response);
7446ae66c84STrond Norbye
7456ae66c84STrond Norbye char *ptr = buf;
7466ae66c84STrond Norbye ptr += len;
7476ae66c84STrond Norbye if (!safe_recv(ptr, response->message.header.response.bodylen)) {
7486ae66c84STrond Norbye return false;
7496ae66c84STrond Norbye }
7506ae66c84STrond Norbye
7516ae66c84STrond Norbye #ifdef MESSAGE_DEBUG
7526ae66c84STrond Norbye usleep(500);
7536ae66c84STrond Norbye ptr = buf;
7546ae66c84STrond Norbye len += response->message.header.response.bodylen;
7556ae66c84STrond Norbye uint8_t val = *ptr;
7566ae66c84STrond Norbye assert(val == (uint8_t)0x81);
7576ae66c84STrond Norbye fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
7586ae66c84STrond Norbye for (int ii = 0; ii < len; ++ii) {
7596ae66c84STrond Norbye if (ii % 4 == 0) {
7606ae66c84STrond Norbye fprintf(stderr, "\n ");
7616ae66c84STrond Norbye }
7626ae66c84STrond Norbye val = *(ptr + ii);
7636ae66c84STrond Norbye fprintf(stderr, " 0x%02x", val);
7646ae66c84STrond Norbye }
7656ae66c84STrond Norbye fprintf(stderr, "\n");
7666ae66c84STrond Norbye #endif
7676ae66c84STrond Norbye return true;
7686ae66c84STrond Norbye }
7696ae66c84STrond Norbye
storage_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen,uint32_t flags,uint32_t exp)7706ae66c84STrond Norbye static off_t storage_command(char*buf,
7716ae66c84STrond Norbye size_t bufsz,
7726ae66c84STrond Norbye uint8_t cmd,
7736ae66c84STrond Norbye const void* key,
7746ae66c84STrond Norbye size_t keylen,
7756ae66c84STrond Norbye const void* dta,
7766ae66c84STrond Norbye size_t dtalen,
7776ae66c84STrond Norbye uint32_t flags,
7786ae66c84STrond Norbye uint32_t exp) {
7796ae66c84STrond Norbye /* all of the storage commands use the same command layout */
7806ae66c84STrond Norbye protocol_binary_request_set *request = (void*)buf;
7816ae66c84STrond Norbye assert(bufsz > sizeof(*request) + keylen + dtalen);
7826ae66c84STrond Norbye
7836ae66c84STrond Norbye memset(request, 0, sizeof(*request));
7846ae66c84STrond Norbye request->message.header.request.magic = PROTOCOL_BINARY_REQ;
7856ae66c84STrond Norbye request->message.header.request.opcode = cmd;
7866ae66c84STrond Norbye request->message.header.request.keylen = htons(keylen);
7876ae66c84STrond Norbye request->message.header.request.extlen = 8;
7886ae66c84STrond Norbye request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
7896ae66c84STrond Norbye request->message.header.request.opaque = 0xdeadbeef;
7906ae66c84STrond Norbye request->message.body.flags = flags;
7916ae66c84STrond Norbye request->message.body.expiration = exp;
7926ae66c84STrond Norbye
7936ae66c84STrond Norbye off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
7946ae66c84STrond Norbye
7956ae66c84STrond Norbye memcpy(buf + key_offset, key, keylen);
7966ae66c84STrond Norbye if (dta != NULL) {
7976ae66c84STrond Norbye memcpy(buf + key_offset + keylen, dta, dtalen);
7986ae66c84STrond Norbye }
7996ae66c84STrond Norbye
8006ae66c84STrond Norbye return key_offset + keylen + dtalen;
8016ae66c84STrond Norbye }
8026ae66c84STrond Norbye
ext_command(char * buf,size_t bufsz,uint8_t cmd,const void * ext,size_t extlen,const void * key,size_t keylen,const void * dta,size_t dtalen)803*7edb1a03SOskari Saarenmaa static off_t ext_command(char* buf,
804*7edb1a03SOskari Saarenmaa size_t bufsz,
805*7edb1a03SOskari Saarenmaa uint8_t cmd,
806*7edb1a03SOskari Saarenmaa const void* ext,
807*7edb1a03SOskari Saarenmaa size_t extlen,
808*7edb1a03SOskari Saarenmaa const void* key,
809*7edb1a03SOskari Saarenmaa size_t keylen,
810*7edb1a03SOskari Saarenmaa const void* dta,
811*7edb1a03SOskari Saarenmaa size_t dtalen) {
812*7edb1a03SOskari Saarenmaa protocol_binary_request_no_extras *request = (void*)buf;
813*7edb1a03SOskari Saarenmaa assert(bufsz > sizeof(*request) + extlen + keylen + dtalen);
814*7edb1a03SOskari Saarenmaa
815*7edb1a03SOskari Saarenmaa memset(request, 0, sizeof(*request));
816*7edb1a03SOskari Saarenmaa request->message.header.request.magic = PROTOCOL_BINARY_REQ;
817*7edb1a03SOskari Saarenmaa request->message.header.request.opcode = cmd;
818*7edb1a03SOskari Saarenmaa request->message.header.request.extlen = extlen;
819*7edb1a03SOskari Saarenmaa request->message.header.request.keylen = htons(keylen);
820*7edb1a03SOskari Saarenmaa request->message.header.request.bodylen = htonl(extlen + keylen + dtalen);
821*7edb1a03SOskari Saarenmaa request->message.header.request.opaque = 0xdeadbeef;
822*7edb1a03SOskari Saarenmaa
823*7edb1a03SOskari Saarenmaa off_t ext_offset = sizeof(protocol_binary_request_no_extras);
824*7edb1a03SOskari Saarenmaa off_t key_offset = ext_offset + extlen;
825*7edb1a03SOskari Saarenmaa off_t dta_offset = key_offset + keylen;
826*7edb1a03SOskari Saarenmaa
827*7edb1a03SOskari Saarenmaa if (ext != NULL) {
828*7edb1a03SOskari Saarenmaa memcpy(buf + ext_offset, ext, extlen);
829*7edb1a03SOskari Saarenmaa }
830*7edb1a03SOskari Saarenmaa if (key != NULL) {
831*7edb1a03SOskari Saarenmaa memcpy(buf + key_offset, key, keylen);
832*7edb1a03SOskari Saarenmaa }
833*7edb1a03SOskari Saarenmaa if (dta != NULL) {
834*7edb1a03SOskari Saarenmaa memcpy(buf + dta_offset, dta, dtalen);
835*7edb1a03SOskari Saarenmaa }
836*7edb1a03SOskari Saarenmaa
837*7edb1a03SOskari Saarenmaa return sizeof(*request) + extlen + keylen + dtalen;
838*7edb1a03SOskari Saarenmaa }
839*7edb1a03SOskari Saarenmaa
raw_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen)8406ae66c84STrond Norbye static off_t raw_command(char* buf,
8416ae66c84STrond Norbye size_t bufsz,
8426ae66c84STrond Norbye uint8_t cmd,
8436ae66c84STrond Norbye const void* key,
8446ae66c84STrond Norbye size_t keylen,
8456ae66c84STrond Norbye const void* dta,
8466ae66c84STrond Norbye size_t dtalen) {
8476ae66c84STrond Norbye /* all of the storage commands use the same command layout */
848*7edb1a03SOskari Saarenmaa return ext_command(buf, bufsz, cmd, NULL, 0, key, keylen, dta, dtalen);
8496ae66c84STrond Norbye }
8506ae66c84STrond Norbye
flush_command(char * buf,size_t bufsz,uint8_t cmd,uint32_t exptime,bool use_extra)8516ae66c84STrond Norbye static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
8526ae66c84STrond Norbye protocol_binary_request_flush *request = (void*)buf;
8536ae66c84STrond Norbye assert(bufsz > sizeof(*request));
8546ae66c84STrond Norbye
8556ae66c84STrond Norbye memset(request, 0, sizeof(*request));
8566ae66c84STrond Norbye request->message.header.request.magic = PROTOCOL_BINARY_REQ;
8576ae66c84STrond Norbye request->message.header.request.opcode = cmd;
8586ae66c84STrond Norbye
8596ae66c84STrond Norbye off_t size = sizeof(protocol_binary_request_no_extras);
8606ae66c84STrond Norbye if (use_extra) {
8616ae66c84STrond Norbye request->message.header.request.extlen = 4;
8626ae66c84STrond Norbye request->message.body.expiration = htonl(exptime);
8636ae66c84STrond Norbye request->message.header.request.bodylen = htonl(4);
8646ae66c84STrond Norbye size += 4;
8656ae66c84STrond Norbye }
8666ae66c84STrond Norbye
8676ae66c84STrond Norbye request->message.header.request.opaque = 0xdeadbeef;
8686ae66c84STrond Norbye
8696ae66c84STrond Norbye return size;
8706ae66c84STrond Norbye }
8716ae66c84STrond Norbye
872d87f568aSdormando
touch_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,uint32_t exptime)873d87f568aSdormando static off_t touch_command(char* buf,
874d87f568aSdormando size_t bufsz,
875d87f568aSdormando uint8_t cmd,
876d87f568aSdormando const void* key,
877d87f568aSdormando size_t keylen,
878d87f568aSdormando uint32_t exptime) {
879d87f568aSdormando protocol_binary_request_touch *request = (void*)buf;
880d87f568aSdormando assert(bufsz > sizeof(*request));
881d87f568aSdormando
882d87f568aSdormando memset(request, 0, sizeof(*request));
883d87f568aSdormando request->message.header.request.magic = PROTOCOL_BINARY_REQ;
884d87f568aSdormando request->message.header.request.opcode = cmd;
885d87f568aSdormando
886d87f568aSdormando request->message.header.request.keylen = htons(keylen);
887d87f568aSdormando request->message.header.request.extlen = 4;
888d87f568aSdormando request->message.body.expiration = htonl(exptime);
889d87f568aSdormando request->message.header.request.bodylen = htonl(keylen + 4);
890d87f568aSdormando
891d87f568aSdormando request->message.header.request.opaque = 0xdeadbeef;
892d87f568aSdormando
893d87f568aSdormando off_t key_offset = sizeof(protocol_binary_request_no_extras) + 4;
894d87f568aSdormando
895d87f568aSdormando memcpy(buf + key_offset, key, keylen);
896d87f568aSdormando return sizeof(protocol_binary_request_no_extras) + 4 + keylen;
897d87f568aSdormando }
898d87f568aSdormando
arithmetic_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,uint64_t delta,uint64_t initial,uint32_t exp)8996ae66c84STrond Norbye static off_t arithmetic_command(char* buf,
9006ae66c84STrond Norbye size_t bufsz,
9016ae66c84STrond Norbye uint8_t cmd,
9026ae66c84STrond Norbye const void* key,
9036ae66c84STrond Norbye size_t keylen,
9046ae66c84STrond Norbye uint64_t delta,
9056ae66c84STrond Norbye uint64_t initial,
9066ae66c84STrond Norbye uint32_t exp) {
9076ae66c84STrond Norbye protocol_binary_request_incr *request = (void*)buf;
9086ae66c84STrond Norbye assert(bufsz > sizeof(*request) + keylen);
9096ae66c84STrond Norbye
9106ae66c84STrond Norbye memset(request, 0, sizeof(*request));
9116ae66c84STrond Norbye request->message.header.request.magic = PROTOCOL_BINARY_REQ;
9126ae66c84STrond Norbye request->message.header.request.opcode = cmd;
9136ae66c84STrond Norbye request->message.header.request.keylen = htons(keylen);
9146ae66c84STrond Norbye request->message.header.request.extlen = 20;
9156ae66c84STrond Norbye request->message.header.request.bodylen = htonl(keylen + 20);
9166ae66c84STrond Norbye request->message.header.request.opaque = 0xdeadbeef;
9176ae66c84STrond Norbye request->message.body.delta = htonll(delta);
9186ae66c84STrond Norbye request->message.body.initial = htonll(initial);
9196ae66c84STrond Norbye request->message.body.expiration = htonl(exp);
9206ae66c84STrond Norbye
9216ae66c84STrond Norbye off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
9226ae66c84STrond Norbye
9236ae66c84STrond Norbye memcpy(buf + key_offset, key, keylen);
9246ae66c84STrond Norbye return key_offset + keylen;
9256ae66c84STrond Norbye }
9266ae66c84STrond Norbye
validate_response_header(protocol_binary_response_no_extras * response,uint8_t cmd,uint16_t status)9276ae66c84STrond Norbye static void validate_response_header(protocol_binary_response_no_extras *response,
9286ae66c84STrond Norbye uint8_t cmd, uint16_t status)
9296ae66c84STrond Norbye {
9306ae66c84STrond Norbye assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
9316ae66c84STrond Norbye assert(response->message.header.response.opcode == cmd);
9326ae66c84STrond Norbye assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
9336ae66c84STrond Norbye assert(response->message.header.response.status == status);
9346ae66c84STrond Norbye assert(response->message.header.response.opaque == 0xdeadbeef);
9356ae66c84STrond Norbye
9366ae66c84STrond Norbye if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
9376ae66c84STrond Norbye switch (cmd) {
9386ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_ADDQ:
9396ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_APPENDQ:
9406ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DECREMENTQ:
9416ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DELETEQ:
9426ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_FLUSHQ:
9436ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_INCREMENTQ:
9446ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_PREPENDQ:
9456ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_QUITQ:
9466ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_REPLACEQ:
9476ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_SETQ:
9486ae66c84STrond Norbye assert("Quiet command shouldn't return on success" == NULL);
9496ae66c84STrond Norbye default:
9506ae66c84STrond Norbye break;
9516ae66c84STrond Norbye }
9526ae66c84STrond Norbye
9536ae66c84STrond Norbye switch (cmd) {
9546ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_ADD:
9556ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_REPLACE:
9566ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_SET:
9576ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_APPEND:
9586ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_PREPEND:
9596ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
9606ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
9616ae66c84STrond Norbye assert(response->message.header.response.bodylen == 0);
9626ae66c84STrond Norbye assert(response->message.header.response.cas != 0);
9636ae66c84STrond Norbye break;
9646ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_FLUSH:
9656ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_NOOP:
9666ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_QUIT:
9676ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DELETE:
9686ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
9696ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
9706ae66c84STrond Norbye assert(response->message.header.response.bodylen == 0);
9716ae66c84STrond Norbye assert(response->message.header.response.cas == 0);
9726ae66c84STrond Norbye break;
9736ae66c84STrond Norbye
9746ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DECREMENT:
9756ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_INCREMENT:
9766ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
9776ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
9786ae66c84STrond Norbye assert(response->message.header.response.bodylen == 8);
9796ae66c84STrond Norbye assert(response->message.header.response.cas != 0);
9806ae66c84STrond Norbye break;
9816ae66c84STrond Norbye
9826ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_STAT:
9836ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
9846ae66c84STrond Norbye /* key and value exists in all packets except in the terminating */
9856ae66c84STrond Norbye assert(response->message.header.response.cas == 0);
9866ae66c84STrond Norbye break;
9876ae66c84STrond Norbye
9886ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_VERSION:
9896ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
9906ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
9916ae66c84STrond Norbye assert(response->message.header.response.bodylen != 0);
9926ae66c84STrond Norbye assert(response->message.header.response.cas == 0);
9936ae66c84STrond Norbye break;
9946ae66c84STrond Norbye
9956ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GET:
9966ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETQ:
997*7edb1a03SOskari Saarenmaa case PROTOCOL_BINARY_CMD_GAT:
998*7edb1a03SOskari Saarenmaa case PROTOCOL_BINARY_CMD_GATQ:
9996ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
10006ae66c84STrond Norbye assert(response->message.header.response.extlen == 4);
10016ae66c84STrond Norbye assert(response->message.header.response.cas != 0);
10026ae66c84STrond Norbye break;
10036ae66c84STrond Norbye
10046ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETK:
10056ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETKQ:
1006*7edb1a03SOskari Saarenmaa case PROTOCOL_BINARY_CMD_GATK:
1007*7edb1a03SOskari Saarenmaa case PROTOCOL_BINARY_CMD_GATKQ:
10086ae66c84STrond Norbye assert(response->message.header.response.keylen != 0);
10096ae66c84STrond Norbye assert(response->message.header.response.extlen == 4);
10106ae66c84STrond Norbye assert(response->message.header.response.cas != 0);
10116ae66c84STrond Norbye break;
10126ae66c84STrond Norbye
10136ae66c84STrond Norbye default:
10146ae66c84STrond Norbye /* Undefined command code */
10156ae66c84STrond Norbye break;
10166ae66c84STrond Norbye }
10176ae66c84STrond Norbye } else {
10186ae66c84STrond Norbye assert(response->message.header.response.cas == 0);
10196ae66c84STrond Norbye assert(response->message.header.response.extlen == 0);
10200d16e8c0Sdormando if (cmd != PROTOCOL_BINARY_CMD_GETK &&
10210d16e8c0Sdormando cmd != PROTOCOL_BINARY_CMD_GATK) {
10226ae66c84STrond Norbye assert(response->message.header.response.keylen == 0);
10236ae66c84STrond Norbye }
10246ae66c84STrond Norbye }
10256ae66c84STrond Norbye }
10266ae66c84STrond Norbye
test_binary_noop(void)10276ae66c84STrond Norbye static enum test_return test_binary_noop(void) {
10286ae66c84STrond Norbye union {
10296ae66c84STrond Norbye protocol_binary_request_no_extras request;
10306ae66c84STrond Norbye protocol_binary_response_no_extras response;
10316ae66c84STrond Norbye char bytes[1024];
10326ae66c84STrond Norbye } buffer;
10336ae66c84STrond Norbye
10346ae66c84STrond Norbye size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
10356ae66c84STrond Norbye PROTOCOL_BINARY_CMD_NOOP,
10366ae66c84STrond Norbye NULL, 0, NULL, 0);
10376ae66c84STrond Norbye
10386ae66c84STrond Norbye safe_send(buffer.bytes, len, false);
10396ae66c84STrond Norbye safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
10406ae66c84STrond Norbye validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
10416ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
10426ae66c84STrond Norbye
10436ae66c84STrond Norbye return TEST_PASS;
10446ae66c84STrond Norbye }
10456ae66c84STrond Norbye
test_binary_quit_impl(uint8_t cmd)10466ae66c84STrond Norbye static enum test_return test_binary_quit_impl(uint8_t cmd) {
10476ae66c84STrond Norbye union {
10486ae66c84STrond Norbye protocol_binary_request_no_extras request;
10496ae66c84STrond Norbye protocol_binary_response_no_extras response;
10506ae66c84STrond Norbye char bytes[1024];
10516ae66c84STrond Norbye } buffer;
10526ae66c84STrond Norbye size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
10536ae66c84STrond Norbye cmd, NULL, 0, NULL, 0);
10546ae66c84STrond Norbye
10556ae66c84STrond Norbye safe_send(buffer.bytes, len, false);
10566ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
10576ae66c84STrond Norbye safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
10586ae66c84STrond Norbye validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
10596ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
10606ae66c84STrond Norbye }
10616ae66c84STrond Norbye
10626ae66c84STrond Norbye /* Socket should be closed now, read should return 0 */
10636ae66c84STrond Norbye assert(read(sock, buffer.bytes, sizeof(buffer.bytes)) == 0);
10646ae66c84STrond Norbye close(sock);
10650731dc82STrond Norbye sock = connect_server("127.0.0.1", port, false);
10666ae66c84STrond Norbye
10676ae66c84STrond Norbye return TEST_PASS;
10686ae66c84STrond Norbye }
10696ae66c84STrond Norbye
test_binary_quit(void)10706ae66c84STrond Norbye static enum test_return test_binary_quit(void) {
10716ae66c84STrond Norbye return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
10726ae66c84STrond Norbye }
10736ae66c84STrond Norbye
test_binary_quitq(void)10746ae66c84STrond Norbye static enum test_return test_binary_quitq(void) {
10756ae66c84STrond Norbye return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
10766ae66c84STrond Norbye }
10776ae66c84STrond Norbye
test_binary_set_impl(const char * key,uint8_t cmd)10786ae66c84STrond Norbye static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
10796ae66c84STrond Norbye union {
10806ae66c84STrond Norbye protocol_binary_request_no_extras request;
10816ae66c84STrond Norbye protocol_binary_response_no_extras response;
10826ae66c84STrond Norbye char bytes[1024];
10836ae66c84STrond Norbye } send, receive;
10846ae66c84STrond Norbye uint64_t value = 0xdeadbeefdeadcafe;
10856ae66c84STrond Norbye size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
10866ae66c84STrond Norbye key, strlen(key), &value, sizeof(value),
10876ae66c84STrond Norbye 0, 0);
10886ae66c84STrond Norbye
10896ae66c84STrond Norbye /* Set should work over and over again */
10906ae66c84STrond Norbye int ii;
10916ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
10926ae66c84STrond Norbye safe_send(send.bytes, len, false);
10936ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_SET) {
10946ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
10956ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
10966ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
10976ae66c84STrond Norbye }
10986ae66c84STrond Norbye }
10996ae66c84STrond Norbye
11006ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
11016ae66c84STrond Norbye return test_binary_noop();
11026ae66c84STrond Norbye }
11036ae66c84STrond Norbye
110452f16b3eSTrond Norbye send.request.message.header.request.cas = receive.response.message.header.response.cas;
110552f16b3eSTrond Norbye safe_send(send.bytes, len, false);
110652f16b3eSTrond Norbye if (cmd == PROTOCOL_BINARY_CMD_SET) {
110752f16b3eSTrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
110852f16b3eSTrond Norbye validate_response_header(&receive.response, cmd,
110952f16b3eSTrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
111052f16b3eSTrond Norbye assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
111152f16b3eSTrond Norbye } else {
111252f16b3eSTrond Norbye return test_binary_noop();
111352f16b3eSTrond Norbye }
111452f16b3eSTrond Norbye
11156ae66c84STrond Norbye return TEST_PASS;
11166ae66c84STrond Norbye }
11176ae66c84STrond Norbye
test_binary_set(void)11186ae66c84STrond Norbye static enum test_return test_binary_set(void) {
11196ae66c84STrond Norbye return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
11206ae66c84STrond Norbye }
11216ae66c84STrond Norbye
test_binary_setq(void)11226ae66c84STrond Norbye static enum test_return test_binary_setq(void) {
11236ae66c84STrond Norbye return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
11246ae66c84STrond Norbye }
11256ae66c84STrond Norbye
11266ae66c84STrond Norbye
test_binary_add_impl(const char * key,uint8_t cmd)11276ae66c84STrond Norbye static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
11286ae66c84STrond Norbye uint64_t value = 0xdeadbeefdeadcafe;
11296ae66c84STrond Norbye union {
11306ae66c84STrond Norbye protocol_binary_request_no_extras request;
11316ae66c84STrond Norbye protocol_binary_response_no_extras response;
11326ae66c84STrond Norbye char bytes[1024];
11336ae66c84STrond Norbye } send, receive;
11346ae66c84STrond Norbye size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
11356ae66c84STrond Norbye strlen(key), &value, sizeof(value),
11366ae66c84STrond Norbye 0, 0);
11376ae66c84STrond Norbye
11386ae66c84STrond Norbye /* Add should only work the first time */
11396ae66c84STrond Norbye int ii;
11406ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
11416ae66c84STrond Norbye safe_send(send.bytes, len, false);
11426ae66c84STrond Norbye if (ii == 0) {
11436ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_ADD) {
11446ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
11456ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
11466ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
11476ae66c84STrond Norbye }
11486ae66c84STrond Norbye } else {
11496ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
11506ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
11516ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
11526ae66c84STrond Norbye }
11536ae66c84STrond Norbye }
11546ae66c84STrond Norbye
11556ae66c84STrond Norbye return TEST_PASS;
11566ae66c84STrond Norbye }
11576ae66c84STrond Norbye
test_binary_add(void)11586ae66c84STrond Norbye static enum test_return test_binary_add(void) {
11596ae66c84STrond Norbye return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
11606ae66c84STrond Norbye }
11616ae66c84STrond Norbye
test_binary_addq(void)11626ae66c84STrond Norbye static enum test_return test_binary_addq(void) {
11636ae66c84STrond Norbye return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
11646ae66c84STrond Norbye }
11656ae66c84STrond Norbye
test_binary_replace_impl(const char * key,uint8_t cmd)11666ae66c84STrond Norbye static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
11676ae66c84STrond Norbye uint64_t value = 0xdeadbeefdeadcafe;
11686ae66c84STrond Norbye union {
11696ae66c84STrond Norbye protocol_binary_request_no_extras request;
11706ae66c84STrond Norbye protocol_binary_response_no_extras response;
11716ae66c84STrond Norbye char bytes[1024];
11726ae66c84STrond Norbye } send, receive;
11736ae66c84STrond Norbye size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
11746ae66c84STrond Norbye key, strlen(key), &value, sizeof(value),
11756ae66c84STrond Norbye 0, 0);
11766ae66c84STrond Norbye safe_send(send.bytes, len, false);
11776ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
11786ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
11796ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
11806ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes),
11816ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
11826ae66c84STrond Norbye key, strlen(key), &value, sizeof(value), 0, 0);
11836ae66c84STrond Norbye safe_send(send.bytes, len, false);
11846ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
11856ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
11866ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
11876ae66c84STrond Norbye
11886ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes), cmd,
11896ae66c84STrond Norbye key, strlen(key), &value, sizeof(value), 0, 0);
11906ae66c84STrond Norbye int ii;
11916ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
11926ae66c84STrond Norbye safe_send(send.bytes, len, false);
11936ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
11946ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
11956ae66c84STrond Norbye validate_response_header(&receive.response,
11966ae66c84STrond Norbye PROTOCOL_BINARY_CMD_REPLACE,
11976ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
11986ae66c84STrond Norbye }
11996ae66c84STrond Norbye }
12006ae66c84STrond Norbye
12016ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
12026ae66c84STrond Norbye test_binary_noop();
12036ae66c84STrond Norbye }
12046ae66c84STrond Norbye
12056ae66c84STrond Norbye return TEST_PASS;
12066ae66c84STrond Norbye }
12076ae66c84STrond Norbye
test_binary_replace(void)12086ae66c84STrond Norbye static enum test_return test_binary_replace(void) {
12096ae66c84STrond Norbye return test_binary_replace_impl("test_binary_replace",
12106ae66c84STrond Norbye PROTOCOL_BINARY_CMD_REPLACE);
12116ae66c84STrond Norbye }
12126ae66c84STrond Norbye
test_binary_replaceq(void)12136ae66c84STrond Norbye static enum test_return test_binary_replaceq(void) {
12146ae66c84STrond Norbye return test_binary_replace_impl("test_binary_replaceq",
12156ae66c84STrond Norbye PROTOCOL_BINARY_CMD_REPLACEQ);
12166ae66c84STrond Norbye }
12176ae66c84STrond Norbye
test_binary_delete_impl(const char * key,uint8_t cmd)12186ae66c84STrond Norbye static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
12196ae66c84STrond Norbye union {
12206ae66c84STrond Norbye protocol_binary_request_no_extras request;
12216ae66c84STrond Norbye protocol_binary_response_no_extras response;
12226ae66c84STrond Norbye char bytes[1024];
12236ae66c84STrond Norbye } send, receive;
12246ae66c84STrond Norbye size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
12256ae66c84STrond Norbye key, strlen(key), NULL, 0);
12266ae66c84STrond Norbye
12276ae66c84STrond Norbye safe_send(send.bytes, len, false);
12286ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12296ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
12306ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
12316ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes),
12326ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
12336ae66c84STrond Norbye key, strlen(key), NULL, 0, 0, 0);
12346ae66c84STrond Norbye safe_send(send.bytes, len, false);
12356ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12366ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
12376ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
12386ae66c84STrond Norbye
12396ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes),
12406ae66c84STrond Norbye cmd, key, strlen(key), NULL, 0);
12416ae66c84STrond Norbye safe_send(send.bytes, len, false);
12426ae66c84STrond Norbye
12436ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
12446ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12456ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
12466ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
12476ae66c84STrond Norbye }
12486ae66c84STrond Norbye
12496ae66c84STrond Norbye safe_send(send.bytes, len, false);
12506ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12516ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
12526ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
12536ae66c84STrond Norbye
12546ae66c84STrond Norbye return TEST_PASS;
12556ae66c84STrond Norbye }
12566ae66c84STrond Norbye
test_binary_delete(void)12576ae66c84STrond Norbye static enum test_return test_binary_delete(void) {
12586ae66c84STrond Norbye return test_binary_delete_impl("test_binary_delete",
12596ae66c84STrond Norbye PROTOCOL_BINARY_CMD_DELETE);
12606ae66c84STrond Norbye }
12616ae66c84STrond Norbye
test_binary_deleteq(void)12626ae66c84STrond Norbye static enum test_return test_binary_deleteq(void) {
12636ae66c84STrond Norbye return test_binary_delete_impl("test_binary_deleteq",
12646ae66c84STrond Norbye PROTOCOL_BINARY_CMD_DELETEQ);
12656ae66c84STrond Norbye }
12666ae66c84STrond Norbye
test_binary_get_impl(const char * key,uint8_t cmd)12676ae66c84STrond Norbye static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
12686ae66c84STrond Norbye union {
12696ae66c84STrond Norbye protocol_binary_request_no_extras request;
12706ae66c84STrond Norbye protocol_binary_response_no_extras response;
12716ae66c84STrond Norbye char bytes[1024];
12726ae66c84STrond Norbye } send, receive;
1273*7edb1a03SOskari Saarenmaa
1274*7edb1a03SOskari Saarenmaa uint32_t expiration = htonl(3600);
1275*7edb1a03SOskari Saarenmaa size_t extlen = 0;
1276*7edb1a03SOskari Saarenmaa if (cmd == PROTOCOL_BINARY_CMD_GAT || cmd == PROTOCOL_BINARY_CMD_GATK)
1277*7edb1a03SOskari Saarenmaa extlen = sizeof(expiration);
1278*7edb1a03SOskari Saarenmaa
1279*7edb1a03SOskari Saarenmaa size_t len = ext_command(send.bytes, sizeof(send.bytes), cmd,
1280*7edb1a03SOskari Saarenmaa extlen ? &expiration : NULL, extlen,
12816ae66c84STrond Norbye key, strlen(key), NULL, 0);
12826ae66c84STrond Norbye
12836ae66c84STrond Norbye safe_send(send.bytes, len, false);
12846ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12856ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
12866ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
12876ae66c84STrond Norbye
12886ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes),
12896ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
12906ae66c84STrond Norbye key, strlen(key), NULL, 0,
12916ae66c84STrond Norbye 0, 0);
12926ae66c84STrond Norbye safe_send(send.bytes, len, false);
12936ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
12946ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
12956ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
12966ae66c84STrond Norbye
12976ae66c84STrond Norbye /* run a little pipeline test ;-) */
12986ae66c84STrond Norbye len = 0;
12996ae66c84STrond Norbye int ii;
13006ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
13016ae66c84STrond Norbye union {
13026ae66c84STrond Norbye protocol_binary_request_no_extras request;
13036ae66c84STrond Norbye char bytes[1024];
13046ae66c84STrond Norbye } temp;
1305*7edb1a03SOskari Saarenmaa size_t l = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
1306*7edb1a03SOskari Saarenmaa extlen ? &expiration : NULL, extlen,
1307*7edb1a03SOskari Saarenmaa key, strlen(key), NULL, 0);
13086ae66c84STrond Norbye memcpy(send.bytes + len, temp.bytes, l);
13096ae66c84STrond Norbye len += l;
13106ae66c84STrond Norbye }
13116ae66c84STrond Norbye
13126ae66c84STrond Norbye safe_send(send.bytes, len, false);
13136ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
13146ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
13156ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
13166ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
13176ae66c84STrond Norbye }
13186ae66c84STrond Norbye
13196ae66c84STrond Norbye return TEST_PASS;
13206ae66c84STrond Norbye }
13216ae66c84STrond Norbye
test_binary_get(void)13226ae66c84STrond Norbye static enum test_return test_binary_get(void) {
13236ae66c84STrond Norbye return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
13246ae66c84STrond Norbye }
13256ae66c84STrond Norbye
test_binary_getk(void)13266ae66c84STrond Norbye static enum test_return test_binary_getk(void) {
13276ae66c84STrond Norbye return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
13286ae66c84STrond Norbye }
13296ae66c84STrond Norbye
test_binary_gat(void)1330*7edb1a03SOskari Saarenmaa static enum test_return test_binary_gat(void) {
1331*7edb1a03SOskari Saarenmaa return test_binary_get_impl("test_binary_gat", PROTOCOL_BINARY_CMD_GAT);
1332*7edb1a03SOskari Saarenmaa }
1333*7edb1a03SOskari Saarenmaa
test_binary_gatk(void)1334*7edb1a03SOskari Saarenmaa static enum test_return test_binary_gatk(void) {
1335*7edb1a03SOskari Saarenmaa return test_binary_get_impl("test_binary_gatk", PROTOCOL_BINARY_CMD_GATK);
1336*7edb1a03SOskari Saarenmaa }
1337*7edb1a03SOskari Saarenmaa
test_binary_getq_impl(const char * key,uint8_t cmd)13386ae66c84STrond Norbye static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
13396ae66c84STrond Norbye const char *missing = "test_binary_getq_missing";
13406ae66c84STrond Norbye union {
13416ae66c84STrond Norbye protocol_binary_request_no_extras request;
13426ae66c84STrond Norbye protocol_binary_response_no_extras response;
13436ae66c84STrond Norbye char bytes[1024];
13446ae66c84STrond Norbye } send, temp, receive;
1345*7edb1a03SOskari Saarenmaa
1346*7edb1a03SOskari Saarenmaa uint32_t expiration = htonl(3600);
1347*7edb1a03SOskari Saarenmaa size_t extlen = 0;
1348*7edb1a03SOskari Saarenmaa if (cmd == PROTOCOL_BINARY_CMD_GATQ || cmd == PROTOCOL_BINARY_CMD_GATKQ)
1349*7edb1a03SOskari Saarenmaa extlen = sizeof(expiration);
1350*7edb1a03SOskari Saarenmaa
13516ae66c84STrond Norbye size_t len = storage_command(send.bytes, sizeof(send.bytes),
13526ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
13536ae66c84STrond Norbye key, strlen(key), NULL, 0,
13546ae66c84STrond Norbye 0, 0);
1355*7edb1a03SOskari Saarenmaa size_t len2 = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
1356*7edb1a03SOskari Saarenmaa extlen ? &expiration : NULL, extlen,
13576ae66c84STrond Norbye missing, strlen(missing), NULL, 0);
13586ae66c84STrond Norbye /* I need to change the first opaque so that I can separate the two
13596ae66c84STrond Norbye * return packets */
13606ae66c84STrond Norbye temp.request.message.header.request.opaque = 0xfeedface;
13616ae66c84STrond Norbye memcpy(send.bytes + len, temp.bytes, len2);
13626ae66c84STrond Norbye len += len2;
13636ae66c84STrond Norbye
1364*7edb1a03SOskari Saarenmaa len2 = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
1365*7edb1a03SOskari Saarenmaa extlen ? &expiration : NULL, extlen,
13666ae66c84STrond Norbye key, strlen(key), NULL, 0);
13676ae66c84STrond Norbye memcpy(send.bytes + len, temp.bytes, len2);
13686ae66c84STrond Norbye len += len2;
13696ae66c84STrond Norbye
13706ae66c84STrond Norbye safe_send(send.bytes, len, false);
13716ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
13726ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
13736ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
13746ae66c84STrond Norbye /* The first GETQ shouldn't return anything */
13756ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
13766ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
13776ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
13786ae66c84STrond Norbye
13796ae66c84STrond Norbye return TEST_PASS;
13806ae66c84STrond Norbye }
13816ae66c84STrond Norbye
test_binary_getq(void)13826ae66c84STrond Norbye static enum test_return test_binary_getq(void) {
13836ae66c84STrond Norbye return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
13846ae66c84STrond Norbye }
13856ae66c84STrond Norbye
test_binary_getkq(void)13866ae66c84STrond Norbye static enum test_return test_binary_getkq(void) {
13876ae66c84STrond Norbye return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
13886ae66c84STrond Norbye }
13896ae66c84STrond Norbye
test_binary_gatq(void)1390*7edb1a03SOskari Saarenmaa static enum test_return test_binary_gatq(void) {
1391*7edb1a03SOskari Saarenmaa return test_binary_getq_impl("test_binary_gatq", PROTOCOL_BINARY_CMD_GATQ);
1392*7edb1a03SOskari Saarenmaa }
1393*7edb1a03SOskari Saarenmaa
test_binary_gatkq(void)1394*7edb1a03SOskari Saarenmaa static enum test_return test_binary_gatkq(void) {
1395*7edb1a03SOskari Saarenmaa return test_binary_getq_impl("test_binary_gatkq", PROTOCOL_BINARY_CMD_GATKQ);
1396*7edb1a03SOskari Saarenmaa }
1397*7edb1a03SOskari Saarenmaa
test_binary_incr_impl(const char * key,uint8_t cmd)13986ae66c84STrond Norbye static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
13996ae66c84STrond Norbye union {
14006ae66c84STrond Norbye protocol_binary_request_no_extras request;
14016ae66c84STrond Norbye protocol_binary_response_no_extras response_header;
14026ae66c84STrond Norbye protocol_binary_response_incr response;
14036ae66c84STrond Norbye char bytes[1024];
14046ae66c84STrond Norbye } send, receive;
14056ae66c84STrond Norbye size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
14066ae66c84STrond Norbye key, strlen(key), 1, 0, 0);
14076ae66c84STrond Norbye
14086ae66c84STrond Norbye int ii;
14096ae66c84STrond Norbye for (ii = 0; ii < 10; ++ii) {
14106ae66c84STrond Norbye safe_send(send.bytes, len, false);
14116ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
14126ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
14136ae66c84STrond Norbye validate_response_header(&receive.response_header, cmd,
14146ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
14156ae66c84STrond Norbye assert(ntohll(receive.response.message.body.value) == ii);
14166ae66c84STrond Norbye }
14176ae66c84STrond Norbye }
14186ae66c84STrond Norbye
14196ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
14206ae66c84STrond Norbye test_binary_noop();
14216ae66c84STrond Norbye }
14226ae66c84STrond Norbye return TEST_PASS;
14236ae66c84STrond Norbye }
14246ae66c84STrond Norbye
test_binary_incr(void)14256ae66c84STrond Norbye static enum test_return test_binary_incr(void) {
14266ae66c84STrond Norbye return test_binary_incr_impl("test_binary_incr",
14276ae66c84STrond Norbye PROTOCOL_BINARY_CMD_INCREMENT);
14286ae66c84STrond Norbye }
14296ae66c84STrond Norbye
test_binary_incrq(void)14306ae66c84STrond Norbye static enum test_return test_binary_incrq(void) {
14316ae66c84STrond Norbye return test_binary_incr_impl("test_binary_incrq",
14326ae66c84STrond Norbye PROTOCOL_BINARY_CMD_INCREMENTQ);
14336ae66c84STrond Norbye }
14346ae66c84STrond Norbye
test_binary_decr_impl(const char * key,uint8_t cmd)14356ae66c84STrond Norbye static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
14366ae66c84STrond Norbye union {
14376ae66c84STrond Norbye protocol_binary_request_no_extras request;
14386ae66c84STrond Norbye protocol_binary_response_no_extras response_header;
14396ae66c84STrond Norbye protocol_binary_response_decr response;
14406ae66c84STrond Norbye char bytes[1024];
14416ae66c84STrond Norbye } send, receive;
14426ae66c84STrond Norbye size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
14436ae66c84STrond Norbye key, strlen(key), 1, 9, 0);
14446ae66c84STrond Norbye
14456ae66c84STrond Norbye int ii;
14466ae66c84STrond Norbye for (ii = 9; ii >= 0; --ii) {
14476ae66c84STrond Norbye safe_send(send.bytes, len, false);
14486ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
14496ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
14506ae66c84STrond Norbye validate_response_header(&receive.response_header, cmd,
14516ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
14526ae66c84STrond Norbye assert(ntohll(receive.response.message.body.value) == ii);
14536ae66c84STrond Norbye }
14546ae66c84STrond Norbye }
14556ae66c84STrond Norbye
14566ae66c84STrond Norbye /* decr on 0 should not wrap */
14576ae66c84STrond Norbye safe_send(send.bytes, len, false);
14586ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
14596ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
14606ae66c84STrond Norbye validate_response_header(&receive.response_header, cmd,
14616ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
14626ae66c84STrond Norbye assert(ntohll(receive.response.message.body.value) == 0);
14636ae66c84STrond Norbye } else {
14646ae66c84STrond Norbye test_binary_noop();
14656ae66c84STrond Norbye }
14666ae66c84STrond Norbye
14676ae66c84STrond Norbye return TEST_PASS;
14686ae66c84STrond Norbye }
14696ae66c84STrond Norbye
test_binary_decr(void)14706ae66c84STrond Norbye static enum test_return test_binary_decr(void) {
14716ae66c84STrond Norbye return test_binary_decr_impl("test_binary_decr",
14726ae66c84STrond Norbye PROTOCOL_BINARY_CMD_DECREMENT);
14736ae66c84STrond Norbye }
14746ae66c84STrond Norbye
test_binary_decrq(void)14756ae66c84STrond Norbye static enum test_return test_binary_decrq(void) {
14766ae66c84STrond Norbye return test_binary_decr_impl("test_binary_decrq",
14776ae66c84STrond Norbye PROTOCOL_BINARY_CMD_DECREMENTQ);
14786ae66c84STrond Norbye }
14796ae66c84STrond Norbye
test_binary_version(void)14806ae66c84STrond Norbye static enum test_return test_binary_version(void) {
14816ae66c84STrond Norbye union {
14826ae66c84STrond Norbye protocol_binary_request_no_extras request;
14836ae66c84STrond Norbye protocol_binary_response_no_extras response;
14846ae66c84STrond Norbye char bytes[1024];
14856ae66c84STrond Norbye } buffer;
14866ae66c84STrond Norbye
14876ae66c84STrond Norbye size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
14886ae66c84STrond Norbye PROTOCOL_BINARY_CMD_VERSION,
14896ae66c84STrond Norbye NULL, 0, NULL, 0);
14906ae66c84STrond Norbye
14916ae66c84STrond Norbye safe_send(buffer.bytes, len, false);
14926ae66c84STrond Norbye safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
14936ae66c84STrond Norbye validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
14946ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
14956ae66c84STrond Norbye
14966ae66c84STrond Norbye return TEST_PASS;
14976ae66c84STrond Norbye }
14986ae66c84STrond Norbye
test_binary_flush_impl(const char * key,uint8_t cmd)14996ae66c84STrond Norbye static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
15006ae66c84STrond Norbye union {
15016ae66c84STrond Norbye protocol_binary_request_no_extras request;
15026ae66c84STrond Norbye protocol_binary_response_no_extras response;
15036ae66c84STrond Norbye char bytes[1024];
15046ae66c84STrond Norbye } send, receive;
15056ae66c84STrond Norbye
15066ae66c84STrond Norbye size_t len = storage_command(send.bytes, sizeof(send.bytes),
15076ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
15086ae66c84STrond Norbye key, strlen(key), NULL, 0, 0, 0);
15096ae66c84STrond Norbye safe_send(send.bytes, len, false);
15106ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15116ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
15126ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15136ae66c84STrond Norbye
15146ae66c84STrond Norbye len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
15156ae66c84STrond Norbye safe_send(send.bytes, len, false);
15166ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
15176ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15186ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
15196ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15206ae66c84STrond Norbye }
15216ae66c84STrond Norbye
15226ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
15236ae66c84STrond Norbye key, strlen(key), NULL, 0);
15246ae66c84STrond Norbye safe_send(send.bytes, len, false);
15256ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15266ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
15276ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15286ae66c84STrond Norbye
15296ae66c84STrond Norbye sleep(2);
15306ae66c84STrond Norbye safe_send(send.bytes, len, false);
15316ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15326ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
15336ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
15346ae66c84STrond Norbye
15356ae66c84STrond Norbye int ii;
15366ae66c84STrond Norbye for (ii = 0; ii < 2; ++ii) {
15376ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes),
15386ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
15396ae66c84STrond Norbye key, strlen(key), NULL, 0, 0, 0);
15406ae66c84STrond Norbye safe_send(send.bytes, len, false);
15416ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15426ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
15436ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15446ae66c84STrond Norbye
15456ae66c84STrond Norbye len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
15466ae66c84STrond Norbye safe_send(send.bytes, len, false);
15476ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
15486ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15496ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
15506ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15516ae66c84STrond Norbye }
15526ae66c84STrond Norbye
15536ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes),
15546ae66c84STrond Norbye PROTOCOL_BINARY_CMD_GET,
15556ae66c84STrond Norbye key, strlen(key), NULL, 0);
15566ae66c84STrond Norbye safe_send(send.bytes, len, false);
15576ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15586ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
15596ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
15606ae66c84STrond Norbye }
15616ae66c84STrond Norbye
15626ae66c84STrond Norbye return TEST_PASS;
15636ae66c84STrond Norbye }
15646ae66c84STrond Norbye
test_binary_flush(void)15656ae66c84STrond Norbye static enum test_return test_binary_flush(void) {
15666ae66c84STrond Norbye return test_binary_flush_impl("test_binary_flush",
15676ae66c84STrond Norbye PROTOCOL_BINARY_CMD_FLUSH);
15686ae66c84STrond Norbye }
15696ae66c84STrond Norbye
test_binary_flushq(void)15706ae66c84STrond Norbye static enum test_return test_binary_flushq(void) {
15716ae66c84STrond Norbye return test_binary_flush_impl("test_binary_flushq",
15726ae66c84STrond Norbye PROTOCOL_BINARY_CMD_FLUSHQ);
15736ae66c84STrond Norbye }
15746ae66c84STrond Norbye
test_binary_concat_impl(const char * key,uint8_t cmd)15756ae66c84STrond Norbye static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
15766ae66c84STrond Norbye union {
15776ae66c84STrond Norbye protocol_binary_request_no_extras request;
15786ae66c84STrond Norbye protocol_binary_response_no_extras response;
15796ae66c84STrond Norbye char bytes[1024];
15806ae66c84STrond Norbye } send, receive;
15816ae66c84STrond Norbye const char *value = "world";
15826ae66c84STrond Norbye
15836ae66c84STrond Norbye size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
15846ae66c84STrond Norbye key, strlen(key), value, strlen(value));
15856ae66c84STrond Norbye
15866ae66c84STrond Norbye
15876ae66c84STrond Norbye safe_send(send.bytes, len, false);
15886ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15896ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
15906ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_NOT_STORED);
15916ae66c84STrond Norbye
15926ae66c84STrond Norbye len = storage_command(send.bytes, sizeof(send.bytes),
15936ae66c84STrond Norbye PROTOCOL_BINARY_CMD_ADD,
15946ae66c84STrond Norbye key, strlen(key), value, strlen(value), 0, 0);
15956ae66c84STrond Norbye safe_send(send.bytes, len, false);
15966ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
15976ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
15986ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
15996ae66c84STrond Norbye
16006ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes), cmd,
16016ae66c84STrond Norbye key, strlen(key), value, strlen(value));
16026ae66c84STrond Norbye safe_send(send.bytes, len, false);
16036ae66c84STrond Norbye
16046ae66c84STrond Norbye if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
16056ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
16066ae66c84STrond Norbye validate_response_header(&receive.response, cmd,
16076ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
16086ae66c84STrond Norbye } else {
16096ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
16106ae66c84STrond Norbye NULL, 0, NULL, 0);
16116ae66c84STrond Norbye safe_send(send.bytes, len, false);
16126ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
16136ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
16146ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
16156ae66c84STrond Norbye }
16166ae66c84STrond Norbye
16176ae66c84STrond Norbye len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
16186ae66c84STrond Norbye key, strlen(key), NULL, 0);
16196ae66c84STrond Norbye
16206ae66c84STrond Norbye safe_send(send.bytes, len, false);
16216ae66c84STrond Norbye safe_recv_packet(receive.bytes, sizeof(receive.bytes));
16226ae66c84STrond Norbye validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
16236ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
16246ae66c84STrond Norbye
16256ae66c84STrond Norbye assert(receive.response.message.header.response.keylen == strlen(key));
16266ae66c84STrond Norbye assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
16276ae66c84STrond Norbye
16286ae66c84STrond Norbye char *ptr = receive.bytes;
16296ae66c84STrond Norbye ptr += sizeof(receive.response);
16306ae66c84STrond Norbye ptr += 4;
16316ae66c84STrond Norbye
16326ae66c84STrond Norbye assert(memcmp(ptr, key, strlen(key)) == 0);
16336ae66c84STrond Norbye ptr += strlen(key);
16346ae66c84STrond Norbye assert(memcmp(ptr, value, strlen(value)) == 0);
16356ae66c84STrond Norbye ptr += strlen(value);
16366ae66c84STrond Norbye assert(memcmp(ptr, value, strlen(value)) == 0);
16376ae66c84STrond Norbye
16386ae66c84STrond Norbye return TEST_PASS;
16396ae66c84STrond Norbye }
16406ae66c84STrond Norbye
test_binary_append(void)16416ae66c84STrond Norbye static enum test_return test_binary_append(void) {
16426ae66c84STrond Norbye return test_binary_concat_impl("test_binary_append",
16436ae66c84STrond Norbye PROTOCOL_BINARY_CMD_APPEND);
16446ae66c84STrond Norbye }
16456ae66c84STrond Norbye
test_binary_prepend(void)16466ae66c84STrond Norbye static enum test_return test_binary_prepend(void) {
16476ae66c84STrond Norbye return test_binary_concat_impl("test_binary_prepend",
16486ae66c84STrond Norbye PROTOCOL_BINARY_CMD_PREPEND);
16496ae66c84STrond Norbye }
16506ae66c84STrond Norbye
test_binary_appendq(void)16516ae66c84STrond Norbye static enum test_return test_binary_appendq(void) {
16526ae66c84STrond Norbye return test_binary_concat_impl("test_binary_appendq",
16536ae66c84STrond Norbye PROTOCOL_BINARY_CMD_APPENDQ);
16546ae66c84STrond Norbye }
16556ae66c84STrond Norbye
test_binary_prependq(void)16566ae66c84STrond Norbye static enum test_return test_binary_prependq(void) {
16576ae66c84STrond Norbye return test_binary_concat_impl("test_binary_prependq",
16586ae66c84STrond Norbye PROTOCOL_BINARY_CMD_PREPENDQ);
16596ae66c84STrond Norbye }
16606ae66c84STrond Norbye
test_binary_stat(void)16616ae66c84STrond Norbye static enum test_return test_binary_stat(void) {
16626ae66c84STrond Norbye union {
16636ae66c84STrond Norbye protocol_binary_request_no_extras request;
16646ae66c84STrond Norbye protocol_binary_response_no_extras response;
16656ae66c84STrond Norbye char bytes[1024];
16666ae66c84STrond Norbye } buffer;
16676ae66c84STrond Norbye
16686ae66c84STrond Norbye size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
16696ae66c84STrond Norbye PROTOCOL_BINARY_CMD_STAT,
16706ae66c84STrond Norbye NULL, 0, NULL, 0);
16716ae66c84STrond Norbye
16726ae66c84STrond Norbye safe_send(buffer.bytes, len, false);
16736ae66c84STrond Norbye do {
16746ae66c84STrond Norbye safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
16756ae66c84STrond Norbye validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
16766ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_SUCCESS);
16776ae66c84STrond Norbye } while (buffer.response.message.header.response.keylen != 0);
16786ae66c84STrond Norbye
16796ae66c84STrond Norbye return TEST_PASS;
16806ae66c84STrond Norbye }
16816ae66c84STrond Norbye
test_binary_illegal(void)16826ae66c84STrond Norbye static enum test_return test_binary_illegal(void) {
16830d16e8c0Sdormando uint8_t cmd = 0x25;
16846ae66c84STrond Norbye while (cmd != 0x00) {
16856ae66c84STrond Norbye union {
16866ae66c84STrond Norbye protocol_binary_request_no_extras request;
16876ae66c84STrond Norbye protocol_binary_response_no_extras response;
16886ae66c84STrond Norbye char bytes[1024];
16896ae66c84STrond Norbye } buffer;
16906ae66c84STrond Norbye size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
16916ae66c84STrond Norbye cmd, NULL, 0, NULL, 0);
16926ae66c84STrond Norbye safe_send(buffer.bytes, len, false);
16936ae66c84STrond Norbye safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
16946ae66c84STrond Norbye validate_response_header(&buffer.response, cmd,
16956ae66c84STrond Norbye PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND);
16966ae66c84STrond Norbye ++cmd;
16976ae66c84STrond Norbye }
16986ae66c84STrond Norbye
16996ae66c84STrond Norbye return TEST_PASS;
17006ae66c84STrond Norbye }
17016ae66c84STrond Norbye
17026ae66c84STrond Norbye volatile bool hickup_thread_running;
17036ae66c84STrond Norbye
binary_hickup_recv_verification_thread(void * arg)17046ae66c84STrond Norbye static void *binary_hickup_recv_verification_thread(void *arg) {
17056ae66c84STrond Norbye protocol_binary_response_no_extras *response = malloc(65*1024);
17066ae66c84STrond Norbye if (response != NULL) {
17076ae66c84STrond Norbye while (safe_recv_packet(response, 65*1024)) {
17086ae66c84STrond Norbye /* Just validate the packet format */
17096ae66c84STrond Norbye validate_response_header(response,
17106ae66c84STrond Norbye response->message.header.response.opcode,
17116ae66c84STrond Norbye response->message.header.response.status);
17126ae66c84STrond Norbye }
17136ae66c84STrond Norbye free(response);
17146ae66c84STrond Norbye }
17156ae66c84STrond Norbye hickup_thread_running = false;
17166ae66c84STrond Norbye allow_closed_read = false;
17176ae66c84STrond Norbye return NULL;
17186ae66c84STrond Norbye }
17196ae66c84STrond Norbye
test_binary_pipeline_hickup_chunk(void * buffer,size_t buffersize)17206ae66c84STrond Norbye static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
17216ae66c84STrond Norbye off_t offset = 0;
17226ae66c84STrond Norbye char *key[256];
17236ae66c84STrond Norbye uint64_t value = 0xfeedfacedeadbeef;
17246ae66c84STrond Norbye
17256ae66c84STrond Norbye while (hickup_thread_running &&
17266ae66c84STrond Norbye offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
17276ae66c84STrond Norbye union {
17286ae66c84STrond Norbye protocol_binary_request_no_extras request;
17296ae66c84STrond Norbye char bytes[65 * 1024];
17306ae66c84STrond Norbye } command;
17316ae66c84STrond Norbye uint8_t cmd = (uint8_t)(rand() & 0xff);
17326ae66c84STrond Norbye size_t len;
17336ae66c84STrond Norbye size_t keylen = (rand() % 250) + 1;
17346ae66c84STrond Norbye
17356ae66c84STrond Norbye switch (cmd) {
17366ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_ADD:
17376ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_ADDQ:
17386ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_REPLACE:
17396ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_REPLACEQ:
17406ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_SET:
17416ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_SETQ:
17426ae66c84STrond Norbye len = storage_command(command.bytes, sizeof(command.bytes), cmd,
17436ae66c84STrond Norbye key, keylen , &value, sizeof(value),
17446ae66c84STrond Norbye 0, 0);
17456ae66c84STrond Norbye break;
17466ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_APPEND:
17476ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_APPENDQ:
17486ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_PREPEND:
17496ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_PREPENDQ:
17506ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes), cmd,
17516ae66c84STrond Norbye key, keylen, &value, sizeof(value));
17526ae66c84STrond Norbye break;
17536ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_FLUSH:
17546ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_FLUSHQ:
17556ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes), cmd,
17566ae66c84STrond Norbye NULL, 0, NULL, 0);
17576ae66c84STrond Norbye break;
17586ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_NOOP:
17596ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes), cmd,
17606ae66c84STrond Norbye NULL, 0, NULL, 0);
17616ae66c84STrond Norbye break;
17626ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DELETE:
17636ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DELETEQ:
17646ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes), cmd,
17656ae66c84STrond Norbye key, keylen, NULL, 0);
17666ae66c84STrond Norbye break;
17676ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DECREMENT:
17686ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_DECREMENTQ:
17696ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_INCREMENT:
17706ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_INCREMENTQ:
17716ae66c84STrond Norbye len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
17726ae66c84STrond Norbye key, keylen, 1, 0, 0);
17736ae66c84STrond Norbye break;
17746ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_VERSION:
17756ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes),
17766ae66c84STrond Norbye PROTOCOL_BINARY_CMD_VERSION,
17776ae66c84STrond Norbye NULL, 0, NULL, 0);
17786ae66c84STrond Norbye break;
17796ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GET:
17806ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETK:
17816ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETKQ:
17826ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_GETQ:
17836ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes), cmd,
17846ae66c84STrond Norbye key, keylen, NULL, 0);
17856ae66c84STrond Norbye break;
17866ae66c84STrond Norbye
1787d87f568aSdormando case PROTOCOL_BINARY_CMD_TOUCH:
1788d87f568aSdormando case PROTOCOL_BINARY_CMD_GAT:
1789d87f568aSdormando case PROTOCOL_BINARY_CMD_GATQ:
17900d16e8c0Sdormando case PROTOCOL_BINARY_CMD_GATK:
17910d16e8c0Sdormando case PROTOCOL_BINARY_CMD_GATKQ:
1792d87f568aSdormando len = touch_command(command.bytes, sizeof(command.bytes), cmd,
1793d87f568aSdormando key, keylen, 10);
1794d87f568aSdormando break;
1795d87f568aSdormando
17966ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_STAT:
17976ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes),
17986ae66c84STrond Norbye PROTOCOL_BINARY_CMD_STAT,
17996ae66c84STrond Norbye NULL, 0, NULL, 0);
18006ae66c84STrond Norbye break;
18016ae66c84STrond Norbye
1802f1307c4dSDustin Sallings case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
1803f1307c4dSDustin Sallings case PROTOCOL_BINARY_CMD_SASL_AUTH:
1804f1307c4dSDustin Sallings case PROTOCOL_BINARY_CMD_SASL_STEP:
1805f1307c4dSDustin Sallings /* Ignoring SASL */
18066ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_QUITQ:
18076ae66c84STrond Norbye case PROTOCOL_BINARY_CMD_QUIT:
18086ae66c84STrond Norbye /* I don't want to pass on the quit commands ;-) */
18096ae66c84STrond Norbye cmd |= 0xf0;
18106ae66c84STrond Norbye /* FALLTHROUGH */
18116ae66c84STrond Norbye default:
18126ae66c84STrond Norbye len = raw_command(command.bytes, sizeof(command.bytes),
18136ae66c84STrond Norbye cmd, NULL, 0, NULL, 0);
18146ae66c84STrond Norbye }
18156ae66c84STrond Norbye
18166ae66c84STrond Norbye if ((len + offset) < buffersize) {
18176ae66c84STrond Norbye memcpy(((char*)buffer) + offset, command.bytes, len);
18186ae66c84STrond Norbye offset += len;
18196ae66c84STrond Norbye } else {
18206ae66c84STrond Norbye break;
18216ae66c84STrond Norbye }
18226ae66c84STrond Norbye }
18236ae66c84STrond Norbye safe_send(buffer, offset, true);
18246ae66c84STrond Norbye
18256ae66c84STrond Norbye return TEST_PASS;
18266ae66c84STrond Norbye }
18276ae66c84STrond Norbye
test_binary_pipeline_hickup(void)18286ae66c84STrond Norbye static enum test_return test_binary_pipeline_hickup(void)
18296ae66c84STrond Norbye {
18306ae66c84STrond Norbye size_t buffersize = 65 * 1024;
18316ae66c84STrond Norbye void *buffer = malloc(buffersize);
18326ae66c84STrond Norbye int ii;
18336ae66c84STrond Norbye
18346ae66c84STrond Norbye pthread_t tid;
18356ae66c84STrond Norbye int ret;
18366ae66c84STrond Norbye allow_closed_read = true;
18376ae66c84STrond Norbye hickup_thread_running = true;
18386ae66c84STrond Norbye if ((ret = pthread_create(&tid, NULL,
18396ae66c84STrond Norbye binary_hickup_recv_verification_thread, NULL)) != 0) {
18406ae66c84STrond Norbye fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
18416ae66c84STrond Norbye return TEST_FAIL;
18426ae66c84STrond Norbye }
18436ae66c84STrond Norbye
18446ae66c84STrond Norbye /* Allow the thread to start */
18456ae66c84STrond Norbye usleep(250);
18466ae66c84STrond Norbye
18476ae66c84STrond Norbye srand((int)time(NULL));
18486ae66c84STrond Norbye for (ii = 0; ii < 2; ++ii) {
18496ae66c84STrond Norbye test_binary_pipeline_hickup_chunk(buffer, buffersize);
18506ae66c84STrond Norbye }
18516ae66c84STrond Norbye
18526ae66c84STrond Norbye /* send quitq to shut down the read thread ;-) */
18536ae66c84STrond Norbye size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
18546ae66c84STrond Norbye NULL, 0, NULL, 0);
18556ae66c84STrond Norbye safe_send(buffer, len, false);
18566ae66c84STrond Norbye
18576ae66c84STrond Norbye pthread_join(tid, NULL);
18586ae66c84STrond Norbye free(buffer);
18596ae66c84STrond Norbye return TEST_PASS;
18606ae66c84STrond Norbye }
18616ae66c84STrond Norbye
1862d8cc25b0STrond Norbye
test_issue_101(void)1863d8cc25b0STrond Norbye static enum test_return test_issue_101(void) {
1864cd3ffe8aSWing Lian enum { max = 2 };
1865d8cc25b0STrond Norbye enum test_return ret = TEST_PASS;
1866d8cc25b0STrond Norbye int fds[max];
1867d8cc25b0STrond Norbye int ii = 0;
1868d8cc25b0STrond Norbye pid_t child = 0;
1869d8cc25b0STrond Norbye
1870655a3a81SDustin Sallings if (getenv("SKIP_TEST_101") != NULL) {
1871655a3a81SDustin Sallings return TEST_SKIP;
1872655a3a81SDustin Sallings }
1873655a3a81SDustin Sallings
1874d8cc25b0STrond Norbye const char *command = "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
1875d8cc25b0STrond Norbye size_t cmdlen = strlen(command);
1876d8cc25b0STrond Norbye
1877d8cc25b0STrond Norbye server_pid = start_server(&port, false, 1000);
1878d8cc25b0STrond Norbye
1879d8cc25b0STrond Norbye for (ii = 0; ii < max; ++ii) {
1880d7b4103aSDustin Sallings fds[ii] = connect_server("127.0.0.1", port, true);
1881d7b4103aSDustin Sallings assert(fds[ii] > 0);
1882d8cc25b0STrond Norbye }
1883d8cc25b0STrond Norbye
1884d8cc25b0STrond Norbye /* Send command on the connection until it blocks */
1885d8cc25b0STrond Norbye for (ii = 0; ii < max; ++ii) {
1886d8cc25b0STrond Norbye bool more = true;
1887d8cc25b0STrond Norbye do {
1888d8cc25b0STrond Norbye ssize_t err = write(fds[ii], command, cmdlen);
1889d8cc25b0STrond Norbye if (err == -1) {
1890d8cc25b0STrond Norbye switch (errno) {
1891d8cc25b0STrond Norbye case EINTR:
1892d8cc25b0STrond Norbye break;
1893d8cc25b0STrond Norbye case ENOMEM:
1894d8cc25b0STrond Norbye case EWOULDBLOCK:
1895d8cc25b0STrond Norbye more = false;
1896d8cc25b0STrond Norbye break;
1897d8cc25b0STrond Norbye default:
1898d8cc25b0STrond Norbye ret = TEST_FAIL;
1899d8cc25b0STrond Norbye goto cleanup;
1900d8cc25b0STrond Norbye }
1901d8cc25b0STrond Norbye }
1902d8cc25b0STrond Norbye } while (more);
1903d8cc25b0STrond Norbye }
1904d8cc25b0STrond Norbye
1905d8cc25b0STrond Norbye child = fork();
1906d8cc25b0STrond Norbye if (child == (pid_t)-1) {
1907d8cc25b0STrond Norbye abort();
1908d8cc25b0STrond Norbye } else if (child > 0) {
1909d8cc25b0STrond Norbye int stat;
1910d8cc25b0STrond Norbye pid_t c;
1911d8cc25b0STrond Norbye while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
1912d8cc25b0STrond Norbye assert(c == child);
1913d8cc25b0STrond Norbye assert(stat == 0);
1914d8cc25b0STrond Norbye } else {
1915d8cc25b0STrond Norbye sock = connect_server("127.0.0.1", port, false);
1916d8cc25b0STrond Norbye ret = test_binary_noop();
1917d8cc25b0STrond Norbye close(sock);
1918d8cc25b0STrond Norbye exit(0);
1919d8cc25b0STrond Norbye }
1920d8cc25b0STrond Norbye
1921d8cc25b0STrond Norbye cleanup:
1922d8cc25b0STrond Norbye /* close all connections */
1923d8cc25b0STrond Norbye for (ii = 0; ii < max; ++ii) {
1924d8cc25b0STrond Norbye close(fds[ii]);
1925d8cc25b0STrond Norbye }
1926d8cc25b0STrond Norbye
1927d8cc25b0STrond Norbye assert(kill(server_pid, SIGTERM) == 0);
1928d8cc25b0STrond Norbye
1929d8cc25b0STrond Norbye return ret;
1930d8cc25b0STrond Norbye }
1931d8cc25b0STrond Norbye
19324c86fa59STrond Norbye typedef enum test_return (*TEST_FUNC)(void);
19334c86fa59STrond Norbye struct testcase {
19344c86fa59STrond Norbye const char *description;
19354c86fa59STrond Norbye TEST_FUNC function;
19364c86fa59STrond Norbye };
19374c86fa59STrond Norbye
19384c86fa59STrond Norbye struct testcase testcases[] = {
19394c86fa59STrond Norbye { "cache_create", cache_create_test },
19404c86fa59STrond Norbye { "cache_constructor", cache_constructor_test },
19414c86fa59STrond Norbye { "cache_constructor_fail", cache_fail_constructor_test },
19424c86fa59STrond Norbye { "cache_destructor", cache_destructor_test },
19434c86fa59STrond Norbye { "cache_reuse", cache_reuse_test },
19444c86fa59STrond Norbye { "cache_redzone", cache_redzone_test },
194516a809e2STrond Norbye { "issue_161", test_issue_161 },
19464c86fa59STrond Norbye { "strtol", test_safe_strtol },
19474c86fa59STrond Norbye { "strtoll", test_safe_strtoll },
19484c86fa59STrond Norbye { "strtoul", test_safe_strtoul },
19494c86fa59STrond Norbye { "strtoull", test_safe_strtoull },
19504c86fa59STrond Norbye { "issue_44", test_issue_44 },
1951891082f3SDustin Sallings { "vperror", test_vperror },
1952d8cc25b0STrond Norbye { "issue_101", test_issue_101 },
19536ae66c84STrond Norbye /* The following tests all run towards the same server */
19546ae66c84STrond Norbye { "start_server", start_memcached_server },
19552c7bfeb8STrond Norbye { "issue_92", test_issue_92 },
195675cc8368STrond Norbye { "issue_102", test_issue_102 },
19576ae66c84STrond Norbye { "binary_noop", test_binary_noop },
19586ae66c84STrond Norbye { "binary_quit", test_binary_quit },
19596ae66c84STrond Norbye { "binary_quitq", test_binary_quitq },
19606ae66c84STrond Norbye { "binary_set", test_binary_set },
19616ae66c84STrond Norbye { "binary_setq", test_binary_setq },
19626ae66c84STrond Norbye { "binary_add", test_binary_add },
19636ae66c84STrond Norbye { "binary_addq", test_binary_addq },
19646ae66c84STrond Norbye { "binary_replace", test_binary_replace },
19656ae66c84STrond Norbye { "binary_replaceq", test_binary_replaceq },
19666ae66c84STrond Norbye { "binary_delete", test_binary_delete },
19676ae66c84STrond Norbye { "binary_deleteq", test_binary_deleteq },
19686ae66c84STrond Norbye { "binary_get", test_binary_get },
19696ae66c84STrond Norbye { "binary_getq", test_binary_getq },
19706ae66c84STrond Norbye { "binary_getk", test_binary_getk },
19716ae66c84STrond Norbye { "binary_getkq", test_binary_getkq },
1972*7edb1a03SOskari Saarenmaa { "binary_gat", test_binary_gat },
1973*7edb1a03SOskari Saarenmaa { "binary_gatq", test_binary_gatq },
1974*7edb1a03SOskari Saarenmaa { "binary_gatk", test_binary_gatk },
1975*7edb1a03SOskari Saarenmaa { "binary_gatkq", test_binary_gatkq },
19766ae66c84STrond Norbye { "binary_incr", test_binary_incr },
19776ae66c84STrond Norbye { "binary_incrq", test_binary_incrq },
19786ae66c84STrond Norbye { "binary_decr", test_binary_decr },
19796ae66c84STrond Norbye { "binary_decrq", test_binary_decrq },
19806ae66c84STrond Norbye { "binary_version", test_binary_version },
19816ae66c84STrond Norbye { "binary_flush", test_binary_flush },
19826ae66c84STrond Norbye { "binary_flushq", test_binary_flushq },
19836ae66c84STrond Norbye { "binary_append", test_binary_append },
19846ae66c84STrond Norbye { "binary_appendq", test_binary_appendq },
19856ae66c84STrond Norbye { "binary_prepend", test_binary_prepend },
19866ae66c84STrond Norbye { "binary_prependq", test_binary_prependq },
19876ae66c84STrond Norbye { "binary_stat", test_binary_stat },
19886ae66c84STrond Norbye { "binary_illegal", test_binary_illegal },
19896ae66c84STrond Norbye { "binary_pipeline_hickup", test_binary_pipeline_hickup },
1990d11dc0eaSBrian Aker { "shutdown", shutdown_memcached_server },
19916ae66c84STrond Norbye { "stop_server", stop_memcached_server },
19924c86fa59STrond Norbye { NULL, NULL }
19934c86fa59STrond Norbye };
19944c86fa59STrond Norbye
main(int argc,char ** argv)19954c86fa59STrond Norbye int main(int argc, char **argv)
19964c86fa59STrond Norbye {
19974c86fa59STrond Norbye int exitcode = 0;
1998b8e106f7SDustin Sallings int ii = 0, num_cases = 0;
1999b8e106f7SDustin Sallings
2000b8e106f7SDustin Sallings for (num_cases = 0; testcases[num_cases].description; num_cases++) {
2001b8e106f7SDustin Sallings /* Just counting */
2002b8e106f7SDustin Sallings }
2003b8e106f7SDustin Sallings
2004b8e106f7SDustin Sallings printf("1..%d\n", num_cases);
20054c86fa59STrond Norbye
20064c86fa59STrond Norbye for (ii = 0; testcases[ii].description != NULL; ++ii) {
20074c86fa59STrond Norbye fflush(stdout);
20086ae66c84STrond Norbye #ifndef DEBUG
20096ae66c84STrond Norbye /* the test program shouldn't run longer than 10 minutes... */
20106ae66c84STrond Norbye alarm(600);
20116ae66c84STrond Norbye #endif
20124c86fa59STrond Norbye enum test_return ret = testcases[ii].function();
20134c86fa59STrond Norbye if (ret == TEST_SKIP) {
2014b8e106f7SDustin Sallings fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
20154c86fa59STrond Norbye } else if (ret == TEST_PASS) {
2016b8e106f7SDustin Sallings fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
20174c86fa59STrond Norbye } else {
2018b8e106f7SDustin Sallings fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
20194c86fa59STrond Norbye exitcode = 1;
20204c86fa59STrond Norbye }
20214c86fa59STrond Norbye fflush(stdout);
20224c86fa59STrond Norbye }
20234c86fa59STrond Norbye
20244c86fa59STrond Norbye return exitcode;
20254c86fa59STrond Norbye }
2026