1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "config.h"
3 #undef NDEBUG
4 #include <pthread.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/wait.h>
8 #include <netdb.h>
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include <netinet/tcp.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22
23 #include "cache.h"
24 #include <memcached/util.h>
25 #include <memcached/protocol_binary.h>
26 #include <memcached/config_parser.h>
27
28 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
29
30 enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
31
32 static pid_t server_pid;
33 static in_port_t port;
34 static int sock;
35 static bool allow_closed_read = false;
36
cache_create_test(void)37 static enum test_return cache_create_test(void)
38 {
39 cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
40 NULL, NULL);
41 assert(cache != NULL);
42 cache_destroy(cache);
43 return TEST_PASS;
44 }
45
46 const uint64_t constructor_pattern = 0xdeadcafebabebeef;
47
cache_constructor(void * buffer,void * notused1,int notused2)48 static int cache_constructor(void *buffer, void *notused1, int notused2) {
49 uint64_t *ptr = buffer;
50 *ptr = constructor_pattern;
51 return 0;
52 }
53
cache_constructor_test(void)54 static enum test_return cache_constructor_test(void)
55 {
56 cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
57 cache_constructor, NULL);
58 assert(cache != NULL);
59 uint64_t *ptr = cache_alloc(cache);
60 uint64_t pattern = *ptr;
61 cache_free(cache, ptr);
62 cache_destroy(cache);
63 return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
64 }
65
cache_fail_constructor(void * buffer,void * notused1,int notused2)66 static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
67 return 1;
68 }
69
cache_fail_constructor_test(void)70 static enum test_return cache_fail_constructor_test(void)
71 {
72 enum test_return ret = TEST_PASS;
73
74 cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
75 cache_fail_constructor, NULL);
76 assert(cache != NULL);
77 uint64_t *ptr = cache_alloc(cache);
78 if (ptr != NULL) {
79 ret = TEST_FAIL;
80 }
81 cache_destroy(cache);
82 return ret;
83 }
84
85 static void *destruct_data = 0;
86
cache_destructor(void * buffer,void * notused)87 static void cache_destructor(void *buffer, void *notused) {
88 destruct_data = buffer;
89 }
90
cache_destructor_test(void)91 static enum test_return cache_destructor_test(void)
92 {
93 cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
94 NULL, cache_destructor);
95 assert(cache != NULL);
96 char *ptr = cache_alloc(cache);
97 cache_free(cache, ptr);
98 cache_destroy(cache);
99
100 return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
101 }
102
cache_reuse_test(void)103 static enum test_return cache_reuse_test(void)
104 {
105 int ii;
106 cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
107 NULL, NULL);
108 char *ptr = cache_alloc(cache);
109 cache_free(cache, ptr);
110 for (ii = 0; ii < 100; ++ii) {
111 char *p = cache_alloc(cache);
112 assert(p == ptr);
113 cache_free(cache, ptr);
114 }
115 cache_destroy(cache);
116 return TEST_PASS;
117 }
118
119
cache_bulkalloc(size_t datasize)120 static enum test_return cache_bulkalloc(size_t datasize)
121 {
122 cache_t *cache = cache_create("test", datasize, sizeof(char*),
123 NULL, NULL);
124 #define ITERATIONS 1024
125 void *ptr[ITERATIONS];
126
127 for (int ii = 0; ii < ITERATIONS; ++ii) {
128 ptr[ii] = cache_alloc(cache);
129 assert(ptr[ii] != 0);
130 memset(ptr[ii], 0xff, datasize);
131 }
132
133 for (int ii = 0; ii < ITERATIONS; ++ii) {
134 cache_free(cache, ptr[ii]);
135 }
136
137 #undef ITERATIONS
138 cache_destroy(cache);
139 return TEST_PASS;
140 }
141
test_issue_161(void)142 static enum test_return test_issue_161(void)
143 {
144 enum test_return ret = cache_bulkalloc(1);
145 if (ret == TEST_PASS) {
146 ret = cache_bulkalloc(512);
147 }
148
149 return ret;
150 }
151
cache_redzone_test(void)152 static enum test_return cache_redzone_test(void)
153 {
154 #ifndef HAVE_UMEM_H
155 cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
156 NULL, NULL);
157
158 /* Ignore SIGABORT */
159 struct sigaction old_action;
160 struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
161 sigemptyset(&action.sa_mask);
162 sigaction(SIGABRT, &action, &old_action);
163
164 /* check memory debug.. */
165 char *p = cache_alloc(cache);
166 char old = *(p - 1);
167 *(p - 1) = 0;
168 cache_free(cache, p);
169 assert(cache_error == -1);
170 *(p - 1) = old;
171
172 p[sizeof(uint32_t)] = 0;
173 cache_free(cache, p);
174 assert(cache_error == 1);
175
176 /* restore signal handler */
177 sigaction(SIGABRT, &old_action, NULL);
178
179 cache_destroy(cache);
180
181 return TEST_PASS;
182 #else
183 return TEST_SKIP;
184 #endif
185 }
186
test_safe_strtoul(void)187 static enum test_return test_safe_strtoul(void) {
188 uint32_t val;
189 assert(safe_strtoul("123", &val));
190 assert(val == 123);
191 assert(safe_strtoul("+123", &val));
192 assert(val == 123);
193 assert(!safe_strtoul("", &val)); // empty
194 assert(!safe_strtoul("123BOGUS", &val)); // non-numeric
195 /* Not sure what it does, but this works with ICC :/
196 assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
197 */
198
199 // extremes:
200 assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
201 assert(val == 4294967295L);
202 /* This actually works on 64-bit ubuntu
203 assert(!safe_strtoul("4294967296", &val)); // 2**32
204 */
205 assert(!safe_strtoul("-1", &val)); // negative
206 return TEST_PASS;
207 }
208
209
test_safe_strtoull(void)210 static enum test_return test_safe_strtoull(void) {
211 uint64_t val;
212 assert(safe_strtoull("123", &val));
213 assert(val == 123);
214 assert(safe_strtoull("+123", &val));
215 assert(val == 123);
216 assert(!safe_strtoull("", &val)); // empty
217 assert(!safe_strtoull("123BOGUS", &val)); // non-numeric
218 assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
219
220 // extremes:
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
225 return TEST_PASS;
226 }
227
test_safe_strtoll(void)228 static enum test_return test_safe_strtoll(void) {
229 int64_t val;
230 assert(safe_strtoll("123", &val));
231 assert(val == 123);
232 assert(safe_strtoll("+123", &val));
233 assert(val == 123);
234 assert(safe_strtoll("-123", &val));
235 assert(val == -123);
236 assert(!safe_strtoll("", &val)); // empty
237 assert(!safe_strtoll("123BOGUS", &val)); // non-numeric
238 assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
239
240 // extremes:
241 assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
242 assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
243 assert(val == 9223372036854775807LL);
244 /*
245 assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
246 assert(val == -9223372036854775808LL);
247 */
248 assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
249
250 // We'll allow space to terminate the string. And leading space.
251 assert(safe_strtoll(" 123 foo", &val));
252 assert(val == 123);
253 return TEST_PASS;
254 }
255
test_safe_strtol(void)256 static enum test_return test_safe_strtol(void) {
257 int32_t val;
258 assert(safe_strtol("123", &val));
259 assert(val == 123);
260 assert(safe_strtol("+123", &val));
261 assert(val == 123);
262 assert(safe_strtol("-123", &val));
263 assert(val == -123);
264 assert(!safe_strtol("", &val)); // empty
265 assert(!safe_strtol("123BOGUS", &val)); // non-numeric
266 assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
267
268 // extremes:
269 /* This actually works on 64-bit ubuntu
270 assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
271 */
272 assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
273 assert(val == 2147483647L);
274 /* This actually works on 64-bit ubuntu
275 assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
276 */
277
278 // We'll allow space to terminate the string. And leading space.
279 assert(safe_strtol(" 123 foo", &val));
280 assert(val == 123);
281 return TEST_PASS;
282 }
283
test_safe_strtof(void)284 static enum test_return test_safe_strtof(void) {
285 float val;
286 assert(safe_strtof("123", &val));
287 assert(val == 123.00f);
288 assert(safe_strtof("+123", &val));
289 assert(val == 123.00f);
290 assert(safe_strtof("-123", &val));
291 assert(val == -123.00f);
292 assert(!safe_strtof("", &val)); // empty
293 assert(!safe_strtof("123BOGUS", &val)); // non-numeric
294
295 // We'll allow space to terminate the string. And leading space.
296 assert(safe_strtof(" 123 foo", &val));
297 assert(val == 123.00f);
298
299 assert(safe_strtof("123.23", &val));
300 assert(val == 123.23f);
301
302 assert(safe_strtof("123.00", &val));
303 assert(val == 123.00f);
304
305 return TEST_PASS;
306 }
307
308 /**
309 * Function to start the server and let it listen on a random port
310 *
311 * @param port_out where to store the TCP port number the server is
312 * listening on
313 * @param daemon set to true if you want to run the memcached server
314 * as a daemon process
315 * @return the pid of the memcached server
316 */
start_server(in_port_t * port_out,bool daemon,int timeout)317 static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
318 char environment[80];
319 snprintf(environment, sizeof(environment),
320 "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
321 char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
322 char pid_file[80];
323 snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
324
325 remove(filename);
326 remove(pid_file);
327
328 char engine[1024];
329 assert(getcwd(engine, sizeof(engine)));
330 strcat(engine, "/.libs/default_engine.so");
331 assert(strlen(engine) < sizeof(engine));
332
333 char blackhole[1024];
334 assert(getcwd(blackhole, sizeof(blackhole)));
335 strcat(blackhole, "/.libs/blackhole_logger.so");
336
337
338 #ifdef __sun
339 /* I want to name the corefiles differently so that they don't
340 overwrite each other
341 */
342 char coreadm[128];
343 snprintf(coreadm, sizeof(coreadm),
344 "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
345 system(coreadm);
346 #endif
347
348 pid_t pid = fork();
349 assert(pid != -1);
350
351 if (pid == 0) {
352 /* Child */
353 char *argv[20];
354 int arg = 0;
355 char tmo[24];
356 snprintf(tmo, sizeof(tmo), "%u", timeout);
357
358 putenv(environment);
359
360 if (!daemon) {
361 argv[arg++] = "./timedrun";
362 argv[arg++] = tmo;
363 }
364 argv[arg++] = "./memcached";
365 argv[arg++] = "-E";
366 argv[arg++] = engine;
367 argv[arg++] = "-X";
368 argv[arg++] = blackhole;
369 argv[arg++] = "-p";
370 argv[arg++] = "-1";
371 argv[arg++] = "-U";
372 argv[arg++] = "0";
373 /* Handle rpmbuild and the like doing this as root */
374 if (getuid() == 0) {
375 argv[arg++] = "-u";
376 argv[arg++] = "root";
377 }
378 if (daemon) {
379 argv[arg++] = "-d";
380 argv[arg++] = "-P";
381 argv[arg++] = pid_file;
382 }
383 #ifdef MESSAGE_DEBUG
384 argv[arg++] = "-vvv";
385 #endif
386 argv[arg++] = NULL;
387 assert(execv(argv[0], argv) != -1);
388 }
389
390 /* Yeah just let us "busy-wait" for the file to be created ;-) */
391 while (access(filename, F_OK) == -1) {
392 usleep(10);
393 }
394
395 FILE *fp = fopen(filename, "r");
396 if (fp == NULL) {
397 fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
398 strerror(errno));
399 assert(false);
400 }
401
402 *port_out = (in_port_t)-1;
403 char buffer[80];
404 while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
405 if (strncmp(buffer, "TCP INET: ", 10) == 0) {
406 int32_t val;
407 assert(safe_strtol(buffer + 10, &val));
408 *port_out = (in_port_t)val;
409 }
410 }
411 fclose(fp);
412 assert(remove(filename) == 0);
413
414 if (daemon) {
415 /* loop and wait for the pid file.. There is a potential race
416 * condition that the server just created the file but isn't
417 * finished writing the content, but I'll take the chance....
418 */
419 while (access(pid_file, F_OK) == -1) {
420 usleep(10);
421 }
422
423 fp = fopen(pid_file, "r");
424 if (fp == NULL) {
425 fprintf(stderr, "Failed to open pid file: %s\n",
426 strerror(errno));
427 assert(false);
428 }
429 assert(fgets(buffer, sizeof(buffer), fp) != NULL);
430 fclose(fp);
431
432 int32_t val;
433 assert(safe_strtol(buffer, &val));
434 pid = (pid_t)val;
435 }
436
437 return pid;
438 }
439
test_issue_44(void)440 static enum test_return test_issue_44(void) {
441 in_port_t port;
442 pid_t pid = start_server(&port, true, 15);
443 assert(kill(pid, SIGHUP) == 0);
444 sleep(1);
445 assert(kill(pid, SIGTERM) == 0);
446
447 return TEST_PASS;
448 }
449
lookuphost(const char * hostname,in_port_t port)450 static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
451 {
452 struct addrinfo *ai = 0;
453 struct addrinfo hints = { .ai_family = AF_UNSPEC,
454 .ai_protocol = IPPROTO_TCP,
455 .ai_socktype = SOCK_STREAM };
456 char service[NI_MAXSERV];
457 int error;
458
459 (void)snprintf(service, NI_MAXSERV, "%d", port);
460 if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
461 if (error != EAI_SYSTEM) {
462 fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
463 } else {
464 perror("getaddrinfo()");
465 }
466 }
467
468 return ai;
469 }
470
connect_server(const char * hostname,in_port_t port,bool nonblock)471 static int connect_server(const char *hostname, in_port_t port, bool nonblock)
472 {
473 struct addrinfo *ai = lookuphost(hostname, port);
474 int sock = -1;
475 if (ai != NULL) {
476 if ((sock = socket(ai->ai_family, ai->ai_socktype,
477 ai->ai_protocol)) != -1) {
478 if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
479 fprintf(stderr, "Failed to connect socket: %s\n",
480 strerror(errno));
481 close(sock);
482 sock = -1;
483 } else if (nonblock) {
484 int flags = fcntl(sock, F_GETFL, 0);
485 if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
486 fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
487 strerror(errno));
488 close(sock);
489 sock = -1;
490 }
491 }
492 } else {
493 fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
494 }
495
496 freeaddrinfo(ai);
497 }
498 return sock;
499 }
500
test_vperror(void)501 static enum test_return test_vperror(void) {
502 int rv = 0;
503 int oldstderr = dup(STDERR_FILENO);
504 char tmpl[sizeof(TMP_TEMPLATE)+1];
505 strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
506
507 int newfile = mkstemp(tmpl);
508 assert(newfile > 0);
509 rv = dup2(newfile, STDERR_FILENO);
510 assert(rv == STDERR_FILENO);
511 rv = close(newfile);
512 assert(rv == 0);
513
514 errno = EIO;
515 vperror("Old McDonald had a farm. %s", "EI EIO");
516
517 /* Restore stderr */
518 rv = dup2(oldstderr, STDERR_FILENO);
519 assert(rv == STDERR_FILENO);
520
521
522 /* Go read the file */
523 char buf[80] = { 0 };
524 FILE *efile = fopen(tmpl, "r");
525 assert(efile);
526 char *prv = fgets(buf, sizeof(buf), efile);
527 assert(prv);
528 fclose(efile);
529
530 unlink(tmpl);
531
532 char expected[80] = { 0 };
533 snprintf(expected, sizeof(expected),
534 "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO));
535
536 /*
537 fprintf(stderr,
538 "\nExpected: ``%s''"
539 "\nGot: ``%s''\n", expected, buf);
540 */
541
542 return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
543 }
544
trim(char * ptr)545 static char* trim(char* ptr) {
546 char *start = ptr;
547 while (isspace(*start)) {
548 ++start;
549 }
550 char *end = start + strlen(start) - 1;
551 if (end != start) {
552 while (isspace(*end)) {
553 *end = '\0';
554 --end;
555 }
556 }
557 return start;
558 }
559
test_config_parser(void)560 static enum test_return test_config_parser(void) {
561 bool bool_val = false;
562 size_t size_val = 0;
563 float float_val = 0;
564 char *string_val = 0;
565
566 /* Set up the different items I can handle */
567 struct config_item items[] = {
568 { .key = "bool",
569 .datatype = DT_BOOL,
570 .value.dt_bool = &bool_val },
571 { .key = "size_t",
572 .datatype = DT_SIZE,
573 .value.dt_size = &size_val },
574 { .key = "float",
575 .datatype = DT_FLOAT,
576 .value.dt_float = &float_val},
577 { .key = "string",
578 .datatype = DT_STRING,
579 .value.dt_string = &string_val},
580 { .key = "config_file",
581 .datatype = DT_CONFIGFILE },
582 { .key = NULL}
583 };
584
585 char outfile[sizeof(TMP_TEMPLATE)+1];
586 strncpy(outfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
587 char cfgfile[sizeof(TMP_TEMPLATE)+1];
588 strncpy(cfgfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
589
590 int newfile = mkstemp(outfile);
591 assert(newfile > 0);
592 FILE *error = fdopen(newfile, "w");
593
594 assert(error != NULL);
595 assert(parse_config("", items, error) == 0);
596 /* Nothing should be found */
597 for (int ii = 0; ii < 5; ++ii) {
598 assert(!items[0].found);
599 }
600
601 assert(parse_config("bool=true", items, error) == 0);
602 assert(bool_val);
603 /* only bool should be found */
604 assert(items[0].found);
605 items[0].found = false;
606 for (int ii = 0; ii < 5; ++ii) {
607 assert(!items[0].found);
608 }
609
610 /* It should allow illegal keywords */
611 assert(parse_config("pacman=dead", items, error) == 1);
612 /* and illegal values */
613 assert(parse_config("bool=12", items, error) == -1);
614 assert(!items[0].found);
615 /* and multiple occurences of the same value */
616 assert(parse_config("size_t=1; size_t=1024", items, error) == 0);
617 assert(items[1].found);
618 assert(size_val == 1024);
619 items[1].found = false;
620
621 /* Empty string */
622 /* XXX: This test fails on Linux, but works on OS X.
623 assert(parse_config("string=", items, error) == 0);
624 assert(items[3].found);
625 assert(strcmp(string_val, "") == 0);
626 items[3].found = false;
627 */
628 /* Plain string */
629 assert(parse_config("string=sval", items, error) == 0);
630 assert(items[3].found);
631 assert(strcmp(string_val, "sval") == 0);
632 items[3].found = false;
633 /* Leading space */
634 assert(parse_config("string= sval", items, error) == 0);
635 assert(items[3].found);
636 assert(strcmp(string_val, "sval") == 0);
637 items[3].found = false;
638 /* Escaped leading space */
639 assert(parse_config("string=\\ sval", items, error) == 0);
640 assert(items[3].found);
641 assert(strcmp(string_val, " sval") == 0);
642 items[3].found = false;
643 /* trailing space */
644 assert(parse_config("string=sval ", items, error) == 0);
645 assert(items[3].found);
646 assert(strcmp(string_val, "sval") == 0);
647 items[3].found = false;
648 /* escaped trailing space */
649 assert(parse_config("string=sval\\ ", items, error) == 0);
650 assert(items[3].found);
651 assert(strcmp(string_val, "sval ") == 0);
652 items[3].found = false;
653 /* escaped stop char */
654 assert(parse_config("string=sval\\;blah=x", items, error) == 0);
655 assert(items[3].found);
656 assert(strcmp(string_val, "sval;blah=x") == 0);
657 items[3].found = false;
658 /* middle space */
659 assert(parse_config("string=s val", items, error) == 0);
660 assert(items[3].found);
661 assert(strcmp(string_val, "s val") == 0);
662 items[3].found = false;
663
664 /* And all of the variables */
665 assert(parse_config("bool=true;size_t=1024;float=12.5;string=somestr",
666 items, error) == 0);
667 assert(bool_val);
668 assert(size_val == 1024);
669 assert(float_val == 12.5f);
670 assert(strcmp(string_val, "somestr") == 0);
671 for (int ii = 0; ii < 5; ++ii) {
672 items[ii].found = false;
673 }
674
675 assert(parse_config("size_t=1k", items, error) == 0);
676 assert(items[1].found);
677 assert(size_val == 1024);
678 items[1].found = false;
679 assert(parse_config("size_t=1m", items, error) == 0);
680 assert(items[1].found);
681 assert(size_val == 1024*1024);
682 items[1].found = false;
683 assert(parse_config("size_t=1g", items, error) == 0);
684 assert(items[1].found);
685 assert(size_val == 1024*1024*1024);
686 items[1].found = false;
687 assert(parse_config("size_t=1K", items, error) == 0);
688 assert(items[1].found);
689 assert(size_val == 1024);
690 items[1].found = false;
691 assert(parse_config("size_t=1M", items, error) == 0);
692 assert(items[1].found);
693 assert(size_val == 1024*1024);
694 items[1].found = false;
695 assert(parse_config("size_t=1G", items, error) == 0);
696 assert(items[1].found);
697 assert(size_val == 1024*1024*1024);
698 items[1].found = false;
699
700 newfile = mkstemp(cfgfile);
701 assert(newfile > 0);
702 FILE *cfg = fdopen(newfile, "w");
703 assert(cfg != NULL);
704 fprintf(cfg, "# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
705 fclose(cfg);
706 char buffer[1024];
707 sprintf(buffer, "config_file=%s", cfgfile);
708 assert(parse_config(buffer, items, error) == 0);
709 assert(bool_val);
710 assert(size_val == 1023);
711 assert(float_val == 12.4f);
712 fclose(error);
713
714 remove(cfgfile);
715 /* Verify that I received the error messages ;-) */
716 error = fopen(outfile, "r");
717 assert(error);
718
719 assert(fgets(buffer, sizeof(buffer), error));
720 assert(strcmp("Unsupported key: <pacman>", trim(buffer)) == 0);
721 assert(fgets(buffer, sizeof(buffer), error));
722 assert(strcmp("Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
723 assert(fgets(buffer, sizeof(buffer), error));
724 assert(strcmp("WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
725 assert(fgets(buffer, sizeof(buffer), error) == NULL);
726
727 remove(outfile);
728 return TEST_PASS;
729 }
730
send_ascii_command(const char * buf)731 static void send_ascii_command(const char *buf) {
732 off_t offset = 0;
733 const char* ptr = buf;
734 size_t len = strlen(buf);
735
736 do {
737 ssize_t nw = send(sock, ptr + offset, len - offset, 0);
738 if (nw == -1) {
739 if (errno != EINTR) {
740 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
741 abort();
742 }
743 } else {
744 offset += nw;
745 }
746 } while (offset < len);
747 }
748
749 /*
750 * This is a dead slow single byte read, but it should only read out
751 * _one_ response and I don't have an input buffer... The current
752 * implementation only supports single-line responses, so if you want to use
753 * it for get commands you need to implement that first ;-)
754 */
read_ascii_response(char * buffer,size_t size)755 static void read_ascii_response(char *buffer, size_t size) {
756 off_t offset = 0;
757 bool need_more = true;
758 do {
759 ssize_t nr = recv(sock, buffer + offset, 1, 0);
760 if (nr == -1) {
761 if (errno != EINTR) {
762 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
763 abort();
764 }
765 } else {
766 assert(nr == 1);
767 if (buffer[offset] == '\n') {
768 need_more = false;
769 buffer[offset + 1] = '\0';
770 }
771 offset += nr;
772 assert(offset + 1 < size);
773 }
774 } while (need_more);
775 }
776
test_issue_92(void)777 static enum test_return test_issue_92(void) {
778 #ifdef FUTURE
779 char buffer[1024];
780
781 close(sock);
782 sock = connect_server("127.0.0.1", port, false);
783
784 send_ascii_command("stats cachedump 1 0 0\r\n");
785 read_ascii_response(buffer, sizeof(buffer));
786 assert(strncmp(buffer, "END", strlen("END")) == 0);
787
788 send_ascii_command("stats cachedump 200 0 0\r\n");
789 read_ascii_response(buffer, sizeof(buffer));
790 assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
791
792 close(sock);
793 sock = connect_server("127.0.0.1", port, false);
794 #endif
795
796 return TEST_PASS;
797 }
798
test_issue_102(void)799 static enum test_return test_issue_102(void) {
800 char buffer[4096];
801 memset(buffer, ' ', sizeof(buffer));
802 buffer[sizeof(buffer) - 1] = '\0';
803
804 close(sock);
805 sock = connect_server("127.0.0.1", port, false);
806
807 send_ascii_command(buffer);
808 /* verify that the server closed the connection */
809 assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
810 close(sock);
811 sock = connect_server("127.0.0.1", port, false);
812
813 snprintf(buffer, sizeof(buffer), "gets ");
814 size_t offset = 5;
815 while (offset < 4000) {
816 offset += snprintf(buffer + offset, sizeof(buffer) - offset,
817 "%010u ", (unsigned int)offset);
818 }
819
820 send_ascii_command(buffer);
821 usleep(250);
822
823 send_ascii_command("\r\n");
824 char rsp[80];
825 read_ascii_response(rsp, sizeof(rsp));
826 assert(strncmp(rsp, "END", strlen("END")) == 0);
827 buffer[3]= ' ';
828 send_ascii_command(buffer);
829 usleep(250);
830 send_ascii_command("\r\n");
831 read_ascii_response(rsp, sizeof(rsp));
832 assert(strncmp(rsp, "END", strlen("END")) == 0);
833
834 memset(buffer, ' ', sizeof(buffer));
835 int len = snprintf(buffer + 101, sizeof(buffer) - 101, "gets foo");
836 buffer[101 + len] = ' ';
837 buffer[sizeof(buffer) - 1] = '\0';
838 send_ascii_command(buffer);
839 /* verify that the server closed the connection */
840 assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
841
842 close(sock);
843 sock = connect_server("127.0.0.1", port, false);
844
845 return TEST_PASS;
846 }
847
start_memcached_server(void)848 static enum test_return start_memcached_server(void) {
849 server_pid = start_server(&port, false, 600);
850 sock = connect_server("127.0.0.1", port, false);
851
852 return TEST_PASS;
853 }
854
stop_memcached_server(void)855 static enum test_return stop_memcached_server(void) {
856 close(sock);
857 assert(kill(server_pid, SIGTERM) == 0);
858 return TEST_PASS;
859 }
860
safe_send(const void * buf,size_t len,bool hickup)861 static void safe_send(const void* buf, size_t len, bool hickup)
862 {
863 off_t offset = 0;
864 const char* ptr = buf;
865 #ifdef MESSAGE_DEBUG
866 uint8_t val = *ptr;
867 assert(val == (uint8_t)0x80);
868 fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
869 for (int ii = 0; ii < len; ++ii) {
870 if (ii % 4 == 0) {
871 fprintf(stderr, "\n ");
872 }
873 val = *(ptr + ii);
874 fprintf(stderr, " 0x%02x", val);
875 }
876 fprintf(stderr, "\n");
877 usleep(500);
878 #endif
879
880 do {
881 size_t num_bytes = len - offset;
882 if (hickup) {
883 if (num_bytes > 1024) {
884 num_bytes = (rand() % 1023) + 1;
885 }
886 }
887
888 ssize_t nw = send(sock, ptr + offset, num_bytes, 0);
889 if (nw == -1) {
890 if (errno != EINTR) {
891 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
892 abort();
893 }
894 } else {
895 if (hickup) {
896 usleep(100);
897 }
898 offset += nw;
899 }
900 } while (offset < len);
901 }
902
safe_recv(void * buf,size_t len)903 static bool safe_recv(void *buf, size_t len) {
904 if (len == 0) {
905 return true;
906 }
907 off_t offset = 0;
908 do {
909 ssize_t nr = recv(sock, ((char*)buf) + offset, len - offset, 0);
910 if (nr == -1) {
911 if (errno != EINTR) {
912 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
913 abort();
914 }
915 } else {
916 if (nr == 0 && allow_closed_read) {
917 return false;
918 }
919 assert(nr != 0);
920 offset += nr;
921 }
922 } while (offset < len);
923
924 return true;
925 }
926
safe_recv_packet(void * buf,size_t size)927 static bool safe_recv_packet(void *buf, size_t size) {
928 protocol_binary_response_no_extras *response = buf;
929 assert(size > sizeof(*response));
930 if (!safe_recv(response, sizeof(*response))) {
931 return false;
932 }
933 response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
934 response->message.header.response.status = ntohs(response->message.header.response.status);
935 response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
936
937 size_t len = sizeof(*response);
938
939 char *ptr = buf;
940 ptr += len;
941 if (!safe_recv(ptr, response->message.header.response.bodylen)) {
942 return false;
943 }
944
945 #ifdef MESSAGE_DEBUG
946 usleep(500);
947 ptr = buf;
948 len += response->message.header.response.bodylen;
949 uint8_t val = *ptr;
950 assert(val == (uint8_t)0x81);
951 fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
952 for (int ii = 0; ii < len; ++ii) {
953 if (ii % 4 == 0) {
954 fprintf(stderr, "\n ");
955 }
956 val = *(ptr + ii);
957 fprintf(stderr, " 0x%02x", val);
958 }
959 fprintf(stderr, "\n");
960 #endif
961 return true;
962 }
963
storage_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen,uint32_t flags,uint32_t exp)964 static off_t storage_command(char*buf,
965 size_t bufsz,
966 uint8_t cmd,
967 const void* key,
968 size_t keylen,
969 const void* dta,
970 size_t dtalen,
971 uint32_t flags,
972 uint32_t exp) {
973 /* all of the storage commands use the same command layout */
974 protocol_binary_request_set *request = (void*)buf;
975 assert(bufsz > sizeof(*request) + keylen + dtalen);
976
977 memset(request, 0, sizeof(*request));
978 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
979 request->message.header.request.opcode = cmd;
980 request->message.header.request.keylen = htons(keylen);
981 request->message.header.request.extlen = 8;
982 request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
983 request->message.header.request.opaque = 0xdeadbeef;
984 request->message.body.flags = flags;
985 request->message.body.expiration = exp;
986
987 off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
988
989 memcpy(buf + key_offset, key, keylen);
990 if (dta != NULL) {
991 memcpy(buf + key_offset + keylen, dta, dtalen);
992 }
993
994 return key_offset + keylen + dtalen;
995 }
996
raw_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen)997 static off_t raw_command(char* buf,
998 size_t bufsz,
999 uint8_t cmd,
1000 const void* key,
1001 size_t keylen,
1002 const void* dta,
1003 size_t dtalen) {
1004 /* all of the storage commands use the same command layout */
1005 protocol_binary_request_no_extras *request = (void*)buf;
1006 assert(bufsz > sizeof(*request) + keylen + dtalen);
1007
1008 memset(request, 0, sizeof(*request));
1009 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1010 request->message.header.request.opcode = cmd;
1011 request->message.header.request.keylen = htons(keylen);
1012 request->message.header.request.bodylen = htonl(keylen + dtalen);
1013 request->message.header.request.opaque = 0xdeadbeef;
1014
1015 off_t key_offset = sizeof(protocol_binary_request_no_extras);
1016
1017 if (key != NULL) {
1018 memcpy(buf + key_offset, key, keylen);
1019 }
1020 if (dta != NULL) {
1021 memcpy(buf + key_offset + keylen, dta, dtalen);
1022 }
1023
1024 return sizeof(*request) + keylen + dtalen;
1025 }
1026
flush_command(char * buf,size_t bufsz,uint8_t cmd,uint32_t exptime,bool use_extra)1027 static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1028 protocol_binary_request_flush *request = (void*)buf;
1029 assert(bufsz > sizeof(*request));
1030
1031 memset(request, 0, sizeof(*request));
1032 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1033 request->message.header.request.opcode = cmd;
1034
1035 off_t size = sizeof(protocol_binary_request_no_extras);
1036 if (use_extra) {
1037 request->message.header.request.extlen = 4;
1038 request->message.body.expiration = htonl(exptime);
1039 request->message.header.request.bodylen = htonl(4);
1040 size += 4;
1041 }
1042
1043 request->message.header.request.opaque = 0xdeadbeef;
1044
1045 return size;
1046 }
1047
arithmetic_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,uint64_t delta,uint64_t initial,uint32_t exp)1048 static off_t arithmetic_command(char* buf,
1049 size_t bufsz,
1050 uint8_t cmd,
1051 const void* key,
1052 size_t keylen,
1053 uint64_t delta,
1054 uint64_t initial,
1055 uint32_t exp) {
1056 protocol_binary_request_incr *request = (void*)buf;
1057 assert(bufsz > sizeof(*request) + keylen);
1058
1059 memset(request, 0, sizeof(*request));
1060 request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1061 request->message.header.request.opcode = cmd;
1062 request->message.header.request.keylen = htons(keylen);
1063 request->message.header.request.extlen = 20;
1064 request->message.header.request.bodylen = htonl(keylen + 20);
1065 request->message.header.request.opaque = 0xdeadbeef;
1066 request->message.body.delta = htonll(delta);
1067 request->message.body.initial = htonll(initial);
1068 request->message.body.expiration = htonl(exp);
1069
1070 off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1071
1072 memcpy(buf + key_offset, key, keylen);
1073 return key_offset + keylen;
1074 }
1075
validate_response_header(protocol_binary_response_no_extras * response,uint8_t cmd,uint16_t status)1076 static void validate_response_header(protocol_binary_response_no_extras *response,
1077 uint8_t cmd, uint16_t status)
1078 {
1079 assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1080 assert(response->message.header.response.opcode == cmd);
1081 assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1082 if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1083 if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1084 response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1085 }
1086 }
1087 assert(response->message.header.response.status == status);
1088 assert(response->message.header.response.opaque == 0xdeadbeef);
1089
1090 if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1091 switch (cmd) {
1092 case PROTOCOL_BINARY_CMD_ADDQ:
1093 case PROTOCOL_BINARY_CMD_APPENDQ:
1094 case PROTOCOL_BINARY_CMD_DECREMENTQ:
1095 case PROTOCOL_BINARY_CMD_DELETEQ:
1096 case PROTOCOL_BINARY_CMD_FLUSHQ:
1097 case PROTOCOL_BINARY_CMD_INCREMENTQ:
1098 case PROTOCOL_BINARY_CMD_PREPENDQ:
1099 case PROTOCOL_BINARY_CMD_QUITQ:
1100 case PROTOCOL_BINARY_CMD_REPLACEQ:
1101 case PROTOCOL_BINARY_CMD_SETQ:
1102 assert("Quiet command shouldn't return on success" == NULL);
1103 default:
1104 break;
1105 }
1106
1107 switch (cmd) {
1108 case PROTOCOL_BINARY_CMD_ADD:
1109 case PROTOCOL_BINARY_CMD_REPLACE:
1110 case PROTOCOL_BINARY_CMD_SET:
1111 case PROTOCOL_BINARY_CMD_APPEND:
1112 case PROTOCOL_BINARY_CMD_PREPEND:
1113 assert(response->message.header.response.keylen == 0);
1114 assert(response->message.header.response.extlen == 0);
1115 assert(response->message.header.response.bodylen == 0);
1116 assert(response->message.header.response.cas != 0);
1117 break;
1118 case PROTOCOL_BINARY_CMD_FLUSH:
1119 case PROTOCOL_BINARY_CMD_NOOP:
1120 case PROTOCOL_BINARY_CMD_QUIT:
1121 case PROTOCOL_BINARY_CMD_DELETE:
1122 assert(response->message.header.response.keylen == 0);
1123 assert(response->message.header.response.extlen == 0);
1124 assert(response->message.header.response.bodylen == 0);
1125 assert(response->message.header.response.cas == 0);
1126 break;
1127
1128 case PROTOCOL_BINARY_CMD_DECREMENT:
1129 case PROTOCOL_BINARY_CMD_INCREMENT:
1130 assert(response->message.header.response.keylen == 0);
1131 assert(response->message.header.response.extlen == 0);
1132 assert(response->message.header.response.bodylen == 8);
1133 assert(response->message.header.response.cas != 0);
1134 break;
1135
1136 case PROTOCOL_BINARY_CMD_STAT:
1137 assert(response->message.header.response.extlen == 0);
1138 /* key and value exists in all packets except in the terminating */
1139 assert(response->message.header.response.cas == 0);
1140 break;
1141
1142 case PROTOCOL_BINARY_CMD_VERSION:
1143 assert(response->message.header.response.keylen == 0);
1144 assert(response->message.header.response.extlen == 0);
1145 assert(response->message.header.response.bodylen != 0);
1146 assert(response->message.header.response.cas == 0);
1147 break;
1148
1149 case PROTOCOL_BINARY_CMD_GET:
1150 case PROTOCOL_BINARY_CMD_GETQ:
1151 assert(response->message.header.response.keylen == 0);
1152 assert(response->message.header.response.extlen == 4);
1153 assert(response->message.header.response.cas != 0);
1154 break;
1155
1156 case PROTOCOL_BINARY_CMD_GETK:
1157 case PROTOCOL_BINARY_CMD_GETKQ:
1158 assert(response->message.header.response.keylen != 0);
1159 assert(response->message.header.response.extlen == 4);
1160 assert(response->message.header.response.cas != 0);
1161 break;
1162
1163 default:
1164 /* Undefined command code */
1165 break;
1166 }
1167 } else {
1168 assert(response->message.header.response.cas == 0);
1169 assert(response->message.header.response.extlen == 0);
1170 if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1171 assert(response->message.header.response.keylen == 0);
1172 }
1173 }
1174 }
1175
test_binary_noop(void)1176 static enum test_return test_binary_noop(void) {
1177 union {
1178 protocol_binary_request_no_extras request;
1179 protocol_binary_response_no_extras response;
1180 char bytes[1024];
1181 } buffer;
1182
1183 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1184 PROTOCOL_BINARY_CMD_NOOP,
1185 NULL, 0, NULL, 0);
1186
1187 safe_send(buffer.bytes, len, false);
1188 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1189 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1190 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1191
1192 return TEST_PASS;
1193 }
1194
test_binary_quit_impl(uint8_t cmd)1195 static enum test_return test_binary_quit_impl(uint8_t cmd) {
1196 union {
1197 protocol_binary_request_no_extras request;
1198 protocol_binary_response_no_extras response;
1199 char bytes[1024];
1200 } buffer;
1201 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1202 cmd, NULL, 0, NULL, 0);
1203
1204 safe_send(buffer.bytes, len, false);
1205 if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1206 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1207 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1208 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1209 }
1210
1211 /* Socket should be closed now, read should return 0 */
1212 assert(recv(sock, buffer.bytes, sizeof(buffer.bytes), 0) == 0);
1213 close(sock);
1214 sock = connect_server("127.0.0.1", port, false);
1215
1216 return TEST_PASS;
1217 }
1218
test_binary_quit(void)1219 static enum test_return test_binary_quit(void) {
1220 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1221 }
1222
test_binary_quitq(void)1223 static enum test_return test_binary_quitq(void) {
1224 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1225 }
1226
test_binary_set_impl(const char * key,uint8_t cmd)1227 static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1228 union {
1229 protocol_binary_request_no_extras request;
1230 protocol_binary_response_no_extras response;
1231 char bytes[1024];
1232 } send, receive;
1233 uint64_t value = 0xdeadbeefdeadcafe;
1234 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1235 key, strlen(key), &value, sizeof(value),
1236 0, 0);
1237
1238 /* Set should work over and over again */
1239 int ii;
1240 for (ii = 0; ii < 10; ++ii) {
1241 safe_send(send.bytes, len, false);
1242 if (cmd == PROTOCOL_BINARY_CMD_SET) {
1243 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1244 validate_response_header(&receive.response, cmd,
1245 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1246 }
1247 }
1248
1249 if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1250 return test_binary_noop();
1251 }
1252
1253 send.request.message.header.request.cas = receive.response.message.header.response.cas;
1254 safe_send(send.bytes, len, false);
1255 if (cmd == PROTOCOL_BINARY_CMD_SET) {
1256 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1257 validate_response_header(&receive.response, cmd,
1258 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1259 assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1260 } else {
1261 return test_binary_noop();
1262 }
1263
1264 return TEST_PASS;
1265 }
1266
test_binary_set(void)1267 static enum test_return test_binary_set(void) {
1268 return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1269 }
1270
test_binary_setq(void)1271 static enum test_return test_binary_setq(void) {
1272 return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1273 }
1274
test_binary_add_impl(const char * key,uint8_t cmd)1275 static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1276 uint64_t value = 0xdeadbeefdeadcafe;
1277 union {
1278 protocol_binary_request_no_extras request;
1279 protocol_binary_response_no_extras response;
1280 char bytes[1024];
1281 } send, receive;
1282 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1283 strlen(key), &value, sizeof(value),
1284 0, 0);
1285
1286 /* Add should only work the first time */
1287 int ii;
1288 for (ii = 0; ii < 10; ++ii) {
1289 safe_send(send.bytes, len, false);
1290 if (ii == 0) {
1291 if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1292 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1293 validate_response_header(&receive.response, cmd,
1294 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1295 }
1296 } else {
1297 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1298 validate_response_header(&receive.response, cmd,
1299 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1300 }
1301 }
1302
1303 return TEST_PASS;
1304 }
1305
test_binary_add(void)1306 static enum test_return test_binary_add(void) {
1307 return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1308 }
1309
test_binary_addq(void)1310 static enum test_return test_binary_addq(void) {
1311 return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1312 }
1313
test_binary_replace_impl(const char * key,uint8_t cmd)1314 static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1315 uint64_t value = 0xdeadbeefdeadcafe;
1316 union {
1317 protocol_binary_request_no_extras request;
1318 protocol_binary_response_no_extras response;
1319 char bytes[1024];
1320 } send, receive;
1321 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1322 key, strlen(key), &value, sizeof(value),
1323 0, 0);
1324 safe_send(send.bytes, len, false);
1325 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1326 validate_response_header(&receive.response, cmd,
1327 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1328 len = storage_command(send.bytes, sizeof(send.bytes),
1329 PROTOCOL_BINARY_CMD_ADD,
1330 key, strlen(key), &value, sizeof(value), 0, 0);
1331 safe_send(send.bytes, len, false);
1332 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1333 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1334 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1335
1336 len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1337 key, strlen(key), &value, sizeof(value), 0, 0);
1338 int ii;
1339 for (ii = 0; ii < 10; ++ii) {
1340 safe_send(send.bytes, len, false);
1341 if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1342 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1343 validate_response_header(&receive.response,
1344 PROTOCOL_BINARY_CMD_REPLACE,
1345 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1346 }
1347 }
1348
1349 if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1350 test_binary_noop();
1351 }
1352
1353 return TEST_PASS;
1354 }
1355
test_binary_replace(void)1356 static enum test_return test_binary_replace(void) {
1357 return test_binary_replace_impl("test_binary_replace",
1358 PROTOCOL_BINARY_CMD_REPLACE);
1359 }
1360
test_binary_replaceq(void)1361 static enum test_return test_binary_replaceq(void) {
1362 return test_binary_replace_impl("test_binary_replaceq",
1363 PROTOCOL_BINARY_CMD_REPLACEQ);
1364 }
1365
test_binary_delete_impl(const char * key,uint8_t cmd)1366 static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1367 union {
1368 protocol_binary_request_no_extras request;
1369 protocol_binary_response_no_extras response;
1370 char bytes[1024];
1371 } send, receive;
1372 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1373 key, strlen(key), NULL, 0);
1374
1375 safe_send(send.bytes, len, false);
1376 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1377 validate_response_header(&receive.response, cmd,
1378 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1379 len = storage_command(send.bytes, sizeof(send.bytes),
1380 PROTOCOL_BINARY_CMD_ADD,
1381 key, strlen(key), NULL, 0, 0, 0);
1382 safe_send(send.bytes, len, false);
1383 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1384 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1385 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1386
1387 len = raw_command(send.bytes, sizeof(send.bytes),
1388 cmd, key, strlen(key), NULL, 0);
1389 safe_send(send.bytes, len, false);
1390
1391 if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1392 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1393 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1394 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1395 }
1396
1397 safe_send(send.bytes, len, false);
1398 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1399 validate_response_header(&receive.response, cmd,
1400 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1401
1402 return TEST_PASS;
1403 }
1404
test_binary_delete(void)1405 static enum test_return test_binary_delete(void) {
1406 return test_binary_delete_impl("test_binary_delete",
1407 PROTOCOL_BINARY_CMD_DELETE);
1408 }
1409
test_binary_deleteq(void)1410 static enum test_return test_binary_deleteq(void) {
1411 return test_binary_delete_impl("test_binary_deleteq",
1412 PROTOCOL_BINARY_CMD_DELETEQ);
1413 }
1414
test_binary_get_impl(const char * key,uint8_t cmd)1415 static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1416 union {
1417 protocol_binary_request_no_extras request;
1418 protocol_binary_response_no_extras response;
1419 char bytes[1024];
1420 } send, receive;
1421 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1422 key, strlen(key), NULL, 0);
1423
1424 safe_send(send.bytes, len, false);
1425 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1426 validate_response_header(&receive.response, cmd,
1427 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1428
1429 len = storage_command(send.bytes, sizeof(send.bytes),
1430 PROTOCOL_BINARY_CMD_ADD,
1431 key, strlen(key), NULL, 0,
1432 0, 0);
1433 safe_send(send.bytes, len, false);
1434 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1435 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1436 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1437
1438 /* run a little pipeline test ;-) */
1439 len = 0;
1440 int ii;
1441 for (ii = 0; ii < 10; ++ii) {
1442 union {
1443 protocol_binary_request_no_extras request;
1444 char bytes[1024];
1445 } temp;
1446 size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1447 cmd, key, strlen(key), NULL, 0);
1448 memcpy(send.bytes + len, temp.bytes, l);
1449 len += l;
1450 }
1451
1452 safe_send(send.bytes, len, false);
1453 for (ii = 0; ii < 10; ++ii) {
1454 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1455 validate_response_header(&receive.response, cmd,
1456 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1457 }
1458
1459 return TEST_PASS;
1460 }
1461
test_binary_get(void)1462 static enum test_return test_binary_get(void) {
1463 return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1464 }
1465
test_binary_getk(void)1466 static enum test_return test_binary_getk(void) {
1467 return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1468 }
1469
test_binary_getq_impl(const char * key,uint8_t cmd)1470 static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1471 const char *missing = "test_binary_getq_missing";
1472 union {
1473 protocol_binary_request_no_extras request;
1474 protocol_binary_response_no_extras response;
1475 char bytes[1024];
1476 } send, temp, receive;
1477 size_t len = storage_command(send.bytes, sizeof(send.bytes),
1478 PROTOCOL_BINARY_CMD_ADD,
1479 key, strlen(key), NULL, 0,
1480 0, 0);
1481 size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1482 missing, strlen(missing), NULL, 0);
1483 /* I need to change the first opaque so that I can separate the two
1484 * return packets */
1485 temp.request.message.header.request.opaque = 0xfeedface;
1486 memcpy(send.bytes + len, temp.bytes, len2);
1487 len += len2;
1488
1489 len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1490 key, strlen(key), NULL, 0);
1491 memcpy(send.bytes + len, temp.bytes, len2);
1492 len += len2;
1493
1494 safe_send(send.bytes, len, false);
1495 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1496 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1497 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1498 /* The first GETQ shouldn't return anything */
1499 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1500 validate_response_header(&receive.response, cmd,
1501 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1502
1503 return TEST_PASS;
1504 }
1505
test_binary_getq(void)1506 static enum test_return test_binary_getq(void) {
1507 return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1508 }
1509
test_binary_getkq(void)1510 static enum test_return test_binary_getkq(void) {
1511 return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1512 }
1513
test_binary_incr_impl(const char * key,uint8_t cmd)1514 static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1515 union {
1516 protocol_binary_request_no_extras request;
1517 protocol_binary_response_no_extras response_header;
1518 protocol_binary_response_incr response;
1519 char bytes[1024];
1520 } send, receive;
1521 size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1522 key, strlen(key), 1, 0, 0);
1523
1524 int ii;
1525 for (ii = 0; ii < 10; ++ii) {
1526 safe_send(send.bytes, len, false);
1527 if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1528 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1529 validate_response_header(&receive.response_header, cmd,
1530 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1531 assert(ntohll(receive.response.message.body.value) == ii);
1532 }
1533 }
1534
1535 if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1536 test_binary_noop();
1537 }
1538 return TEST_PASS;
1539 }
1540
test_binary_incr(void)1541 static enum test_return test_binary_incr(void) {
1542 return test_binary_incr_impl("test_binary_incr",
1543 PROTOCOL_BINARY_CMD_INCREMENT);
1544 }
1545
test_binary_incrq(void)1546 static enum test_return test_binary_incrq(void) {
1547 return test_binary_incr_impl("test_binary_incrq",
1548 PROTOCOL_BINARY_CMD_INCREMENTQ);
1549 }
1550
test_binary_decr_impl(const char * key,uint8_t cmd)1551 static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1552 union {
1553 protocol_binary_request_no_extras request;
1554 protocol_binary_response_no_extras response_header;
1555 protocol_binary_response_decr response;
1556 char bytes[1024];
1557 } send, receive;
1558 size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1559 key, strlen(key), 1, 9, 0);
1560
1561 int ii;
1562 for (ii = 9; ii >= 0; --ii) {
1563 safe_send(send.bytes, len, false);
1564 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1565 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1566 validate_response_header(&receive.response_header, cmd,
1567 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1568 assert(ntohll(receive.response.message.body.value) == ii);
1569 }
1570 }
1571
1572 /* decr on 0 should not wrap */
1573 safe_send(send.bytes, len, false);
1574 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1575 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1576 validate_response_header(&receive.response_header, cmd,
1577 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1578 assert(ntohll(receive.response.message.body.value) == 0);
1579 } else {
1580 test_binary_noop();
1581 }
1582
1583 return TEST_PASS;
1584 }
1585
test_binary_decr(void)1586 static enum test_return test_binary_decr(void) {
1587 return test_binary_decr_impl("test_binary_decr",
1588 PROTOCOL_BINARY_CMD_DECREMENT);
1589 }
1590
test_binary_decrq(void)1591 static enum test_return test_binary_decrq(void) {
1592 return test_binary_decr_impl("test_binary_decrq",
1593 PROTOCOL_BINARY_CMD_DECREMENTQ);
1594 }
1595
test_binary_version(void)1596 static enum test_return test_binary_version(void) {
1597 union {
1598 protocol_binary_request_no_extras request;
1599 protocol_binary_response_no_extras response;
1600 char bytes[1024];
1601 } buffer;
1602
1603 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1604 PROTOCOL_BINARY_CMD_VERSION,
1605 NULL, 0, NULL, 0);
1606
1607 safe_send(buffer.bytes, len, false);
1608 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1609 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1610 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1611
1612 return TEST_PASS;
1613 }
1614
test_binary_flush_impl(const char * key,uint8_t cmd)1615 static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1616 union {
1617 protocol_binary_request_no_extras request;
1618 protocol_binary_response_no_extras response;
1619 char bytes[1024];
1620 } send, receive;
1621
1622 size_t len = storage_command(send.bytes, sizeof(send.bytes),
1623 PROTOCOL_BINARY_CMD_ADD,
1624 key, strlen(key), NULL, 0, 0, 0);
1625 safe_send(send.bytes, len, false);
1626 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1627 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1628 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1629
1630 len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1631 safe_send(send.bytes, len, false);
1632 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1633 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1634 validate_response_header(&receive.response, cmd,
1635 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1636 }
1637
1638 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1639 key, strlen(key), NULL, 0);
1640 safe_send(send.bytes, len, false);
1641 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1642 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1643 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1644
1645 sleep(2);
1646 safe_send(send.bytes, len, false);
1647 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1648 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1649 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1650
1651 int ii;
1652 for (ii = 0; ii < 2; ++ii) {
1653 len = storage_command(send.bytes, sizeof(send.bytes),
1654 PROTOCOL_BINARY_CMD_ADD,
1655 key, strlen(key), NULL, 0, 0, 0);
1656 safe_send(send.bytes, len, false);
1657 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1658 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1659 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1660
1661 len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1662 safe_send(send.bytes, len, false);
1663 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1664 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1665 validate_response_header(&receive.response, cmd,
1666 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1667 }
1668
1669 len = raw_command(send.bytes, sizeof(send.bytes),
1670 PROTOCOL_BINARY_CMD_GET,
1671 key, strlen(key), NULL, 0);
1672 safe_send(send.bytes, len, false);
1673 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1674 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1675 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1676 }
1677
1678 return TEST_PASS;
1679 }
1680
test_binary_flush(void)1681 static enum test_return test_binary_flush(void) {
1682 return test_binary_flush_impl("test_binary_flush",
1683 PROTOCOL_BINARY_CMD_FLUSH);
1684 }
1685
test_binary_flushq(void)1686 static enum test_return test_binary_flushq(void) {
1687 return test_binary_flush_impl("test_binary_flushq",
1688 PROTOCOL_BINARY_CMD_FLUSHQ);
1689 }
1690
test_binary_cas(void)1691 static enum test_return test_binary_cas(void) {
1692 union {
1693 protocol_binary_request_no_extras request;
1694 protocol_binary_response_no_extras response;
1695 char bytes[1024];
1696 } send, receive;
1697
1698 size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1699 0, false);
1700 safe_send(send.bytes, len, false);
1701 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1702 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1703 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1704
1705 uint64_t value = 0xdeadbeefdeadcafe;
1706 len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1707 "FOO", 3, &value, sizeof(value), 0, 0);
1708
1709 send.request.message.header.request.cas = 0x7ffffff;
1710 safe_send(send.bytes, len, false);
1711 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1712 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1713 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1714
1715 send.request.message.header.request.cas = 0x0;
1716 safe_send(send.bytes, len, false);
1717 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1718 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1719 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1720
1721 send.request.message.header.request.cas = receive.response.message.header.response.cas;
1722 safe_send(send.bytes, len, false);
1723 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1724 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1725 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1726
1727 send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
1728 safe_send(send.bytes, len, false);
1729 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1730 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1731 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1732 return TEST_PASS;
1733 }
1734
test_binary_concat_impl(const char * key,uint8_t cmd)1735 static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
1736 union {
1737 protocol_binary_request_no_extras request;
1738 protocol_binary_response_no_extras response;
1739 char bytes[1024];
1740 } send, receive;
1741 const char *value = "world";
1742
1743 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1744 key, strlen(key), value, strlen(value));
1745
1746
1747 safe_send(send.bytes, len, false);
1748 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1749 validate_response_header(&receive.response, cmd,
1750 PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1751
1752 len = storage_command(send.bytes, sizeof(send.bytes),
1753 PROTOCOL_BINARY_CMD_ADD,
1754 key, strlen(key), value, strlen(value), 0, 0);
1755 safe_send(send.bytes, len, false);
1756 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1757 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1758 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1759
1760 len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1761 key, strlen(key), value, strlen(value));
1762 safe_send(send.bytes, len, false);
1763
1764 if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1765 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1766 validate_response_header(&receive.response, cmd,
1767 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1768 } else {
1769 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
1770 NULL, 0, NULL, 0);
1771 safe_send(send.bytes, len, false);
1772 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1773 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
1774 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1775 }
1776
1777 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
1778 key, strlen(key), NULL, 0);
1779
1780 safe_send(send.bytes, len, false);
1781 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1782 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
1783 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1784
1785 assert(receive.response.message.header.response.keylen == strlen(key));
1786 assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
1787
1788 char *ptr = receive.bytes;
1789 ptr += sizeof(receive.response);
1790 ptr += 4;
1791
1792 assert(memcmp(ptr, key, strlen(key)) == 0);
1793 ptr += strlen(key);
1794 assert(memcmp(ptr, value, strlen(value)) == 0);
1795 ptr += strlen(value);
1796 assert(memcmp(ptr, value, strlen(value)) == 0);
1797
1798 return TEST_PASS;
1799 }
1800
test_binary_append(void)1801 static enum test_return test_binary_append(void) {
1802 return test_binary_concat_impl("test_binary_append",
1803 PROTOCOL_BINARY_CMD_APPEND);
1804 }
1805
test_binary_prepend(void)1806 static enum test_return test_binary_prepend(void) {
1807 return test_binary_concat_impl("test_binary_prepend",
1808 PROTOCOL_BINARY_CMD_PREPEND);
1809 }
1810
test_binary_appendq(void)1811 static enum test_return test_binary_appendq(void) {
1812 return test_binary_concat_impl("test_binary_appendq",
1813 PROTOCOL_BINARY_CMD_APPENDQ);
1814 }
1815
test_binary_prependq(void)1816 static enum test_return test_binary_prependq(void) {
1817 return test_binary_concat_impl("test_binary_prependq",
1818 PROTOCOL_BINARY_CMD_PREPENDQ);
1819 }
1820
test_binary_stat(void)1821 static enum test_return test_binary_stat(void) {
1822 union {
1823 protocol_binary_request_no_extras request;
1824 protocol_binary_response_no_extras response;
1825 char bytes[1024];
1826 } buffer;
1827
1828 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1829 PROTOCOL_BINARY_CMD_STAT,
1830 NULL, 0, NULL, 0);
1831
1832 safe_send(buffer.bytes, len, false);
1833 do {
1834 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1835 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
1836 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1837 } while (buffer.response.message.header.response.keylen != 0);
1838
1839 return TEST_PASS;
1840 }
1841
test_binary_scrub(void)1842 static enum test_return test_binary_scrub(void) {
1843 union {
1844 protocol_binary_request_no_extras request;
1845 protocol_binary_response_no_extras response;
1846 char bytes[1024];
1847 } buffer;
1848
1849 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1850 PROTOCOL_BINARY_CMD_SCRUB,
1851 NULL, 0, NULL, 0);
1852
1853 safe_send(buffer.bytes, len, false);
1854 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1855 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
1856 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1857
1858 return TEST_PASS;
1859 }
1860
1861
1862 volatile bool hickup_thread_running;
1863
binary_hickup_recv_verification_thread(void * arg)1864 static void *binary_hickup_recv_verification_thread(void *arg) {
1865 protocol_binary_response_no_extras *response = malloc(65*1024);
1866 if (response != NULL) {
1867 while (safe_recv_packet(response, 65*1024)) {
1868 /* Just validate the packet format */
1869 validate_response_header(response,
1870 response->message.header.response.opcode,
1871 response->message.header.response.status);
1872 }
1873 free(response);
1874 }
1875 hickup_thread_running = false;
1876 allow_closed_read = false;
1877 return NULL;
1878 }
1879
test_binary_pipeline_hickup_chunk(void * buffer,size_t buffersize)1880 static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
1881 off_t offset = 0;
1882 char *key[256];
1883 uint64_t value = 0xfeedfacedeadbeef;
1884
1885 while (hickup_thread_running &&
1886 offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
1887 union {
1888 protocol_binary_request_no_extras request;
1889 char bytes[65 * 1024];
1890 } command;
1891 uint8_t cmd = (uint8_t)(rand() & 0xff);
1892 size_t len;
1893 size_t keylen = (rand() % 250) + 1;
1894
1895 switch (cmd) {
1896 case PROTOCOL_BINARY_CMD_ADD:
1897 case PROTOCOL_BINARY_CMD_ADDQ:
1898 case PROTOCOL_BINARY_CMD_REPLACE:
1899 case PROTOCOL_BINARY_CMD_REPLACEQ:
1900 case PROTOCOL_BINARY_CMD_SET:
1901 case PROTOCOL_BINARY_CMD_SETQ:
1902 len = storage_command(command.bytes, sizeof(command.bytes), cmd,
1903 key, keylen , &value, sizeof(value),
1904 0, 0);
1905 break;
1906 case PROTOCOL_BINARY_CMD_APPEND:
1907 case PROTOCOL_BINARY_CMD_APPENDQ:
1908 case PROTOCOL_BINARY_CMD_PREPEND:
1909 case PROTOCOL_BINARY_CMD_PREPENDQ:
1910 len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1911 key, keylen, &value, sizeof(value));
1912 break;
1913 case PROTOCOL_BINARY_CMD_FLUSH:
1914 case PROTOCOL_BINARY_CMD_FLUSHQ:
1915 len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1916 NULL, 0, NULL, 0);
1917 break;
1918 case PROTOCOL_BINARY_CMD_NOOP:
1919 len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1920 NULL, 0, NULL, 0);
1921 break;
1922 case PROTOCOL_BINARY_CMD_DELETE:
1923 case PROTOCOL_BINARY_CMD_DELETEQ:
1924 len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1925 key, keylen, NULL, 0);
1926 break;
1927 case PROTOCOL_BINARY_CMD_DECREMENT:
1928 case PROTOCOL_BINARY_CMD_DECREMENTQ:
1929 case PROTOCOL_BINARY_CMD_INCREMENT:
1930 case PROTOCOL_BINARY_CMD_INCREMENTQ:
1931 len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
1932 key, keylen, 1, 0, 0);
1933 break;
1934 case PROTOCOL_BINARY_CMD_VERSION:
1935 len = raw_command(command.bytes, sizeof(command.bytes),
1936 PROTOCOL_BINARY_CMD_VERSION,
1937 NULL, 0, NULL, 0);
1938 break;
1939 case PROTOCOL_BINARY_CMD_GET:
1940 case PROTOCOL_BINARY_CMD_GETK:
1941 case PROTOCOL_BINARY_CMD_GETKQ:
1942 case PROTOCOL_BINARY_CMD_GETQ:
1943 len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1944 key, keylen, NULL, 0);
1945 break;
1946
1947 case PROTOCOL_BINARY_CMD_STAT:
1948 len = raw_command(command.bytes, sizeof(command.bytes),
1949 PROTOCOL_BINARY_CMD_STAT,
1950 NULL, 0, NULL, 0);
1951 break;
1952
1953 default:
1954 // don't run commands we don't know
1955 continue;
1956 }
1957
1958 if ((len + offset) < buffersize) {
1959 memcpy(((char*)buffer) + offset, command.bytes, len);
1960 offset += len;
1961 } else {
1962 break;
1963 }
1964 }
1965 safe_send(buffer, offset, true);
1966
1967 return TEST_PASS;
1968 }
1969
test_binary_pipeline_hickup(void)1970 static enum test_return test_binary_pipeline_hickup(void)
1971 {
1972 size_t buffersize = 65 * 1024;
1973 void *buffer = malloc(buffersize);
1974 int ii;
1975
1976 pthread_t tid;
1977 int ret;
1978 allow_closed_read = true;
1979 hickup_thread_running = true;
1980 if ((ret = pthread_create(&tid, NULL,
1981 binary_hickup_recv_verification_thread, NULL)) != 0) {
1982 fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
1983 return TEST_FAIL;
1984 }
1985
1986 /* Allow the thread to start */
1987 usleep(250);
1988
1989 srand((int)time(NULL));
1990 for (ii = 0; ii < 2; ++ii) {
1991 test_binary_pipeline_hickup_chunk(buffer, buffersize);
1992 }
1993
1994 /* send quitq to shut down the read thread ;-) */
1995 size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
1996 NULL, 0, NULL, 0);
1997 safe_send(buffer, len, false);
1998
1999 pthread_join(tid, NULL);
2000 free(buffer);
2001 return TEST_PASS;
2002 }
2003
test_binary_verbosity(void)2004 static enum test_return test_binary_verbosity(void) {
2005 union {
2006 protocol_binary_request_verbosity request;
2007 protocol_binary_response_no_extras response;
2008 char bytes[1024];
2009 } buffer;
2010
2011 for (int ii = 10; ii > -1; --ii) {
2012 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2013 PROTOCOL_BINARY_CMD_VERBOSITY,
2014 NULL, 0, NULL, 0);
2015 buffer.request.message.header.request.extlen = 4;
2016 buffer.request.message.header.request.bodylen = ntohl(4);
2017 buffer.request.message.body.level = (uint32_t)ntohl(ii);
2018 safe_send(buffer.bytes, len + sizeof(4), false);
2019 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2020 validate_response_header(&buffer.response,
2021 PROTOCOL_BINARY_CMD_VERBOSITY,
2022 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2023 }
2024
2025 return TEST_PASS;
2026 }
2027
test_issue_101(void)2028 static enum test_return test_issue_101(void) {
2029 const int max = 2;
2030 enum test_return ret = TEST_PASS;
2031 int fds[max];
2032 int ii = 0;
2033 pid_t child = 0;
2034
2035 if (getenv("DONT_SKIP_TEST_101") == NULL) {
2036 return TEST_SKIP;
2037 }
2038
2039 const char *command = "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
2040 size_t cmdlen = strlen(command);
2041
2042 server_pid = start_server(&port, false, 1000);
2043
2044 for (ii = 0; ii < max; ++ii) {
2045 fds[ii] = connect_server("127.0.0.1", port, true);
2046 assert(fds[ii] > 0);
2047 }
2048
2049 /* Send command on the connection until it blocks */
2050 for (ii = 0; ii < max; ++ii) {
2051 bool more = true;
2052 do {
2053 ssize_t err = send(fds[ii], command, cmdlen, 0);
2054 if (err == -1) {
2055 switch (errno) {
2056 case EINTR:
2057 break;
2058 case ENOMEM:
2059 case EWOULDBLOCK:
2060 more = false;
2061 break;
2062 default:
2063 ret = TEST_FAIL;
2064 goto cleanup;
2065 }
2066 }
2067 } while (more);
2068 }
2069
2070 child = fork();
2071 if (child == (pid_t)-1) {
2072 abort();
2073 } else if (child > 0) {
2074 int stat;
2075 pid_t c;
2076 while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
2077 assert(c == child);
2078 assert(stat == 0);
2079 } else {
2080 sock = connect_server("127.0.0.1", port, false);
2081 ret = test_binary_noop();
2082 close(sock);
2083 exit(0);
2084 }
2085
2086 cleanup:
2087 /* close all connections */
2088 for (ii = 0; ii < max; ++ii) {
2089 close(fds[ii]);
2090 }
2091
2092 assert(kill(server_pid, SIGTERM) == 0);
2093
2094 return ret;
2095 }
2096
2097 typedef enum test_return (*TEST_FUNC)(void);
2098 struct testcase {
2099 const char *description;
2100 TEST_FUNC function;
2101 };
2102
2103 struct testcase testcases[] = {
2104 { "cache_create", cache_create_test },
2105 { "cache_constructor", cache_constructor_test },
2106 { "cache_constructor_fail", cache_fail_constructor_test },
2107 { "cache_destructor", cache_destructor_test },
2108 { "cache_reuse", cache_reuse_test },
2109 { "cache_redzone", cache_redzone_test },
2110 { "issue_161", test_issue_161 },
2111 { "strtof", test_safe_strtof },
2112 { "strtol", test_safe_strtol },
2113 { "strtoll", test_safe_strtoll },
2114 { "strtoul", test_safe_strtoul },
2115 { "strtoull", test_safe_strtoull },
2116 { "issue_44", test_issue_44 },
2117 { "vperror", test_vperror },
2118 { "issue_101", test_issue_101 },
2119 { "config_parser", test_config_parser },
2120 /* The following tests all run towards the same server */
2121 { "start_server", start_memcached_server },
2122 { "issue_92", test_issue_92 },
2123 { "issue_102", test_issue_102 },
2124 { "binary_noop", test_binary_noop },
2125 { "binary_quit", test_binary_quit },
2126 { "binary_quitq", test_binary_quitq },
2127 { "binary_set", test_binary_set },
2128 { "binary_setq", test_binary_setq },
2129 { "binary_add", test_binary_add },
2130 { "binary_addq", test_binary_addq },
2131 { "binary_replace", test_binary_replace },
2132 { "binary_replaceq", test_binary_replaceq },
2133 { "binary_delete", test_binary_delete },
2134 { "binary_deleteq", test_binary_deleteq },
2135 { "binary_get", test_binary_get },
2136 { "binary_getq", test_binary_getq },
2137 { "binary_getk", test_binary_getk },
2138 { "binary_getkq", test_binary_getkq },
2139 { "binary_incr", test_binary_incr },
2140 { "binary_incrq", test_binary_incrq },
2141 { "binary_decr", test_binary_decr },
2142 { "binary_decrq", test_binary_decrq },
2143 { "binary_version", test_binary_version },
2144 { "binary_flush", test_binary_flush },
2145 { "binary_flushq", test_binary_flushq },
2146 { "binary_cas", test_binary_cas },
2147 { "binary_append", test_binary_append },
2148 { "binary_appendq", test_binary_appendq },
2149 { "binary_prepend", test_binary_prepend },
2150 { "binary_prependq", test_binary_prependq },
2151 { "binary_stat", test_binary_stat },
2152 { "binary_scrub", test_binary_scrub },
2153 { "binary_verbosity", test_binary_verbosity },
2154 { "binary_pipeline_hickup", test_binary_pipeline_hickup },
2155 { "stop_server", stop_memcached_server },
2156 { NULL, NULL }
2157 };
2158
main(int argc,char ** argv)2159 int main(int argc, char **argv)
2160 {
2161 int exitcode = 0;
2162 int ii = 0, num_cases = 0;
2163
2164 /* Use unbuffered stdio */
2165 setbuf(stdout, NULL);
2166 setbuf(stderr, NULL);
2167
2168 for (num_cases = 0; testcases[num_cases].description; num_cases++) {
2169 /* Just counting */
2170 }
2171
2172 printf("1..%d\n", num_cases);
2173
2174 for (ii = 0; testcases[ii].description != NULL; ++ii) {
2175 fflush(stdout);
2176 #if 0
2177 /* the test program shouldn't run longer than 10 minutes... */
2178 alarm(600);
2179 #endif
2180 enum test_return ret = testcases[ii].function();
2181 if (ret == TEST_SKIP) {
2182 fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
2183 } else if (ret == TEST_PASS) {
2184 fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
2185 } else {
2186 fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
2187 exitcode = 1;
2188 }
2189 fflush(stdout);
2190 }
2191
2192 return exitcode;
2193 }
2194