2
* Copyright (C) 2006-2009 Brian Aker
5
* Use and distribution licensed under the BSD license. See
6
* the COPYING file in the parent directory for full text.
12
/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
20
#include "poll/poll.h"
33
#include <sys/types.h>
36
#include <libmemcached-1.0/memcached.h>
37
#include <libmemcached/socket.hpp>
38
#include <libmemcached/memcached/protocol_binary.h>
39
#include <libmemcached/byteorder.h>
40
#include <clients/utilities.h>
43
/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
44
* optimize the conversion functions, but the prototypes generate warnings
45
* from gcc. The conversion methods isn't the bottleneck for my app, so
46
* just remove the warnings by undef'ing the optimization ..
52
/* Should we generate coredumps when we enounter an error (-c) */
53
static bool do_core= false;
54
/* connection to the server */
55
static memcached_socket_t sock;
56
/* Should the output from test failures be verbose or quiet? */
57
static bool verbose= false;
59
/* The number of seconds to wait for an IO-operation */
60
static int timeout= 2;
63
* Instead of having to cast between the different datatypes we create
64
* a union of all of the different types of pacages we want to send.
65
* A lot of the different commands use the same packet layout, so I'll
66
* just define the different types I need. The typedefs only contain
67
* the header of the message, so we need some space for keys and body
68
* To avoid to have to do multiple writes, lets add a chunk of memory
69
* to use. 1k should be more than enough for header, key and body.
73
protocol_binary_request_no_extras plain;
74
protocol_binary_request_flush flush;
75
protocol_binary_request_incr incr;
76
protocol_binary_request_set set;
82
protocol_binary_response_no_extras plain;
83
protocol_binary_response_incr incr;
84
protocol_binary_response_decr decr;
90
TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
94
* Try to get an addrinfo struct for a given port on a given host
96
static struct addrinfo *lookuphost(const char *hostname, const char *port)
98
struct addrinfo *ai= 0;
99
struct addrinfo hints;
100
memset(&hints, 0, sizeof(struct addrinfo));
101
hints.ai_family=AF_UNSPEC;
102
hints.ai_protocol=IPPROTO_TCP;
103
hints.ai_socktype=SOCK_STREAM;
105
int error= getaddrinfo(hostname, port, &hints, &ai);
108
if (error != EAI_SYSTEM)
109
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
111
perror("getaddrinfo()");
118
* Set the socket in nonblocking mode
119
* @return -1 if failure, the socket otherwise
121
static memcached_socket_t set_noblock(void)
125
if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
127
perror("Failed to set nonblocking io");
129
return INVALID_SOCKET;
132
int flags= fcntl(sock, F_GETFL, 0);
135
perror("Failed to get socket flags");
136
memcached_close_socket(sock);
137
return INVALID_SOCKET;
140
if ((flags & O_NONBLOCK) != O_NONBLOCK)
142
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
144
perror("Failed to set socket to nonblocking mode");
145
memcached_close_socket(sock);
146
return INVALID_SOCKET;
154
* Try to open a connection to the server
155
* @param hostname the name of the server to connect to
156
* @param port the port number (or service) to connect to
157
* @return positive integer if success, -1 otherwise
159
static memcached_socket_t connect_server(const char *hostname, const char *port)
161
struct addrinfo *ai= lookuphost(hostname, port);
162
sock= INVALID_SOCKET;
165
if ((sock= socket(ai->ai_family, ai->ai_socktype,
166
ai->ai_protocol)) != INVALID_SOCKET)
168
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
170
fprintf(stderr, "Failed to connect socket: %s\n",
171
strerror(get_socket_errno()));
173
sock= INVALID_SOCKET;
181
fprintf(stderr, "Failed to create socket: %s\n",
182
strerror(get_socket_errno()));
190
static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
194
if (direction == POLLOUT)
196
ret= send(fd, buf, len, 0);
200
ret= recv(fd, buf, len, 0);
203
if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK)
206
memset(&fds, 0, sizeof(struct pollfd));
207
fds.events= direction;
210
int err= poll(&fds, 1, timeout * 1000);
213
if (direction == POLLOUT)
215
ret= send(fd, buf, len, 0);
219
ret= recv(fd, buf, len, 0);
228
perror("Failed to poll");
237
* Ensure that an expression is true. If it isn't print out a message similar
238
* to assert() and create a coredump if the user wants that. If not an error
239
* message is returned.
242
static enum test_return ensure(bool val, const char *expression, const char *file, int line)
248
fprintf(stderr, "\n%s:%d: %s", file, line, expression);
262
#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
263
#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
266
* Send a chunk of memory over the socket (retry if the call is iterrupted
268
static enum test_return retry_write(const void* buf, size_t len)
271
const char* ptr= static_cast<const char *>(buf);
275
size_t num_bytes= len - offset;
276
ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
279
verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
286
} while (offset < len);
292
* Resend a packet to the server (All fields in the command header should
293
* be in network byte order)
295
static enum test_return resend_packet(command *cmd)
297
size_t length= sizeof (protocol_binary_request_no_extras) +
298
ntohl(cmd->plain.message.header.request.bodylen);
300
execute(retry_write(cmd, length));
305
* Send a command to the server. The command header needs to be updated
306
* to network byte order
308
static enum test_return send_packet(command *cmd)
310
/* Fix the byteorder of the header */
311
cmd->plain.message.header.request.keylen=
312
ntohs(cmd->plain.message.header.request.keylen);
313
cmd->plain.message.header.request.bodylen=
314
ntohl(cmd->plain.message.header.request.bodylen);
315
cmd->plain.message.header.request.cas=
316
memcached_ntohll(cmd->plain.message.header.request.cas);
318
execute(resend_packet(cmd));
323
* Read a fixed length chunk of data from the server
325
static enum test_return retry_read(void *buf, size_t len)
330
ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
333
fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
334
verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
343
} while (offset < len);
349
* Receive a response from the server and conver the fields in the header
350
* to local byte order
352
static enum test_return recv_packet(response *rsp)
354
execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
356
/* Fix the byte order in the packet header */
357
rsp->plain.message.header.response.keylen=
358
ntohs(rsp->plain.message.header.response.keylen);
359
rsp->plain.message.header.response.status=
360
ntohs(rsp->plain.message.header.response.status);
361
rsp->plain.message.header.response.bodylen=
362
ntohl(rsp->plain.message.header.response.bodylen);
363
rsp->plain.message.header.response.cas=
364
memcached_ntohll(rsp->plain.message.header.response.cas);
366
size_t bodysz= rsp->plain.message.header.response.bodylen;
368
execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
374
* Create a storage command (add, set, replace etc)
376
* @param cmd destination buffer
377
* @param cc the storage command to create
378
* @param key the key to store
379
* @param keylen the length of the key
380
* @param dta the data to store with the key
381
* @param dtalen the length of the data to store with the key
382
* @param flags the flags to store along with the key
383
* @param exptime the expiry time for the key
385
static void storage_command(command *cmd,
394
/* all of the storage commands use the same command layout */
395
protocol_binary_request_set *request= &cmd->set;
397
memset(request, 0, sizeof (*request));
398
request->message.header.request.magic= PROTOCOL_BINARY_REQ;
399
request->message.header.request.opcode= cc;
400
request->message.header.request.keylen= (uint16_t)keylen;
401
request->message.header.request.extlen= 8;
402
request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
403
request->message.header.request.opaque= 0xdeadbeef;
404
request->message.body.flags= flags;
405
request->message.body.expiration= exptime;
407
off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
408
memcpy(cmd->bytes + key_offset, key, keylen);
410
memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
414
* Create a basic command to send to the server
415
* @param cmd destination buffer
416
* @param cc the command to create
417
* @param key the key to store
418
* @param keylen the length of the key
419
* @param dta the data to store with the key
420
* @param dtalen the length of the data to store with the key
422
static void raw_command(command *cmd,
429
/* all of the storage commands use the same command layout */
430
memset(cmd, 0, sizeof (*cmd));
431
cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
432
cmd->plain.message.header.request.opcode= cc;
433
cmd->plain.message.header.request.keylen= (uint16_t)keylen;
434
cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
435
cmd->plain.message.header.request.opaque= 0xdeadbeef;
437
off_t key_offset= sizeof (protocol_binary_request_no_extras);
440
memcpy(cmd->bytes + key_offset, key, keylen);
443
memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
447
* Create the flush command
448
* @param cmd destination buffer
449
* @param cc the command to create (FLUSH/FLUSHQ)
450
* @param exptime when to flush
451
* @param use_extra to force using of the extra field?
453
static void flush_command(command *cmd,
454
uint8_t cc, uint32_t exptime, bool use_extra)
456
memset(cmd, 0, sizeof (cmd->flush));
457
cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
458
cmd->flush.message.header.request.opcode= cc;
459
cmd->flush.message.header.request.opaque= 0xdeadbeef;
461
if (exptime != 0 || use_extra)
463
cmd->flush.message.header.request.extlen= 4;
464
cmd->flush.message.body.expiration= htonl(exptime);
465
cmd->flush.message.header.request.bodylen= 4;
470
* Create a incr/decr command
471
* @param cc the cmd to create (FLUSH/FLUSHQ)
472
* @param key the key to operate on
473
* @param keylen the number of bytes in the key
474
* @param delta the number to add/subtract
475
* @param initial the initial value if the key doesn't exist
476
* @param exptime when the key should expire if it isn't set
478
static void arithmetic_command(command *cmd,
486
memset(cmd, 0, sizeof (cmd->incr));
487
cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
488
cmd->incr.message.header.request.opcode= cc;
489
cmd->incr.message.header.request.keylen= (uint16_t)keylen;
490
cmd->incr.message.header.request.extlen= 20;
491
cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
492
cmd->incr.message.header.request.opaque= 0xdeadbeef;
493
cmd->incr.message.body.delta= memcached_htonll(delta);
494
cmd->incr.message.body.initial= memcached_htonll(initial);
495
cmd->incr.message.body.expiration= htonl(exptime);
497
off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
498
memcpy(cmd->bytes + key_offset, key, keylen);
502
* Validate the response header from the server
503
* @param rsp the response to check
504
* @param cc the expected command
505
* @param status the expected status
507
static enum test_return do_validate_response_header(response *rsp,
508
uint8_t cc, uint16_t status)
510
verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
511
verify(rsp->plain.message.header.response.opcode == cc);
512
verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
513
verify(rsp->plain.message.header.response.status == status);
514
verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
516
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
519
case PROTOCOL_BINARY_CMD_ADDQ:
520
case PROTOCOL_BINARY_CMD_APPENDQ:
521
case PROTOCOL_BINARY_CMD_DECREMENTQ:
522
case PROTOCOL_BINARY_CMD_DELETEQ:
523
case PROTOCOL_BINARY_CMD_FLUSHQ:
524
case PROTOCOL_BINARY_CMD_INCREMENTQ:
525
case PROTOCOL_BINARY_CMD_PREPENDQ:
526
case PROTOCOL_BINARY_CMD_QUITQ:
527
case PROTOCOL_BINARY_CMD_REPLACEQ:
528
case PROTOCOL_BINARY_CMD_SETQ:
529
verify("Quiet command shouldn't return on success" == NULL);
535
case PROTOCOL_BINARY_CMD_ADD:
536
case PROTOCOL_BINARY_CMD_REPLACE:
537
case PROTOCOL_BINARY_CMD_SET:
538
case PROTOCOL_BINARY_CMD_APPEND:
539
case PROTOCOL_BINARY_CMD_PREPEND:
540
verify(rsp->plain.message.header.response.keylen == 0);
541
verify(rsp->plain.message.header.response.extlen == 0);
542
verify(rsp->plain.message.header.response.bodylen == 0);
543
verify(rsp->plain.message.header.response.cas != 0);
545
case PROTOCOL_BINARY_CMD_FLUSH:
546
case PROTOCOL_BINARY_CMD_NOOP:
547
case PROTOCOL_BINARY_CMD_QUIT:
548
case PROTOCOL_BINARY_CMD_DELETE:
549
verify(rsp->plain.message.header.response.keylen == 0);
550
verify(rsp->plain.message.header.response.extlen == 0);
551
verify(rsp->plain.message.header.response.bodylen == 0);
552
verify(rsp->plain.message.header.response.cas == 0);
555
case PROTOCOL_BINARY_CMD_DECREMENT:
556
case PROTOCOL_BINARY_CMD_INCREMENT:
557
verify(rsp->plain.message.header.response.keylen == 0);
558
verify(rsp->plain.message.header.response.extlen == 0);
559
verify(rsp->plain.message.header.response.bodylen == 8);
560
verify(rsp->plain.message.header.response.cas != 0);
563
case PROTOCOL_BINARY_CMD_STAT:
564
verify(rsp->plain.message.header.response.extlen == 0);
565
/* key and value exists in all packets except in the terminating */
566
verify(rsp->plain.message.header.response.cas == 0);
569
case PROTOCOL_BINARY_CMD_VERSION:
570
verify(rsp->plain.message.header.response.keylen == 0);
571
verify(rsp->plain.message.header.response.extlen == 0);
572
verify(rsp->plain.message.header.response.bodylen != 0);
573
verify(rsp->plain.message.header.response.cas == 0);
576
case PROTOCOL_BINARY_CMD_GET:
577
case PROTOCOL_BINARY_CMD_GETQ:
578
verify(rsp->plain.message.header.response.keylen == 0);
579
verify(rsp->plain.message.header.response.extlen == 4);
580
verify(rsp->plain.message.header.response.cas != 0);
583
case PROTOCOL_BINARY_CMD_GETK:
584
case PROTOCOL_BINARY_CMD_GETKQ:
585
verify(rsp->plain.message.header.response.keylen != 0);
586
verify(rsp->plain.message.header.response.extlen == 4);
587
verify(rsp->plain.message.header.response.cas != 0);
591
/* Undefined command code */
597
verify(rsp->plain.message.header.response.cas == 0);
598
verify(rsp->plain.message.header.response.extlen == 0);
599
if (cc != PROTOCOL_BINARY_CMD_GETK)
601
verify(rsp->plain.message.header.response.keylen == 0);
608
/* We call verify(validate_response_header), but that macro
609
* expects a boolean expression, and the function returns
610
* an enum.... Let's just create a macro to avoid cluttering
611
* the code with all of the == TEST_PASS ;-)
613
#define validate_response_header(a,b,c) \
614
do_validate_response_header(a,b,c) == TEST_PASS
617
static enum test_return send_binary_noop(void)
620
raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
621
execute(send_packet(&cmd));
625
static enum test_return receive_binary_noop(void)
628
execute(recv_packet(&rsp));
629
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
630
PROTOCOL_BINARY_RESPONSE_SUCCESS));
634
static enum test_return test_binary_noop(void)
636
execute(send_binary_noop());
637
execute(receive_binary_noop());
641
static enum test_return test_binary_quit_impl(uint8_t cc)
645
raw_command(&cmd, cc, NULL, 0, NULL, 0);
647
execute(send_packet(&cmd));
648
if (cc == PROTOCOL_BINARY_CMD_QUIT)
650
execute(recv_packet(&rsp));
651
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
652
PROTOCOL_BINARY_RESPONSE_SUCCESS));
655
/* Socket should be closed now, read should return EXIT_SUCCESS */
656
verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
658
return TEST_PASS_RECONNECT;
661
static enum test_return test_binary_quit(void)
663
return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
666
static enum test_return test_binary_quitq(void)
668
return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
671
static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
676
uint64_t value= 0xdeadbeefdeadcafeULL;
677
storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
679
/* set should always work */
680
for (int ii= 0; ii < 10; ii++)
684
execute(send_packet(&cmd));
688
execute(resend_packet(&cmd));
691
if (cc == PROTOCOL_BINARY_CMD_SET)
693
execute(recv_packet(&rsp));
694
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
697
execute(test_binary_noop());
701
* We need to get the current CAS id, and at this time we haven't
702
* verified that we have a working get
704
if (cc == PROTOCOL_BINARY_CMD_SETQ)
706
cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
707
execute(resend_packet(&cmd));
708
execute(recv_packet(&rsp));
709
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
710
PROTOCOL_BINARY_RESPONSE_SUCCESS));
711
cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
714
/* try to set with the correct CAS value */
715
cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
716
execute(resend_packet(&cmd));
717
if (cc == PROTOCOL_BINARY_CMD_SET)
719
execute(recv_packet(&rsp));
720
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
723
execute(test_binary_noop());
725
/* try to set with an incorrect CAS value */
726
cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
727
execute(resend_packet(&cmd));
728
execute(send_binary_noop());
729
execute(recv_packet(&rsp));
730
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
731
execute(receive_binary_noop());
736
static enum test_return test_binary_set(void)
738
return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
741
static enum test_return test_binary_setq(void)
743
return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
746
static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
750
uint64_t value= 0xdeadbeefdeadcafeULL;
751
storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
753
/* first add should work, rest of them should fail (even with cas
755
for (int ii=0; ii < 10; ii++)
758
execute(send_packet(&cmd));
760
execute(resend_packet(&cmd));
762
if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
764
uint16_t expected_result;
766
expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
768
expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
770
execute(send_binary_noop());
771
execute(recv_packet(&rsp));
772
execute(receive_binary_noop());
773
verify(validate_response_header(&rsp, cc, expected_result));
776
execute(test_binary_noop());
782
static enum test_return test_binary_add(void)
784
return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
787
static enum test_return test_binary_addq(void)
789
return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
792
static enum test_return binary_set_item(const char *key, const char *value)
796
storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
797
value, strlen(value), 0, 0);
798
execute(send_packet(&cmd));
799
execute(recv_packet(&rsp));
800
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
801
PROTOCOL_BINARY_RESPONSE_SUCCESS));
805
static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
809
uint64_t value= 0xdeadbeefdeadcafeULL;
810
storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
812
/* first replace should fail, successive should succeed (when the
814
for (int ii= 0; ii < 10; ii++)
818
execute(send_packet(&cmd));
822
execute(resend_packet(&cmd));
825
if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
827
uint16_t expected_result;
830
expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
834
expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
837
execute(send_binary_noop());
838
execute(recv_packet(&rsp));
839
execute(receive_binary_noop());
840
verify(validate_response_header(&rsp, cc, expected_result));
843
execute(binary_set_item(key, key));
847
execute(test_binary_noop());
851
/* verify that replace with CAS value works! */
852
cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
853
execute(resend_packet(&cmd));
855
if (cc == PROTOCOL_BINARY_CMD_REPLACE)
857
execute(recv_packet(&rsp));
858
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
861
execute(test_binary_noop());
863
/* try to set with an incorrect CAS value */
864
cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
865
execute(resend_packet(&cmd));
866
execute(send_binary_noop());
867
execute(recv_packet(&rsp));
868
execute(receive_binary_noop());
869
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
874
static enum test_return test_binary_replace(void)
876
return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
879
static enum test_return test_binary_replaceq(void)
881
return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
884
static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
888
raw_command(&cmd, cc, key, strlen(key), NULL, 0);
890
/* The delete shouldn't work the first time, because the item isn't there */
891
execute(send_packet(&cmd));
892
execute(send_binary_noop());
893
execute(recv_packet(&rsp));
894
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
895
execute(receive_binary_noop());
896
execute(binary_set_item(key, key));
898
/* The item should be present now, resend*/
899
execute(resend_packet(&cmd));
900
if (cc == PROTOCOL_BINARY_CMD_DELETE)
902
execute(recv_packet(&rsp));
903
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
906
execute(test_binary_noop());
911
static enum test_return test_binary_delete(void)
913
return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
916
static enum test_return test_binary_deleteq(void)
918
return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
921
static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
926
raw_command(&cmd, cc, key, strlen(key), NULL, 0);
927
execute(send_packet(&cmd));
928
execute(send_binary_noop());
930
if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
932
execute(recv_packet(&rsp));
933
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
936
execute(receive_binary_noop());
938
execute(binary_set_item(key, key));
939
execute(resend_packet(&cmd));
940
execute(send_binary_noop());
942
execute(recv_packet(&rsp));
943
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
944
execute(receive_binary_noop());
949
static enum test_return test_binary_get(void)
951
return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
954
static enum test_return test_binary_getk(void)
956
return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
959
static enum test_return test_binary_getq(void)
961
return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
964
static enum test_return test_binary_getkq(void)
966
return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
969
static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
973
arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
976
for (ii= 0; ii < 10; ++ii)
979
execute(send_packet(&cmd));
981
execute(resend_packet(&cmd));
983
if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
985
execute(recv_packet(&rsp));
986
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
987
verify(memcached_ntohll(rsp.incr.message.body.value) == ii);
990
execute(test_binary_noop());
993
/* @todo add incorrect CAS */
997
static enum test_return test_binary_incr(void)
999
return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
1002
static enum test_return test_binary_incrq(void)
1004
return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
1007
static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
1011
arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
1014
for (ii= 9; ii > -1; --ii)
1017
execute(send_packet(&cmd));
1019
execute(resend_packet(&cmd));
1021
if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
1023
execute(recv_packet(&rsp));
1024
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
1025
verify(memcached_ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
1028
execute(test_binary_noop());
1031
/* decr 0 should not wrap */
1032
execute(resend_packet(&cmd));
1033
if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
1035
execute(recv_packet(&rsp));
1036
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
1037
verify(memcached_ntohll(rsp.decr.message.body.value) == 0);
1041
/* @todo get the value and verify! */
1045
/* @todo add incorrect cas */
1046
execute(test_binary_noop());
1050
static enum test_return test_binary_decr(void)
1052
return test_binary_decr_impl("test_binary_decr",
1053
PROTOCOL_BINARY_CMD_DECREMENT);
1056
static enum test_return test_binary_decrq(void)
1058
return test_binary_decr_impl("test_binary_decrq",
1059
PROTOCOL_BINARY_CMD_DECREMENTQ);
1062
static enum test_return test_binary_version(void)
1066
raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
1068
execute(send_packet(&cmd));
1069
execute(recv_packet(&rsp));
1070
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
1071
PROTOCOL_BINARY_RESPONSE_SUCCESS));
1076
static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
1081
for (int ii= 0; ii < 2; ++ii)
1083
execute(binary_set_item(key, key));
1084
flush_command(&cmd, cc, 0, ii == 0);
1085
execute(send_packet(&cmd));
1087
if (cc == PROTOCOL_BINARY_CMD_FLUSH)
1089
execute(recv_packet(&rsp));
1090
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
1093
execute(test_binary_noop());
1095
raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
1096
execute(send_packet(&cmd));
1097
execute(recv_packet(&rsp));
1098
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
1099
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
1105
static enum test_return test_binary_flush(void)
1107
return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
1110
static enum test_return test_binary_flushq(void)
1112
return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
1115
static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
1121
if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
1130
execute(binary_set_item(key, value));
1132
if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
1141
raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
1142
execute(send_packet(&cmd));
1143
if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
1145
execute(recv_packet(&rsp));
1146
verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
1150
execute(test_binary_noop());
1153
raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
1154
execute(send_packet(&cmd));
1155
execute(recv_packet(&rsp));
1156
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
1157
PROTOCOL_BINARY_RESPONSE_SUCCESS));
1158
verify(rsp.plain.message.header.response.bodylen - 4 == 11);
1159
verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
1164
static enum test_return test_binary_append(void)
1166
return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
1169
static enum test_return test_binary_prepend(void)
1171
return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
1174
static enum test_return test_binary_appendq(void)
1176
return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
1179
static enum test_return test_binary_prependq(void)
1181
return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
1184
static enum test_return test_binary_stat(void)
1189
raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
1190
execute(send_packet(&cmd));
1194
execute(recv_packet(&rsp));
1195
verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
1196
PROTOCOL_BINARY_RESPONSE_SUCCESS));
1197
} while (rsp.plain.message.header.response.keylen != 0);
1202
static enum test_return send_string(const char *cmd)
1204
execute(retry_write(cmd, strlen(cmd)));
1208
static enum test_return receive_line(char *buffer, size_t size)
1211
while (offset < size)
1213
execute(retry_read(buffer + offset, 1));
1214
if (buffer[offset] == '\n')
1216
if (offset + 1 < size)
1218
buffer[offset + 1]= '\0';
1230
static enum test_return receive_response(const char *msg) {
1232
execute(receive_line(buffer, sizeof(buffer)));
1233
if (strcmp(msg, buffer) != 0) {
1234
fprintf(stderr, "[%s]\n", buffer);
1236
verify(strcmp(msg, buffer) == 0);
1240
static enum test_return receive_error_response(void)
1243
execute(receive_line(buffer, sizeof(buffer)));
1244
verify(strncmp(buffer, "ERROR", 5) == 0 ||
1245
strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
1246
strncmp(buffer, "SERVER_ERROR", 12) == 0);
1250
static enum test_return test_ascii_quit(void)
1252
/* Verify that quit handles unknown options */
1253
execute(send_string("quit foo bar\r\n"));
1254
execute(receive_error_response());
1256
/* quit doesn't support noreply */
1257
execute(send_string("quit noreply\r\n"));
1258
execute(receive_error_response());
1260
/* Verify that quit works */
1261
execute(send_string("quit\r\n"));
1263
/* Socket should be closed now, read should return EXIT_SUCCESS */
1265
verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
1266
return TEST_PASS_RECONNECT;
1270
static enum test_return test_ascii_version(void)
1272
/* Verify that version command handles unknown options */
1273
execute(send_string("version foo bar\r\n"));
1274
execute(receive_error_response());
1276
/* version doesn't support noreply */
1277
execute(send_string("version noreply\r\n"));
1278
execute(receive_error_response());
1280
/* Verify that verify works */
1281
execute(send_string("version\r\n"));
1283
execute(receive_line(buffer, sizeof(buffer)));
1284
verify(strncmp(buffer, "VERSION ", 8) == 0);
1289
static enum test_return test_ascii_verbosity(void)
1291
/* This command does not adhere to the spec! */
1292
execute(send_string("verbosity foo bar my\r\n"));
1293
execute(receive_error_response());
1295
execute(send_string("verbosity noreply\r\n"));
1296
execute(receive_error_response());
1298
execute(send_string("verbosity 0 noreply\r\n"));
1299
execute(test_ascii_version());
1301
execute(send_string("verbosity\r\n"));
1302
execute(receive_error_response());
1304
execute(send_string("verbosity 1\r\n"));
1305
execute(receive_response("OK\r\n"));
1307
execute(send_string("verbosity 0\r\n"));
1308
execute(receive_response("OK\r\n"));
1315
static enum test_return test_ascii_set_impl(const char* key, bool noreply)
1317
/* @todo add tests for bogus format! */
1319
snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
1320
execute(send_string(buffer));
1324
execute(receive_response("STORED\r\n"));
1327
return test_ascii_version();
1330
static enum test_return test_ascii_set(void)
1332
return test_ascii_set_impl("test_ascii_set", false);
1335
static enum test_return test_ascii_set_noreply(void)
1337
return test_ascii_set_impl("test_ascii_set_noreply", true);
1340
static enum test_return test_ascii_add_impl(const char* key, bool noreply)
1342
/* @todo add tests for bogus format! */
1344
snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
1345
execute(send_string(buffer));
1349
execute(receive_response("STORED\r\n"));
1352
execute(send_string(buffer));
1356
execute(receive_response("NOT_STORED\r\n"));
1359
return test_ascii_version();
1362
static enum test_return test_ascii_add(void)
1364
return test_ascii_add_impl("test_ascii_add", false);
1367
static enum test_return test_ascii_add_noreply(void)
1369
return test_ascii_add_impl("test_ascii_add_noreply", true);
1372
static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
1376
execute(receive_line(buffer, sizeof(buffer)));
1377
verify(strncmp(buffer, "VALUE ", 6) == 0);
1378
char *end= strchr(buffer + 6, ' ');
1379
verify(end != NULL);
1384
*key= strdup(buffer + 6);
1385
verify(*key != NULL);
1388
unsigned long val= strtoul(ptr, &end, 10); /* flags */
1391
verify(end != NULL);
1392
*ndata = (ssize_t)strtoul(end, &end, 10); /* size */
1394
verify(end != NULL);
1395
while (end and *end != '\n' and isspace(*end))
1397
verify(end and *end == '\n');
1399
*value= static_cast<char*>(malloc((size_t)*ndata));
1400
verify(*value != NULL);
1402
execute(retry_read(*value, (size_t)*ndata));
1404
execute(retry_read(buffer, 2));
1405
verify(memcmp(buffer, "\r\n", 2) == 0);
1410
static enum test_return ascii_get_value(const char *key, const char *value)
1414
size_t datasize= strlen(value);
1416
verify(datasize < sizeof(buffer));
1417
execute(receive_line(buffer, sizeof(buffer)));
1418
verify(strncmp(buffer, "VALUE ", 6) == 0);
1419
verify(strncmp(buffer + 6, key, strlen(key)) == 0);
1420
char *ptr= buffer + 6 + strlen(key) + 1;
1423
unsigned long val= strtoul(ptr, &end, 10); /* flags */
1426
verify(end != NULL);
1427
val= strtoul(end, &end, 10); /* size */
1429
verify(val == datasize);
1430
verify(end != NULL);
1431
while (end and *end != '\n' and isspace(*end))
1435
verify(end and *end == '\n');
1437
execute(retry_read(buffer, datasize));
1438
verify(memcmp(buffer, value, datasize) == 0);
1440
execute(retry_read(buffer, 2));
1441
verify(memcmp(buffer, "\r\n", 2) == 0);
1446
static enum test_return ascii_get_item(const char *key, const char *value,
1453
datasize= strlen(value);
1456
verify(datasize < sizeof(buffer));
1457
snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
1458
execute(send_string(buffer));
1462
execute(ascii_get_value(key, value));
1465
execute(retry_read(buffer, 5));
1466
verify(memcmp(buffer, "END\r\n", 5) == 0);
1471
static enum test_return ascii_gets_value(const char *key, const char *value,
1476
size_t datasize= strlen(value);
1478
verify(datasize < sizeof(buffer));
1479
execute(receive_line(buffer, sizeof(buffer)));
1480
verify(strncmp(buffer, "VALUE ", 6) == 0);
1481
verify(strncmp(buffer + 6, key, strlen(key)) == 0);
1482
char *ptr= buffer + 6 + strlen(key) + 1;
1485
unsigned long val= strtoul(ptr, &end, 10); /* flags */
1488
verify(end != NULL);
1489
val= strtoul(end, &end, 10); /* size */
1491
verify(val == datasize);
1492
verify(end != NULL);
1493
*cas= strtoul(end, &end, 10); /* cas */
1495
verify(val == datasize);
1496
verify(end != NULL);
1498
while (end and *end != '\n' and isspace(*end))
1502
verify(end and *end == '\n');
1504
execute(retry_read(buffer, datasize));
1505
verify(memcmp(buffer, value, datasize) == 0);
1507
execute(retry_read(buffer, 2));
1508
verify(memcmp(buffer, "\r\n", 2) == 0);
1513
static enum test_return ascii_gets_item(const char *key, const char *value,
1514
bool exist, unsigned long *cas)
1520
datasize= strlen(value);
1523
verify(datasize < sizeof(buffer));
1524
snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
1525
execute(send_string(buffer));
1528
execute(ascii_gets_value(key, value, cas));
1530
execute(retry_read(buffer, 5));
1531
verify(memcmp(buffer, "END\r\n", 5) == 0);
1536
static enum test_return ascii_set_item(const char *key, const char *value)
1539
size_t len= strlen(value);
1540
snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
1541
execute(send_string(buffer));
1542
execute(retry_write(value, len));
1543
execute(send_string("\r\n"));
1544
execute(receive_response("STORED\r\n"));
1548
static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
1551
snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
1552
execute(send_string(buffer));
1556
execute(test_ascii_version());
1560
execute(receive_response("NOT_STORED\r\n"));
1563
execute(ascii_set_item(key, "value"));
1564
execute(ascii_get_item(key, "value", true));
1567
execute(send_string(buffer));
1570
execute(test_ascii_version());
1572
execute(receive_response("STORED\r\n"));
1574
return test_ascii_version();
1577
static enum test_return test_ascii_replace(void)
1579
return test_ascii_replace_impl("test_ascii_replace", false);
1582
static enum test_return test_ascii_replace_noreply(void)
1584
return test_ascii_replace_impl("test_ascii_replace_noreply", true);
1587
static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
1592
execute(ascii_set_item(key, "value"));
1593
execute(ascii_gets_item(key, "value", true, &cas));
1595
snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
1596
execute(send_string(buffer));
1600
execute(test_ascii_version());
1604
execute(receive_response("STORED\r\n"));
1607
/* reexecute the same command should fail due to illegal cas */
1608
execute(send_string(buffer));
1612
execute(test_ascii_version());
1616
execute(receive_response("EXISTS\r\n"));
1619
return test_ascii_version();
1622
static enum test_return test_ascii_cas(void)
1624
return test_ascii_cas_impl("test_ascii_cas", false);
1627
static enum test_return test_ascii_cas_noreply(void)
1629
return test_ascii_cas_impl("test_ascii_cas_noreply", true);
1632
static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
1634
execute(ascii_set_item(key, "value"));
1636
execute(send_string("delete\r\n"));
1637
execute(receive_error_response());
1638
/* BUG: the server accepts delete a b */
1639
execute(send_string("delete a b c d e\r\n"));
1640
execute(receive_error_response());
1643
snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
1644
execute(send_string(buffer));
1647
execute(test_ascii_version());
1649
execute(receive_response("DELETED\r\n"));
1651
execute(ascii_get_item(key, "value", false));
1652
execute(send_string(buffer));
1654
execute(test_ascii_version());
1656
execute(receive_response("NOT_FOUND\r\n"));
1661
static enum test_return test_ascii_delete(void)
1663
return test_ascii_delete_impl("test_ascii_delete", false);
1666
static enum test_return test_ascii_delete_noreply(void)
1668
return test_ascii_delete_impl("test_ascii_delete_noreply", true);
1671
static enum test_return test_ascii_get(void)
1673
execute(ascii_set_item("test_ascii_get", "value"));
1675
execute(send_string("get\r\n"));
1676
execute(receive_error_response());
1677
execute(ascii_get_item("test_ascii_get", "value", true));
1678
execute(ascii_get_item("test_ascii_get_notfound", "value", false));
1683
static enum test_return test_ascii_gets(void)
1685
execute(ascii_set_item("test_ascii_gets", "value"));
1687
execute(send_string("gets\r\n"));
1688
execute(receive_error_response());
1690
execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
1691
execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
1696
static enum test_return test_ascii_mget(void)
1698
const uint32_t nkeys= 5;
1699
const char * const keys[]= {
1702
/* test_ascii_mget_3 does not exist :) */
1708
for (uint32_t x= 0; x < nkeys; ++x)
1710
execute(ascii_set_item(keys[x], "value"));
1713
/* Ask for a key that doesn't exist as well */
1714
execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
1715
"test_ascii_mget4 test_ascii_mget5 "
1716
"test_ascii_mget6\r\n"));
1718
char *returned[nkeys];
1720
for (uint32_t x= 0; x < nkeys; ++x)
1724
execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
1725
verify(nbytes == 5);
1726
verify(memcmp(v, "value", 5) == 0);
1731
execute(retry_read(buffer, 5));
1732
verify(memcmp(buffer, "END\r\n", 5) == 0);
1734
/* verify that we got all the keys we expected */
1735
for (uint32_t x= 0; x < nkeys; ++x)
1738
for (uint32_t y= 0; y < nkeys; ++y)
1740
if (strcmp(keys[x], returned[y]) == 0)
1749
for (uint32_t x= 0; x < nkeys; ++x)
1757
static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
1760
snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
1762
execute(ascii_set_item(key, "0"));
1763
for (int x= 1; x < 11; ++x)
1765
execute(send_string(cmd));
1768
execute(test_ascii_version());
1772
execute(receive_line(buffer, sizeof(buffer)));
1773
int val= atoi(buffer);
1778
execute(ascii_get_item(key, "10", true));
1783
static enum test_return test_ascii_incr(void)
1785
return test_ascii_incr_impl("test_ascii_incr", false);
1788
static enum test_return test_ascii_incr_noreply(void)
1790
return test_ascii_incr_impl("test_ascii_incr_noreply", true);
1793
static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
1796
snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
1798
execute(ascii_set_item(key, "9"));
1799
for (int x= 8; x > -1; --x)
1801
execute(send_string(cmd));
1805
execute(test_ascii_version());
1810
execute(receive_line(buffer, sizeof(buffer)));
1811
int val= atoi(buffer);
1816
execute(ascii_get_item(key, "0", true));
1818
/* verify that it doesn't wrap */
1819
execute(send_string(cmd));
1822
execute(test_ascii_version());
1827
execute(receive_line(buffer, sizeof(buffer)));
1829
execute(ascii_get_item(key, "0", true));
1834
static enum test_return test_ascii_decr(void)
1836
return test_ascii_decr_impl("test_ascii_decr", false);
1839
static enum test_return test_ascii_decr_noreply(void)
1841
return test_ascii_decr_impl("test_ascii_decr_noreply", true);
1845
static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
1848
/* Verify that the flush_all command handles unknown options */
1849
/* Bug in the current memcached server! */
1850
execute(send_string("flush_all foo bar\r\n"));
1851
execute(receive_error_response());
1854
execute(ascii_set_item(key, key));
1855
execute(ascii_get_item(key, key, true));
1859
execute(send_string("flush_all noreply\r\n"));
1860
execute(test_ascii_version());
1864
execute(send_string("flush_all\r\n"));
1865
execute(receive_response("OK\r\n"));
1868
execute(ascii_get_item(key, key, false));
1873
static enum test_return test_ascii_flush(void)
1875
return test_ascii_flush_impl("test_ascii_flush", false);
1878
static enum test_return test_ascii_flush_noreply(void)
1880
return test_ascii_flush_impl("test_ascii_flush_noreply", true);
1883
static enum test_return test_ascii_concat_impl(const char *key,
1894
execute(ascii_set_item(key, value));
1906
snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
1907
append ? "append" : "prepend",
1908
key, (unsigned int)strlen(value), noreply ? " noreply" : "",
1910
execute(send_string(cmd));
1914
execute(test_ascii_version());
1918
execute(receive_response("STORED\r\n"));
1921
execute(ascii_get_item(key, "hello world", true));
1923
snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
1924
append ? "append" : "prepend",
1925
key, (unsigned int)strlen(value), noreply ? " noreply" : "",
1927
execute(send_string(cmd));
1931
execute(test_ascii_version());
1935
execute(receive_response("NOT_STORED\r\n"));
1941
static enum test_return test_ascii_append(void)
1943
return test_ascii_concat_impl("test_ascii_append", true, false);
1946
static enum test_return test_ascii_prepend(void)
1948
return test_ascii_concat_impl("test_ascii_prepend", false, false);
1951
static enum test_return test_ascii_append_noreply(void)
1953
return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
1956
static enum test_return test_ascii_prepend_noreply(void)
1958
return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
1961
static enum test_return test_ascii_stat(void)
1963
execute(send_string("stats noreply\r\n"));
1964
execute(receive_error_response());
1965
execute(send_string("stats\r\n"));
1968
execute(receive_line(buffer, sizeof(buffer)));
1969
} while (strcmp(buffer, "END\r\n") != 0);
1971
return TEST_PASS_RECONNECT;
1974
typedef enum test_return(*TEST_FUNC)(void);
1978
const char *description;
1982
struct testcase testcases[]= {
1983
{ "ascii quit", test_ascii_quit },
1984
{ "ascii version", test_ascii_version },
1985
{ "ascii verbosity", test_ascii_verbosity },
1986
{ "ascii set", test_ascii_set },
1987
{ "ascii set noreply", test_ascii_set_noreply },
1988
{ "ascii get", test_ascii_get },
1989
{ "ascii gets", test_ascii_gets },
1990
{ "ascii mget", test_ascii_mget },
1991
{ "ascii flush", test_ascii_flush },
1992
{ "ascii flush noreply", test_ascii_flush_noreply },
1993
{ "ascii add", test_ascii_add },
1994
{ "ascii add noreply", test_ascii_add_noreply },
1995
{ "ascii replace", test_ascii_replace },
1996
{ "ascii replace noreply", test_ascii_replace_noreply },
1997
{ "ascii cas", test_ascii_cas },
1998
{ "ascii cas noreply", test_ascii_cas_noreply },
1999
{ "ascii delete", test_ascii_delete },
2000
{ "ascii delete noreply", test_ascii_delete_noreply },
2001
{ "ascii incr", test_ascii_incr },
2002
{ "ascii incr noreply", test_ascii_incr_noreply },
2003
{ "ascii decr", test_ascii_decr },
2004
{ "ascii decr noreply", test_ascii_decr_noreply },
2005
{ "ascii append", test_ascii_append },
2006
{ "ascii append noreply", test_ascii_append_noreply },
2007
{ "ascii prepend", test_ascii_prepend },
2008
{ "ascii prepend noreply", test_ascii_prepend_noreply },
2009
{ "ascii stat", test_ascii_stat },
2010
{ "binary noop", test_binary_noop },
2011
{ "binary quit", test_binary_quit },
2012
{ "binary quitq", test_binary_quitq },
2013
{ "binary set", test_binary_set },
2014
{ "binary setq", test_binary_setq },
2015
{ "binary flush", test_binary_flush },
2016
{ "binary flushq", test_binary_flushq },
2017
{ "binary add", test_binary_add },
2018
{ "binary addq", test_binary_addq },
2019
{ "binary replace", test_binary_replace },
2020
{ "binary replaceq", test_binary_replaceq },
2021
{ "binary delete", test_binary_delete },
2022
{ "binary deleteq", test_binary_deleteq },
2023
{ "binary get", test_binary_get },
2024
{ "binary getq", test_binary_getq },
2025
{ "binary getk", test_binary_getk },
2026
{ "binary getkq", test_binary_getkq },
2027
{ "binary incr", test_binary_incr },
2028
{ "binary incrq", test_binary_incrq },
2029
{ "binary decr", test_binary_decr },
2030
{ "binary decrq", test_binary_decrq },
2031
{ "binary version", test_binary_version },
2032
{ "binary append", test_binary_append },
2033
{ "binary appendq", test_binary_appendq },
2034
{ "binary prepend", test_binary_prepend },
2035
{ "binary prependq", test_binary_prependq },
2036
{ "binary stat", test_binary_stat },
2040
const int ascii_tests = 1;
2041
const int binary_tests = 2;
2049
int main(int argc, char **argv)
2051
static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
2052
struct test_type_st tests= { true, true };
2055
const char *hostname= "localhost";
2056
const char *port= "11211";
2059
const char *testname= NULL;
2063
while ((cmd= getopt(argc, argv, "qt:vch:p:PT:?ab")) != EOF)
2068
tests.binary= false;
2077
timeout= atoi(optarg);
2080
fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
2081
return EXIT_FAILURE;
2085
case 'v': verbose= true;
2088
case 'c': do_core= true;
2091
case 'h': hostname= optarg;
2094
case 'p': port= optarg;
2101
case 'P': prompt= true;
2104
case 'T': testname= optarg;
2108
fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
2109
"\t-c\tGenerate coredump if a test fails\n"
2110
"\t-v\tVerbose test output (print out the assertion)\n"
2111
"\t-t n\tSet the timeout for io-operations to n seconds\n"
2112
"\t-P\tPrompt the user before starting a test.\n"
2113
"\t\t\t\"skip\" will skip the test\n"
2114
"\t\t\t\"quit\" will terminate memcapable\n"
2115
"\t\t\tEverything else will start the test\n"
2116
"\t-T n\tJust run the test named n\n"
2117
"\t-a\tOnly test the ascii protocol\n"
2118
"\t-b\tOnly test the binary protocol\n",
2120
return EXIT_SUCCESS;
2124
initialize_sockets();
2125
sock= connect_server(hostname, port);
2126
if (sock == INVALID_SOCKET)
2128
fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
2129
hostname, port, strerror(get_socket_errno()));
2130
return EXIT_FAILURE;
2133
for (int ii= 0; testcases[ii].description != NULL; ++ii)
2135
if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
2140
if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
2141
(testcases[ii].description[0] == 'b' && (tests.binary) == 0))
2146
fprintf(stdout, "%-40s", testcases[ii].description);
2151
fprintf(stdout, "\nPress <return> when you are ready? ");
2152
char buffer[80] = {0};
2153
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
2154
if (strncmp(buffer, "skip", 4) == 0)
2156
fprintf(stdout, "%-40s%s\n", testcases[ii].description,
2157
status_msg[TEST_SKIP]);
2161
if (strncmp(buffer, "quit", 4) == 0)
2167
fprintf(stdout, "%-40s", testcases[ii].description);
2171
bool reconnect= false;
2172
enum test_return ret= testcases[ii].function();
2173
if (ret == TEST_FAIL)
2178
fprintf(stderr, "\n");
2180
else if (ret == TEST_PASS_RECONNECT)
2183
fprintf(stderr, "%s\n", status_msg[ret]);
2187
if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
2189
fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname, port, strerror(get_socket_errno()));
2190
fprintf(stderr, "%d of %d tests failed\n", failed, total);
2191
return EXIT_FAILURE;
2199
fprintf(stdout, "All tests passed\n");
2203
fprintf(stderr, "%d of %d tests failed\n", failed, total);
2206
return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;