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