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, but I'll take the chance....
387 while (access(pid_file
, F_OK
) == -1) {
391 fp
= fopen(pid_file
, "r");
393 fprintf(stderr
, "Failed to open pid file: %s\n",
397 assert(fgets(buffer
, sizeof(buffer
), fp
) != NULL
);
401 assert(safe_strtol(buffer
, &val
));
408 static enum test_return
test_issue_44(void) {
410 pid_t pid
= start_server(&port
, true, 15);
411 assert(kill(pid
, SIGHUP
) == 0);
413 assert(kill(pid
, SIGTERM
) == 0);
418 static struct addrinfo
*lookuphost(const char *hostname
, in_port_t port
)
420 struct addrinfo
*ai
= 0;
421 struct addrinfo hints
= { .ai_family
= AF_UNSPEC
,
422 .ai_protocol
= IPPROTO_TCP
,
423 .ai_socktype
= SOCK_STREAM
};
424 char service
[NI_MAXSERV
];
427 (void)snprintf(service
, NI_MAXSERV
, "%d", port
);
428 if ((error
= getaddrinfo(hostname
, service
, &hints
, &ai
)) != 0) {
429 if (error
!= EAI_SYSTEM
) {
430 fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(error
));
432 perror("getaddrinfo()");
439 static int connect_server(const char *hostname
, in_port_t port
, bool nonblock
)
441 struct addrinfo
*ai
= lookuphost(hostname
, port
);
444 if ((sock
= socket(ai
->ai_family
, ai
->ai_socktype
,
445 ai
->ai_protocol
)) != -1) {
446 if (connect(sock
, ai
->ai_addr
, ai
->ai_addrlen
) == -1) {
447 fprintf(stderr
, "Failed to connect socket: %s\n",
451 } else if (nonblock
) {
452 int flags
= fcntl(sock
, F_GETFL
, 0);
453 if (flags
< 0 || fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) < 0) {
454 fprintf(stderr
, "Failed to enable nonblocking mode: %s\n",
461 fprintf(stderr
, "Failed to create socket: %s\n", strerror(errno
));
469 static enum test_return
test_vperror(void) {
471 int oldstderr
= dup(STDERR_FILENO
);
472 char tmpl
[sizeof(TMP_TEMPLATE
)+1];
473 strncpy(tmpl
, TMP_TEMPLATE
, sizeof(TMP_TEMPLATE
)+1);
475 int newfile
= mkstemp(tmpl
);
477 rv
= dup2(newfile
, STDERR_FILENO
);
478 assert(rv
== STDERR_FILENO
);
483 vperror("Old McDonald had a farm. %s", "EI EIO");
486 rv
= dup2(oldstderr
, STDERR_FILENO
);
487 assert(rv
== STDERR_FILENO
);
490 /* Go read the file */
491 char buf
[80] = { 0 };
492 FILE *efile
= fopen(tmpl
, "r");
494 char *prv
= fgets(buf
, sizeof(buf
), efile
);
500 char expected
[80] = { 0 };
501 snprintf(expected
, sizeof(expected
),
502 "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO
));
507 "\nGot: ``%s''\n", expected, buf);
510 return strcmp(expected
, buf
) == 0 ? TEST_PASS
: TEST_FAIL
;
513 static void send_ascii_command(const char *buf
) {
515 const char* ptr
= buf
;
516 size_t len
= strlen(buf
);
519 ssize_t nw
= write(sock
, ptr
+ offset
, len
- offset
);
521 if (errno
!= EINTR
) {
522 fprintf(stderr
, "Failed to write: %s\n", strerror(errno
));
528 } while (offset
< len
);
532 * This is a dead slow single byte read, but it should only read out
533 * _one_ response and I don't have an input buffer... The current
534 * implementation only supports single-line responses, so if you want to use
535 * it for get commands you need to implement that first ;-)
537 static void read_ascii_response(char *buffer
, size_t size
) {
539 bool need_more
= true;
541 ssize_t nr
= read(sock
, buffer
+ offset
, 1);
543 if (errno
!= EINTR
) {
544 fprintf(stderr
, "Failed to read: %s\n", strerror(errno
));
549 if (buffer
[offset
] == '\n') {
551 buffer
[offset
+ 1] = '\0';
554 assert(offset
+ 1 < size
);
559 static enum test_return
test_issue_92(void) {
563 sock
= connect_server("127.0.0.1", port
, false);
565 send_ascii_command("stats cachedump 1 0 0\r\n");
566 read_ascii_response(buffer
, sizeof(buffer
));
567 assert(strncmp(buffer
, "END", strlen("END")) == 0);
569 send_ascii_command("stats cachedump 200 0 0\r\n");
570 read_ascii_response(buffer
, sizeof(buffer
));
571 assert(strncmp(buffer
, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
574 sock
= connect_server("127.0.0.1", port
, false);
578 static enum test_return
test_issue_102(void) {
580 memset(buffer
, ' ', sizeof(buffer
));
581 buffer
[sizeof(buffer
) - 1] = '\0';
584 sock
= connect_server("127.0.0.1", port
, false);
586 send_ascii_command(buffer
);
587 /* verify that the server closed the connection */
588 assert(read(sock
, buffer
, sizeof(buffer
)) == 0);
590 sock
= connect_server("127.0.0.1", port
, false);
592 snprintf(buffer
, sizeof(buffer
), "gets ");
594 while (offset
< 4000) {
595 offset
+= snprintf(buffer
+ offset
, sizeof(buffer
) - offset
,
596 "%010u ", (unsigned int)offset
);
599 send_ascii_command(buffer
);
602 send_ascii_command("\r\n");
604 read_ascii_response(rsp
, sizeof(rsp
));
605 assert(strncmp(rsp
, "END", strlen("END")) == 0);
607 send_ascii_command(buffer
);
609 send_ascii_command("\r\n");
610 read_ascii_response(rsp
, sizeof(rsp
));
611 assert(strncmp(rsp
, "END", strlen("END")) == 0);
613 memset(buffer
, ' ', sizeof(buffer
));
614 int len
= snprintf(buffer
+ 101, sizeof(buffer
) - 101, "gets foo");
615 buffer
[101 + len
] = ' ';
616 buffer
[sizeof(buffer
) - 1] = '\0';
617 send_ascii_command(buffer
);
618 /* verify that the server closed the connection */
619 assert(read(sock
, buffer
, sizeof(buffer
)) == 0);
622 sock
= connect_server("127.0.0.1", port
, false);
627 static enum test_return
start_memcached_server(void) {
628 server_pid
= start_server(&port
, false, 600);
629 sock
= connect_server("127.0.0.1", port
, false);
633 static enum test_return
stop_memcached_server(void) {
635 assert(kill(server_pid
, SIGTERM
) == 0);
639 static void safe_send(const void* buf
, size_t len
, bool hickup
)
642 const char* ptr
= buf
;
645 assert(val
== (uint8_t)0x80);
646 fprintf(stderr
, "About to send %lu bytes:", (unsigned long)len
);
647 for (int ii
= 0; ii
< len
; ++ii
) {
649 fprintf(stderr
, "\n ");
652 fprintf(stderr
, " 0x%02x", val
);
654 fprintf(stderr
, "\n");
659 size_t num_bytes
= len
- offset
;
661 if (num_bytes
> 1024) {
662 num_bytes
= (rand() % 1023) + 1;
666 ssize_t nw
= write(sock
, ptr
+ offset
, num_bytes
);
668 if (errno
!= EINTR
) {
669 fprintf(stderr
, "Failed to write: %s\n", strerror(errno
));
678 } while (offset
< len
);
681 static bool safe_recv(void *buf
, size_t len
) {
687 ssize_t nr
= read(sock
, ((char*)buf
) + offset
, len
- offset
);
689 if (errno
!= EINTR
) {
690 fprintf(stderr
, "Failed to read: %s\n", strerror(errno
));
694 if (nr
== 0 && allow_closed_read
) {
700 } while (offset
< len
);
705 static bool safe_recv_packet(void *buf
, size_t size
) {
706 protocol_binary_response_no_extras
*response
= buf
;
707 assert(size
> sizeof(*response
));
708 if (!safe_recv(response
, sizeof(*response
))) {
711 response
->message
.header
.response
.keylen
= ntohs(response
->message
.header
.response
.keylen
);
712 response
->message
.header
.response
.status
= ntohs(response
->message
.header
.response
.status
);
713 response
->message
.header
.response
.bodylen
= ntohl(response
->message
.header
.response
.bodylen
);
715 size_t len
= sizeof(*response
);
719 if (!safe_recv(ptr
, response
->message
.header
.response
.bodylen
)) {
726 len
+= response
->message
.header
.response
.bodylen
;
728 assert(val
== (uint8_t)0x81);
729 fprintf(stderr
, "Received %lu bytes:", (unsigned long)len
);
730 for (int ii
= 0; ii
< len
; ++ii
) {
732 fprintf(stderr
, "\n ");
735 fprintf(stderr
, " 0x%02x", val
);
737 fprintf(stderr
, "\n");
742 static off_t
storage_command(char*buf
,
751 /* all of the storage commands use the same command layout */
752 protocol_binary_request_set
*request
= (void*)buf
;
753 assert(bufsz
> sizeof(*request
) + keylen
+ dtalen
);
755 memset(request
, 0, sizeof(*request
));
756 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
757 request
->message
.header
.request
.opcode
= cmd
;
758 request
->message
.header
.request
.keylen
= htons(keylen
);
759 request
->message
.header
.request
.extlen
= 8;
760 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 8 + dtalen
);
761 request
->message
.header
.request
.opaque
= 0xdeadbeef;
762 request
->message
.body
.flags
= flags
;
763 request
->message
.body
.expiration
= exp
;
765 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 8;
767 memcpy(buf
+ key_offset
, key
, keylen
);
769 memcpy(buf
+ key_offset
+ keylen
, dta
, dtalen
);
772 return key_offset
+ keylen
+ dtalen
;
775 static off_t
raw_command(char* buf
,
782 /* all of the storage commands use the same command layout */
783 protocol_binary_request_no_extras
*request
= (void*)buf
;
784 assert(bufsz
> sizeof(*request
) + keylen
+ dtalen
);
786 memset(request
, 0, sizeof(*request
));
787 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
788 request
->message
.header
.request
.opcode
= cmd
;
789 request
->message
.header
.request
.keylen
= htons(keylen
);
790 request
->message
.header
.request
.bodylen
= htonl(keylen
+ dtalen
);
791 request
->message
.header
.request
.opaque
= 0xdeadbeef;
793 off_t key_offset
= sizeof(protocol_binary_request_no_extras
);
796 memcpy(buf
+ key_offset
, key
, keylen
);
799 memcpy(buf
+ key_offset
+ keylen
, dta
, dtalen
);
802 return sizeof(*request
) + keylen
+ dtalen
;
805 static off_t
flush_command(char* buf
, size_t bufsz
, uint8_t cmd
, uint32_t exptime
, bool use_extra
) {
806 protocol_binary_request_flush
*request
= (void*)buf
;
807 assert(bufsz
> sizeof(*request
));
809 memset(request
, 0, sizeof(*request
));
810 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
811 request
->message
.header
.request
.opcode
= cmd
;
813 off_t size
= sizeof(protocol_binary_request_no_extras
);
815 request
->message
.header
.request
.extlen
= 4;
816 request
->message
.body
.expiration
= htonl(exptime
);
817 request
->message
.header
.request
.bodylen
= htonl(4);
821 request
->message
.header
.request
.opaque
= 0xdeadbeef;
827 static off_t
touch_command(char* buf
,
833 protocol_binary_request_touch
*request
= (void*)buf
;
834 assert(bufsz
> sizeof(*request
));
836 memset(request
, 0, sizeof(*request
));
837 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
838 request
->message
.header
.request
.opcode
= cmd
;
840 request
->message
.header
.request
.keylen
= htons(keylen
);
841 request
->message
.header
.request
.extlen
= 4;
842 request
->message
.body
.expiration
= htonl(exptime
);
843 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 4);
845 request
->message
.header
.request
.opaque
= 0xdeadbeef;
847 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 4;
849 memcpy(buf
+ key_offset
, key
, keylen
);
850 return sizeof(protocol_binary_request_no_extras
) + 4 + keylen
;
853 static off_t
arithmetic_command(char* buf
,
861 protocol_binary_request_incr
*request
= (void*)buf
;
862 assert(bufsz
> sizeof(*request
) + keylen
);
864 memset(request
, 0, sizeof(*request
));
865 request
->message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
866 request
->message
.header
.request
.opcode
= cmd
;
867 request
->message
.header
.request
.keylen
= htons(keylen
);
868 request
->message
.header
.request
.extlen
= 20;
869 request
->message
.header
.request
.bodylen
= htonl(keylen
+ 20);
870 request
->message
.header
.request
.opaque
= 0xdeadbeef;
871 request
->message
.body
.delta
= htonll(delta
);
872 request
->message
.body
.initial
= htonll(initial
);
873 request
->message
.body
.expiration
= htonl(exp
);
875 off_t key_offset
= sizeof(protocol_binary_request_no_extras
) + 20;
877 memcpy(buf
+ key_offset
, key
, keylen
);
878 return key_offset
+ keylen
;
881 static void validate_response_header(protocol_binary_response_no_extras
*response
,
882 uint8_t cmd
, uint16_t status
)
884 assert(response
->message
.header
.response
.magic
== PROTOCOL_BINARY_RES
);
885 assert(response
->message
.header
.response
.opcode
== cmd
);
886 assert(response
->message
.header
.response
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
887 assert(response
->message
.header
.response
.status
== status
);
888 assert(response
->message
.header
.response
.opaque
== 0xdeadbeef);
890 if (status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
892 case PROTOCOL_BINARY_CMD_ADDQ
:
893 case PROTOCOL_BINARY_CMD_APPENDQ
:
894 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
895 case PROTOCOL_BINARY_CMD_DELETEQ
:
896 case PROTOCOL_BINARY_CMD_FLUSHQ
:
897 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
898 case PROTOCOL_BINARY_CMD_PREPENDQ
:
899 case PROTOCOL_BINARY_CMD_QUITQ
:
900 case PROTOCOL_BINARY_CMD_REPLACEQ
:
901 case PROTOCOL_BINARY_CMD_SETQ
:
902 assert("Quiet command shouldn't return on success" == NULL
);
908 case PROTOCOL_BINARY_CMD_ADD
:
909 case PROTOCOL_BINARY_CMD_REPLACE
:
910 case PROTOCOL_BINARY_CMD_SET
:
911 case PROTOCOL_BINARY_CMD_APPEND
:
912 case PROTOCOL_BINARY_CMD_PREPEND
:
913 assert(response
->message
.header
.response
.keylen
== 0);
914 assert(response
->message
.header
.response
.extlen
== 0);
915 assert(response
->message
.header
.response
.bodylen
== 0);
916 assert(response
->message
.header
.response
.cas
!= 0);
918 case PROTOCOL_BINARY_CMD_FLUSH
:
919 case PROTOCOL_BINARY_CMD_NOOP
:
920 case PROTOCOL_BINARY_CMD_QUIT
:
921 case PROTOCOL_BINARY_CMD_DELETE
:
922 assert(response
->message
.header
.response
.keylen
== 0);
923 assert(response
->message
.header
.response
.extlen
== 0);
924 assert(response
->message
.header
.response
.bodylen
== 0);
925 assert(response
->message
.header
.response
.cas
== 0);
928 case PROTOCOL_BINARY_CMD_DECREMENT
:
929 case PROTOCOL_BINARY_CMD_INCREMENT
:
930 assert(response
->message
.header
.response
.keylen
== 0);
931 assert(response
->message
.header
.response
.extlen
== 0);
932 assert(response
->message
.header
.response
.bodylen
== 8);
933 assert(response
->message
.header
.response
.cas
!= 0);
936 case PROTOCOL_BINARY_CMD_STAT
:
937 assert(response
->message
.header
.response
.extlen
== 0);
938 /* key and value exists in all packets except in the terminating */
939 assert(response
->message
.header
.response
.cas
== 0);
942 case PROTOCOL_BINARY_CMD_VERSION
:
943 assert(response
->message
.header
.response
.keylen
== 0);
944 assert(response
->message
.header
.response
.extlen
== 0);
945 assert(response
->message
.header
.response
.bodylen
!= 0);
946 assert(response
->message
.header
.response
.cas
== 0);
949 case PROTOCOL_BINARY_CMD_GET
:
950 case PROTOCOL_BINARY_CMD_GETQ
:
951 assert(response
->message
.header
.response
.keylen
== 0);
952 assert(response
->message
.header
.response
.extlen
== 4);
953 assert(response
->message
.header
.response
.cas
!= 0);
956 case PROTOCOL_BINARY_CMD_GETK
:
957 case PROTOCOL_BINARY_CMD_GETKQ
:
958 assert(response
->message
.header
.response
.keylen
!= 0);
959 assert(response
->message
.header
.response
.extlen
== 4);
960 assert(response
->message
.header
.response
.cas
!= 0);
964 /* Undefined command code */
968 assert(response
->message
.header
.response
.cas
== 0);
969 assert(response
->message
.header
.response
.extlen
== 0);
970 if (cmd
!= PROTOCOL_BINARY_CMD_GETK
&&
971 cmd
!= PROTOCOL_BINARY_CMD_GATK
) {
972 assert(response
->message
.header
.response
.keylen
== 0);
977 static enum test_return
test_binary_noop(void) {
979 protocol_binary_request_no_extras request
;
980 protocol_binary_response_no_extras response
;
984 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
985 PROTOCOL_BINARY_CMD_NOOP
,
988 safe_send(buffer
.bytes
, len
, false);
989 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
990 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_NOOP
,
991 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
996 static enum test_return
test_binary_quit_impl(uint8_t cmd
) {
998 protocol_binary_request_no_extras request
;
999 protocol_binary_response_no_extras response
;
1002 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1003 cmd
, NULL
, 0, NULL
, 0);
1005 safe_send(buffer
.bytes
, len
, false);
1006 if (cmd
== PROTOCOL_BINARY_CMD_QUIT
) {
1007 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1008 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_QUIT
,
1009 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1012 /* Socket should be closed now, read should return 0 */
1013 assert(read(sock
, buffer
.bytes
, sizeof(buffer
.bytes
)) == 0);
1015 sock
= connect_server("127.0.0.1", port
, false);
1020 static enum test_return
test_binary_quit(void) {
1021 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT
);
1024 static enum test_return
test_binary_quitq(void) {
1025 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ
);
1028 static enum test_return
test_binary_set_impl(const char *key
, uint8_t cmd
) {
1030 protocol_binary_request_no_extras request
;
1031 protocol_binary_response_no_extras response
;
1034 uint64_t value
= 0xdeadbeefdeadcafe;
1035 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1036 key
, strlen(key
), &value
, sizeof(value
),
1039 /* Set should work over and over again */
1041 for (ii
= 0; ii
< 10; ++ii
) {
1042 safe_send(send
.bytes
, len
, false);
1043 if (cmd
== PROTOCOL_BINARY_CMD_SET
) {
1044 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1045 validate_response_header(&receive
.response
, cmd
,
1046 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1050 if (cmd
== PROTOCOL_BINARY_CMD_SETQ
) {
1051 return test_binary_noop();
1054 send
.request
.message
.header
.request
.cas
= receive
.response
.message
.header
.response
.cas
;
1055 safe_send(send
.bytes
, len
, false);
1056 if (cmd
== PROTOCOL_BINARY_CMD_SET
) {
1057 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1058 validate_response_header(&receive
.response
, cmd
,
1059 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1060 assert(receive
.response
.message
.header
.response
.cas
!= send
.request
.message
.header
.request
.cas
);
1062 return test_binary_noop();
1068 static enum test_return
test_binary_set(void) {
1069 return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET
);
1072 static enum test_return
test_binary_setq(void) {
1073 return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ
);
1077 static enum test_return
test_binary_add_impl(const char *key
, uint8_t cmd
) {
1078 uint64_t value
= 0xdeadbeefdeadcafe;
1080 protocol_binary_request_no_extras request
;
1081 protocol_binary_response_no_extras response
;
1084 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
, key
,
1085 strlen(key
), &value
, sizeof(value
),
1088 /* Add should only work the first time */
1090 for (ii
= 0; ii
< 10; ++ii
) {
1091 safe_send(send
.bytes
, len
, false);
1093 if (cmd
== PROTOCOL_BINARY_CMD_ADD
) {
1094 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1095 validate_response_header(&receive
.response
, cmd
,
1096 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1099 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1100 validate_response_header(&receive
.response
, cmd
,
1101 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
1108 static enum test_return
test_binary_add(void) {
1109 return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD
);
1112 static enum test_return
test_binary_addq(void) {
1113 return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ
);
1116 static enum test_return
test_binary_replace_impl(const char* key
, uint8_t cmd
) {
1117 uint64_t value
= 0xdeadbeefdeadcafe;
1119 protocol_binary_request_no_extras request
;
1120 protocol_binary_response_no_extras response
;
1123 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1124 key
, strlen(key
), &value
, sizeof(value
),
1126 safe_send(send
.bytes
, len
, false);
1127 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1128 validate_response_header(&receive
.response
, cmd
,
1129 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1130 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1131 PROTOCOL_BINARY_CMD_ADD
,
1132 key
, strlen(key
), &value
, sizeof(value
), 0, 0);
1133 safe_send(send
.bytes
, len
, false);
1134 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1135 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1136 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1138 len
= storage_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1139 key
, strlen(key
), &value
, sizeof(value
), 0, 0);
1141 for (ii
= 0; ii
< 10; ++ii
) {
1142 safe_send(send
.bytes
, len
, false);
1143 if (cmd
== PROTOCOL_BINARY_CMD_REPLACE
) {
1144 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1145 validate_response_header(&receive
.response
,
1146 PROTOCOL_BINARY_CMD_REPLACE
,
1147 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1151 if (cmd
== PROTOCOL_BINARY_CMD_REPLACEQ
) {
1158 static enum test_return
test_binary_replace(void) {
1159 return test_binary_replace_impl("test_binary_replace",
1160 PROTOCOL_BINARY_CMD_REPLACE
);
1163 static enum test_return
test_binary_replaceq(void) {
1164 return test_binary_replace_impl("test_binary_replaceq",
1165 PROTOCOL_BINARY_CMD_REPLACEQ
);
1168 static enum test_return
test_binary_delete_impl(const char *key
, uint8_t cmd
) {
1170 protocol_binary_request_no_extras request
;
1171 protocol_binary_response_no_extras response
;
1174 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1175 key
, strlen(key
), NULL
, 0);
1177 safe_send(send
.bytes
, len
, false);
1178 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1179 validate_response_header(&receive
.response
, cmd
,
1180 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1181 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1182 PROTOCOL_BINARY_CMD_ADD
,
1183 key
, strlen(key
), NULL
, 0, 0, 0);
1184 safe_send(send
.bytes
, len
, false);
1185 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1186 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1187 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1189 len
= raw_command(send
.bytes
, sizeof(send
.bytes
),
1190 cmd
, key
, strlen(key
), NULL
, 0);
1191 safe_send(send
.bytes
, len
, false);
1193 if (cmd
== PROTOCOL_BINARY_CMD_DELETE
) {
1194 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1195 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_DELETE
,
1196 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1199 safe_send(send
.bytes
, len
, false);
1200 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1201 validate_response_header(&receive
.response
, cmd
,
1202 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1207 static enum test_return
test_binary_delete(void) {
1208 return test_binary_delete_impl("test_binary_delete",
1209 PROTOCOL_BINARY_CMD_DELETE
);
1212 static enum test_return
test_binary_deleteq(void) {
1213 return test_binary_delete_impl("test_binary_deleteq",
1214 PROTOCOL_BINARY_CMD_DELETEQ
);
1217 static enum test_return
test_binary_get_impl(const char *key
, uint8_t cmd
) {
1219 protocol_binary_request_no_extras request
;
1220 protocol_binary_response_no_extras response
;
1223 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1224 key
, strlen(key
), NULL
, 0);
1226 safe_send(send
.bytes
, len
, false);
1227 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1228 validate_response_header(&receive
.response
, cmd
,
1229 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1231 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1232 PROTOCOL_BINARY_CMD_ADD
,
1233 key
, strlen(key
), NULL
, 0,
1235 safe_send(send
.bytes
, len
, false);
1236 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1237 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1238 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1240 /* run a little pipeline test ;-) */
1243 for (ii
= 0; ii
< 10; ++ii
) {
1245 protocol_binary_request_no_extras request
;
1248 size_t l
= raw_command(temp
.bytes
, sizeof(temp
.bytes
),
1249 cmd
, key
, strlen(key
), NULL
, 0);
1250 memcpy(send
.bytes
+ len
, temp
.bytes
, l
);
1254 safe_send(send
.bytes
, len
, false);
1255 for (ii
= 0; ii
< 10; ++ii
) {
1256 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1257 validate_response_header(&receive
.response
, cmd
,
1258 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1264 static enum test_return
test_binary_get(void) {
1265 return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET
);
1268 static enum test_return
test_binary_getk(void) {
1269 return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK
);
1272 static enum test_return
test_binary_getq_impl(const char *key
, uint8_t cmd
) {
1273 const char *missing
= "test_binary_getq_missing";
1275 protocol_binary_request_no_extras request
;
1276 protocol_binary_response_no_extras response
;
1278 } send
, temp
, receive
;
1279 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1280 PROTOCOL_BINARY_CMD_ADD
,
1281 key
, strlen(key
), NULL
, 0,
1283 size_t len2
= raw_command(temp
.bytes
, sizeof(temp
.bytes
), cmd
,
1284 missing
, strlen(missing
), NULL
, 0);
1285 /* I need to change the first opaque so that I can separate the two
1287 temp
.request
.message
.header
.request
.opaque
= 0xfeedface;
1288 memcpy(send
.bytes
+ len
, temp
.bytes
, len2
);
1291 len2
= raw_command(temp
.bytes
, sizeof(temp
.bytes
), cmd
,
1292 key
, strlen(key
), NULL
, 0);
1293 memcpy(send
.bytes
+ len
, temp
.bytes
, len2
);
1296 safe_send(send
.bytes
, len
, false);
1297 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1298 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1299 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1300 /* The first GETQ shouldn't return anything */
1301 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1302 validate_response_header(&receive
.response
, cmd
,
1303 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1308 static enum test_return
test_binary_getq(void) {
1309 return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ
);
1312 static enum test_return
test_binary_getkq(void) {
1313 return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ
);
1316 static enum test_return
test_binary_incr_impl(const char* key
, uint8_t cmd
) {
1318 protocol_binary_request_no_extras request
;
1319 protocol_binary_response_no_extras response_header
;
1320 protocol_binary_response_incr response
;
1323 size_t len
= arithmetic_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1324 key
, strlen(key
), 1, 0, 0);
1327 for (ii
= 0; ii
< 10; ++ii
) {
1328 safe_send(send
.bytes
, len
, false);
1329 if (cmd
== PROTOCOL_BINARY_CMD_INCREMENT
) {
1330 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1331 validate_response_header(&receive
.response_header
, cmd
,
1332 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1333 assert(ntohll(receive
.response
.message
.body
.value
) == ii
);
1337 if (cmd
== PROTOCOL_BINARY_CMD_INCREMENTQ
) {
1343 static enum test_return
test_binary_incr(void) {
1344 return test_binary_incr_impl("test_binary_incr",
1345 PROTOCOL_BINARY_CMD_INCREMENT
);
1348 static enum test_return
test_binary_incrq(void) {
1349 return test_binary_incr_impl("test_binary_incrq",
1350 PROTOCOL_BINARY_CMD_INCREMENTQ
);
1353 static enum test_return
test_binary_decr_impl(const char* key
, uint8_t cmd
) {
1355 protocol_binary_request_no_extras request
;
1356 protocol_binary_response_no_extras response_header
;
1357 protocol_binary_response_decr response
;
1360 size_t len
= arithmetic_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1361 key
, strlen(key
), 1, 9, 0);
1364 for (ii
= 9; ii
>= 0; --ii
) {
1365 safe_send(send
.bytes
, len
, false);
1366 if (cmd
== PROTOCOL_BINARY_CMD_DECREMENT
) {
1367 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1368 validate_response_header(&receive
.response_header
, cmd
,
1369 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1370 assert(ntohll(receive
.response
.message
.body
.value
) == ii
);
1374 /* decr on 0 should not wrap */
1375 safe_send(send
.bytes
, len
, false);
1376 if (cmd
== PROTOCOL_BINARY_CMD_DECREMENT
) {
1377 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1378 validate_response_header(&receive
.response_header
, cmd
,
1379 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1380 assert(ntohll(receive
.response
.message
.body
.value
) == 0);
1388 static enum test_return
test_binary_decr(void) {
1389 return test_binary_decr_impl("test_binary_decr",
1390 PROTOCOL_BINARY_CMD_DECREMENT
);
1393 static enum test_return
test_binary_decrq(void) {
1394 return test_binary_decr_impl("test_binary_decrq",
1395 PROTOCOL_BINARY_CMD_DECREMENTQ
);
1398 static enum test_return
test_binary_version(void) {
1400 protocol_binary_request_no_extras request
;
1401 protocol_binary_response_no_extras response
;
1405 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1406 PROTOCOL_BINARY_CMD_VERSION
,
1409 safe_send(buffer
.bytes
, len
, false);
1410 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1411 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_VERSION
,
1412 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1417 static enum test_return
test_binary_flush_impl(const char *key
, uint8_t cmd
) {
1419 protocol_binary_request_no_extras request
;
1420 protocol_binary_response_no_extras response
;
1424 size_t len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1425 PROTOCOL_BINARY_CMD_ADD
,
1426 key
, strlen(key
), NULL
, 0, 0, 0);
1427 safe_send(send
.bytes
, len
, false);
1428 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1429 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1430 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1432 len
= flush_command(send
.bytes
, sizeof(send
.bytes
), cmd
, 2, true);
1433 safe_send(send
.bytes
, len
, false);
1434 if (cmd
== PROTOCOL_BINARY_CMD_FLUSH
) {
1435 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1436 validate_response_header(&receive
.response
, cmd
,
1437 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1440 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_GET
,
1441 key
, strlen(key
), NULL
, 0);
1442 safe_send(send
.bytes
, len
, false);
1443 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1444 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1445 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1448 safe_send(send
.bytes
, len
, false);
1449 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1450 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1451 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1454 for (ii
= 0; ii
< 2; ++ii
) {
1455 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1456 PROTOCOL_BINARY_CMD_ADD
,
1457 key
, strlen(key
), NULL
, 0, 0, 0);
1458 safe_send(send
.bytes
, len
, false);
1459 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1460 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1461 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1463 len
= flush_command(send
.bytes
, sizeof(send
.bytes
), cmd
, 0, ii
== 0);
1464 safe_send(send
.bytes
, len
, false);
1465 if (cmd
== PROTOCOL_BINARY_CMD_FLUSH
) {
1466 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1467 validate_response_header(&receive
.response
, cmd
,
1468 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1471 len
= raw_command(send
.bytes
, sizeof(send
.bytes
),
1472 PROTOCOL_BINARY_CMD_GET
,
1473 key
, strlen(key
), NULL
, 0);
1474 safe_send(send
.bytes
, len
, false);
1475 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1476 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GET
,
1477 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
1483 static enum test_return
test_binary_flush(void) {
1484 return test_binary_flush_impl("test_binary_flush",
1485 PROTOCOL_BINARY_CMD_FLUSH
);
1488 static enum test_return
test_binary_flushq(void) {
1489 return test_binary_flush_impl("test_binary_flushq",
1490 PROTOCOL_BINARY_CMD_FLUSHQ
);
1493 static enum test_return
test_binary_concat_impl(const char *key
, uint8_t cmd
) {
1495 protocol_binary_request_no_extras request
;
1496 protocol_binary_response_no_extras response
;
1499 const char *value
= "world";
1501 size_t len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1502 key
, strlen(key
), value
, strlen(value
));
1505 safe_send(send
.bytes
, len
, false);
1506 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1507 validate_response_header(&receive
.response
, cmd
,
1508 PROTOCOL_BINARY_RESPONSE_NOT_STORED
);
1510 len
= storage_command(send
.bytes
, sizeof(send
.bytes
),
1511 PROTOCOL_BINARY_CMD_ADD
,
1512 key
, strlen(key
), value
, strlen(value
), 0, 0);
1513 safe_send(send
.bytes
, len
, false);
1514 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1515 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_ADD
,
1516 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1518 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), cmd
,
1519 key
, strlen(key
), value
, strlen(value
));
1520 safe_send(send
.bytes
, len
, false);
1522 if (cmd
== PROTOCOL_BINARY_CMD_APPEND
|| cmd
== PROTOCOL_BINARY_CMD_PREPEND
) {
1523 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1524 validate_response_header(&receive
.response
, cmd
,
1525 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1527 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_NOOP
,
1529 safe_send(send
.bytes
, len
, false);
1530 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1531 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_NOOP
,
1532 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1535 len
= raw_command(send
.bytes
, sizeof(send
.bytes
), PROTOCOL_BINARY_CMD_GETK
,
1536 key
, strlen(key
), NULL
, 0);
1538 safe_send(send
.bytes
, len
, false);
1539 safe_recv_packet(receive
.bytes
, sizeof(receive
.bytes
));
1540 validate_response_header(&receive
.response
, PROTOCOL_BINARY_CMD_GETK
,
1541 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1543 assert(receive
.response
.message
.header
.response
.keylen
== strlen(key
));
1544 assert(receive
.response
.message
.header
.response
.bodylen
== (strlen(key
) + 2*strlen(value
) + 4));
1546 char *ptr
= receive
.bytes
;
1547 ptr
+= sizeof(receive
.response
);
1550 assert(memcmp(ptr
, key
, strlen(key
)) == 0);
1552 assert(memcmp(ptr
, value
, strlen(value
)) == 0);
1553 ptr
+= strlen(value
);
1554 assert(memcmp(ptr
, value
, strlen(value
)) == 0);
1559 static enum test_return
test_binary_append(void) {
1560 return test_binary_concat_impl("test_binary_append",
1561 PROTOCOL_BINARY_CMD_APPEND
);
1564 static enum test_return
test_binary_prepend(void) {
1565 return test_binary_concat_impl("test_binary_prepend",
1566 PROTOCOL_BINARY_CMD_PREPEND
);
1569 static enum test_return
test_binary_appendq(void) {
1570 return test_binary_concat_impl("test_binary_appendq",
1571 PROTOCOL_BINARY_CMD_APPENDQ
);
1574 static enum test_return
test_binary_prependq(void) {
1575 return test_binary_concat_impl("test_binary_prependq",
1576 PROTOCOL_BINARY_CMD_PREPENDQ
);
1579 static enum test_return
test_binary_stat(void) {
1581 protocol_binary_request_no_extras request
;
1582 protocol_binary_response_no_extras response
;
1586 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1587 PROTOCOL_BINARY_CMD_STAT
,
1590 safe_send(buffer
.bytes
, len
, false);
1592 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1593 validate_response_header(&buffer
.response
, PROTOCOL_BINARY_CMD_STAT
,
1594 PROTOCOL_BINARY_RESPONSE_SUCCESS
);
1595 } while (buffer
.response
.message
.header
.response
.keylen
!= 0);
1600 static enum test_return
test_binary_illegal(void) {
1602 while (cmd
!= 0x00) {
1604 protocol_binary_request_no_extras request
;
1605 protocol_binary_response_no_extras response
;
1608 size_t len
= raw_command(buffer
.bytes
, sizeof(buffer
.bytes
),
1609 cmd
, NULL
, 0, NULL
, 0);
1610 safe_send(buffer
.bytes
, len
, false);
1611 safe_recv_packet(buffer
.bytes
, sizeof(buffer
.bytes
));
1612 validate_response_header(&buffer
.response
, cmd
,
1613 PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
);
1620 volatile bool hickup_thread_running
;
1622 static void *binary_hickup_recv_verification_thread(void *arg
) {
1623 protocol_binary_response_no_extras
*response
= malloc(65*1024);
1624 if (response
!= NULL
) {
1625 while (safe_recv_packet(response
, 65*1024)) {
1626 /* Just validate the packet format */
1627 validate_response_header(response
,
1628 response
->message
.header
.response
.opcode
,
1629 response
->message
.header
.response
.status
);
1633 hickup_thread_running
= false;
1634 allow_closed_read
= false;
1638 static enum test_return
test_binary_pipeline_hickup_chunk(void *buffer
, size_t buffersize
) {
1641 uint64_t value
= 0xfeedfacedeadbeef;
1643 while (hickup_thread_running
&&
1644 offset
+ sizeof(protocol_binary_request_no_extras
) < buffersize
) {
1646 protocol_binary_request_no_extras request
;
1647 char bytes
[65 * 1024];
1649 uint8_t cmd
= (uint8_t)(rand() & 0xff);
1651 size_t keylen
= (rand() % 250) + 1;
1654 case PROTOCOL_BINARY_CMD_ADD
:
1655 case PROTOCOL_BINARY_CMD_ADDQ
:
1656 case PROTOCOL_BINARY_CMD_REPLACE
:
1657 case PROTOCOL_BINARY_CMD_REPLACEQ
:
1658 case PROTOCOL_BINARY_CMD_SET
:
1659 case PROTOCOL_BINARY_CMD_SETQ
:
1660 len
= storage_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1661 key
, keylen
, &value
, sizeof(value
),
1664 case PROTOCOL_BINARY_CMD_APPEND
:
1665 case PROTOCOL_BINARY_CMD_APPENDQ
:
1666 case PROTOCOL_BINARY_CMD_PREPEND
:
1667 case PROTOCOL_BINARY_CMD_PREPENDQ
:
1668 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1669 key
, keylen
, &value
, sizeof(value
));
1671 case PROTOCOL_BINARY_CMD_FLUSH
:
1672 case PROTOCOL_BINARY_CMD_FLUSHQ
:
1673 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1676 case PROTOCOL_BINARY_CMD_NOOP
:
1677 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1680 case PROTOCOL_BINARY_CMD_DELETE
:
1681 case PROTOCOL_BINARY_CMD_DELETEQ
:
1682 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1683 key
, keylen
, NULL
, 0);
1685 case PROTOCOL_BINARY_CMD_DECREMENT
:
1686 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
1687 case PROTOCOL_BINARY_CMD_INCREMENT
:
1688 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
1689 len
= arithmetic_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1690 key
, keylen
, 1, 0, 0);
1692 case PROTOCOL_BINARY_CMD_VERSION
:
1693 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1694 PROTOCOL_BINARY_CMD_VERSION
,
1697 case PROTOCOL_BINARY_CMD_GET
:
1698 case PROTOCOL_BINARY_CMD_GETK
:
1699 case PROTOCOL_BINARY_CMD_GETKQ
:
1700 case PROTOCOL_BINARY_CMD_GETQ
:
1701 len
= raw_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1702 key
, keylen
, NULL
, 0);
1705 case PROTOCOL_BINARY_CMD_TOUCH
:
1706 case PROTOCOL_BINARY_CMD_GAT
:
1707 case PROTOCOL_BINARY_CMD_GATQ
:
1708 case PROTOCOL_BINARY_CMD_GATK
:
1709 case PROTOCOL_BINARY_CMD_GATKQ
:
1710 len
= touch_command(command
.bytes
, sizeof(command
.bytes
), cmd
,
1714 case PROTOCOL_BINARY_CMD_STAT
:
1715 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1716 PROTOCOL_BINARY_CMD_STAT
,
1720 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
1721 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
1722 case PROTOCOL_BINARY_CMD_SASL_STEP
:
1724 case PROTOCOL_BINARY_CMD_QUITQ
:
1725 case PROTOCOL_BINARY_CMD_QUIT
:
1726 /* I don't want to pass on the quit commands ;-) */
1730 len
= raw_command(command
.bytes
, sizeof(command
.bytes
),
1731 cmd
, NULL
, 0, NULL
, 0);
1734 if ((len
+ offset
) < buffersize
) {
1735 memcpy(((char*)buffer
) + offset
, command
.bytes
, len
);
1741 safe_send(buffer
, offset
, true);
1746 static enum test_return
test_binary_pipeline_hickup(void)
1748 size_t buffersize
= 65 * 1024;
1749 void *buffer
= malloc(buffersize
);
1754 allow_closed_read
= true;
1755 hickup_thread_running
= true;
1756 if ((ret
= pthread_create(&tid
, NULL
,
1757 binary_hickup_recv_verification_thread
, NULL
)) != 0) {
1758 fprintf(stderr
, "Can't create thread: %s\n", strerror(ret
));
1762 /* Allow the thread to start */
1765 srand((int)time(NULL
));
1766 for (ii
= 0; ii
< 2; ++ii
) {
1767 test_binary_pipeline_hickup_chunk(buffer
, buffersize
);
1770 /* send quitq to shut down the read thread ;-) */
1771 size_t len
= raw_command(buffer
, buffersize
, PROTOCOL_BINARY_CMD_QUITQ
,
1773 safe_send(buffer
, len
, false);
1775 pthread_join(tid
, NULL
);
1781 static enum test_return
test_issue_101(void) {
1783 enum test_return ret
= TEST_PASS
;
1788 if (getenv("SKIP_TEST_101") != NULL
) {
1792 const char *command
= "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
1793 size_t cmdlen
= strlen(command
);
1795 server_pid
= start_server(&port
, false, 1000);
1797 for (ii
= 0; ii
< max
; ++ii
) {
1798 fds
[ii
] = connect_server("127.0.0.1", port
, true);
1799 assert(fds
[ii
] > 0);
1802 /* Send command on the connection until it blocks */
1803 for (ii
= 0; ii
< max
; ++ii
) {
1806 ssize_t err
= write(fds
[ii
], command
, cmdlen
);
1824 if (child
== (pid_t
)-1) {
1826 } else if (child
> 0) {
1829 while ((c
= waitpid(child
, &stat
, 0)) == (pid_t
)-1 && errno
== EINTR
);
1833 sock
= connect_server("127.0.0.1", port
, false);
1834 ret
= test_binary_noop();
1840 /* close all connections */
1841 for (ii
= 0; ii
< max
; ++ii
) {
1845 assert(kill(server_pid
, SIGTERM
) == 0);
1850 typedef enum test_return (*TEST_FUNC
)(void);
1852 const char *description
;
1856 struct testcase testcases
[] = {
1857 { "cache_create", cache_create_test
},
1858 { "cache_constructor", cache_constructor_test
},
1859 { "cache_constructor_fail", cache_fail_constructor_test
},
1860 { "cache_destructor", cache_destructor_test
},
1861 { "cache_reuse", cache_reuse_test
},
1862 { "cache_redzone", cache_redzone_test
},
1863 { "issue_161", test_issue_161
},
1864 { "strtol", test_safe_strtol
},
1865 { "strtoll", test_safe_strtoll
},
1866 { "strtoul", test_safe_strtoul
},
1867 { "strtoull", test_safe_strtoull
},
1868 { "issue_44", test_issue_44
},
1869 { "vperror", test_vperror
},
1870 { "issue_101", test_issue_101
},
1871 /* The following tests all run towards the same server */
1872 { "start_server", start_memcached_server
},
1873 { "issue_92", test_issue_92
},
1874 { "issue_102", test_issue_102
},
1875 { "binary_noop", test_binary_noop
},
1876 { "binary_quit", test_binary_quit
},
1877 { "binary_quitq", test_binary_quitq
},
1878 { "binary_set", test_binary_set
},
1879 { "binary_setq", test_binary_setq
},
1880 { "binary_add", test_binary_add
},
1881 { "binary_addq", test_binary_addq
},
1882 { "binary_replace", test_binary_replace
},
1883 { "binary_replaceq", test_binary_replaceq
},
1884 { "binary_delete", test_binary_delete
},
1885 { "binary_deleteq", test_binary_deleteq
},
1886 { "binary_get", test_binary_get
},
1887 { "binary_getq", test_binary_getq
},
1888 { "binary_getk", test_binary_getk
},
1889 { "binary_getkq", test_binary_getkq
},
1890 { "binary_incr", test_binary_incr
},
1891 { "binary_incrq", test_binary_incrq
},
1892 { "binary_decr", test_binary_decr
},
1893 { "binary_decrq", test_binary_decrq
},
1894 { "binary_version", test_binary_version
},
1895 { "binary_flush", test_binary_flush
},
1896 { "binary_flushq", test_binary_flushq
},
1897 { "binary_append", test_binary_append
},
1898 { "binary_appendq", test_binary_appendq
},
1899 { "binary_prepend", test_binary_prepend
},
1900 { "binary_prependq", test_binary_prependq
},
1901 { "binary_stat", test_binary_stat
},
1902 { "binary_illegal", test_binary_illegal
},
1903 { "binary_pipeline_hickup", test_binary_pipeline_hickup
},
1904 { "stop_server", stop_memcached_server
},
1908 int main(int argc
, char **argv
)
1911 int ii
= 0, num_cases
= 0;
1913 for (num_cases
= 0; testcases
[num_cases
].description
; num_cases
++) {
1917 printf("1..%d\n", num_cases
);
1919 for (ii
= 0; testcases
[ii
].description
!= NULL
; ++ii
) {
1922 /* the test program shouldn't run longer than 10 minutes... */
1925 enum test_return ret
= testcases
[ii
].function();
1926 if (ret
== TEST_SKIP
) {
1927 fprintf(stdout
, "ok # SKIP %d - %s\n", ii
+ 1, testcases
[ii
].description
);
1928 } else if (ret
== TEST_PASS
) {
1929 fprintf(stdout
, "ok %d - %s\n", ii
+ 1, testcases
[ii
].description
);
1931 fprintf(stdout
, "not ok %d - %s\n", ii
+ 1, testcases
[ii
].description
);