6 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netinet/tcp.h>
19 #include <netinet/in.h>
24 #include <memcached/util.h>
25 #include <memcached/protocol_binary.h>
26 #include <memcached/config_parser.h>
28 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
30 enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
32 static pid_t server_pid;
33 static in_port_t port;
35 static bool allow_closed_read =
false;
37 static enum test_return cache_create_test(
void)
39 cache_t *cache = cache_create(
"test",
sizeof(uint32_t),
sizeof(
char*),
41 assert(cache != NULL);
46 const uint64_t constructor_pattern = 0xdeadcafebabebeef;
48 static int cache_constructor(
void *buffer,
void *notused1,
int notused2) {
49 uint64_t *ptr = buffer;
50 *ptr = constructor_pattern;
54 static enum test_return cache_constructor_test(
void)
56 cache_t *cache = cache_create(
"test",
sizeof(uint64_t),
sizeof(uint64_t),
57 cache_constructor, NULL);
58 assert(cache != NULL);
59 uint64_t *ptr = cache_alloc(cache);
60 uint64_t pattern = *ptr;
61 cache_free(cache, ptr);
63 return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
66 static int cache_fail_constructor(
void *buffer,
void *notused1,
int notused2) {
70 static enum test_return cache_fail_constructor_test(
void)
72 enum test_return
ret = TEST_PASS;
74 cache_t *cache = cache_create(
"test",
sizeof(uint64_t),
sizeof(uint64_t),
75 cache_fail_constructor, NULL);
76 assert(cache != NULL);
77 uint64_t *ptr = cache_alloc(cache);
85 static void *destruct_data = 0;
87 static void cache_destructor(
void *buffer,
void *notused) {
88 destruct_data = buffer;
91 static enum test_return cache_destructor_test(
void)
93 cache_t *cache = cache_create(
"test",
sizeof(uint32_t),
sizeof(
char*),
94 NULL, cache_destructor);
95 assert(cache != NULL);
96 char *ptr = cache_alloc(cache);
97 cache_free(cache, ptr);
100 return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
103 static enum test_return cache_reuse_test(
void)
106 cache_t *cache = cache_create(
"test",
sizeof(uint32_t),
sizeof(
char*),
108 char *ptr = cache_alloc(cache);
109 cache_free(cache, ptr);
110 for (ii = 0; ii < 100; ++ii) {
111 char *p = cache_alloc(cache);
113 cache_free(cache, ptr);
115 cache_destroy(cache);
120 static enum test_return cache_bulkalloc(
size_t datasize)
122 cache_t *cache = cache_create(
"test", datasize,
sizeof(
char*),
124 #define ITERATIONS 1024
125 void *ptr[ITERATIONS];
127 for (
int ii = 0; ii < ITERATIONS; ++ii) {
128 ptr[ii] = cache_alloc(cache);
129 assert(ptr[ii] != 0);
130 memset(ptr[ii], 0xff, datasize);
133 for (
int ii = 0; ii < ITERATIONS; ++ii) {
134 cache_free(cache, ptr[ii]);
138 cache_destroy(cache);
142 static enum test_return test_issue_161(
void)
144 enum test_return ret = cache_bulkalloc(1);
145 if (ret == TEST_PASS) {
146 ret = cache_bulkalloc(512);
152 static enum test_return cache_redzone_test(
void)
155 cache_t *cache = cache_create(
"test",
sizeof(uint32_t),
sizeof(
char*),
160 struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
161 sigemptyset(&action.sa_mask);
162 sigaction(SIGABRT, &action, &old_action);
165 char *p = cache_alloc(cache);
168 cache_free(cache, p);
169 assert(cache_error == -1);
172 p[
sizeof(uint32_t)] = 0;
173 cache_free(cache, p);
174 assert(cache_error == 1);
179 cache_destroy(cache);
187 static enum test_return test_safe_strtoul(
void) {
189 assert(safe_strtoul(
"123", &val));
191 assert(safe_strtoul(
"+123", &val));
193 assert(!safe_strtoul(
"", &val));
194 assert(!safe_strtoul(
"123BOGUS", &val));
200 assert(safe_strtoul(
"4294967295", &val));
201 assert(val == 4294967295L);
205 assert(!safe_strtoul(
"-1", &val));
210 static enum test_return test_safe_strtoull(
void) {
212 assert(safe_strtoull(
"123", &val));
214 assert(safe_strtoull(
"+123", &val));
216 assert(!safe_strtoull(
"", &val));
217 assert(!safe_strtoull(
"123BOGUS", &val));
218 assert(!safe_strtoull(
"92837498237498237498029383", &val));
221 assert(safe_strtoull(
"18446744073709551615", &val));
222 assert(val == 18446744073709551615ULL);
223 assert(!safe_strtoull(
"18446744073709551616", &val));
224 assert(!safe_strtoull(
"-1", &val));
228 static enum test_return test_safe_strtoll(
void) {
230 assert(safe_strtoll(
"123", &val));
232 assert(safe_strtoll(
"+123", &val));
234 assert(safe_strtoll(
"-123", &val));
236 assert(!safe_strtoll(
"", &val));
237 assert(!safe_strtoll(
"123BOGUS", &val));
238 assert(!safe_strtoll(
"92837498237498237498029383", &val));
241 assert(!safe_strtoll(
"18446744073709551615", &val));
242 assert(safe_strtoll(
"9223372036854775807", &val));
243 assert(val == 9223372036854775807LL);
248 assert(!safe_strtoll(
"-9223372036854775809", &val));
251 assert(safe_strtoll(
" 123 foo", &val));
256 static enum test_return test_safe_strtol(
void) {
258 assert(safe_strtol(
"123", &val));
260 assert(safe_strtol(
"+123", &val));
262 assert(safe_strtol(
"-123", &val));
264 assert(!safe_strtol(
"", &val));
265 assert(!safe_strtol(
"123BOGUS", &val));
266 assert(!safe_strtol(
"92837498237498237498029383", &val));
272 assert(safe_strtol(
"2147483647", &val));
273 assert(val == 2147483647L);
279 assert(safe_strtol(
" 123 foo", &val));
284 static enum test_return test_safe_strtof(
void) {
286 assert(safe_strtof(
"123", &val));
287 assert(val == 123.00f);
288 assert(safe_strtof(
"+123", &val));
289 assert(val == 123.00f);
290 assert(safe_strtof(
"-123", &val));
291 assert(val == -123.00f);
292 assert(!safe_strtof(
"", &val));
293 assert(!safe_strtof(
"123BOGUS", &val));
296 assert(safe_strtof(
" 123 foo", &val));
297 assert(val == 123.00f);
299 assert(safe_strtof(
"123.23", &val));
300 assert(val == 123.23f);
302 assert(safe_strtof(
"123.00", &val));
303 assert(val == 123.00f);
317 static pid_t start_server(in_port_t *port_out,
bool daemon,
int timeout) {
318 char environment[80];
319 snprintf(environment,
sizeof(environment),
320 "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (
long)getpid());
321 char *filename= environment + strlen(
"MEMCACHED_PORT_FILENAME=");
323 snprintf(pid_file,
sizeof(pid_file),
"/tmp/pid.%lu", (
long)getpid());
329 assert(getcwd(engine,
sizeof(engine)));
330 strcat(engine,
"/.libs/default_engine.so");
331 assert(strlen(engine) <
sizeof(engine));
333 char blackhole[1024];
334 assert(getcwd(blackhole,
sizeof(blackhole)));
335 strcat(blackhole,
"/.libs/blackhole_logger.so");
343 snprintf(coreadm,
sizeof(coreadm),
344 "coreadm -p core.%%f.%%p %lu", (
unsigned long)getpid());
356 snprintf(tmo,
sizeof(tmo),
"%u", timeout);
361 argv[arg++] =
"./timedrun";
364 argv[arg++] =
"./memcached";
366 argv[arg++] = engine;
368 argv[arg++] = blackhole;
376 argv[arg++] =
"root";
381 argv[arg++] = pid_file;
384 argv[arg++] =
"-vvv";
387 assert(execv(argv[0], argv) != -1);
391 while (access(filename, F_OK) == -1) {
395 FILE *fp = fopen(filename,
"r");
397 fprintf(stderr,
"Failed to open the file containing port numbers: %s\n",
402 *port_out = (in_port_t)-1;
404 while ((fgets(buffer,
sizeof(buffer), fp)) != NULL) {
405 if (strncmp(buffer,
"TCP INET: ", 10) == 0) {
407 assert(safe_strtol(buffer + 10, &val));
408 *port_out = (in_port_t)val;
412 assert(
remove(filename) == 0);
419 while (access(pid_file, F_OK) == -1) {
423 fp = fopen(pid_file,
"r");
425 fprintf(stderr,
"Failed to open pid file: %s\n",
429 assert(fgets(buffer,
sizeof(buffer), fp) != NULL);
433 assert(safe_strtol(buffer, &val));
440 static enum test_return test_issue_44(
void) {
442 pid_t pid = start_server(&port,
true, 15);
443 assert(
kill(pid, SIGHUP) == 0);
445 assert(
kill(pid, SIGTERM) == 0);
450 static struct addrinfo *lookuphost(
const char *hostname, in_port_t port)
453 struct addrinfo hints = { .ai_family = AF_UNSPEC,
454 .ai_protocol = IPPROTO_TCP,
455 .ai_socktype = SOCK_STREAM };
456 char service[NI_MAXSERV];
459 (void)snprintf(service, NI_MAXSERV,
"%d", port);
460 if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
461 if (error != EAI_SYSTEM) {
462 fprintf(stderr,
"getaddrinfo(): %s\n", gai_strerror(error));
464 perror(
"getaddrinfo()");
471 static int connect_server(
const char *hostname, in_port_t port,
bool nonblock)
473 struct addrinfo *ai = lookuphost(hostname, port);
476 if ((sock = socket(ai->ai_family, ai->ai_socktype,
477 ai->ai_protocol)) != -1) {
478 if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
479 fprintf(stderr,
"Failed to connect socket: %s\n",
483 }
else if (nonblock) {
484 int flags = fcntl(sock, F_GETFL, 0);
485 if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
486 fprintf(stderr,
"Failed to enable nonblocking mode: %s\n",
493 fprintf(stderr,
"Failed to create socket: %s\n", strerror(errno));
501 static enum test_return test_vperror(
void) {
503 int oldstderr = dup(STDERR_FILENO);
504 char tmpl[
sizeof(TMP_TEMPLATE)+1];
505 strncpy(tmpl, TMP_TEMPLATE,
sizeof(TMP_TEMPLATE)+1);
507 int newfile = mkstemp(tmpl);
509 rv = dup2(newfile, STDERR_FILENO);
510 assert(rv == STDERR_FILENO);
515 vperror(
"Old McDonald had a farm. %s",
"EI EIO");
518 rv = dup2(oldstderr, STDERR_FILENO);
519 assert(rv == STDERR_FILENO);
523 char buf[80] = { 0 };
524 FILE *efile = fopen(tmpl,
"r");
526 char *prv = fgets(buf,
sizeof(buf), efile);
532 char expected[80] = { 0 };
533 snprintf(expected,
sizeof(expected),
534 "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO));
542 return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
545 static char* trim(
char* ptr) {
547 while (isspace(*start)) {
550 char *end = start + strlen(start) - 1;
552 while (isspace(*end)) {
560 static enum test_return test_config_parser(
void) {
561 bool bool_val =
false;
564 char *string_val = 0;
570 .value.dt_bool = &bool_val },
573 .value.dt_size = &size_val },
575 .datatype = DT_FLOAT,
576 .value.dt_float = &float_val},
578 .datatype = DT_STRING,
579 .value.dt_string = &string_val},
580 { .key =
"config_file",
581 .datatype = DT_CONFIGFILE },
585 char outfile[
sizeof(TMP_TEMPLATE)+1];
586 strncpy(outfile, TMP_TEMPLATE,
sizeof(TMP_TEMPLATE)+1);
587 char cfgfile[
sizeof(TMP_TEMPLATE)+1];
588 strncpy(cfgfile, TMP_TEMPLATE,
sizeof(TMP_TEMPLATE)+1);
590 int newfile = mkstemp(outfile);
592 FILE *error = fdopen(newfile,
"w");
594 assert(error != NULL);
595 assert(parse_config(
"", items, error) == 0);
597 for (
int ii = 0; ii < 5; ++ii) {
598 assert(!items[0].
found);
601 assert(parse_config(
"bool=true", items, error) == 0);
604 assert(items[0].
found);
605 items[0].
found =
false;
606 for (
int ii = 0; ii < 5; ++ii) {
607 assert(!items[0].
found);
611 assert(parse_config(
"pacman=dead", items, error) == 1);
613 assert(parse_config(
"bool=12", items, error) == -1);
614 assert(!items[0].
found);
616 assert(parse_config(
"size_t=1; size_t=1024", items, error) == 0);
617 assert(items[1].
found);
618 assert(size_val == 1024);
619 items[1].
found =
false;
629 assert(parse_config(
"string=sval", items, error) == 0);
630 assert(items[3].
found);
631 assert(strcmp(string_val,
"sval") == 0);
632 items[3].
found =
false;
634 assert(parse_config(
"string= sval", items, error) == 0);
635 assert(items[3].
found);
636 assert(strcmp(string_val,
"sval") == 0);
637 items[3].
found =
false;
639 assert(parse_config(
"string=\\ sval", items, error) == 0);
640 assert(items[3].
found);
641 assert(strcmp(string_val,
" sval") == 0);
642 items[3].
found =
false;
644 assert(parse_config(
"string=sval ", items, error) == 0);
645 assert(items[3].
found);
646 assert(strcmp(string_val,
"sval") == 0);
647 items[3].
found =
false;
649 assert(parse_config(
"string=sval\\ ", items, error) == 0);
650 assert(items[3].
found);
651 assert(strcmp(string_val,
"sval ") == 0);
652 items[3].
found =
false;
654 assert(parse_config(
"string=sval\\;blah=x", items, error) == 0);
655 assert(items[3].
found);
656 assert(strcmp(string_val,
"sval;blah=x") == 0);
657 items[3].
found =
false;
659 assert(parse_config(
"string=s val", items, error) == 0);
660 assert(items[3].
found);
661 assert(strcmp(string_val,
"s val") == 0);
662 items[3].
found =
false;
665 assert(parse_config(
"bool=true;size_t=1024;float=12.5;string=somestr",
668 assert(size_val == 1024);
669 assert(float_val == 12.5f);
670 assert(strcmp(string_val,
"somestr") == 0);
671 for (
int ii = 0; ii < 5; ++ii) {
672 items[ii].
found =
false;
675 assert(parse_config(
"size_t=1k", items, error) == 0);
676 assert(items[1].
found);
677 assert(size_val == 1024);
678 items[1].
found =
false;
679 assert(parse_config(
"size_t=1m", items, error) == 0);
680 assert(items[1].
found);
681 assert(size_val == 1024*1024);
682 items[1].
found =
false;
683 assert(parse_config(
"size_t=1g", items, error) == 0);
684 assert(items[1].
found);
685 assert(size_val == 1024*1024*1024);
686 items[1].
found =
false;
687 assert(parse_config(
"size_t=1K", items, error) == 0);
688 assert(items[1].
found);
689 assert(size_val == 1024);
690 items[1].
found =
false;
691 assert(parse_config(
"size_t=1M", items, error) == 0);
692 assert(items[1].
found);
693 assert(size_val == 1024*1024);
694 items[1].
found =
false;
695 assert(parse_config(
"size_t=1G", items, error) == 0);
696 assert(items[1].
found);
697 assert(size_val == 1024*1024*1024);
698 items[1].
found =
false;
700 newfile = mkstemp(cfgfile);
702 FILE *cfg = fdopen(newfile,
"w");
704 fprintf(cfg,
"# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
707 sprintf(buffer,
"config_file=%s", cfgfile);
708 assert(parse_config(buffer, items, error) == 0);
710 assert(size_val == 1023);
711 assert(float_val == 12.4f);
716 error = fopen(outfile,
"r");
719 assert(fgets(buffer,
sizeof(buffer), error));
720 assert(strcmp(
"Unsupported key: <pacman>", trim(buffer)) == 0);
721 assert(fgets(buffer,
sizeof(buffer), error));
722 assert(strcmp(
"Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
723 assert(fgets(buffer,
sizeof(buffer), error));
724 assert(strcmp(
"WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
725 assert(fgets(buffer,
sizeof(buffer), error) == NULL);
731 static void send_ascii_command(
const char *buf) {
733 const char* ptr =
buf;
734 size_t len = strlen(buf);
737 ssize_t nw = send(sock, ptr + offset, len - offset, 0);
739 if (errno != EINTR) {
740 fprintf(stderr,
"Failed to write: %s\n", strerror(errno));
746 }
while (offset < len);
755 static void read_ascii_response(
char *buffer,
size_t size) {
757 bool need_more =
true;
759 ssize_t nr = recv(sock, buffer + offset, 1, 0);
761 if (errno != EINTR) {
762 fprintf(stderr,
"Failed to read: %s\n", strerror(errno));
767 if (buffer[offset] ==
'\n') {
769 buffer[offset + 1] =
'\0';
772 assert(offset + 1 < size);
777 static enum test_return test_issue_92(
void) {
782 sock = connect_server(
"127.0.0.1", port,
false);
784 send_ascii_command(
"stats cachedump 1 0 0\r\n");
785 read_ascii_response(buffer,
sizeof(buffer));
786 assert(strncmp(buffer,
"END", strlen(
"END")) == 0);
788 send_ascii_command(
"stats cachedump 200 0 0\r\n");
789 read_ascii_response(buffer,
sizeof(buffer));
790 assert(strncmp(buffer,
"CLIENT_ERROR", strlen(
"CLIENT_ERROR")) == 0);
793 sock = connect_server(
"127.0.0.1", port,
false);
799 static enum test_return test_issue_102(
void) {
801 memset(buffer,
' ',
sizeof(buffer));
802 buffer[
sizeof(buffer) - 1] =
'\0';
805 sock = connect_server(
"127.0.0.1", port,
false);
807 send_ascii_command(buffer);
809 assert(recv(sock, buffer,
sizeof(buffer), 0) == 0);
811 sock = connect_server(
"127.0.0.1", port,
false);
813 snprintf(buffer,
sizeof(buffer),
"gets ");
815 while (offset < 4000) {
816 offset += snprintf(buffer + offset,
sizeof(buffer) - offset,
817 "%010u ", (
unsigned int)offset);
820 send_ascii_command(buffer);
823 send_ascii_command(
"\r\n");
825 read_ascii_response(rsp,
sizeof(rsp));
826 assert(strncmp(rsp,
"END", strlen(
"END")) == 0);
828 send_ascii_command(buffer);
830 send_ascii_command(
"\r\n");
831 read_ascii_response(rsp,
sizeof(rsp));
832 assert(strncmp(rsp,
"END", strlen(
"END")) == 0);
834 memset(buffer,
' ',
sizeof(buffer));
835 int len = snprintf(buffer + 101,
sizeof(buffer) - 101,
"gets foo");
836 buffer[101 + len] =
' ';
837 buffer[
sizeof(buffer) - 1] =
'\0';
838 send_ascii_command(buffer);
840 assert(recv(sock, buffer,
sizeof(buffer), 0) == 0);
843 sock = connect_server(
"127.0.0.1", port,
false);
848 static enum test_return start_memcached_server(
void) {
849 server_pid = start_server(&port,
false, 600);
850 sock = connect_server(
"127.0.0.1", port,
false);
855 static enum test_return stop_memcached_server(
void) {
857 assert(
kill(server_pid, SIGTERM) == 0);
861 static void safe_send(
const void* buf,
size_t len,
bool hickup)
864 const char* ptr =
buf;
867 assert(val == (uint8_t)0x80);
868 fprintf(stderr,
"About to send %lu bytes:", (
unsigned long)len);
869 for (
int ii = 0; ii < len; ++ii) {
871 fprintf(stderr,
"\n ");
874 fprintf(stderr,
" 0x%02x", val);
876 fprintf(stderr,
"\n");
881 size_t num_bytes = len -
offset;
883 if (num_bytes > 1024) {
884 num_bytes = (rand() % 1023) + 1;
888 ssize_t nw = send(sock, ptr + offset, num_bytes, 0);
890 if (errno != EINTR) {
891 fprintf(stderr,
"Failed to write: %s\n", strerror(errno));
900 }
while (offset < len);
903 static bool safe_recv(
void *buf,
size_t len) {
909 ssize_t nr = recv(sock, ((
char*)buf) + offset, len - offset, 0);
911 if (errno != EINTR) {
912 fprintf(stderr,
"Failed to read: %s\n", strerror(errno));
916 if (nr == 0 && allow_closed_read) {
922 }
while (offset < len);
927 static bool safe_recv_packet(
void *buf,
size_t size) {
929 assert(size >
sizeof(*response));
930 if (!safe_recv(response,
sizeof(*response))) {
933 response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
934 response->message.header.response.status = ntohs(response->message.header.response.status);
935 response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
937 size_t len =
sizeof(*response);
941 if (!safe_recv(ptr, response->message.header.response.bodylen)) {
948 len += response->message.header.response.bodylen;
950 assert(val == (uint8_t)0x81);
951 fprintf(stderr,
"Received %lu bytes:", (
unsigned long)len);
952 for (
int ii = 0; ii < len; ++ii) {
954 fprintf(stderr,
"\n ");
957 fprintf(stderr,
" 0x%02x", val);
959 fprintf(stderr,
"\n");
964 static off_t storage_command(
char*buf,
975 assert(bufsz >
sizeof(*request) + keylen + dtalen);
977 memset(request, 0,
sizeof(*request));
978 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
979 request->message.header.request.opcode = cmd;
980 request->message.header.request.keylen = htons(keylen);
981 request->message.header.request.extlen = 8;
982 request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
983 request->message.header.request.opaque = 0xdeadbeef;
984 request->message.body.flags =
flags;
985 request->message.body.expiration = exp;
989 memcpy(buf + key_offset, key, keylen);
991 memcpy(buf + key_offset + keylen, dta, dtalen);
994 return key_offset + keylen + dtalen;
997 static off_t raw_command(
char* buf,
1006 assert(bufsz >
sizeof(*request) + keylen + dtalen);
1008 memset(request, 0,
sizeof(*request));
1009 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1010 request->message.header.request.opcode = cmd;
1011 request->message.header.request.keylen = htons(keylen);
1012 request->message.header.request.bodylen = htonl(keylen + dtalen);
1013 request->message.header.request.opaque = 0xdeadbeef;
1018 memcpy(buf + key_offset, key, keylen);
1021 memcpy(buf + key_offset + keylen, dta, dtalen);
1024 return sizeof(*request) + keylen + dtalen;
1027 static off_t flush_command(
char* buf,
size_t bufsz, uint8_t cmd, uint32_t exptime,
bool use_extra) {
1029 assert(bufsz >
sizeof(*request));
1031 memset(request, 0,
sizeof(*request));
1032 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1033 request->message.header.request.opcode = cmd;
1037 request->message.header.request.extlen = 4;
1038 request->message.body.expiration = htonl(exptime);
1039 request->message.header.request.bodylen = htonl(4);
1043 request->message.header.request.opaque = 0xdeadbeef;
1048 static off_t arithmetic_command(
char* buf,
1057 assert(bufsz >
sizeof(*request) + keylen);
1059 memset(request, 0,
sizeof(*request));
1060 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1061 request->message.header.request.opcode = cmd;
1062 request->message.header.request.keylen = htons(keylen);
1063 request->message.header.request.extlen = 20;
1064 request->message.header.request.bodylen = htonl(keylen + 20);
1065 request->message.header.request.opaque = 0xdeadbeef;
1066 request->message.body.delta = htonll(delta);
1067 request->message.body.initial = htonll(initial);
1068 request->message.body.expiration = htonl(exp);
1072 memcpy(buf + key_offset, key, keylen);
1073 return key_offset + keylen;
1077 uint8_t cmd, uint16_t status)
1079 assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1080 assert(response->message.header.response.opcode == cmd);
1081 assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1082 if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1083 if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1084 response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1087 assert(response->message.header.response.status == status);
1088 assert(response->message.header.response.opaque == 0xdeadbeef);
1090 if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1092 case PROTOCOL_BINARY_CMD_ADDQ:
1093 case PROTOCOL_BINARY_CMD_APPENDQ:
1094 case PROTOCOL_BINARY_CMD_DECREMENTQ:
1095 case PROTOCOL_BINARY_CMD_DELETEQ:
1096 case PROTOCOL_BINARY_CMD_FLUSHQ:
1097 case PROTOCOL_BINARY_CMD_INCREMENTQ:
1098 case PROTOCOL_BINARY_CMD_PREPENDQ:
1099 case PROTOCOL_BINARY_CMD_QUITQ:
1100 case PROTOCOL_BINARY_CMD_REPLACEQ:
1101 case PROTOCOL_BINARY_CMD_SETQ:
1102 assert(
"Quiet command shouldn't return on success" == NULL);
1108 case PROTOCOL_BINARY_CMD_ADD:
1109 case PROTOCOL_BINARY_CMD_REPLACE:
1110 case PROTOCOL_BINARY_CMD_SET:
1111 case PROTOCOL_BINARY_CMD_APPEND:
1112 case PROTOCOL_BINARY_CMD_PREPEND:
1113 assert(response->message.header.response.keylen == 0);
1114 assert(response->message.header.response.extlen == 0);
1115 assert(response->message.header.response.bodylen == 0);
1116 assert(response->message.header.response.cas != 0);
1118 case PROTOCOL_BINARY_CMD_FLUSH:
1119 case PROTOCOL_BINARY_CMD_NOOP:
1120 case PROTOCOL_BINARY_CMD_QUIT:
1121 case PROTOCOL_BINARY_CMD_DELETE:
1122 assert(response->message.header.response.keylen == 0);
1123 assert(response->message.header.response.extlen == 0);
1124 assert(response->message.header.response.bodylen == 0);
1125 assert(response->message.header.response.cas == 0);
1128 case PROTOCOL_BINARY_CMD_DECREMENT:
1129 case PROTOCOL_BINARY_CMD_INCREMENT:
1130 assert(response->message.header.response.keylen == 0);
1131 assert(response->message.header.response.extlen == 0);
1132 assert(response->message.header.response.bodylen == 8);
1133 assert(response->message.header.response.cas != 0);
1136 case PROTOCOL_BINARY_CMD_STAT:
1137 assert(response->message.header.response.extlen == 0);
1139 assert(response->message.header.response.cas == 0);
1142 case PROTOCOL_BINARY_CMD_VERSION:
1143 assert(response->message.header.response.keylen == 0);
1144 assert(response->message.header.response.extlen == 0);
1145 assert(response->message.header.response.bodylen != 0);
1146 assert(response->message.header.response.cas == 0);
1149 case PROTOCOL_BINARY_CMD_GET:
1150 case PROTOCOL_BINARY_CMD_GETQ:
1151 assert(response->message.header.response.keylen == 0);
1152 assert(response->message.header.response.extlen == 4);
1153 assert(response->message.header.response.cas != 0);
1156 case PROTOCOL_BINARY_CMD_GETK:
1157 case PROTOCOL_BINARY_CMD_GETKQ:
1158 assert(response->message.header.response.keylen != 0);
1159 assert(response->message.header.response.extlen == 4);
1160 assert(response->message.header.response.cas != 0);
1168 assert(response->message.header.response.cas == 0);
1169 assert(response->message.header.response.extlen == 0);
1170 if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1171 assert(response->message.header.response.keylen == 0);
1176 static enum test_return test_binary_noop(
void) {
1183 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
1184 PROTOCOL_BINARY_CMD_NOOP,
1187 safe_send(buffer.bytes, len,
false);
1188 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
1189 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1190 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1195 static enum test_return test_binary_quit_impl(uint8_t cmd) {
1201 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
1202 cmd, NULL, 0, NULL, 0);
1204 safe_send(buffer.bytes, len,
false);
1205 if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1206 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
1207 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1208 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1212 assert(recv(sock, buffer.bytes,
sizeof(buffer.bytes), 0) == 0);
1214 sock = connect_server(
"127.0.0.1", port,
false);
1219 static enum test_return test_binary_quit(
void) {
1220 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1223 static enum test_return test_binary_quitq(
void) {
1224 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1227 static enum test_return test_binary_set_impl(
const char *key, uint8_t cmd) {
1233 uint64_t value = 0xdeadbeefdeadcafe;
1234 size_t len = storage_command(send.bytes,
sizeof(send.bytes), cmd,
1235 key, strlen(key), &value,
sizeof(value),
1240 for (ii = 0; ii < 10; ++ii) {
1241 safe_send(send.bytes, len,
false);
1242 if (cmd == PROTOCOL_BINARY_CMD_SET) {
1243 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1244 validate_response_header(&receive.response, cmd,
1245 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1249 if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1250 return test_binary_noop();
1253 send.request.message.header.request.cas = receive.response.message.header.response.cas;
1254 safe_send(send.bytes, len,
false);
1255 if (cmd == PROTOCOL_BINARY_CMD_SET) {
1256 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1257 validate_response_header(&receive.response, cmd,
1258 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1259 assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1261 return test_binary_noop();
1267 static enum test_return test_binary_set(
void) {
1268 return test_binary_set_impl(
"test_binary_set", PROTOCOL_BINARY_CMD_SET);
1271 static enum test_return test_binary_setq(
void) {
1272 return test_binary_set_impl(
"test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1275 static enum test_return test_binary_add_impl(
const char *key, uint8_t cmd) {
1276 uint64_t value = 0xdeadbeefdeadcafe;
1282 size_t len = storage_command(send.bytes,
sizeof(send.bytes), cmd, key,
1283 strlen(key), &value,
sizeof(value),
1288 for (ii = 0; ii < 10; ++ii) {
1289 safe_send(send.bytes, len,
false);
1291 if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1292 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1293 validate_response_header(&receive.response, cmd,
1294 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1297 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1298 validate_response_header(&receive.response, cmd,
1299 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1306 static enum test_return test_binary_add(
void) {
1307 return test_binary_add_impl(
"test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1310 static enum test_return test_binary_addq(
void) {
1311 return test_binary_add_impl(
"test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1314 static enum test_return test_binary_replace_impl(
const char* key, uint8_t cmd) {
1315 uint64_t value = 0xdeadbeefdeadcafe;
1321 size_t len = storage_command(send.bytes,
sizeof(send.bytes), cmd,
1322 key, strlen(key), &value,
sizeof(value),
1324 safe_send(send.bytes, len,
false);
1325 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1326 validate_response_header(&receive.response, cmd,
1327 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1328 len = storage_command(send.bytes,
sizeof(send.bytes),
1329 PROTOCOL_BINARY_CMD_ADD,
1330 key, strlen(key), &value,
sizeof(value), 0, 0);
1331 safe_send(send.bytes, len,
false);
1332 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1333 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1334 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1336 len = storage_command(send.bytes,
sizeof(send.bytes), cmd,
1337 key, strlen(key), &value,
sizeof(value), 0, 0);
1339 for (ii = 0; ii < 10; ++ii) {
1340 safe_send(send.bytes, len,
false);
1341 if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1342 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1343 validate_response_header(&receive.response,
1344 PROTOCOL_BINARY_CMD_REPLACE,
1345 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1349 if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1356 static enum test_return test_binary_replace(
void) {
1357 return test_binary_replace_impl(
"test_binary_replace",
1358 PROTOCOL_BINARY_CMD_REPLACE);
1361 static enum test_return test_binary_replaceq(
void) {
1362 return test_binary_replace_impl(
"test_binary_replaceq",
1363 PROTOCOL_BINARY_CMD_REPLACEQ);
1366 static enum test_return test_binary_delete_impl(
const char *key, uint8_t cmd) {
1372 size_t len = raw_command(send.bytes,
sizeof(send.bytes), cmd,
1373 key, strlen(key), NULL, 0);
1375 safe_send(send.bytes, len,
false);
1376 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1377 validate_response_header(&receive.response, cmd,
1378 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1379 len = storage_command(send.bytes,
sizeof(send.bytes),
1380 PROTOCOL_BINARY_CMD_ADD,
1381 key, strlen(key), NULL, 0, 0, 0);
1382 safe_send(send.bytes, len,
false);
1383 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1384 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1385 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1387 len = raw_command(send.bytes,
sizeof(send.bytes),
1388 cmd, key, strlen(key), NULL, 0);
1389 safe_send(send.bytes, len,
false);
1391 if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1392 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1393 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1394 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1397 safe_send(send.bytes, len,
false);
1398 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1399 validate_response_header(&receive.response, cmd,
1400 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1405 static enum test_return test_binary_delete(
void) {
1406 return test_binary_delete_impl(
"test_binary_delete",
1407 PROTOCOL_BINARY_CMD_DELETE);
1410 static enum test_return test_binary_deleteq(
void) {
1411 return test_binary_delete_impl(
"test_binary_deleteq",
1412 PROTOCOL_BINARY_CMD_DELETEQ);
1415 static enum test_return test_binary_get_impl(
const char *key, uint8_t cmd) {
1421 size_t len = raw_command(send.bytes,
sizeof(send.bytes), cmd,
1422 key, strlen(key), NULL, 0);
1424 safe_send(send.bytes, len,
false);
1425 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1426 validate_response_header(&receive.response, cmd,
1427 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1429 len = storage_command(send.bytes,
sizeof(send.bytes),
1430 PROTOCOL_BINARY_CMD_ADD,
1431 key, strlen(key), NULL, 0,
1433 safe_send(send.bytes, len,
false);
1434 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1435 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1436 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1441 for (ii = 0; ii < 10; ++ii) {
1446 size_t l = raw_command(
temp.bytes,
sizeof(
temp.bytes),
1447 cmd, key, strlen(key), NULL, 0);
1448 memcpy(send.bytes + len,
temp.bytes, l);
1452 safe_send(send.bytes, len,
false);
1453 for (ii = 0; ii < 10; ++ii) {
1454 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1455 validate_response_header(&receive.response, cmd,
1456 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1462 static enum test_return test_binary_get(
void) {
1463 return test_binary_get_impl(
"test_binary_get", PROTOCOL_BINARY_CMD_GET);
1466 static enum test_return test_binary_getk(
void) {
1467 return test_binary_get_impl(
"test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1470 static enum test_return test_binary_getq_impl(
const char *key, uint8_t cmd) {
1471 const char *missing =
"test_binary_getq_missing";
1476 } send,
temp, receive;
1477 size_t len = storage_command(send.bytes,
sizeof(send.bytes),
1478 PROTOCOL_BINARY_CMD_ADD,
1479 key, strlen(key), NULL, 0,
1481 size_t len2 = raw_command(temp.bytes,
sizeof(temp.bytes), cmd,
1482 missing, strlen(missing), NULL, 0);
1485 temp.request.message.header.request.opaque = 0xfeedface;
1486 memcpy(send.bytes + len, temp.bytes, len2);
1489 len2 = raw_command(temp.bytes,
sizeof(temp.bytes), cmd,
1490 key, strlen(key), NULL, 0);
1491 memcpy(send.bytes + len, temp.bytes, len2);
1494 safe_send(send.bytes, len,
false);
1495 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1496 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1497 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1499 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1500 validate_response_header(&receive.response, cmd,
1501 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1506 static enum test_return test_binary_getq(
void) {
1507 return test_binary_getq_impl(
"test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1510 static enum test_return test_binary_getkq(
void) {
1511 return test_binary_getq_impl(
"test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1514 static enum test_return test_binary_incr_impl(
const char* key, uint8_t cmd) {
1521 size_t len = arithmetic_command(send.bytes,
sizeof(send.bytes), cmd,
1522 key, strlen(key), 1, 0, 0);
1525 for (ii = 0; ii < 10; ++ii) {
1526 safe_send(send.bytes, len,
false);
1527 if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1528 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1529 validate_response_header(&receive.response_header, cmd,
1530 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1531 assert(ntohll(receive.response.message.body.value) == ii);
1535 if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1541 static enum test_return test_binary_incr(
void) {
1542 return test_binary_incr_impl(
"test_binary_incr",
1543 PROTOCOL_BINARY_CMD_INCREMENT);
1546 static enum test_return test_binary_incrq(
void) {
1547 return test_binary_incr_impl(
"test_binary_incrq",
1548 PROTOCOL_BINARY_CMD_INCREMENTQ);
1551 static enum test_return test_binary_decr_impl(
const char* key, uint8_t cmd) {
1558 size_t len = arithmetic_command(send.bytes,
sizeof(send.bytes), cmd,
1559 key, strlen(key), 1, 9, 0);
1562 for (ii = 9; ii >= 0; --ii) {
1563 safe_send(send.bytes, len,
false);
1564 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1565 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1566 validate_response_header(&receive.response_header, cmd,
1567 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1568 assert(ntohll(receive.response.message.body.value) == ii);
1573 safe_send(send.bytes, len,
false);
1574 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1575 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1576 validate_response_header(&receive.response_header, cmd,
1577 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1578 assert(ntohll(receive.response.message.body.value) == 0);
1586 static enum test_return test_binary_decr(
void) {
1587 return test_binary_decr_impl(
"test_binary_decr",
1588 PROTOCOL_BINARY_CMD_DECREMENT);
1591 static enum test_return test_binary_decrq(
void) {
1592 return test_binary_decr_impl(
"test_binary_decrq",
1593 PROTOCOL_BINARY_CMD_DECREMENTQ);
1596 static enum test_return test_binary_version(
void) {
1603 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
1604 PROTOCOL_BINARY_CMD_VERSION,
1607 safe_send(buffer.bytes, len,
false);
1608 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
1609 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1610 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1615 static enum test_return test_binary_flush_impl(
const char *key, uint8_t cmd) {
1622 size_t len = storage_command(send.bytes,
sizeof(send.bytes),
1623 PROTOCOL_BINARY_CMD_ADD,
1624 key, strlen(key), NULL, 0, 0, 0);
1625 safe_send(send.bytes, len,
false);
1626 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1627 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1628 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1630 len = flush_command(send.bytes,
sizeof(send.bytes), cmd, 2,
true);
1631 safe_send(send.bytes, len,
false);
1632 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1633 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1634 validate_response_header(&receive.response, cmd,
1635 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1638 len = raw_command(send.bytes,
sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1639 key, strlen(key), NULL, 0);
1640 safe_send(send.bytes, len,
false);
1641 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1642 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1643 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1646 safe_send(send.bytes, len,
false);
1647 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1648 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1649 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1652 for (ii = 0; ii < 2; ++ii) {
1653 len = storage_command(send.bytes,
sizeof(send.bytes),
1654 PROTOCOL_BINARY_CMD_ADD,
1655 key, strlen(key), NULL, 0, 0, 0);
1656 safe_send(send.bytes, len,
false);
1657 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1658 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1659 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1661 len = flush_command(send.bytes,
sizeof(send.bytes), cmd, 0, ii == 0);
1662 safe_send(send.bytes, len,
false);
1663 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1664 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1665 validate_response_header(&receive.response, cmd,
1666 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1669 len = raw_command(send.bytes,
sizeof(send.bytes),
1670 PROTOCOL_BINARY_CMD_GET,
1671 key, strlen(key), NULL, 0);
1672 safe_send(send.bytes, len,
false);
1673 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1674 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1675 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1681 static enum test_return test_binary_flush(
void) {
1682 return test_binary_flush_impl(
"test_binary_flush",
1683 PROTOCOL_BINARY_CMD_FLUSH);
1686 static enum test_return test_binary_flushq(
void) {
1687 return test_binary_flush_impl(
"test_binary_flushq",
1688 PROTOCOL_BINARY_CMD_FLUSHQ);
1691 static enum test_return test_binary_cas(
void) {
1698 size_t len = flush_command(send.bytes,
sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1700 safe_send(send.bytes, len,
false);
1701 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1702 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1703 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1705 uint64_t value = 0xdeadbeefdeadcafe;
1706 len = storage_command(send.bytes,
sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1707 "FOO", 3, &value,
sizeof(value), 0, 0);
1709 send.request.message.header.request.cas = 0x7ffffff;
1710 safe_send(send.bytes, len,
false);
1711 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1712 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1713 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1715 send.request.message.header.request.cas = 0x0;
1716 safe_send(send.bytes, len,
false);
1717 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1718 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1719 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1721 send.request.message.header.request.cas = receive.response.message.header.response.cas;
1722 safe_send(send.bytes, len,
false);
1723 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1724 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1725 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1727 send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
1728 safe_send(send.bytes, len,
false);
1729 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1730 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1731 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1735 static enum test_return test_binary_concat_impl(
const char *key, uint8_t cmd) {
1741 const char *value =
"world";
1743 size_t len = raw_command(send.bytes,
sizeof(send.bytes), cmd,
1744 key, strlen(key), value, strlen(value));
1747 safe_send(send.bytes, len,
false);
1748 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1749 validate_response_header(&receive.response, cmd,
1750 PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1752 len = storage_command(send.bytes,
sizeof(send.bytes),
1753 PROTOCOL_BINARY_CMD_ADD,
1754 key, strlen(key), value, strlen(value), 0, 0);
1755 safe_send(send.bytes, len,
false);
1756 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1757 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1758 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1760 len = raw_command(send.bytes,
sizeof(send.bytes), cmd,
1761 key, strlen(key), value, strlen(value));
1762 safe_send(send.bytes, len,
false);
1764 if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1765 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1766 validate_response_header(&receive.response, cmd,
1767 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1769 len = raw_command(send.bytes,
sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
1771 safe_send(send.bytes, len,
false);
1772 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1773 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
1774 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1777 len = raw_command(send.bytes,
sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
1778 key, strlen(key), NULL, 0);
1780 safe_send(send.bytes, len,
false);
1781 safe_recv_packet(receive.bytes,
sizeof(receive.bytes));
1782 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
1783 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1785 assert(receive.response.message.header.response.keylen == strlen(key));
1786 assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
1788 char *ptr = receive.bytes;
1789 ptr +=
sizeof(receive.response);
1792 assert(memcmp(ptr, key, strlen(key)) == 0);
1794 assert(memcmp(ptr, value, strlen(value)) == 0);
1795 ptr += strlen(value);
1796 assert(memcmp(ptr, value, strlen(value)) == 0);
1801 static enum test_return test_binary_append(
void) {
1802 return test_binary_concat_impl(
"test_binary_append",
1803 PROTOCOL_BINARY_CMD_APPEND);
1806 static enum test_return test_binary_prepend(
void) {
1807 return test_binary_concat_impl(
"test_binary_prepend",
1808 PROTOCOL_BINARY_CMD_PREPEND);
1811 static enum test_return test_binary_appendq(
void) {
1812 return test_binary_concat_impl(
"test_binary_appendq",
1813 PROTOCOL_BINARY_CMD_APPENDQ);
1816 static enum test_return test_binary_prependq(
void) {
1817 return test_binary_concat_impl(
"test_binary_prependq",
1818 PROTOCOL_BINARY_CMD_PREPENDQ);
1821 static enum test_return test_binary_stat(
void) {
1828 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
1829 PROTOCOL_BINARY_CMD_STAT,
1832 safe_send(buffer.bytes, len,
false);
1834 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
1835 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
1836 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1837 }
while (buffer.response.message.header.response.keylen != 0);
1842 static enum test_return test_binary_scrub(
void) {
1849 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
1850 PROTOCOL_BINARY_CMD_SCRUB,
1853 safe_send(buffer.bytes, len,
false);
1854 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
1855 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
1856 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1862 volatile bool hickup_thread_running;
1864 static void *binary_hickup_recv_verification_thread(
void *arg) {
1866 if (response != NULL) {
1867 while (safe_recv_packet(response, 65*1024)) {
1869 validate_response_header(response,
1870 response->message.header.response.opcode,
1871 response->message.header.response.status);
1875 hickup_thread_running =
false;
1876 allow_closed_read =
false;
1880 static enum test_return test_binary_pipeline_hickup_chunk(
void *buffer,
size_t buffersize) {
1883 uint64_t value = 0xfeedfacedeadbeef;
1885 while (hickup_thread_running &&
1889 char bytes[65 * 1024];
1891 uint8_t cmd = (uint8_t)(rand() & 0xff);
1893 size_t keylen = (rand() % 250) + 1;
1896 case PROTOCOL_BINARY_CMD_ADD:
1897 case PROTOCOL_BINARY_CMD_ADDQ:
1898 case PROTOCOL_BINARY_CMD_REPLACE:
1899 case PROTOCOL_BINARY_CMD_REPLACEQ:
1900 case PROTOCOL_BINARY_CMD_SET:
1901 case PROTOCOL_BINARY_CMD_SETQ:
1902 len = storage_command(command.bytes,
sizeof(command.bytes), cmd,
1903 key, keylen , &value,
sizeof(value),
1906 case PROTOCOL_BINARY_CMD_APPEND:
1907 case PROTOCOL_BINARY_CMD_APPENDQ:
1908 case PROTOCOL_BINARY_CMD_PREPEND:
1909 case PROTOCOL_BINARY_CMD_PREPENDQ:
1910 len = raw_command(command.bytes,
sizeof(command.bytes), cmd,
1911 key, keylen, &value,
sizeof(value));
1913 case PROTOCOL_BINARY_CMD_FLUSH:
1914 case PROTOCOL_BINARY_CMD_FLUSHQ:
1915 len = raw_command(command.bytes,
sizeof(command.bytes), cmd,
1918 case PROTOCOL_BINARY_CMD_NOOP:
1919 len = raw_command(command.bytes,
sizeof(command.bytes), cmd,
1922 case PROTOCOL_BINARY_CMD_DELETE:
1923 case PROTOCOL_BINARY_CMD_DELETEQ:
1924 len = raw_command(command.bytes,
sizeof(command.bytes), cmd,
1925 key, keylen, NULL, 0);
1927 case PROTOCOL_BINARY_CMD_DECREMENT:
1928 case PROTOCOL_BINARY_CMD_DECREMENTQ:
1929 case PROTOCOL_BINARY_CMD_INCREMENT:
1930 case PROTOCOL_BINARY_CMD_INCREMENTQ:
1931 len = arithmetic_command(command.bytes,
sizeof(command.bytes), cmd,
1932 key, keylen, 1, 0, 0);
1934 case PROTOCOL_BINARY_CMD_VERSION:
1935 len = raw_command(command.bytes,
sizeof(command.bytes),
1936 PROTOCOL_BINARY_CMD_VERSION,
1939 case PROTOCOL_BINARY_CMD_GET:
1940 case PROTOCOL_BINARY_CMD_GETK:
1941 case PROTOCOL_BINARY_CMD_GETKQ:
1942 case PROTOCOL_BINARY_CMD_GETQ:
1943 len = raw_command(command.bytes,
sizeof(command.bytes), cmd,
1944 key, keylen, NULL, 0);
1947 case PROTOCOL_BINARY_CMD_STAT:
1948 len = raw_command(command.bytes,
sizeof(command.bytes),
1949 PROTOCOL_BINARY_CMD_STAT,
1958 if ((len + offset) < buffersize) {
1959 memcpy(((
char*)buffer) + offset, command.bytes, len);
1965 safe_send(buffer, offset,
true);
1970 static enum test_return test_binary_pipeline_hickup(
void)
1972 size_t buffersize = 65 * 1024;
1973 void *buffer = malloc(buffersize);
1978 allow_closed_read =
true;
1979 hickup_thread_running =
true;
1980 if ((ret = pthread_create(&tid, NULL,
1981 binary_hickup_recv_verification_thread, NULL)) != 0) {
1982 fprintf(stderr,
"Can't create thread: %s\n", strerror(ret));
1989 srand((
int)time(NULL));
1990 for (ii = 0; ii < 2; ++ii) {
1991 test_binary_pipeline_hickup_chunk(buffer, buffersize);
1995 size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
1997 safe_send(buffer, len,
false);
1999 pthread_join(tid, NULL);
2004 static enum test_return test_binary_verbosity(
void) {
2011 for (
int ii = 10; ii > -1; --ii) {
2012 size_t len = raw_command(buffer.bytes,
sizeof(buffer.bytes),
2013 PROTOCOL_BINARY_CMD_VERBOSITY,
2015 buffer.request.message.header.request.extlen = 4;
2016 buffer.request.message.header.request.bodylen = ntohl(4);
2017 buffer.request.message.body.level = (uint32_t)ntohl(ii);
2018 safe_send(buffer.bytes, len +
sizeof(4),
false);
2019 safe_recv_packet(buffer.bytes,
sizeof(buffer.bytes));
2020 validate_response_header(&buffer.response,
2021 PROTOCOL_BINARY_CMD_VERBOSITY,
2022 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2028 static enum test_return test_issue_101(
void) {
2030 enum test_return ret = TEST_PASS;
2035 if (getenv(
"DONT_SKIP_TEST_101") == NULL) {
2039 const char *command =
"stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
2040 size_t cmdlen = strlen(command);
2042 server_pid = start_server(&port,
false, 1000);
2044 for (ii = 0; ii < max; ++ii) {
2045 fds[ii] = connect_server(
"127.0.0.1", port,
true);
2046 assert(fds[ii] > 0);
2050 for (ii = 0; ii < max; ++ii) {
2053 ssize_t err = send(fds[ii], command, cmdlen, 0);
2071 if (child == (pid_t)-1) {
2073 }
else if (child > 0) {
2076 while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
2080 sock = connect_server(
"127.0.0.1", port,
false);
2081 ret = test_binary_noop();
2088 for (ii = 0; ii < max; ++ii) {
2092 assert(
kill(server_pid, SIGTERM) == 0);
2097 typedef enum test_return (*TEST_FUNC)(void);
2099 const char *description;
2104 {
"cache_create", cache_create_test },
2105 {
"cache_constructor", cache_constructor_test },
2106 {
"cache_constructor_fail", cache_fail_constructor_test },
2107 {
"cache_destructor", cache_destructor_test },
2108 {
"cache_reuse", cache_reuse_test },
2109 {
"cache_redzone", cache_redzone_test },
2110 {
"issue_161", test_issue_161 },
2111 {
"strtof", test_safe_strtof },
2112 {
"strtol", test_safe_strtol },
2113 {
"strtoll", test_safe_strtoll },
2114 {
"strtoul", test_safe_strtoul },
2115 {
"strtoull", test_safe_strtoull },
2116 {
"issue_44", test_issue_44 },
2117 {
"vperror", test_vperror },
2118 {
"issue_101", test_issue_101 },
2119 {
"config_parser", test_config_parser },
2121 {
"start_server", start_memcached_server },
2122 {
"issue_92", test_issue_92 },
2123 {
"issue_102", test_issue_102 },
2124 {
"binary_noop", test_binary_noop },
2125 {
"binary_quit", test_binary_quit },
2126 {
"binary_quitq", test_binary_quitq },
2127 {
"binary_set", test_binary_set },
2128 {
"binary_setq", test_binary_setq },
2129 {
"binary_add", test_binary_add },
2130 {
"binary_addq", test_binary_addq },
2131 {
"binary_replace", test_binary_replace },
2132 {
"binary_replaceq", test_binary_replaceq },
2133 {
"binary_delete", test_binary_delete },
2134 {
"binary_deleteq", test_binary_deleteq },
2135 {
"binary_get", test_binary_get },
2136 {
"binary_getq", test_binary_getq },
2137 {
"binary_getk", test_binary_getk },
2138 {
"binary_getkq", test_binary_getkq },
2139 {
"binary_incr", test_binary_incr },
2140 {
"binary_incrq", test_binary_incrq },
2141 {
"binary_decr", test_binary_decr },
2142 {
"binary_decrq", test_binary_decrq },
2143 {
"binary_version", test_binary_version },
2144 {
"binary_flush", test_binary_flush },
2145 {
"binary_flushq", test_binary_flushq },
2146 {
"binary_cas", test_binary_cas },
2147 {
"binary_append", test_binary_append },
2148 {
"binary_appendq", test_binary_appendq },
2149 {
"binary_prepend", test_binary_prepend },
2150 {
"binary_prependq", test_binary_prependq },
2151 {
"binary_stat", test_binary_stat },
2152 {
"binary_scrub", test_binary_scrub },
2153 {
"binary_verbosity", test_binary_verbosity },
2154 {
"binary_pipeline_hickup", test_binary_pipeline_hickup },
2155 {
"stop_server", stop_memcached_server },
2159 int main(
int argc,
char **argv)
2162 int ii = 0, num_cases = 0;
2165 setbuf(stdout, NULL);
2166 setbuf(stderr, NULL);
2168 for (num_cases = 0; testcases[num_cases].description; num_cases++) {
2172 printf(
"1..%d\n", num_cases);
2174 for (ii = 0; testcases[ii].description != NULL; ++ii) {
2180 enum test_return ret = testcases[ii].function();
2181 if (ret == TEST_SKIP) {
2182 fprintf(stdout,
"ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
2183 }
else if (ret == TEST_PASS) {
2184 fprintf(stdout,
"ok %d - %s\n", ii + 1, testcases[ii].description);
2186 fprintf(stdout,
"not ok %d - %s\n", ii + 1, testcases[ii].description);