1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
5 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <netinet/tcp.h>
18 #include <netinet/in.h>
24 #include "protocol_binary.h"
26 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
28 enum test_return
{ TEST_SKIP
, TEST_PASS
, TEST_FAIL
};
30 static pid_t server_pid
;
31 static in_port_t port
;
33 static bool allow_closed_read
= false;
35 static enum test_return
cache_create_test(void)
37 cache_t
*cache
= cache_create("test", sizeof(uint32_t), sizeof(char*),
39 assert(cache
!= NULL
);
44 const uint64_t constructor_pattern
= 0xdeadcafebabebeef;
46 static int cache_constructor(void *buffer
, void *notused1
, int notused2
) {
47 uint64_t *ptr
= buffer
;
48 *ptr
= constructor_pattern
;
52 static enum test_return
cache_constructor_test(void)
54 cache_t
*cache
= cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
55 cache_constructor
, NULL
);
56 assert(cache
!= NULL
);
57 uint64_t *ptr
= cache_alloc(cache
);
58 uint64_t pattern
= *ptr
;
59 cache_free(cache
, ptr
);
61 return (pattern
== constructor_pattern
) ? TEST_PASS
: TEST_FAIL
;
64 static int cache_fail_constructor(void *buffer
, void *notused1
, int notused2
) {
68 static enum test_return
cache_fail_constructor_test(void)
70 enum test_return ret
= TEST_PASS
;
72 cache_t
*cache
= cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
73 cache_fail_constructor
, NULL
);
74 assert(cache
!= NULL
);
75 uint64_t *ptr
= cache_alloc(cache
);
83 static void *destruct_data
= 0;
85 static void cache_destructor(void *buffer
, void *notused
) {
86 destruct_data
= buffer
;
89 static enum test_return
cache_destructor_test(void)
91 cache_t
*cache
= cache_create("test", sizeof(uint32_t), sizeof(char*),
92 NULL
, cache_destructor
);
93 assert(cache
!= NULL
);
94 char *ptr
= cache_alloc(cache
);
95 cache_free(cache
, ptr
);
98 return (ptr
== destruct_data
) ? TEST_PASS
: TEST_FAIL
;
101 static enum test_return
cache_reuse_test(void)
104 cache_t
*cache
= cache_create("test", sizeof(uint32_t), sizeof(char*),
106 char *ptr
= cache_alloc(cache
);
107 cache_free(cache
, ptr
);
108 for (ii
= 0; ii
< 100; ++ii
) {
109 char *p
= cache_alloc(cache
);
111 cache_free(cache
, ptr
);
113 cache_destroy(cache
);
118 static enum test_return
cache_bulkalloc(size_t datasize
)
120 cache_t
*cache
= cache_create("test", datasize
, sizeof(char*),
122 #define ITERATIONS 1024
123 void *ptr
[ITERATIONS
];
125 for (int ii
= 0; ii
< ITERATIONS
; ++ii
) {
126 ptr
[ii
] = cache_alloc(cache
);
127 assert(ptr
[ii
] != 0);
128 memset(ptr
[ii
], 0xff, datasize
);
131 for (int ii
= 0; ii
< ITERATIONS
; ++ii
) {
132 cache_free(cache
, ptr
[ii
]);
136 cache_destroy(cache
);
140 static enum test_return
test_issue_161(void)
142 enum test_return ret
= cache_bulkalloc(1);
143 if (ret
== TEST_PASS
) {
144 ret
= cache_bulkalloc(512);
150 static enum test_return
cache_redzone_test(void)
153 cache_t
*cache
= cache_create("test", sizeof(uint32_t), sizeof(char*),
156 /* Ignore SIGABORT */
157 struct sigaction old_action
;
158 struct sigaction action
= { .sa_handler
= SIG_IGN
, .sa_flags
= 0};
159 sigemptyset(&action
.sa_mask
);
160 sigaction(SIGABRT
, &action
, &old_action
);
162 /* check memory debug.. */
163 char *p
= cache_alloc(cache
);
166 cache_free(cache
, p
);
167 assert(cache_error
== -1);
170 p
[sizeof(uint32_t)] = 0;
171 cache_free(cache
, p
);
172 assert(cache_error
== 1);
174 /* restore signal handler */
175 sigaction(SIGABRT
, &old_action
, NULL
);
177 cache_destroy(cache
);
185 static enum test_return
test_safe_strtoul(void) {
187 assert(safe_strtoul("123", &val
));
189 assert(safe_strtoul("+123", &val
));
191 assert(!safe_strtoul("", &val
)); // empty
192 assert(!safe_strtoul("123BOGUS", &val
)); // non-numeric
193 assert(!safe_strtoul(" issue221", &val
)); // non-numeric
194 /* Not sure what it does, but this works with ICC :/
195 assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
199 assert(safe_strtoul("4294967295", &val
)); // 2**32 - 1
200 assert(val
== 4294967295L);
201 /* This actually works on 64-bit ubuntu
202 assert(!safe_strtoul("4294967296", &val)); // 2**32
204 assert(!safe_strtoul("-1", &val
)); // negative
209 static enum test_return
test_safe_strtoull(void) {
211 assert(safe_strtoull("123", &val
));
213 assert(safe_strtoull("+123", &val
));
215 assert(!safe_strtoull("", &val
)); // empty
216 assert(!safe_strtoull("123BOGUS", &val
)); // non-numeric
217 assert(!safe_strtoull("92837498237498237498029383", &val
)); // out of range
218 assert(!safe_strtoull(" issue221", &val
)); // non-numeric
221 assert(safe_strtoull("18446744073709551615", &val
)); // 2**64 - 1
222 assert(val
== 18446744073709551615ULL);
223 assert(!safe_strtoull("18446744073709551616", &val
)); // 2**64
224 assert(!safe_strtoull("-1", &val
)); // negative
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
)); // empty
237 assert(!safe_strtoll("123BOGUS", &val
)); // non-numeric
238 assert(!safe_strtoll("92837498237498237498029383", &val
)); // out of range
239 assert(!safe_strtoll(" issue221", &val
)); // non-numeric
242 assert(!safe_strtoll("18446744073709551615", &val
)); // 2**64 - 1
243 assert(safe_strtoll("9223372036854775807", &val
)); // 2**63 - 1
244 assert(val
== 9223372036854775807LL);
246 assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
247 assert(val == -9223372036854775808LL);
249 assert(!safe_strtoll("-9223372036854775809", &val
)); // -2**63 - 1
251 // We'll allow space to terminate the string. And leading space.
252 assert(safe_strtoll(" 123 foo", &val
));
257 static enum test_return
test_safe_strtol(void) {
259 assert(safe_strtol("123", &val
));
261 assert(safe_strtol("+123", &val
));
263 assert(safe_strtol("-123", &val
));
265 assert(!safe_strtol("", &val
)); // empty
266 assert(!safe_strtol("123BOGUS", &val
)); // non-numeric
267 assert(!safe_strtol("92837498237498237498029383", &val
)); // out of range
268 assert(!safe_strtol(" issue221", &val
)); // non-numeric
271 /* This actually works on 64-bit ubuntu
272 assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
274 assert(safe_strtol("2147483647", &val
)); // (- (expt 2.0 31) 1)
275 assert(val
== 2147483647L);
276 /* This actually works on 64-bit ubuntu
277 assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
280 // We'll allow space to terminate the string. And leading space.
281 assert(safe_strtol(" 123 foo", &val
));
287 * Function to start the server and let it listen on a random port
289 * @param port_out where to store the TCP port number the server is
291 * @param daemon set to true if you want to run the memcached server
292 * as a daemon process
293 * @return the pid of the memcached server
295 static pid_t
start_server(in_port_t
*port_out
, bool daemon
, int timeout
) {
296 char environment
[80];
297 snprintf(environment
, sizeof(environment
),
298 "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
299 char *filename
= environment
+ strlen("MEMCACHED_PORT_FILENAME=");
301 snprintf(pid_file
, sizeof(pid_file
), "/tmp/pid.%lu", (long)getpid());
307 /* I want to name the corefiles differently so that they don't
311 snprintf(coreadm
, sizeof(coreadm
),
312 "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
324 snprintf(tmo
, sizeof(tmo
), "%u", timeout
);
328 putenv("LD_PRELOAD=watchmalloc.so.1");
329 putenv("MALLOC_DEBUG=WATCH");
333 argv
[arg
++] = "./timedrun";
336 argv
[arg
++] = "./memcached-debug";
341 /* Handle rpmbuild and the like doing this as root */
344 argv
[arg
++] = "root";
349 argv
[arg
++] = pid_file
;
352 argv
[arg
++] = "-vvv";
355 assert(execv(argv
[0], argv
) != -1);
358 /* Yeah just let us "busy-wait" for the file to be created ;-) */
359 while (access(filename
, F_OK
) == -1) {
363 FILE *fp
= fopen(filename
, "r");
365 fprintf(stderr
, "Failed to open the file containing port numbers: %s\n",
370 *port_out
= (in_port_t
)-1;
372 while ((fgets(buffer
, sizeof(buffer
), fp
)) != NULL
) {
373 if (strncmp(buffer
, "TCP INET: ", 10) == 0) {
375 assert(safe_strtol(buffer
+ 10, &val
));
376 *port_out
= (in_port_t
)val
;
380 assert(remove(filename
) == 0);
383 /* loop and wait for the pid file.. There is a potential race
384 * condition that the server just created the file but isn't
385 * finished writing the content, so we loop a few times
387 while (access(pid_file
, F_OK
) == -1) {
391 fp
= fopen(pid_file
, "r");
393 fprintf(stderr
, "Failed to open pid file: %s\n",
398 /* Avoid race by retrying 20 times */
399 for (int x
= 0; x
< 20 && fgets(buffer
, sizeof(buffer
), fp
) == NULL
; x
++) {
405 assert(safe_strtol(buffer
, &val
));
412 static enum test_return
test_issue_44(void) {
414 pid_t pid
= start_server(&port
, true, 15);
415 assert(kill(pid
, SIGHUP
) == 0);
417 assert(kill(pid
, SIGTERM
) == 0);
422 static struct addrinfo
*lookuphost(const char *hostname
, in_port_t port
)
424 struct addrinfo
*ai
= 0;
425 struct addrinfo hints
= { .ai_family
= AF_UNSPEC
,
426 .ai_protocol
= IPPROTO_TCP
,
427 .ai_socktype
= SOCK_STREAM
};
428 char service
[NI_MAXSERV
];
431 (void)snprintf(service
, NI_MAXSERV
, "%d", port
);
432 if ((error
= getaddrinfo(hostname
, service
, &hints
, &ai
)) != 0) {
433 if (error
!= EAI_SYSTEM
) {
434 fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(error
));
436 perror("getaddrinfo()");
443 static int connect_server(const char *hostname
, in_port_t port
, bool nonblock
)
445 struct addrinfo
*ai
= lookuphost(hostname
, port
);
448 if ((sock
= socket(ai
->ai_family
, ai
->ai_socktype
,
449 ai
->ai_protocol
)) != -1) {
450 if (connect(sock
, ai
->ai_addr
, ai
->ai_addrlen
) == -1) {
451 fprintf(stderr
, "Failed to connect socket: %s\n",
455 } else if (nonblock
) {
456 int flags
= fcntl(sock
, F_GETFL
, 0);
457 if (flags
< 0 || fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) < 0) {
458 fprintf(stderr
, "Failed to enable nonblocking mode: %s\n",
465 fprintf(stderr
, "Failed to create socket: %s\n", strerror(errno
));
473 static enum test_return
test_vperror(void) {
475 int oldstderr
= dup(STDERR_FILENO
);
476 char tmpl
[sizeof(TMP_TEMPLATE
)+1];
477 strncpy(tmpl
, TMP_TEMPLATE
, sizeof(TMP_TEMPLATE
)+1);
479 int newfile
= mkstemp(tmpl
);
481 rv
= dup2(newfile
, STDERR_FILENO
);
482 assert(rv
== STDERR_FILENO
);
487 vperror("Old McDonald had a farm. %s", "EI EIO");
490 rv
= dup2(oldstderr
, STDERR_FILENO
);
491 assert(rv
== STDERR_FILENO
);
494 /* Go read the file */
495 char buf
[80] = { 0 };
496 FILE *efile
= fopen(tmpl
, "r");
498 char *prv
= fgets(buf
, sizeof(buf
), efile
);
504 char expected
[80] = { 0 };
505 snprintf(expected
, sizeof(expected
),
506 "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO
));
511 "\nGot: ``%s''\n", expected, buf);
514 return strcmp(expected
, buf
) == 0 ? TEST_PASS
: TEST_FAIL
;
517 static void send_ascii_command(const char *buf
) {
519 const char* ptr
= buf
;
520 size_t len
= strlen(buf
);
523 ssize_t nw
= write(sock
, ptr
+ offset
, len
- offset
);
525 if (errno
!= EINTR
) {
526 fprintf(stderr
, "Failed to write: %s\n", strerror(errno
));
532 } while (offset
< len
);
536 * This is a dead slow single byte read, but it should only read out
537 * _one_ response and I don't have an input buffer... The current
538 * implementation only supports single-line responses, so if you want to use
539 * it for get commands you need to implement that first ;-)
541 static void read_ascii_response(char *buffer
, size_t size
) {
543 bool need_more
= true;
545 ssize_t nr
= read(sock
, buffer
+ offset
, 1);
547 if (errno
!= EINTR
) {
548 fprintf(stderr
, "Failed to read: %s\n", strerror(errno
));
553 if (buffer
[offset
] == '\n') {
555 buffer
[offset
+ 1] = '\0';
558 assert(offset
+ 1 < size
);
563 static enum test_return
test_issue_92(void) {
567 sock
= connect_server("127.0.0.1", port
, false);
569 send_ascii_command("stats cachedump 1 0 0\r\n");
570 read_ascii_response(buffer
, sizeof(buffer
));
571 assert(strncmp(buffer
, "END", strlen("END")) == 0);
573 send_ascii_command("stats cachedump 200 0 0\r\n");
574 read_ascii_response(buffer
, sizeof(buffer
));
575 assert(strncmp(buffer
, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
578 sock
= connect_server("127.0.0.1", port
, false);
582 static enum test_return
test_issue_102(void) {
584 memset(buffer
, ' ', sizeof(buffer
));
585 buffer
[sizeof(buffer
) - 1] = '\0';
588 sock
= connect_server("127.0.0.1", port
, false);
590 send_ascii_command(buffer
);
591 /* verify that the server closed the connection */
592 assert(read(sock
, buffer
, sizeof(buffer
)) == 0);
594 sock
= connect_server("127.0.0.1", port
, false);
596 snprintf(buffer
, sizeof(buffer
), "gets ");
598 while (offset
< 4000) {
599 offset
+= snprintf(buffer
+ offset
, sizeof(buffer
) - offset
,
600 "%010u ", (unsigned int)offset
);
603 send_ascii_command(buffer
);
606 send_ascii_command("\r\n");
608 read_ascii_response(rsp
, sizeof(rsp
));
609 assert(strncmp(rsp
, "END", strlen("END")) == 0);
611 send_ascii_command(buffer
);
613 send_ascii_command("\r\n");
614 read_ascii_response(rsp
, sizeof(rsp
));
615 assert(strncmp(rsp
, "END", strlen("END")) == 0);
617 memset(buffer
, ' ', sizeof(buffer
));
618 int len
= snprintf(buffer
+ 101, sizeof(buffer
) - 101, "gets foo");
619 buffer
[101 + len
] = ' ';
620 buffer
[sizeof(buffer
) - 1] = '\0';
621 send_ascii_command(buffer
);
622 /* verify that the server closed the connection */
623 assert(read(sock
, buffer
, sizeof(buffer
)) == 0);
626 sock
= connect_server("127.0.0.1", port
, false);
631 static enum test_return
start_memcached_server(void) {
632 server_pid
= start_server(&port
, false, 600);
633 sock
= connect_server("127.0.0.1", port
, false);
637 static enum test_return
stop_memcached_server(void) {
639 assert(kill(server_pid
, SIGTERM
) == 0);
643 static void safe_send(const void* buf
, size_t len
, bool hickup
)
646 const char* ptr
= buf
;
649 assert(val
== (uint8_t)0x80);
650 fprintf(stderr
, "About to send %lu bytes:", (unsigned long)len
);
651 for (int ii
= 0; ii
< len
; ++ii
) {
653 fprintf(stderr
, "\n ");
656 fprintf(stderr
, " 0x%02x", val
);
658 fprintf(stderr
, "\n");
663 size_t num_bytes
= len
- offset
;
665 if (num_bytes
> 1024) {
666 num_bytes
= (rand() % 1023) + 1;
670 ssize_t nw
= write(sock
, ptr
+ offset
, num_bytes
);
672 if (errno
!= EINTR
) {
673 fprintf(stderr
, "Failed to write: %s\n", strerror(errno
));
682 } while (offset
< len
);
685 static bool safe_recv(void *buf
, size_t len
) {
691 ssize_t nr
= read(sock
, ((char*)buf
) + offset
, len
- offset
);
693 if (errno
!= EINTR
) {
694 fprintf(stderr
, "Failed to read: %s\n", strerror(errno
));
698 if (nr
== 0 && allow_closed_read
) {
704 } while (offset
< len
);
709 static bool safe_recv_packet(void *buf
, size_t size
) {
710 protocol_binary_response_no_extras
*response
= buf
;
711 assert(size
> sizeof(*response
));
712 if (!safe_recv(response
, sizeof(*response
))) {
715 response
->message
.header
.response
.keylen
= ntohs(response
->message
.header
.response
.keylen
);
716 response
->message
.header
.response
.status
= ntohs(response
->message
.header
.response
.status
);
717 response
->message
.header
.response
.bodylen
= ntohl(response
->message
.header
.response
.bodylen
);
719 size_t len
= sizeof(*response
);
723 if (!safe_recv(ptr
, response
->message
.header
.response
.bodylen
)) {
730 len
+= response
->message
.header
.response
.bodylen
;
732 assert(val
== (uint8_t)0x81);
733 fprintf(stderr
, "Received %lu bytes:", (unsigned long)len
);
734 for (int ii
= 0; ii
< len
; ++ii
) {
736 fprintf(stderr
, "\n ");
739 fprintf(stderr
, " 0x%02x", val
);
741 fprintf(stderr
, "\n");
746 static off_t
storage_command(char*buf
,
755 /* all of the storage commands use the same command layout */
756 protocol_binary_request_set
*request
= (void*)buf
;
757 assert(bufsz
> sizeof(*request
) + keylen
+ dtalen
);
759 memset(request
, 0, sizeof(*request
));
760 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
761 request
->message
.header
.request
.opcode
= cmd
;
762 request
->message
.header
.request
.keylen
= htons(keylen
);
763 request
->message
.header
.request
.extlen
= 8;
764 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 8 + dtalen
);
765 request
->message
.header
.request
.opaque
= 0xdeadbeef;
766 request
->message
.body
.flags
= flags
;
767 request
->message
.body
.expiration
= exp
;
769 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 8;
771 memcpy(buf
+ key_offset
, key
, keylen
);
773 memcpy(buf
+ key_offset
+ keylen
, dta
, dtalen
);
776 return key_offset
+ keylen
+ dtalen
;
779 static off_t
raw_command(char* buf
,
786 /* all of the storage commands use the same command layout */
787 protocol_binary_request_no_extras
*request
= (void*)buf
;
788 assert(bufsz
> sizeof(*request
) + keylen
+ dtalen
);
790 memset(request
, 0, sizeof(*request
));
791 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
792 request
->message
.header
.request
.opcode
= cmd
;
793 request
->message
.header
.request
.keylen
= htons(keylen
);
794 request
->message
.header
.request
.bodylen
= htonl(keylen
+ dtalen
);
795 request
->message
.header
.request
.opaque
= 0xdeadbeef;
797 off_t key_offset
= sizeof(protocol_binary_request_no_extras
);
800 memcpy(buf
+ key_offset
, key
, keylen
);
803 memcpy(buf
+ key_offset
+ keylen
, dta
, dtalen
);
806 return sizeof(*request
) + keylen
+ dtalen
;
809 static off_t
flush_command(char* buf
, size_t bufsz
, uint8_t cmd
, uint32_t exptime
, bool use_extra
) {
810 protocol_binary_request_flush
*request
= (void*)buf
;
811 assert(bufsz
> sizeof(*request
));
813 memset(request
, 0, sizeof(*request
));
814 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
815 request
->message
.header
.request
.opcode
= cmd
;
817 off_t size
= sizeof(protocol_binary_request_no_extras
);
819 request
->message
.header
.request
.extlen
= 4;
820 request
->message
.body
.expiration
= htonl(exptime
);
821 request
->message
.header
.request
.bodylen
= htonl(4);
825 request
->message
.header
.request
.opaque
= 0xdeadbeef;
831 static off_t
touch_command(char* buf
,
837 protocol_binary_request_touch
*request
= (void*)buf
;
838 assert(bufsz
> sizeof(*request
));
840 memset(request
, 0, sizeof(*request
));
841 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
842 request
->message
.header
.request
.opcode
= cmd
;
844 request
->message
.header
.request
.keylen
= htons(keylen
);
845 request
->message
.header
.request
.extlen
= 4;
846 request
->message
.body
.expiration
= htonl(exptime
);
847 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 4);
849 request
->message
.header
.request
.opaque
= 0xdeadbeef;
851 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 4;
853 memcpy(buf
+ key_offset
, key
, keylen
);
854 return sizeof(protocol_binary_request_no_extras
) + 4 + keylen
;
857 static off_t
arithmetic_command(char* buf
,
865 protocol_binary_request_incr
*request
= (void*)buf
;
866 assert(bufsz
> sizeof(*request
) + keylen
);
868 memset(request
, 0, sizeof(*request
));
869 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
870 request
->message
.header
.request
.opcode
= cmd
;
871 request
->message
.header
.request
.keylen
= htons(keylen
);
872 request
->message
.header
.request
.extlen
= 20;
873 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 20);
874 request
->message
.header
.request
.opaque
= 0xdeadbeef;
875 request
->message
.body
.delta
= htonll(delta
);
876 request
->message
.body
.initial
= htonll(initial
);
877 request
->message
.body
.expiration
= htonl(exp
);
879 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 20;
881 memcpy(buf
+ key_offset
, key
, keylen
);
882 return key_offset
+ keylen
;
885 static void validate_response_header(protocol_binary_response_no_extras
*response
,
886 uint8_t cmd
, uint16_t status
)
888 assert(response
->message
.header
.response
.magic
== PROTOCOL_BINARY_RES
);
889 assert(response
->message
.header
.response
.opcode
== cmd
);
890 assert(response
->message
.header
.response
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
891 assert(response
->message
.header
.response
.status
== status
);
892 assert(response
->message
.header
.response
.opaque
== 0xdeadbeef);
894 if (status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
896 case PROTOCOL_BINARY_CMD_ADDQ
:
897 case PROTOCOL_BINARY_CMD_APPENDQ
:
898 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
899 case PROTOCOL_BINARY_CMD_DELETEQ
:
900 case PROTOCOL_BINARY_CMD_FLUSHQ
:
901 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
902 case PROTOCOL_BINARY_CMD_PREPENDQ
:
903 case PROTOCOL_BINARY_CMD_QUITQ
:
904 case PROTOCOL_BINARY_CMD_REPLACEQ
:
905 case PROTOCOL_BINARY_CMD_SETQ
:
906 assert("Quiet command shouldn't return on success" == NULL
);
912 case PROTOCOL_BINARY_CMD_ADD
:
913 case PROTOCOL_BINARY_CMD_REPLACE
:
914 case PROTOCOL_BINARY_CMD_SET
:
915 case PROTOCOL_BINARY_CMD_APPEND
:
916 case PROTOCOL_BINARY_CMD_PREPEND
:
917 assert(response
->message
.header
.response
.keylen
== 0);
918 assert(response
->message
.header
.response
.extlen
== 0);
919 assert(response
->message
.header
.response
.bodylen
== 0);
920 assert(response
->message
.header
.response
.cas
!= 0);
922 case PROTOCOL_BINARY_CMD_FLUSH
:
923 case PROTOCOL_BINARY_CMD_NOOP
:
924 case PROTOCOL_BINARY_CMD_QUIT
:
925 case PROTOCOL_BINARY_CMD_DELETE
:
926 assert(response
->message
.header
.response
.keylen
== 0);
927 assert(response
->message
.header
.response
.extlen
== 0);
928 assert(response
->message
.header
.response
.bodylen
== 0);
929 assert(response
->message
.header
.response
.cas
== 0);
932 case PROTOCOL_BINARY_CMD_DECREMENT
:
933 case PROTOCOL_BINARY_CMD_INCREMENT
:
934 assert(response
->message
.header
.response
.keylen
== 0);
935 assert(response
->message
.header
.response
.extlen
== 0);
936 assert(response
->message
.header
.response
.bodylen
== 8);
937 assert(response
->message
.header
.response
.cas
!= 0);
940 case PROTOCOL_BINARY_CMD_STAT
:
941 assert(response
->message
.header
.response
.extlen
== 0);
942 /* key and value exists in all packets except in the terminating */
943 assert(response
->message
.header
.response
.cas
== 0);
946 case PROTOCOL_BINARY_CMD_VERSION
:
947 assert(response
->message
.header
.response
.keylen
== 0);
948 assert(response
->message
.header
.response
.extlen
== 0);
949 assert(response
->message
.header
.response
.bodylen
!= 0);
950 assert(response
->message
.header
.response
.cas
== 0);
953 case PROTOCOL_BINARY_CMD_GET
:
954 case PROTOCOL_BINARY_CMD_GETQ
:
955 assert(response
->message
.header
.response
.keylen
== 0);
956 assert(response
->message
.header
.response
.extlen
== 4);
957 assert(response
->message
.header
.response
.cas
!= 0);
960 case PROTOCOL_BINARY_CMD_GETK
:
961 case PROTOCOL_BINARY_CMD_GETKQ
:
962 assert(response
->message
.header
.response
.keylen
!= 0);
963 assert(response
->message
.header
.response
.extlen
== 4);
964 assert(response
->message
.header
.response
.cas
!= 0);
968 /* Undefined command code */
972 assert(response
->message
.header
.response
.cas
== 0);
973 assert(response
->message
.header
.response
.extlen
== 0);
974 if (cmd
!= PROTOCOL_BINARY_CMD_GETK
&&
975 cmd
!= PROTOCOL_BINARY_CMD_GATK
) {
976 assert(response
->message
.header
.response
.keylen
== 0);
981 static enum test_return
test_binary_noop(void) {
983 protocol_binary_request_no_extras request
;
984 protocol_binary_response_no_extras response
;
988 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
989 PROTOCOL_BINARY_CMD_NOOP
,
992 safe_send(buffer
.bytes
, len
, false);
993 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
994 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_NOOP
,
995 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1000 static enum test_return
test_binary_quit_impl(uint8_t cmd
) {
1002 protocol_binary_request_no_extras request
;
1003 protocol_binary_response_no_extras response
;
1006 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1007 cmd
, NULL
, 0, NULL
, 0);
1009 safe_send(buffer
.bytes
, len
, false);
1010 if (cmd
== PROTOCOL_BINARY_CMD_QUIT
) {
1011 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1012 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_QUIT
,
1013 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1016 /* Socket should be closed now, read should return 0 */
1017 assert(read(sock
, buffer
.bytes
, sizeof(buffer
.bytes
)) == 0);
1019 sock
= connect_server("127.0.0.1", port
, false);
1024 static enum test_return
test_binary_quit(void) {
1025 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT
);
1028 static enum test_return
test_binary_quitq(void) {
1029 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ
);
1032 static enum test_return
test_binary_set_impl(const char *key
, uint8_t cmd
) {
1034 protocol_binary_request_no_extras request
;
1035 protocol_binary_response_no_extras response
;
1038 uint64_t value
= 0xdeadbeefdeadcafe;
1039 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1040 key
, strlen(key
), &value
, sizeof(value
),
1043 /* Set should work over and over again */
1045 for (ii
= 0; ii
< 10; ++ii
) {
1046 safe_send(send
.bytes
, len
, false);
1047 if (cmd
== PROTOCOL_BINARY_CMD_SET
) {
1048 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1049 validate_response_header(&receive
.response
, cmd
,
1050 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1054 if (cmd
== PROTOCOL_BINARY_CMD_SETQ
) {
1055 return test_binary_noop();
1058 send
.request
.message
.header
.request
.cas
= receive
.response
.message
.header
.response
.cas
;
1059 safe_send(send
.bytes
, len
, false);
1060 if (cmd
== PROTOCOL_BINARY_CMD_SET
) {
1061 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1062 validate_response_header(&receive
.response
, cmd
,
1063 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1064 assert(receive
.response
.message
.header
.response
.cas
!= send
.request
.message
.header
.request
.cas
);
1066 return test_binary_noop();
1072 static enum test_return
test_binary_set(void) {
1073 return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET
);
1076 static enum test_return
test_binary_setq(void) {
1077 return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ
);
1081 static enum test_return
test_binary_add_impl(const char *key
, uint8_t cmd
) {
1082 uint64_t value
= 0xdeadbeefdeadcafe;
1084 protocol_binary_request_no_extras request
;
1085 protocol_binary_response_no_extras response
;
1088 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
, key
,
1089 strlen(key
), &value
, sizeof(value
),
1092 /* Add should only work the first time */
1094 for (ii
= 0; ii
< 10; ++ii
) {
1095 safe_send(send
.bytes
, len
, false);
1097 if (cmd
== PROTOCOL_BINARY_CMD_ADD
) {
1098 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1099 validate_response_header(&receive
.response
, cmd
,
1100 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1103 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1104 validate_response_header(&receive
.response
, cmd
,
1105 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
1112 static enum test_return
test_binary_add(void) {
1113 return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD
);
1116 static enum test_return
test_binary_addq(void) {
1117 return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ
);
1120 static enum test_return
test_binary_replace_impl(const char* key
, uint8_t cmd
) {
1121 uint64_t value
= 0xdeadbeefdeadcafe;
1123 protocol_binary_request_no_extras request
;
1124 protocol_binary_response_no_extras response
;
1127 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1128 key
, strlen(key
), &value
, sizeof(value
),
1130 safe_send(send
.bytes
, len
, false);
1131 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1132 validate_response_header(&receive
.response
, cmd
,
1133 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1134 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1135 PROTOCOL_BINARY_CMD_ADD
,
1136 key
, strlen(key
), &value
, sizeof(value
), 0, 0);
1137 safe_send(send
.bytes
, len
, false);
1138 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1139 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1140 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1142 len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1143 key
, strlen(key
), &value
, sizeof(value
), 0, 0);
1145 for (ii
= 0; ii
< 10; ++ii
) {
1146 safe_send(send
.bytes
, len
, false);
1147 if (cmd
== PROTOCOL_BINARY_CMD_REPLACE
) {
1148 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1149 validate_response_header(&receive
.response
,
1150 PROTOCOL_BINARY_CMD_REPLACE
,
1151 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1155 if (cmd
== PROTOCOL_BINARY_CMD_REPLACEQ
) {
1162 static enum test_return
test_binary_replace(void) {
1163 return test_binary_replace_impl("test_binary_replace",
1164 PROTOCOL_BINARY_CMD_REPLACE
);
1167 static enum test_return
test_binary_replaceq(void) {
1168 return test_binary_replace_impl("test_binary_replaceq",
1169 PROTOCOL_BINARY_CMD_REPLACEQ
);
1172 static enum test_return
test_binary_delete_impl(const char *key
, uint8_t cmd
) {
1174 protocol_binary_request_no_extras request
;
1175 protocol_binary_response_no_extras response
;
1178 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1179 key
, strlen(key
), NULL
, 0);
1181 safe_send(send
.bytes
, len
, false);
1182 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1183 validate_response_header(&receive
.response
, cmd
,
1184 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1185 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1186 PROTOCOL_BINARY_CMD_ADD
,
1187 key
, strlen(key
), NULL
, 0, 0, 0);
1188 safe_send(send
.bytes
, len
, false);
1189 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1190 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1191 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1193 len
= raw_command(send
.bytes
, sizeof(send
.bytes
),
1194 cmd
, key
, strlen(key
), NULL
, 0);
1195 safe_send(send
.bytes
, len
, false);
1197 if (cmd
== PROTOCOL_BINARY_CMD_DELETE
) {
1198 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1199 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_DELETE
,
1200 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1203 safe_send(send
.bytes
, len
, false);
1204 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1205 validate_response_header(&receive
.response
, cmd
,
1206 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1211 static enum test_return
test_binary_delete(void) {
1212 return test_binary_delete_impl("test_binary_delete",
1213 PROTOCOL_BINARY_CMD_DELETE
);
1216 static enum test_return
test_binary_deleteq(void) {
1217 return test_binary_delete_impl("test_binary_deleteq",
1218 PROTOCOL_BINARY_CMD_DELETEQ
);
1221 static enum test_return
test_binary_get_impl(const char *key
, uint8_t cmd
) {
1223 protocol_binary_request_no_extras request
;
1224 protocol_binary_response_no_extras response
;
1227 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1228 key
, strlen(key
), NULL
, 0);
1230 safe_send(send
.bytes
, len
, false);
1231 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1232 validate_response_header(&receive
.response
, cmd
,
1233 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1235 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1236 PROTOCOL_BINARY_CMD_ADD
,
1237 key
, strlen(key
), NULL
, 0,
1239 safe_send(send
.bytes
, len
, false);
1240 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1241 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1242 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1244 /* run a little pipeline test ;-) */
1247 for (ii
= 0; ii
< 10; ++ii
) {
1249 protocol_binary_request_no_extras request
;
1252 size_t l
= raw_command(temp
.bytes
, sizeof(temp
.bytes
),
1253 cmd
, key
, strlen(key
), NULL
, 0);
1254 memcpy(send
.bytes
+ len
, temp
.bytes
, l
);
1258 safe_send(send
.bytes
, len
, false);
1259 for (ii
= 0; ii
< 10; ++ii
) {
1260 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1261 validate_response_header(&receive
.response
, cmd
,
1262 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1268 static enum test_return
test_binary_get(void) {
1269 return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET
);
1272 static enum test_return
test_binary_getk(void) {
1273 return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK
);
1276 static enum test_return
test_binary_getq_impl(const char *key
, uint8_t cmd
) {
1277 const char *missing
= "test_binary_getq_missing";
1279 protocol_binary_request_no_extras request
;
1280 protocol_binary_response_no_extras response
;
1282 } send
, temp
, receive
;
1283 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1284 PROTOCOL_BINARY_CMD_ADD
,
1285 key
, strlen(key
), NULL
, 0,
1287 size_t len2
= raw_command(temp
.bytes
, sizeof(temp
.bytes
), cmd
,
1288 missing
, strlen(missing
), NULL
, 0);
1289 /* I need to change the first opaque so that I can separate the two
1291 temp
.request
.message
.header
.request
.opaque
= 0xfeedface;
1292 memcpy(send
.bytes
+ len
, temp
.bytes
, len2
);
1295 len2
= raw_command(temp
.bytes
, sizeof(temp
.bytes
), cmd
,
1296 key
, strlen(key
), NULL
, 0);
1297 memcpy(send
.bytes
+ len
, temp
.bytes
, len2
);
1300 safe_send(send
.bytes
, len
, false);
1301 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1302 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1303 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1304 /* The first GETQ shouldn't return anything */
1305 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1306 validate_response_header(&receive
.response
, cmd
,
1307 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1312 static enum test_return
test_binary_getq(void) {
1313 return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ
);
1316 static enum test_return
test_binary_getkq(void) {
1317 return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ
);
1320 static enum test_return
test_binary_incr_impl(const char* key
, uint8_t cmd
) {
1322 protocol_binary_request_no_extras request
;
1323 protocol_binary_response_no_extras response_header
;
1324 protocol_binary_response_incr response
;
1327 size_t len
= arithmetic_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1328 key
, strlen(key
), 1, 0, 0);
1331 for (ii
= 0; ii
< 10; ++ii
) {
1332 safe_send(send
.bytes
, len
, false);
1333 if (cmd
== PROTOCOL_BINARY_CMD_INCREMENT
) {
1334 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1335 validate_response_header(&receive
.response_header
, cmd
,
1336 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1337 assert(ntohll(receive
.response
.message
.body
.value
) == ii
);
1341 if (cmd
== PROTOCOL_BINARY_CMD_INCREMENTQ
) {
1347 static enum test_return
test_binary_incr(void) {
1348 return test_binary_incr_impl("test_binary_incr",
1349 PROTOCOL_BINARY_CMD_INCREMENT
);
1352 static enum test_return
test_binary_incrq(void) {
1353 return test_binary_incr_impl("test_binary_incrq",
1354 PROTOCOL_BINARY_CMD_INCREMENTQ
);
1357 static enum test_return
test_binary_decr_impl(const char* key
, uint8_t cmd
) {
1359 protocol_binary_request_no_extras request
;
1360 protocol_binary_response_no_extras response_header
;
1361 protocol_binary_response_decr response
;
1364 size_t len
= arithmetic_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1365 key
, strlen(key
), 1, 9, 0);
1368 for (ii
= 9; ii
>= 0; --ii
) {
1369 safe_send(send
.bytes
, len
, false);
1370 if (cmd
== PROTOCOL_BINARY_CMD_DECREMENT
) {
1371 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1372 validate_response_header(&receive
.response_header
, cmd
,
1373 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1374 assert(ntohll(receive
.response
.message
.body
.value
) == ii
);
1378 /* decr on 0 should not wrap */
1379 safe_send(send
.bytes
, len
, false);
1380 if (cmd
== PROTOCOL_BINARY_CMD_DECREMENT
) {
1381 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1382 validate_response_header(&receive
.response_header
, cmd
,
1383 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1384 assert(ntohll(receive
.response
.message
.body
.value
) == 0);
1392 static enum test_return
test_binary_decr(void) {
1393 return test_binary_decr_impl("test_binary_decr",
1394 PROTOCOL_BINARY_CMD_DECREMENT
);
1397 static enum test_return
test_binary_decrq(void) {
1398 return test_binary_decr_impl("test_binary_decrq",
1399 PROTOCOL_BINARY_CMD_DECREMENTQ
);
1402 static enum test_return
test_binary_version(void) {
1404 protocol_binary_request_no_extras request
;
1405 protocol_binary_response_no_extras response
;
1409 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1410 PROTOCOL_BINARY_CMD_VERSION
,
1413 safe_send(buffer
.bytes
, len
, false);
1414 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1415 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_VERSION
,
1416 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1421 static enum test_return
test_binary_flush_impl(const char *key
, uint8_t cmd
) {
1423 protocol_binary_request_no_extras request
;
1424 protocol_binary_response_no_extras response
;
1428 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1429 PROTOCOL_BINARY_CMD_ADD
,
1430 key
, strlen(key
), NULL
, 0, 0, 0);
1431 safe_send(send
.bytes
, len
, false);
1432 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1433 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1434 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1436 len
= flush_command(send
.bytes
, sizeof(send
.bytes
), cmd
, 2, true);
1437 safe_send(send
.bytes
, len
, false);
1438 if (cmd
== PROTOCOL_BINARY_CMD_FLUSH
) {
1439 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1440 validate_response_header(&receive
.response
, cmd
,
1441 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1444 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_GET
,
1445 key
, strlen(key
), NULL
, 0);
1446 safe_send(send
.bytes
, len
, false);
1447 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1448 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1449 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1452 safe_send(send
.bytes
, len
, false);
1453 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1454 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1455 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1458 for (ii
= 0; ii
< 2; ++ii
) {
1459 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1460 PROTOCOL_BINARY_CMD_ADD
,
1461 key
, strlen(key
), NULL
, 0, 0, 0);
1462 safe_send(send
.bytes
, len
, false);
1463 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1464 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1465 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1467 len
= flush_command(send
.bytes
, sizeof(send
.bytes
), cmd
, 0, ii
== 0);
1468 safe_send(send
.bytes
, len
, false);
1469 if (cmd
== PROTOCOL_BINARY_CMD_FLUSH
) {
1470 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1471 validate_response_header(&receive
.response
, cmd
,
1472 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1475 len
= raw_command(send
.bytes
, sizeof(send
.bytes
),
1476 PROTOCOL_BINARY_CMD_GET
,
1477 key
, strlen(key
), NULL
, 0);
1478 safe_send(send
.bytes
, len
, false);
1479 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1480 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1481 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1487 static enum test_return
test_binary_flush(void) {
1488 return test_binary_flush_impl("test_binary_flush",
1489 PROTOCOL_BINARY_CMD_FLUSH
);
1492 static enum test_return
test_binary_flushq(void) {
1493 return test_binary_flush_impl("test_binary_flushq",
1494 PROTOCOL_BINARY_CMD_FLUSHQ
);
1497 static enum test_return
test_binary_concat_impl(const char *key
, uint8_t cmd
) {
1499 protocol_binary_request_no_extras request
;
1500 protocol_binary_response_no_extras response
;
1503 const char *value
= "world";
1505 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1506 key
, strlen(key
), value
, strlen(value
));
1509 safe_send(send
.bytes
, len
, false);
1510 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1511 validate_response_header(&receive
.response
, cmd
,
1512 PROTOCOL_BINARY_RESPONSE_NOT_STORED
);
1514 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1515 PROTOCOL_BINARY_CMD_ADD
,
1516 key
, strlen(key
), value
, strlen(value
), 0, 0);
1517 safe_send(send
.bytes
, len
, false);
1518 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1519 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1520 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1522 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1523 key
, strlen(key
), value
, strlen(value
));
1524 safe_send(send
.bytes
, len
, false);
1526 if (cmd
== PROTOCOL_BINARY_CMD_APPEND
|| cmd
== PROTOCOL_BINARY_CMD_PREPEND
) {
1527 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1528 validate_response_header(&receive
.response
, cmd
,
1529 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1531 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_NOOP
,
1533 safe_send(send
.bytes
, len
, false);
1534 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1535 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_NOOP
,
1536 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1539 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_GETK
,
1540 key
, strlen(key
), NULL
, 0);
1542 safe_send(send
.bytes
, len
, false);
1543 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1544 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GETK
,
1545 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1547 assert(receive
.response
.message
.header
.response
.keylen
== strlen(key
));
1548 assert(receive
.response
.message
.header
.response
.bodylen
== (strlen(key
) + 2*strlen(value
) + 4));
1550 char *ptr
= receive
.bytes
;
1551 ptr
+= sizeof(receive
.response
);
1554 assert(memcmp(ptr
, key
, strlen(key
)) == 0);
1556 assert(memcmp(ptr
, value
, strlen(value
)) == 0);
1557 ptr
+= strlen(value
);
1558 assert(memcmp(ptr
, value
, strlen(value
)) == 0);
1563 static enum test_return
test_binary_append(void) {
1564 return test_binary_concat_impl("test_binary_append",
1565 PROTOCOL_BINARY_CMD_APPEND
);
1568 static enum test_return
test_binary_prepend(void) {
1569 return test_binary_concat_impl("test_binary_prepend",
1570 PROTOCOL_BINARY_CMD_PREPEND
);
1573 static enum test_return
test_binary_appendq(void) {
1574 return test_binary_concat_impl("test_binary_appendq",
1575 PROTOCOL_BINARY_CMD_APPENDQ
);
1578 static enum test_return
test_binary_prependq(void) {
1579 return test_binary_concat_impl("test_binary_prependq",
1580 PROTOCOL_BINARY_CMD_PREPENDQ
);
1583 static enum test_return
test_binary_stat(void) {
1585 protocol_binary_request_no_extras request
;
1586 protocol_binary_response_no_extras response
;
1590 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1591 PROTOCOL_BINARY_CMD_STAT
,
1594 safe_send(buffer
.bytes
, len
, false);
1596 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1597 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_STAT
,
1598 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1599 } while (buffer
.response
.message
.header
.response
.keylen
!= 0);
1604 static enum test_return
test_binary_illegal(void) {
1606 while (cmd
!= 0x00) {
1608 protocol_binary_request_no_extras request
;
1609 protocol_binary_response_no_extras response
;
1612 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1613 cmd
, NULL
, 0, NULL
, 0);
1614 safe_send(buffer
.bytes
, len
, false);
1615 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1616 validate_response_header(&buffer
.response
, cmd
,
1617 PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
);
1624 volatile bool hickup_thread_running
;
1626 static void *binary_hickup_recv_verification_thread(void *arg
) {
1627 protocol_binary_response_no_extras
*response
= malloc(65*1024);
1628 if (response
!= NULL
) {
1629 while (safe_recv_packet(response
, 65*1024)) {
1630 /* Just validate the packet format */
1631 validate_response_header(response
,
1632 response
->message
.header
.response
.opcode
,
1633 response
->message
.header
.response
.status
);
1637 hickup_thread_running
= false;
1638 allow_closed_read
= false;
1642 static enum test_return
test_binary_pipeline_hickup_chunk(void *buffer
, size_t buffersize
) {
1645 uint64_t value
= 0xfeedfacedeadbeef;
1647 while (hickup_thread_running
&&
1648 offset
+ sizeof(protocol_binary_request_no_extras
) < buffersize
) {
1650 protocol_binary_request_no_extras request
;
1651 char bytes
[65 * 1024];
1653 uint8_t cmd
= (uint8_t)(rand() & 0xff);
1655 size_t keylen
= (rand() % 250) + 1;
1658 case PROTOCOL_BINARY_CMD_ADD
:
1659 case PROTOCOL_BINARY_CMD_ADDQ
:
1660 case PROTOCOL_BINARY_CMD_REPLACE
:
1661 case PROTOCOL_BINARY_CMD_REPLACEQ
:
1662 case PROTOCOL_BINARY_CMD_SET
:
1663 case PROTOCOL_BINARY_CMD_SETQ
:
1664 len
= storage_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1665 key
, keylen
, &value
, sizeof(value
),
1668 case PROTOCOL_BINARY_CMD_APPEND
:
1669 case PROTOCOL_BINARY_CMD_APPENDQ
:
1670 case PROTOCOL_BINARY_CMD_PREPEND
:
1671 case PROTOCOL_BINARY_CMD_PREPENDQ
:
1672 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1673 key
, keylen
, &value
, sizeof(value
));
1675 case PROTOCOL_BINARY_CMD_FLUSH
:
1676 case PROTOCOL_BINARY_CMD_FLUSHQ
:
1677 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1680 case PROTOCOL_BINARY_CMD_NOOP
:
1681 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1684 case PROTOCOL_BINARY_CMD_DELETE
:
1685 case PROTOCOL_BINARY_CMD_DELETEQ
:
1686 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1687 key
, keylen
, NULL
, 0);
1689 case PROTOCOL_BINARY_CMD_DECREMENT
:
1690 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
1691 case PROTOCOL_BINARY_CMD_INCREMENT
:
1692 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
1693 len
= arithmetic_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1694 key
, keylen
, 1, 0, 0);
1696 case PROTOCOL_BINARY_CMD_VERSION
:
1697 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1698 PROTOCOL_BINARY_CMD_VERSION
,
1701 case PROTOCOL_BINARY_CMD_GET
:
1702 case PROTOCOL_BINARY_CMD_GETK
:
1703 case PROTOCOL_BINARY_CMD_GETKQ
:
1704 case PROTOCOL_BINARY_CMD_GETQ
:
1705 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1706 key
, keylen
, NULL
, 0);
1709 case PROTOCOL_BINARY_CMD_TOUCH
:
1710 case PROTOCOL_BINARY_CMD_GAT
:
1711 case PROTOCOL_BINARY_CMD_GATQ
:
1712 case PROTOCOL_BINARY_CMD_GATK
:
1713 case PROTOCOL_BINARY_CMD_GATKQ
:
1714 len
= touch_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1718 case PROTOCOL_BINARY_CMD_STAT
:
1719 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1720 PROTOCOL_BINARY_CMD_STAT
,
1724 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
1725 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
1726 case PROTOCOL_BINARY_CMD_SASL_STEP
:
1728 case PROTOCOL_BINARY_CMD_QUITQ
:
1729 case PROTOCOL_BINARY_CMD_QUIT
:
1730 /* I don't want to pass on the quit commands ;-) */
1734 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1735 cmd
, NULL
, 0, NULL
, 0);
1738 if ((len
+ offset
) < buffersize
) {
1739 memcpy(((char*)buffer
) + offset
, command
.bytes
, len
);
1745 safe_send(buffer
, offset
, true);
1750 static enum test_return
test_binary_pipeline_hickup(void)
1752 size_t buffersize
= 65 * 1024;
1753 void *buffer
= malloc(buffersize
);
1758 allow_closed_read
= true;
1759 hickup_thread_running
= true;
1760 if ((ret
= pthread_create(&tid
, NULL
,
1761 binary_hickup_recv_verification_thread
, NULL
)) != 0) {
1762 fprintf(stderr
, "Can't create thread: %s\n", strerror(ret
));
1766 /* Allow the thread to start */
1769 srand((int)time(NULL
));
1770 for (ii
= 0; ii
< 2; ++ii
) {
1771 test_binary_pipeline_hickup_chunk(buffer
, buffersize
);
1774 /* send quitq to shut down the read thread ;-) */
1775 size_t len
= raw_command(buffer
, buffersize
, PROTOCOL_BINARY_CMD_QUITQ
,
1777 safe_send(buffer
, len
, false);
1779 pthread_join(tid
, NULL
);
1785 static enum test_return
test_issue_101(void) {
1787 enum test_return ret
= TEST_PASS
;
1792 if (getenv("SKIP_TEST_101") != NULL
) {
1796 const char *command
= "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
1797 size_t cmdlen
= strlen(command
);
1799 server_pid
= start_server(&port
, false, 1000);
1801 for (ii
= 0; ii
< max
; ++ii
) {
1802 fds
[ii
] = connect_server("127.0.0.1", port
, true);
1803 assert(fds
[ii
] > 0);
1806 /* Send command on the connection until it blocks */
1807 for (ii
= 0; ii
< max
; ++ii
) {
1810 ssize_t err
= write(fds
[ii
], command
, cmdlen
);
1828 if (child
== (pid_t
)-1) {
1830 } else if (child
> 0) {
1833 while ((c
= waitpid(child
, &stat
, 0)) == (pid_t
)-1 && errno
== EINTR
);
1837 sock
= connect_server("127.0.0.1", port
, false);
1838 ret
= test_binary_noop();
1844 /* close all connections */
1845 for (ii
= 0; ii
< max
; ++ii
) {
1849 assert(kill(server_pid
, SIGTERM
) == 0);
1854 typedef enum test_return (*TEST_FUNC
)(void);
1856 const char *description
;
1860 struct testcase testcases
[] = {
1861 { "cache_create", cache_create_test
},
1862 { "cache_constructor", cache_constructor_test
},
1863 { "cache_constructor_fail", cache_fail_constructor_test
},
1864 { "cache_destructor", cache_destructor_test
},
1865 { "cache_reuse", cache_reuse_test
},
1866 { "cache_redzone", cache_redzone_test
},
1867 { "issue_161", test_issue_161
},
1868 { "strtol", test_safe_strtol
},
1869 { "strtoll", test_safe_strtoll
},
1870 { "strtoul", test_safe_strtoul
},
1871 { "strtoull", test_safe_strtoull
},
1872 { "issue_44", test_issue_44
},
1873 { "vperror", test_vperror
},
1874 { "issue_101", test_issue_101
},
1875 /* The following tests all run towards the same server */
1876 { "start_server", start_memcached_server
},
1877 { "issue_92", test_issue_92
},
1878 { "issue_102", test_issue_102
},
1879 { "binary_noop", test_binary_noop
},
1880 { "binary_quit", test_binary_quit
},
1881 { "binary_quitq", test_binary_quitq
},
1882 { "binary_set", test_binary_set
},
1883 { "binary_setq", test_binary_setq
},
1884 { "binary_add", test_binary_add
},
1885 { "binary_addq", test_binary_addq
},
1886 { "binary_replace", test_binary_replace
},
1887 { "binary_replaceq", test_binary_replaceq
},
1888 { "binary_delete", test_binary_delete
},
1889 { "binary_deleteq", test_binary_deleteq
},
1890 { "binary_get", test_binary_get
},
1891 { "binary_getq", test_binary_getq
},
1892 { "binary_getk", test_binary_getk
},
1893 { "binary_getkq", test_binary_getkq
},
1894 { "binary_incr", test_binary_incr
},
1895 { "binary_incrq", test_binary_incrq
},
1896 { "binary_decr", test_binary_decr
},
1897 { "binary_decrq", test_binary_decrq
},
1898 { "binary_version", test_binary_version
},
1899 { "binary_flush", test_binary_flush
},
1900 { "binary_flushq", test_binary_flushq
},
1901 { "binary_append", test_binary_append
},
1902 { "binary_appendq", test_binary_appendq
},
1903 { "binary_prepend", test_binary_prepend
},
1904 { "binary_prependq", test_binary_prependq
},
1905 { "binary_stat", test_binary_stat
},
1906 { "binary_illegal", test_binary_illegal
},
1907 { "binary_pipeline_hickup", test_binary_pipeline_hickup
},
1908 { "stop_server", stop_memcached_server
},
1912 int main(int argc
, char **argv
)
1915 int ii
= 0, num_cases
= 0;
1917 for (num_cases
= 0; testcases
[num_cases
].description
; num_cases
++) {
1921 printf("1..%d\n", num_cases
);
1923 for (ii
= 0; testcases
[ii
].description
!= NULL
; ++ii
) {
1926 /* the test program shouldn't run longer than 10 minutes... */
1929 enum test_return ret
= testcases
[ii
].function();
1930 if (ret
== TEST_SKIP
) {
1931 fprintf(stdout
, "ok # SKIP %d - %s\n", ii
+ 1, testcases
[ii
].description
);
1932 } else if (ret
== TEST_PASS
) {
1933 fprintf(stdout
, "ok %d - %s\n", ii
+ 1, testcases
[ii
].description
);
1935 fprintf(stdout
, "not ok %d - %s\n", ii
+ 1, testcases
[ii
].description
);