|
Packit |
4e8bc4 |
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
4e8bc4 |
#undef NDEBUG
|
|
Packit |
4e8bc4 |
#include <pthread.h>
|
|
Packit |
4e8bc4 |
#include <sys/types.h>
|
|
Packit |
4e8bc4 |
#include <sys/socket.h>
|
|
Packit |
4e8bc4 |
#include <sys/wait.h>
|
|
Packit |
4e8bc4 |
#include <netdb.h>
|
|
Packit |
4e8bc4 |
#include <arpa/inet.h>
|
|
Packit |
4e8bc4 |
#include <netinet/in.h>
|
|
Packit |
4e8bc4 |
#include <netinet/tcp.h>
|
|
Packit |
4e8bc4 |
#include <signal.h>
|
|
Packit |
4e8bc4 |
#include <stdio.h>
|
|
Packit |
4e8bc4 |
#include <stdlib.h>
|
|
Packit |
4e8bc4 |
#include <errno.h>
|
|
Packit |
4e8bc4 |
#include <assert.h>
|
|
Packit |
4e8bc4 |
#include <string.h>
|
|
Packit |
4e8bc4 |
#include <unistd.h>
|
|
Packit |
4e8bc4 |
#include <netinet/in.h>
|
|
Packit |
4e8bc4 |
#include <fcntl.h>
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#include "config.h"
|
|
Packit |
4e8bc4 |
#include "cache.h"
|
|
Packit |
4e8bc4 |
#include "hash.h"
|
|
Packit |
4e8bc4 |
#include "stats_prefix.h"
|
|
Packit |
4e8bc4 |
#include "util.h"
|
|
Packit |
4e8bc4 |
#include "protocol_binary.h"
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
#include <openssl/ssl.h>
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
struct conn {
|
|
Packit |
4e8bc4 |
int sock;
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
SSL_CTX *ssl_ctx;
|
|
Packit |
4e8bc4 |
SSL *ssl;
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
ssize_t (*read)(struct conn *c, void *buf, size_t count);
|
|
Packit |
4e8bc4 |
ssize_t (*write)(struct conn *c, const void *buf, size_t count);
|
|
Packit |
4e8bc4 |
};
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
struct settings {
|
|
Packit |
4e8bc4 |
char *hash_algorithm;
|
|
Packit |
4e8bc4 |
};
|
|
Packit |
4e8bc4 |
struct settings settings;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static ssize_t tcp_read(struct conn *c, void *buf, size_t count);
|
|
Packit |
4e8bc4 |
static ssize_t tcp_write(struct conn *c, const void *buf, size_t count);
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
static ssize_t ssl_read(struct conn *c, void *buf, size_t count);
|
|
Packit |
4e8bc4 |
static ssize_t ssl_write(struct conn *c, const void *buf, size_t count);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
ssize_t tcp_read(struct conn *c, void *buf, size_t count) {
|
|
Packit |
4e8bc4 |
assert(c != NULL);
|
|
Packit |
4e8bc4 |
return read(c->sock, buf, count);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
ssize_t tcp_write(struct conn *c, const void *buf, size_t count) {
|
|
Packit |
4e8bc4 |
assert(c != NULL);
|
|
Packit |
4e8bc4 |
return write(c->sock, buf, count);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
ssize_t ssl_read(struct conn *c, void *buf, size_t count) {
|
|
Packit |
4e8bc4 |
assert(c != NULL);
|
|
Packit |
4e8bc4 |
return SSL_read(c->ssl, buf, count);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
ssize_t ssl_write(struct conn *c, const void *buf, size_t count) {
|
|
Packit |
4e8bc4 |
assert(c != NULL);
|
|
Packit |
4e8bc4 |
return SSL_write(c->ssl, buf, count);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static pid_t server_pid;
|
|
Packit |
4e8bc4 |
static in_port_t port;
|
|
Packit |
4e8bc4 |
static struct conn *con = NULL;
|
|
Packit |
4e8bc4 |
static bool allow_closed_read = false;
|
|
Packit |
4e8bc4 |
static bool enable_ssl = false;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void close_conn() {
|
|
Packit |
4e8bc4 |
if (con == NULL) return;
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
if (con->ssl) {
|
|
Packit |
4e8bc4 |
SSL_shutdown(con->ssl);
|
|
Packit |
4e8bc4 |
SSL_free(con->ssl);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
if (con->ssl_ctx)
|
|
Packit |
4e8bc4 |
SSL_CTX_free(con->ssl_ctx);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
if (con->sock > 0) close(con->sock);
|
|
Packit |
4e8bc4 |
free(con);
|
|
Packit |
4e8bc4 |
con = NULL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_create_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
|
|
Packit |
4e8bc4 |
NULL, NULL);
|
|
Packit |
4e8bc4 |
assert(cache != NULL);
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
const uint64_t constructor_pattern = 0xdeadcafebabebeef;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static int cache_constructor(void *buffer, void *notused1, int notused2) {
|
|
Packit |
4e8bc4 |
uint64_t *ptr = buffer;
|
|
Packit |
4e8bc4 |
*ptr = constructor_pattern;
|
|
Packit |
4e8bc4 |
return 0;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_constructor_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
|
|
Packit |
4e8bc4 |
cache_constructor, NULL);
|
|
Packit |
4e8bc4 |
assert(cache != NULL);
|
|
Packit |
4e8bc4 |
uint64_t *ptr = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
uint64_t pattern = *ptr;
|
|
Packit |
4e8bc4 |
cache_free(cache, ptr);
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
|
|
Packit |
4e8bc4 |
return 1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_fail_constructor_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
enum test_return ret = TEST_PASS;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
|
|
Packit |
4e8bc4 |
cache_fail_constructor, NULL);
|
|
Packit |
4e8bc4 |
assert(cache != NULL);
|
|
Packit |
4e8bc4 |
uint64_t *ptr = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
if (ptr != NULL) {
|
|
Packit |
4e8bc4 |
ret = TEST_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
return ret;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void *destruct_data = 0;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void cache_destructor(void *buffer, void *notused) {
|
|
Packit |
4e8bc4 |
destruct_data = buffer;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_destructor_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
|
|
Packit |
4e8bc4 |
NULL, cache_destructor);
|
|
Packit |
4e8bc4 |
assert(cache != NULL);
|
|
Packit |
4e8bc4 |
char *ptr = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
cache_free(cache, ptr);
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_reuse_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
|
|
Packit |
4e8bc4 |
NULL, NULL);
|
|
Packit |
4e8bc4 |
char *ptr = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
cache_free(cache, ptr);
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 100; ++ii) {
|
|
Packit |
4e8bc4 |
char *p = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
assert(p == ptr);
|
|
Packit |
4e8bc4 |
cache_free(cache, ptr);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_bulkalloc(size_t datasize)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", datasize, sizeof(char*),
|
|
Packit |
4e8bc4 |
NULL, NULL);
|
|
Packit |
4e8bc4 |
#define ITERATIONS 1024
|
|
Packit |
4e8bc4 |
void *ptr[ITERATIONS];
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
for (int ii = 0; ii < ITERATIONS; ++ii) {
|
|
Packit |
4e8bc4 |
ptr[ii] = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
assert(ptr[ii] != 0);
|
|
Packit |
4e8bc4 |
memset(ptr[ii], 0xff, datasize);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
for (int ii = 0; ii < ITERATIONS; ++ii) {
|
|
Packit |
4e8bc4 |
cache_free(cache, ptr[ii]);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#undef ITERATIONS
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_issue_161(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
enum test_return ret = cache_bulkalloc(1);
|
|
Packit |
4e8bc4 |
if (ret == TEST_PASS) {
|
|
Packit |
4e8bc4 |
ret = cache_bulkalloc(512);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return ret;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return cache_redzone_test(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
#ifndef HAVE_UMEM_H
|
|
Packit |
4e8bc4 |
cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
|
|
Packit |
4e8bc4 |
NULL, NULL);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Ignore SIGABRT */
|
|
Packit |
4e8bc4 |
struct sigaction old_action;
|
|
Packit |
4e8bc4 |
struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
|
|
Packit |
4e8bc4 |
sigemptyset(&action.sa_mask);
|
|
Packit |
4e8bc4 |
sigaction(SIGABRT, &action, &old_action);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* check memory debug.. */
|
|
Packit |
4e8bc4 |
char *p = cache_alloc(cache);
|
|
Packit |
4e8bc4 |
char old = *(p - 1);
|
|
Packit |
4e8bc4 |
*(p - 1) = 0;
|
|
Packit |
4e8bc4 |
cache_free(cache, p);
|
|
Packit |
4e8bc4 |
assert(cache_error == -1);
|
|
Packit |
4e8bc4 |
*(p - 1) = old;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
p[sizeof(uint32_t)] = 0;
|
|
Packit |
4e8bc4 |
cache_free(cache, p);
|
|
Packit |
4e8bc4 |
assert(cache_error == 1);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* restore signal handler */
|
|
Packit |
4e8bc4 |
sigaction(SIGABRT, &old_action, NULL);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
cache_destroy(cache);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
#else
|
|
Packit |
4e8bc4 |
return TEST_SKIP;
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_stats_prefix_find(void) {
|
|
Packit |
4e8bc4 |
PREFIX_STATS *pfs1, *pfs2;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
stats_prefix_clear();
|
|
Packit |
4e8bc4 |
pfs1 = stats_prefix_find("abc", 3);
|
|
Packit |
4e8bc4 |
assert(pfs1 == NULL);
|
|
Packit |
4e8bc4 |
pfs1 = stats_prefix_find("abc|", 4);
|
|
Packit |
4e8bc4 |
assert(pfs1 == NULL);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
pfs1 = stats_prefix_find("abc:", 4);
|
|
Packit |
4e8bc4 |
assert(pfs1 != NULL);
|
|
Packit |
4e8bc4 |
assert(0ULL == (pfs1->num_gets + pfs1->num_sets + pfs1->num_deletes + pfs1->num_hits));
|
|
Packit |
4e8bc4 |
pfs2 = stats_prefix_find("abc:", 4);
|
|
Packit |
4e8bc4 |
assert(pfs1 == pfs2);
|
|
Packit |
4e8bc4 |
pfs2 = stats_prefix_find("abc:d", 5);
|
|
Packit |
4e8bc4 |
assert(pfs1 == pfs2);
|
|
Packit |
4e8bc4 |
pfs2 = stats_prefix_find("xyz123:", 6);
|
|
Packit |
4e8bc4 |
assert(pfs1 != pfs2);
|
|
Packit |
4e8bc4 |
pfs2 = stats_prefix_find("ab:", 3);
|
|
Packit |
4e8bc4 |
assert(pfs1 != pfs2);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_stats_prefix_record_get(void) {
|
|
Packit |
4e8bc4 |
PREFIX_STATS *pfs;
|
|
Packit |
4e8bc4 |
stats_prefix_clear();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("abc:123", 7, false);
|
|
Packit |
4e8bc4 |
pfs = stats_prefix_find("abc:123", 7);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("abc:456", 7, false);
|
|
Packit |
4e8bc4 |
assert(2 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("abc:456", 7, true);
|
|
Packit |
4e8bc4 |
assert(3 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("def:", 4, true);
|
|
Packit |
4e8bc4 |
assert(3 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_stats_prefix_record_delete(void) {
|
|
Packit |
4e8bc4 |
PREFIX_STATS *pfs;
|
|
Packit |
4e8bc4 |
stats_prefix_clear();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
stats_prefix_record_delete("abc:123", 7);
|
|
Packit |
4e8bc4 |
pfs = stats_prefix_find("abc:123", 7);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_deletes);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_sets);
|
|
Packit |
4e8bc4 |
stats_prefix_record_delete("def:", 4);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_deletes);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_stats_prefix_record_set(void) {
|
|
Packit |
4e8bc4 |
PREFIX_STATS *pfs;
|
|
Packit |
4e8bc4 |
stats_prefix_clear();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
stats_prefix_record_set("abc:123", 7);
|
|
Packit |
4e8bc4 |
pfs = stats_prefix_find("abc:123", 7);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_gets);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_hits);
|
|
Packit |
4e8bc4 |
assert(0 == pfs->num_deletes);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_sets);
|
|
Packit |
4e8bc4 |
stats_prefix_record_delete("def:", 4);
|
|
Packit |
4e8bc4 |
assert(1 == pfs->num_sets);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_stats_prefix_dump(void) {
|
|
Packit |
4e8bc4 |
int hashval = hash("abc", 3) % PREFIX_HASH_SIZE;
|
|
Packit |
4e8bc4 |
char tmp[500];
|
|
Packit Service |
2e1ee7 |
char *expected;
|
|
Packit |
4e8bc4 |
int keynum;
|
|
Packit |
4e8bc4 |
int length;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
stats_prefix_clear();
|
|
Packit |
4e8bc4 |
|
|
Packit Service |
2e1ee7 |
assert(strcmp("END\r\n", stats_prefix_dump(&length)) == 0);
|
|
Packit |
4e8bc4 |
assert(5 == length);
|
|
Packit |
4e8bc4 |
stats_prefix_record_set("abc:123", 7);
|
|
Packit |
4e8bc4 |
expected = "PREFIX abc get 0 hit 0 set 1 del 0\r\nEND\r\n";
|
|
Packit Service |
2e1ee7 |
assert(strcmp(expected, stats_prefix_dump(&length)) == 0);
|
|
Packit |
4e8bc4 |
assert(strlen(expected) == length);
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("abc:123", 7, false);
|
|
Packit |
4e8bc4 |
expected = "PREFIX abc get 1 hit 0 set 1 del 0\r\nEND\r\n";
|
|
Packit Service |
2e1ee7 |
assert(strcmp(expected, stats_prefix_dump(&length)) == 0);
|
|
Packit |
4e8bc4 |
assert(strlen(expected) == length);
|
|
Packit |
4e8bc4 |
stats_prefix_record_get("abc:123", 7, true);
|
|
Packit |
4e8bc4 |
expected = "PREFIX abc get 2 hit 1 set 1 del 0\r\nEND\r\n";
|
|
Packit Service |
2e1ee7 |
assert(strcmp(expected, stats_prefix_dump(&length)) == 0);
|
|
Packit |
4e8bc4 |
assert(strlen(expected) == length);
|
|
Packit |
4e8bc4 |
stats_prefix_record_delete("abc:123", 7);
|
|
Packit |
4e8bc4 |
expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\nEND\r\n";
|
|
Packit Service |
2e1ee7 |
assert(strcmp(expected, stats_prefix_dump(&length)) == 0);
|
|
Packit |
4e8bc4 |
assert(strlen(expected) == length);
|
|
Packit |
4e8bc4 |
|
|
Packit Service |
2e1ee7 |
/* The order of results might change if we switch hash functions. */
|
|
Packit |
4e8bc4 |
stats_prefix_record_delete("def:123", 7);
|
|
Packit Service |
2e1ee7 |
expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\n"
|
|
Packit Service |
2e1ee7 |
"PREFIX def get 0 hit 0 set 0 del 1\r\n"
|
|
Packit Service |
2e1ee7 |
"END\r\n";
|
|
Packit Service |
2e1ee7 |
assert(strcmp(expected, stats_prefix_dump(&length)) == 0);
|
|
Packit Service |
2e1ee7 |
assert(strlen(expected) == length);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Find a key that hashes to the same bucket as "abc" */
|
|
Packit |
4e8bc4 |
bool found_match = false;
|
|
Packit |
4e8bc4 |
for (keynum = 0; keynum < PREFIX_HASH_SIZE * 100; keynum++) {
|
|
Packit |
4e8bc4 |
snprintf(tmp, sizeof(tmp), "%d:", keynum);
|
|
Packit |
4e8bc4 |
/* -1 because only the prefix portion is used when hashing */
|
|
Packit |
4e8bc4 |
if (hashval == hash(tmp, strlen(tmp) - 1) % PREFIX_HASH_SIZE) {
|
|
Packit |
4e8bc4 |
found_match = true;
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
assert(found_match);
|
|
Packit |
4e8bc4 |
stats_prefix_record_set(tmp, strlen(tmp));
|
|
Packit Service |
2e1ee7 |
snprintf(tmp, sizeof(tmp),
|
|
Packit Service |
2e1ee7 |
"PREFIX %d get 0 hit 0 set 1 del 0\r\n"
|
|
Packit Service |
2e1ee7 |
"PREFIX abc get 2 hit 1 set 1 del 1\r\n"
|
|
Packit Service |
2e1ee7 |
"PREFIX def get 0 hit 0 set 0 del 1\r\n"
|
|
Packit Service |
2e1ee7 |
"END\r\n", keynum);
|
|
Packit Service |
2e1ee7 |
assert(strcmp(tmp, stats_prefix_dump(&length)) == 0);
|
|
Packit Service |
2e1ee7 |
assert(strlen(tmp) == length);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_safe_strtoul(void) {
|
|
Packit |
4e8bc4 |
uint32_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtoul("123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtoul("+123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul("", &val)); // empty
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul("123BOGUS", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul(" issue221", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
/* Not sure what it does, but this works with ICC :/
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// extremes:
|
|
Packit |
4e8bc4 |
assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
|
|
Packit |
4e8bc4 |
assert(val == 4294967295L);
|
|
Packit |
4e8bc4 |
/* This actually works on 64-bit ubuntu
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul("4294967296", &val)); // 2**32
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
assert(!safe_strtoul("-1", &val)); // negative
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_safe_strtoull(void) {
|
|
Packit |
4e8bc4 |
uint64_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtoull("123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtoull("+123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull("", &val)); // empty
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull("123BOGUS", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull(" issue221", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// extremes:
|
|
Packit |
4e8bc4 |
assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
|
|
Packit |
4e8bc4 |
assert(val == 18446744073709551615ULL);
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
|
|
Packit |
4e8bc4 |
assert(!safe_strtoull("-1", &val)); // negative
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_safe_strtoll(void) {
|
|
Packit |
4e8bc4 |
int64_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtoll("123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtoll("+123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtoll("-123", &val));
|
|
Packit |
4e8bc4 |
assert(val == -123);
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll("", &val)); // empty
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll("123BOGUS", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll(" issue221", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// extremes:
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
|
|
Packit |
4e8bc4 |
assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
|
|
Packit |
4e8bc4 |
assert(val == 9223372036854775807LL);
|
|
Packit |
4e8bc4 |
/*
|
|
Packit |
4e8bc4 |
assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
|
|
Packit |
4e8bc4 |
assert(val == -9223372036854775808LL);
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// We'll allow space to terminate the string. And leading space.
|
|
Packit |
4e8bc4 |
assert(safe_strtoll(" 123 foo", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_safe_strtol(void) {
|
|
Packit |
4e8bc4 |
int32_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtol("123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtol("+123", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
assert(safe_strtol("-123", &val));
|
|
Packit |
4e8bc4 |
assert(val == -123);
|
|
Packit |
4e8bc4 |
assert(!safe_strtol("", &val)); // empty
|
|
Packit |
4e8bc4 |
assert(!safe_strtol("123BOGUS", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
|
|
Packit |
4e8bc4 |
assert(!safe_strtol(" issue221", &val)); // non-numeric
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// extremes:
|
|
Packit |
4e8bc4 |
/* This actually works on 64-bit ubuntu
|
|
Packit |
4e8bc4 |
assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
|
|
Packit |
4e8bc4 |
assert(val == 2147483647L);
|
|
Packit |
4e8bc4 |
/* This actually works on 64-bit ubuntu
|
|
Packit |
4e8bc4 |
assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
// We'll allow space to terminate the string. And leading space.
|
|
Packit |
4e8bc4 |
assert(safe_strtol(" 123 foo", &val));
|
|
Packit |
4e8bc4 |
assert(val == 123);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/**
|
|
Packit |
4e8bc4 |
* Function to start the server and let it listen on a random port
|
|
Packit |
4e8bc4 |
*
|
|
Packit |
4e8bc4 |
* @param port_out where to store the TCP port number the server is
|
|
Packit |
4e8bc4 |
* listening on
|
|
Packit |
4e8bc4 |
* @param daemon set to true if you want to run the memcached server
|
|
Packit |
4e8bc4 |
* as a daemon process
|
|
Packit |
4e8bc4 |
* @return the pid of the memcached server
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
|
|
Packit |
4e8bc4 |
char environment[80];
|
|
Packit |
4e8bc4 |
snprintf(environment, sizeof(environment),
|
|
Packit |
4e8bc4 |
"MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
|
|
Packit |
4e8bc4 |
char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
|
|
Packit |
4e8bc4 |
char pid_file[80];
|
|
Packit |
4e8bc4 |
snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
remove(filename);
|
|
Packit |
4e8bc4 |
remove(pid_file);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#ifdef __sun
|
|
Packit |
4e8bc4 |
/* I want to name the corefiles differently so that they don't
|
|
Packit |
4e8bc4 |
overwrite each other
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
char coreadm[128];
|
|
Packit |
4e8bc4 |
snprintf(coreadm, sizeof(coreadm),
|
|
Packit |
4e8bc4 |
"coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
|
|
Packit |
4e8bc4 |
system(coreadm);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
pid_t pid = fork();
|
|
Packit |
4e8bc4 |
assert(pid != -1);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (pid == 0) {
|
|
Packit |
4e8bc4 |
/* Child */
|
|
Packit |
4e8bc4 |
char *argv[24];
|
|
Packit |
4e8bc4 |
int arg = 0;
|
|
Packit |
4e8bc4 |
char tmo[24];
|
|
Packit |
4e8bc4 |
snprintf(tmo, sizeof(tmo), "%u", timeout);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
putenv(environment);
|
|
Packit |
4e8bc4 |
#ifdef __sun
|
|
Packit |
4e8bc4 |
putenv("LD_PRELOAD=watchmalloc.so.1");
|
|
Packit |
4e8bc4 |
putenv("MALLOC_DEBUG=WATCH");
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (!daemon) {
|
|
Packit |
4e8bc4 |
argv[arg++] = "./timedrun";
|
|
Packit |
4e8bc4 |
argv[arg++] = tmo;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
argv[arg++] = "./memcached-debug";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-A";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-p";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-1";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-U";
|
|
Packit |
4e8bc4 |
argv[arg++] = "0";
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
if (enable_ssl) {
|
|
Packit |
4e8bc4 |
argv[arg++] = "-Z";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-o";
|
|
Packit |
4e8bc4 |
argv[arg++] = "ssl_chain_cert=t/server_crt.pem";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-o";
|
|
Packit |
4e8bc4 |
argv[arg++] = "ssl_key=t/server_key.pem";
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
/* Handle rpmbuild and the like doing this as root */
|
|
Packit |
4e8bc4 |
if (getuid() == 0) {
|
|
Packit |
4e8bc4 |
argv[arg++] = "-u";
|
|
Packit |
4e8bc4 |
argv[arg++] = "root";
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
if (daemon) {
|
|
Packit |
4e8bc4 |
argv[arg++] = "-d";
|
|
Packit |
4e8bc4 |
argv[arg++] = "-P";
|
|
Packit |
4e8bc4 |
argv[arg++] = pid_file;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#ifdef MESSAGE_DEBUG
|
|
Packit |
4e8bc4 |
argv[arg++] = "-vvv";
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
#ifdef HAVE_DROP_PRIVILEGES
|
|
Packit |
4e8bc4 |
argv[arg++] = "-o";
|
|
Packit |
4e8bc4 |
argv[arg++] = "relaxed_privileges";
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
argv[arg++] = NULL;
|
|
Packit |
4e8bc4 |
assert(execv(argv[0], argv) != -1);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Yeah just let us "busy-wait" for the file to be created ;-) */
|
|
Packit |
4e8bc4 |
while (access(filename, F_OK) == -1) {
|
|
Packit |
4e8bc4 |
usleep(10);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
FILE *fp = fopen(filename, "r");
|
|
Packit |
4e8bc4 |
if (fp == NULL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
assert(false);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
*port_out = (in_port_t)-1;
|
|
Packit |
4e8bc4 |
char buffer[80];
|
|
Packit |
4e8bc4 |
while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
|
|
Packit |
4e8bc4 |
if (strncmp(buffer, "TCP INET: ", 10) == 0) {
|
|
Packit |
4e8bc4 |
int32_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtol(buffer + 10, &val));
|
|
Packit |
4e8bc4 |
*port_out = (in_port_t)val;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
fclose(fp);
|
|
Packit |
4e8bc4 |
assert(remove(filename) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (daemon) {
|
|
Packit |
4e8bc4 |
/* loop and wait for the pid file.. There is a potential race
|
|
Packit |
4e8bc4 |
* condition that the server just created the file but isn't
|
|
Packit |
4e8bc4 |
* finished writing the content, so we loop a few times
|
|
Packit |
4e8bc4 |
* reading as well */
|
|
Packit |
4e8bc4 |
while (access(pid_file, F_OK) == -1) {
|
|
Packit |
4e8bc4 |
usleep(10);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
fp = fopen(pid_file, "r");
|
|
Packit |
4e8bc4 |
if (fp == NULL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to open pid file: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
assert(false);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Avoid race by retrying 20 times */
|
|
Packit |
4e8bc4 |
for (int x = 0; x < 20 && fgets(buffer, sizeof(buffer), fp) == NULL; x++) {
|
|
Packit |
4e8bc4 |
usleep(10);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
fclose(fp);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int32_t val;
|
|
Packit |
4e8bc4 |
assert(safe_strtol(buffer, &val));
|
|
Packit |
4e8bc4 |
pid = (pid_t)val;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return pid;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_issue_44(void) {
|
|
Packit |
4e8bc4 |
in_port_t port;
|
|
Packit |
4e8bc4 |
pid_t pid = start_server(&port, true, 15);
|
|
Packit |
4e8bc4 |
assert(kill(pid, SIGHUP) == 0);
|
|
Packit |
4e8bc4 |
sleep(1);
|
|
Packit |
4e8bc4 |
assert(kill(pid, SIGTERM) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
struct addrinfo *ai = 0;
|
|
Packit |
4e8bc4 |
struct addrinfo hints = { .ai_family = AF_UNSPEC,
|
|
Packit |
4e8bc4 |
.ai_protocol = IPPROTO_TCP,
|
|
Packit |
4e8bc4 |
.ai_socktype = SOCK_STREAM };
|
|
Packit |
4e8bc4 |
char service[NI_MAXSERV];
|
|
Packit |
4e8bc4 |
int error;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
(void)snprintf(service, NI_MAXSERV, "%d", port);
|
|
Packit |
4e8bc4 |
if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
|
|
Packit |
4e8bc4 |
if (error != EAI_SYSTEM) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
perror("getaddrinfo()");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return ai;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static struct conn *connect_server(const char *hostname, in_port_t port,
|
|
Packit |
4e8bc4 |
bool nonblock, const bool ssl)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
struct conn *c;
|
|
Packit |
4e8bc4 |
if (!(c = (struct conn *)calloc(1, sizeof(struct conn)))) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to allocate the client connection: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
return NULL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
struct addrinfo *ai = lookuphost(hostname, port);
|
|
Packit |
4e8bc4 |
int sock = -1;
|
|
Packit |
4e8bc4 |
if (ai != NULL) {
|
|
Packit |
4e8bc4 |
if ((sock = socket(ai->ai_family, ai->ai_socktype,
|
|
Packit |
4e8bc4 |
ai->ai_protocol)) != -1) {
|
|
Packit |
4e8bc4 |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to connect socket: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
close(sock);
|
|
Packit |
4e8bc4 |
sock = -1;
|
|
Packit |
4e8bc4 |
} else if (nonblock) {
|
|
Packit |
4e8bc4 |
int flags = fcntl(sock, F_GETFL, 0);
|
|
Packit |
4e8bc4 |
if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
close(sock);
|
|
Packit |
4e8bc4 |
sock = -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
freeaddrinfo(ai);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
c->sock = sock;
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
if (sock > 0 && ssl) {
|
|
Packit |
4e8bc4 |
c->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
|
Packit |
4e8bc4 |
if (c->ssl_ctx == NULL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to create the SSL context: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
close(sock);
|
|
Packit |
4e8bc4 |
sock = -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
c->ssl = SSL_new(c->ssl_ctx);
|
|
Packit |
4e8bc4 |
if (c->ssl == NULL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to create the SSL object: %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
close(sock);
|
|
Packit |
4e8bc4 |
sock = -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
SSL_set_fd (c->ssl, c->sock);
|
|
Packit |
4e8bc4 |
int ret = SSL_connect(c->ssl);
|
|
Packit |
4e8bc4 |
if (ret < 0) {
|
|
Packit |
4e8bc4 |
int err = SSL_get_error(c->ssl, ret);
|
|
Packit |
4e8bc4 |
if (err == SSL_ERROR_SYSCALL || err == SSL_ERROR_SSL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "SSL connection failed with error code : %s\n",
|
|
Packit |
4e8bc4 |
strerror(errno));
|
|
Packit |
4e8bc4 |
close(sock);
|
|
Packit |
4e8bc4 |
sock = -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
c->read = ssl_read;
|
|
Packit |
4e8bc4 |
c->write = ssl_write;
|
|
Packit |
4e8bc4 |
} else
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
c->read = tcp_read;
|
|
Packit |
4e8bc4 |
c->write = tcp_write;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
return c;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_vperror(void) {
|
|
Packit |
4e8bc4 |
int rv = 0;
|
|
Packit |
4e8bc4 |
int oldstderr = dup(STDERR_FILENO);
|
|
Packit |
4e8bc4 |
assert(oldstderr >= 0);
|
|
Packit |
4e8bc4 |
char tmpl[sizeof(TMP_TEMPLATE)+1];
|
|
Packit |
4e8bc4 |
strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int newfile = mkstemp(tmpl);
|
|
Packit |
4e8bc4 |
assert(newfile > 0);
|
|
Packit |
4e8bc4 |
rv = dup2(newfile, STDERR_FILENO);
|
|
Packit |
4e8bc4 |
assert(rv == STDERR_FILENO);
|
|
Packit |
4e8bc4 |
rv = close(newfile);
|
|
Packit |
4e8bc4 |
assert(rv == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
errno = EIO;
|
|
Packit |
4e8bc4 |
vperror("Old McDonald had a farm. %s", "EI EIO");
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Restore stderr */
|
|
Packit |
4e8bc4 |
rv = dup2(oldstderr, STDERR_FILENO);
|
|
Packit |
4e8bc4 |
assert(rv == STDERR_FILENO);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Go read the file */
|
|
Packit |
4e8bc4 |
char buf[80] = { 0 };
|
|
Packit |
4e8bc4 |
FILE *efile = fopen(tmpl, "r");
|
|
Packit |
4e8bc4 |
assert(efile);
|
|
Packit |
4e8bc4 |
char *prv = fgets(buf, sizeof(buf), efile);
|
|
Packit |
4e8bc4 |
assert(prv);
|
|
Packit |
4e8bc4 |
fclose(efile);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
unlink(tmpl);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
char expected[80] = { 0 };
|
|
Packit |
4e8bc4 |
snprintf(expected, sizeof(expected),
|
|
Packit |
4e8bc4 |
"Old McDonald had a farm. EI EIO: %s\n", strerror(EIO));
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/*
|
|
Packit |
4e8bc4 |
fprintf(stderr,
|
|
Packit |
4e8bc4 |
"\nExpected: ``%s''"
|
|
Packit |
4e8bc4 |
"\nGot: ``%s''\n", expected, buf);
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void send_ascii_command(const char *buf) {
|
|
Packit |
4e8bc4 |
off_t offset = 0;
|
|
Packit |
4e8bc4 |
const char* ptr = buf;
|
|
Packit |
4e8bc4 |
size_t len = strlen(buf);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
ssize_t nw = con->write((void*)con, ptr + offset, len - offset);
|
|
Packit |
4e8bc4 |
if (nw == -1) {
|
|
Packit |
4e8bc4 |
if (errno != EINTR) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to write: %s\n", strerror(errno));
|
|
Packit |
4e8bc4 |
abort();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
offset += nw;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} while (offset < len);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/*
|
|
Packit |
4e8bc4 |
* This is a dead slow single byte read, but it should only read out
|
|
Packit |
4e8bc4 |
* _one_ response and I don't have an input buffer... The current
|
|
Packit |
4e8bc4 |
* implementation only supports single-line responses, so if you want to use
|
|
Packit |
4e8bc4 |
* it for get commands you need to implement that first ;-)
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
static void read_ascii_response(char *buffer, size_t size) {
|
|
Packit |
4e8bc4 |
off_t offset = 0;
|
|
Packit |
4e8bc4 |
bool need_more = true;
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
ssize_t nr = con->read(con, buffer + offset, 1);
|
|
Packit |
4e8bc4 |
if (nr == -1) {
|
|
Packit |
4e8bc4 |
if (errno != EINTR) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to read: %s\n", strerror(errno));
|
|
Packit |
4e8bc4 |
abort();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
assert(nr == 1);
|
|
Packit |
4e8bc4 |
if (buffer[offset] == '\n') {
|
|
Packit |
4e8bc4 |
need_more = false;
|
|
Packit |
4e8bc4 |
buffer[offset + 1] = '\0';
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
offset += nr;
|
|
Packit |
4e8bc4 |
assert(offset + 1 < size);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} while (need_more);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_issue_92(void) {
|
|
Packit |
4e8bc4 |
char buffer[1024];
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command("stats cachedump 1 0 0\r\n");
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
read_ascii_response(buffer, sizeof(buffer));
|
|
Packit |
4e8bc4 |
assert(strncmp(buffer, "END", strlen("END")) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command("stats cachedump 200 0 0\r\n");
|
|
Packit |
4e8bc4 |
read_ascii_response(buffer, sizeof(buffer));
|
|
Packit |
4e8bc4 |
assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_issue_102(void) {
|
|
Packit |
4e8bc4 |
char buffer[4096];
|
|
Packit |
4e8bc4 |
memset(buffer, ' ', sizeof(buffer));
|
|
Packit |
4e8bc4 |
buffer[sizeof(buffer) - 1] = '\0';
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command(buffer);
|
|
Packit |
4e8bc4 |
/* verify that the server closed the connection */
|
|
Packit |
4e8bc4 |
assert(con->read(con, buffer, sizeof(buffer)) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
snprintf(buffer, sizeof(buffer), "gets ");
|
|
Packit |
4e8bc4 |
size_t offset = 5;
|
|
Packit |
4e8bc4 |
while (offset < 4000) {
|
|
Packit |
4e8bc4 |
offset += snprintf(buffer + offset, sizeof(buffer) - offset,
|
|
Packit |
4e8bc4 |
"%010u ", (unsigned int)offset);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command(buffer);
|
|
Packit |
4e8bc4 |
usleep(250);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command("\r\n");
|
|
Packit |
4e8bc4 |
char rsp[80];
|
|
Packit |
4e8bc4 |
read_ascii_response(rsp, sizeof(rsp));
|
|
Packit |
4e8bc4 |
assert(strncmp(rsp, "END", strlen("END")) == 0);
|
|
Packit |
4e8bc4 |
buffer[3]= ' ';
|
|
Packit |
4e8bc4 |
send_ascii_command(buffer);
|
|
Packit |
4e8bc4 |
usleep(250);
|
|
Packit |
4e8bc4 |
send_ascii_command("\r\n");
|
|
Packit |
4e8bc4 |
read_ascii_response(rsp, sizeof(rsp));
|
|
Packit |
4e8bc4 |
assert(strncmp(rsp, "END", strlen("END")) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(buffer, ' ', sizeof(buffer));
|
|
Packit |
4e8bc4 |
int len = snprintf(buffer + 101, sizeof(buffer) - 101, "gets foo");
|
|
Packit |
4e8bc4 |
buffer[101 + len] = ' ';
|
|
Packit |
4e8bc4 |
buffer[sizeof(buffer) - 1] = '\0';
|
|
Packit |
4e8bc4 |
send_ascii_command(buffer);
|
|
Packit |
4e8bc4 |
/* verify that the server closed the connection */
|
|
Packit |
4e8bc4 |
assert(con->read(con, buffer, sizeof(buffer)) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return start_memcached_server(void) {
|
|
Packit |
4e8bc4 |
server_pid = start_server(&port, false, 600);
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return stop_memcached_server(void) {
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
if (server_pid != -1) {
|
|
Packit |
4e8bc4 |
assert(kill(server_pid, SIGTERM) == 0);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return shutdown_memcached_server(void) {
|
|
Packit |
4e8bc4 |
char buffer[1024];
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send_ascii_command("shutdown\r\n");
|
|
Packit |
4e8bc4 |
/* verify that the server closed the connection */
|
|
Packit |
4e8bc4 |
assert(con->read(con, buffer, sizeof(buffer)) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* We set server_pid to -1 so that we don't later call kill() */
|
|
Packit |
4e8bc4 |
if (kill(server_pid, 0) == 0) {
|
|
Packit |
4e8bc4 |
server_pid = -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void safe_send(const void* buf, size_t len, bool hickup)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
off_t offset = 0;
|
|
Packit |
4e8bc4 |
const char* ptr = buf;
|
|
Packit |
4e8bc4 |
#ifdef MESSAGE_DEBUG
|
|
Packit |
4e8bc4 |
uint8_t val = *ptr;
|
|
Packit |
4e8bc4 |
assert(val == (uint8_t)0x80);
|
|
Packit |
4e8bc4 |
fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
|
|
Packit |
4e8bc4 |
for (int ii = 0; ii < len; ++ii) {
|
|
Packit |
4e8bc4 |
if (ii % 4 == 0) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "\n ");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
val = *(ptr + ii);
|
|
Packit |
4e8bc4 |
fprintf(stderr, " 0x%02x", val);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
fprintf(stderr, "\n");
|
|
Packit |
4e8bc4 |
usleep(500);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
size_t num_bytes = len - offset;
|
|
Packit |
4e8bc4 |
if (hickup) {
|
|
Packit |
4e8bc4 |
if (num_bytes > 1024) {
|
|
Packit |
4e8bc4 |
num_bytes = (rand() % 1023) + 1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
ssize_t nw = con->write(con, ptr + offset, num_bytes);
|
|
Packit |
4e8bc4 |
if (nw == -1) {
|
|
Packit |
4e8bc4 |
if (errno != EINTR) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to write: %s\n", strerror(errno));
|
|
Packit |
4e8bc4 |
abort();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
if (hickup) {
|
|
Packit |
4e8bc4 |
usleep(100);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
offset += nw;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} while (offset < len);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static bool safe_recv(void *buf, size_t len) {
|
|
Packit |
4e8bc4 |
if (len == 0) {
|
|
Packit |
4e8bc4 |
return true;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
off_t offset = 0;
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
ssize_t nr = con->read(con, ((char*)buf) + offset, len - offset);
|
|
Packit |
4e8bc4 |
if (nr == -1) {
|
|
Packit |
4e8bc4 |
if (errno != EINTR) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to read: %s\n", strerror(errno));
|
|
Packit |
4e8bc4 |
abort();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
if (nr == 0 && allow_closed_read) {
|
|
Packit |
4e8bc4 |
return false;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
assert(nr != 0);
|
|
Packit |
4e8bc4 |
offset += nr;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} while (offset < len);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return true;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static bool safe_recv_packet(void *buf, size_t size) {
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras *response = buf;
|
|
Packit |
4e8bc4 |
assert(size > sizeof(*response));
|
|
Packit |
4e8bc4 |
if (!safe_recv(response, sizeof(*response))) {
|
|
Packit |
4e8bc4 |
return false;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
|
|
Packit |
4e8bc4 |
response->message.header.response.status = ntohs(response->message.header.response.status);
|
|
Packit |
4e8bc4 |
response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = sizeof(*response);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
char *ptr = buf;
|
|
Packit |
4e8bc4 |
ptr += len;
|
|
Packit |
4e8bc4 |
if (!safe_recv(ptr, response->message.header.response.bodylen)) {
|
|
Packit |
4e8bc4 |
return false;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#ifdef MESSAGE_DEBUG
|
|
Packit |
4e8bc4 |
usleep(500);
|
|
Packit |
4e8bc4 |
ptr = buf;
|
|
Packit |
4e8bc4 |
len += response->message.header.response.bodylen;
|
|
Packit |
4e8bc4 |
uint8_t val = *ptr;
|
|
Packit |
4e8bc4 |
assert(val == (uint8_t)0x81);
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
|
|
Packit |
4e8bc4 |
for (int ii = 0; ii < len; ++ii) {
|
|
Packit |
4e8bc4 |
if (ii % 4 == 0) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "\n ");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
val = *(ptr + ii);
|
|
Packit |
4e8bc4 |
fprintf(stderr, " 0x%02x", val);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
fprintf(stderr, "\n");
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
return true;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t storage_command(char*buf,
|
|
Packit |
4e8bc4 |
size_t bufsz,
|
|
Packit |
4e8bc4 |
uint8_t cmd,
|
|
Packit |
4e8bc4 |
const void* key,
|
|
Packit |
4e8bc4 |
size_t keylen,
|
|
Packit |
4e8bc4 |
const void* dta,
|
|
Packit |
4e8bc4 |
size_t dtalen,
|
|
Packit |
4e8bc4 |
uint32_t flags,
|
|
Packit |
4e8bc4 |
uint32_t exp) {
|
|
Packit |
4e8bc4 |
/* all of the storage commands use the same command layout */
|
|
Packit |
4e8bc4 |
protocol_binary_request_set *request = (void*)buf;
|
|
Packit |
4e8bc4 |
assert(bufsz > sizeof(*request) + keylen + dtalen);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(request, 0, sizeof(*request));
|
|
Packit |
4e8bc4 |
request->message.header.request.magic = PROTOCOL_BINARY_REQ;
|
|
Packit |
4e8bc4 |
request->message.header.request.opcode = cmd;
|
|
Packit |
4e8bc4 |
request->message.header.request.keylen = htons(keylen);
|
|
Packit |
4e8bc4 |
request->message.header.request.extlen = 8;
|
|
Packit |
4e8bc4 |
request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
|
|
Packit |
4e8bc4 |
request->message.header.request.opaque = 0xdeadbeef;
|
|
Packit |
4e8bc4 |
request->message.body.flags = flags;
|
|
Packit |
4e8bc4 |
request->message.body.expiration = exp;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memcpy(buf + key_offset, key, keylen);
|
|
Packit |
4e8bc4 |
if (dta != NULL) {
|
|
Packit |
4e8bc4 |
memcpy(buf + key_offset + keylen, dta, dtalen);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return key_offset + keylen + dtalen;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t ext_command(char* buf,
|
|
Packit |
4e8bc4 |
size_t bufsz,
|
|
Packit |
4e8bc4 |
uint8_t cmd,
|
|
Packit |
4e8bc4 |
const void* ext,
|
|
Packit |
4e8bc4 |
size_t extlen,
|
|
Packit |
4e8bc4 |
const void* key,
|
|
Packit |
4e8bc4 |
size_t keylen,
|
|
Packit |
4e8bc4 |
const void* dta,
|
|
Packit |
4e8bc4 |
size_t dtalen) {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras *request = (void*)buf;
|
|
Packit |
4e8bc4 |
assert(bufsz > sizeof(*request) + extlen + keylen + dtalen);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(request, 0, sizeof(*request));
|
|
Packit |
4e8bc4 |
request->message.header.request.magic = PROTOCOL_BINARY_REQ;
|
|
Packit |
4e8bc4 |
request->message.header.request.opcode = cmd;
|
|
Packit |
4e8bc4 |
request->message.header.request.extlen = extlen;
|
|
Packit |
4e8bc4 |
request->message.header.request.keylen = htons(keylen);
|
|
Packit |
4e8bc4 |
request->message.header.request.bodylen = htonl(extlen + keylen + dtalen);
|
|
Packit |
4e8bc4 |
request->message.header.request.opaque = 0xdeadbeef;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
off_t ext_offset = sizeof(protocol_binary_request_no_extras);
|
|
Packit |
4e8bc4 |
off_t key_offset = ext_offset + extlen;
|
|
Packit |
4e8bc4 |
off_t dta_offset = key_offset + keylen;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (ext != NULL) {
|
|
Packit |
4e8bc4 |
memcpy(buf + ext_offset, ext, extlen);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
if (key != NULL) {
|
|
Packit |
4e8bc4 |
memcpy(buf + key_offset, key, keylen);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
if (dta != NULL) {
|
|
Packit |
4e8bc4 |
memcpy(buf + dta_offset, dta, dtalen);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return sizeof(*request) + extlen + keylen + dtalen;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t raw_command(char* buf,
|
|
Packit |
4e8bc4 |
size_t bufsz,
|
|
Packit |
4e8bc4 |
uint8_t cmd,
|
|
Packit |
4e8bc4 |
const void* key,
|
|
Packit |
4e8bc4 |
size_t keylen,
|
|
Packit |
4e8bc4 |
const void* dta,
|
|
Packit |
4e8bc4 |
size_t dtalen) {
|
|
Packit |
4e8bc4 |
/* all of the storage commands use the same command layout */
|
|
Packit |
4e8bc4 |
return ext_command(buf, bufsz, cmd, NULL, 0, key, keylen, dta, dtalen);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
|
|
Packit |
4e8bc4 |
protocol_binary_request_flush *request = (void*)buf;
|
|
Packit |
4e8bc4 |
assert(bufsz > sizeof(*request));
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(request, 0, sizeof(*request));
|
|
Packit |
4e8bc4 |
request->message.header.request.magic = PROTOCOL_BINARY_REQ;
|
|
Packit |
4e8bc4 |
request->message.header.request.opcode = cmd;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
off_t size = sizeof(protocol_binary_request_no_extras);
|
|
Packit |
4e8bc4 |
if (use_extra) {
|
|
Packit |
4e8bc4 |
request->message.header.request.extlen = 4;
|
|
Packit |
4e8bc4 |
request->message.body.expiration = htonl(exptime);
|
|
Packit |
4e8bc4 |
request->message.header.request.bodylen = htonl(4);
|
|
Packit |
4e8bc4 |
size += 4;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
request->message.header.request.opaque = 0xdeadbeef;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return size;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t touch_command(char* buf,
|
|
Packit |
4e8bc4 |
size_t bufsz,
|
|
Packit |
4e8bc4 |
uint8_t cmd,
|
|
Packit |
4e8bc4 |
const void* key,
|
|
Packit |
4e8bc4 |
size_t keylen,
|
|
Packit |
4e8bc4 |
uint32_t exptime) {
|
|
Packit |
4e8bc4 |
protocol_binary_request_touch *request = (void*)buf;
|
|
Packit |
4e8bc4 |
assert(bufsz > sizeof(*request));
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(request, 0, sizeof(*request));
|
|
Packit |
4e8bc4 |
request->message.header.request.magic = PROTOCOL_BINARY_REQ;
|
|
Packit |
4e8bc4 |
request->message.header.request.opcode = cmd;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
request->message.header.request.keylen = htons(keylen);
|
|
Packit |
4e8bc4 |
request->message.header.request.extlen = 4;
|
|
Packit |
4e8bc4 |
request->message.body.expiration = htonl(exptime);
|
|
Packit |
4e8bc4 |
request->message.header.request.bodylen = htonl(keylen + 4);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
request->message.header.request.opaque = 0xdeadbeef;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
off_t key_offset = sizeof(protocol_binary_request_no_extras) + 4;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memcpy(buf + key_offset, key, keylen);
|
|
Packit |
4e8bc4 |
return sizeof(protocol_binary_request_no_extras) + 4 + keylen;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static off_t arithmetic_command(char* buf,
|
|
Packit |
4e8bc4 |
size_t bufsz,
|
|
Packit |
4e8bc4 |
uint8_t cmd,
|
|
Packit |
4e8bc4 |
const void* key,
|
|
Packit |
4e8bc4 |
size_t keylen,
|
|
Packit |
4e8bc4 |
uint64_t delta,
|
|
Packit |
4e8bc4 |
uint64_t initial,
|
|
Packit |
4e8bc4 |
uint32_t exp) {
|
|
Packit |
4e8bc4 |
protocol_binary_request_incr *request = (void*)buf;
|
|
Packit |
4e8bc4 |
assert(bufsz > sizeof(*request) + keylen);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(request, 0, sizeof(*request));
|
|
Packit |
4e8bc4 |
request->message.header.request.magic = PROTOCOL_BINARY_REQ;
|
|
Packit |
4e8bc4 |
request->message.header.request.opcode = cmd;
|
|
Packit |
4e8bc4 |
request->message.header.request.keylen = htons(keylen);
|
|
Packit |
4e8bc4 |
request->message.header.request.extlen = 20;
|
|
Packit |
4e8bc4 |
request->message.header.request.bodylen = htonl(keylen + 20);
|
|
Packit |
4e8bc4 |
request->message.header.request.opaque = 0xdeadbeef;
|
|
Packit |
4e8bc4 |
request->message.body.delta = htonll(delta);
|
|
Packit |
4e8bc4 |
request->message.body.initial = htonll(initial);
|
|
Packit |
4e8bc4 |
request->message.body.expiration = htonl(exp);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memcpy(buf + key_offset, key, keylen);
|
|
Packit |
4e8bc4 |
return key_offset + keylen;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void validate_response_header(protocol_binary_response_no_extras *response,
|
|
Packit |
4e8bc4 |
uint8_t cmd, uint16_t status)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.opcode == cmd);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.status == status);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.opaque == 0xdeadbeef);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
|
Packit |
4e8bc4 |
switch (cmd) {
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_ADDQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_APPENDQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DECREMENTQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DELETEQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_FLUSHQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_INCREMENTQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_PREPENDQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_QUITQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_REPLACEQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SETQ:
|
|
Packit |
4e8bc4 |
assert("Quiet command shouldn't return on success" == NULL);
|
|
Packit |
4e8bc4 |
default:
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
switch (cmd) {
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_ADD:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_REPLACE:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SET:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_APPEND:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_PREPEND:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.bodylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas != 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_FLUSH:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_NOOP:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_QUIT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DELETE:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.bodylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas == 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DECREMENT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_INCREMENT:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.bodylen == 8);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas != 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_STAT:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
/* key and value exists in all packets except in the terminating */
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas == 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_VERSION:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.bodylen != 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas == 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GET:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GAT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATQ:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 4);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas != 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETK:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETKQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATK:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATKQ:
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen != 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 4);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas != 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
default:
|
|
Packit |
4e8bc4 |
/* Undefined command code */
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.cas == 0);
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.extlen == 0);
|
|
Packit |
4e8bc4 |
if (cmd != PROTOCOL_BINARY_CMD_GETK &&
|
|
Packit |
4e8bc4 |
cmd != PROTOCOL_BINARY_CMD_GATK) {
|
|
Packit |
4e8bc4 |
assert(response->message.header.response.keylen == 0);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_noop(void) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} buffer;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_NOOP,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(buffer.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_quit_impl(uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} buffer;
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
|
|
Packit |
4e8bc4 |
cmd, NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(buffer.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Socket should be closed now, read should return 0 */
|
|
Packit |
4e8bc4 |
assert(con->read(con, buffer.bytes, sizeof(buffer.bytes)) == 0);
|
|
Packit |
4e8bc4 |
close_conn();
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_quit(void) {
|
|
Packit |
4e8bc4 |
return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_quitq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
uint64_t value = 0xdeadbeefdeadcafe;
|
|
Packit |
4e8bc4 |
size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), &value, sizeof(value),
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Set should work over and over again */
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_SET) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
|
|
Packit |
4e8bc4 |
return test_binary_noop();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
send.request.message.header.request.cas = receive.response.message.header.response.cas;
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_SET) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
return test_binary_noop();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_set(void) {
|
|
Packit |
4e8bc4 |
return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_setq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
uint64_t value = 0xdeadbeefdeadcafe;
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
|
|
Packit |
4e8bc4 |
strlen(key), &value, sizeof(value),
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Add should only work the first time */
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (ii == 0) {
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_ADD) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_add(void) {
|
|
Packit |
4e8bc4 |
return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_addq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
uint64_t value = 0xdeadbeefdeadcafe;
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), &value, sizeof(value),
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), &value, sizeof(value), 0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), &value, sizeof(value), 0, 0);
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_REPLACE,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
|
|
Packit |
4e8bc4 |
test_binary_noop();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_replace(void) {
|
|
Packit |
4e8bc4 |
return test_binary_replace_impl("test_binary_replace",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_REPLACE);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_replaceq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_replace_impl("test_binary_replaceq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_REPLACEQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0, 0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
cmd, key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_delete(void) {
|
|
Packit |
4e8bc4 |
return test_binary_delete_impl("test_binary_delete",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_DELETE);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_deleteq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_delete_impl("test_binary_deleteq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_DELETEQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
uint32_t expiration = htonl(3600);
|
|
Packit |
4e8bc4 |
size_t extlen = 0;
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_GAT || cmd == PROTOCOL_BINARY_CMD_GATK)
|
|
Packit |
4e8bc4 |
extlen = sizeof(expiration);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = ext_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
extlen ? &expiration : NULL, extlen,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0,
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* run a little pipeline test ;-) */
|
|
Packit |
4e8bc4 |
len = 0;
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} temp;
|
|
Packit |
4e8bc4 |
size_t l = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
|
|
Packit |
4e8bc4 |
extlen ? &expiration : NULL, extlen,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
memcpy(send.bytes + len, temp.bytes, l);
|
|
Packit |
4e8bc4 |
len += l;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_get(void) {
|
|
Packit |
4e8bc4 |
return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_getk(void) {
|
|
Packit |
4e8bc4 |
return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_gat(void) {
|
|
Packit |
4e8bc4 |
return test_binary_get_impl("test_binary_gat", PROTOCOL_BINARY_CMD_GAT);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_gatk(void) {
|
|
Packit |
4e8bc4 |
return test_binary_get_impl("test_binary_gatk", PROTOCOL_BINARY_CMD_GATK);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
const char *missing = "test_binary_getq_missing";
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, temp, receive;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
uint32_t expiration = htonl(3600);
|
|
Packit |
4e8bc4 |
size_t extlen = 0;
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_GATQ || cmd == PROTOCOL_BINARY_CMD_GATKQ)
|
|
Packit |
4e8bc4 |
extlen = sizeof(expiration);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0,
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
size_t len2 = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
|
|
Packit |
4e8bc4 |
extlen ? &expiration : NULL, extlen,
|
|
Packit |
4e8bc4 |
missing, strlen(missing), NULL, 0);
|
|
Packit |
4e8bc4 |
/* I need to change the first opaque so that I can separate the two
|
|
Packit |
4e8bc4 |
* return packets */
|
|
Packit |
4e8bc4 |
temp.request.message.header.request.opaque = 0xfeedface;
|
|
Packit |
4e8bc4 |
memcpy(send.bytes + len, temp.bytes, len2);
|
|
Packit |
4e8bc4 |
len += len2;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len2 = ext_command(temp.bytes, sizeof(temp.bytes), cmd,
|
|
Packit |
4e8bc4 |
extlen ? &expiration : NULL, extlen,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
memcpy(send.bytes + len, temp.bytes, len2);
|
|
Packit |
4e8bc4 |
len += len2;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
/* The first GETQ shouldn't return anything */
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_getq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_getkq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_gatq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_getq_impl("test_binary_gatq", PROTOCOL_BINARY_CMD_GATQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_gatkq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_getq_impl("test_binary_gatkq", PROTOCOL_BINARY_CMD_GATKQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response_header;
|
|
Packit |
4e8bc4 |
protocol_binary_response_incr response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), 1, 0, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 10; ++ii) {
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response_header, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
assert(ntohll(receive.response.message.body.value) == ii);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
|
|
Packit |
4e8bc4 |
test_binary_noop();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_incr(void) {
|
|
Packit |
4e8bc4 |
return test_binary_incr_impl("test_binary_incr",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_INCREMENT);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_incrq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_incr_impl("test_binary_incrq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_INCREMENTQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response_header;
|
|
Packit |
4e8bc4 |
protocol_binary_response_decr response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), 1, 9, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 9; ii >= 0; --ii) {
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response_header, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
assert(ntohll(receive.response.message.body.value) == ii);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* decr on 0 should not wrap */
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response_header, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
assert(ntohll(receive.response.message.body.value) == 0);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
test_binary_noop();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_decr(void) {
|
|
Packit |
4e8bc4 |
return test_binary_decr_impl("test_binary_decr",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_DECREMENT);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_decrq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_decr_impl("test_binary_decrq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_DECREMENTQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_version(void) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} buffer;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_VERSION,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(buffer.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0, 0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
sleep(2);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 2; ++ii) {
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0, 0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_GET,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_flush(void) {
|
|
Packit |
4e8bc4 |
return test_binary_flush_impl("test_binary_flush",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_FLUSH);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_flushq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_flush_impl("test_binary_flushq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_FLUSHQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} send, receive;
|
|
Packit |
4e8bc4 |
const char *value = "world";
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), value, strlen(value));
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_NOT_STORED);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = storage_command(send.bytes, sizeof(send.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
key, strlen(key), value, strlen(value), 0, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, strlen(key), value, strlen(value));
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
|
|
Packit |
4e8bc4 |
key, strlen(key), NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(send.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(receive.bytes, sizeof(receive.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
assert(receive.response.message.header.response.keylen == strlen(key));
|
|
Packit |
4e8bc4 |
assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
char *ptr = receive.bytes;
|
|
Packit |
4e8bc4 |
ptr += sizeof(receive.response);
|
|
Packit |
4e8bc4 |
ptr += 4;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
assert(memcmp(ptr, key, strlen(key)) == 0);
|
|
Packit |
4e8bc4 |
ptr += strlen(key);
|
|
Packit |
4e8bc4 |
assert(memcmp(ptr, value, strlen(value)) == 0);
|
|
Packit |
4e8bc4 |
ptr += strlen(value);
|
|
Packit |
4e8bc4 |
assert(memcmp(ptr, value, strlen(value)) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_append(void) {
|
|
Packit |
4e8bc4 |
return test_binary_concat_impl("test_binary_append",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_APPEND);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_prepend(void) {
|
|
Packit |
4e8bc4 |
return test_binary_concat_impl("test_binary_prepend",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_PREPEND);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_appendq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_concat_impl("test_binary_appendq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_APPENDQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_prependq(void) {
|
|
Packit |
4e8bc4 |
return test_binary_concat_impl("test_binary_prependq",
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_PREPENDQ);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_stat(void) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} buffer;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_STAT,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
safe_send(buffer.bytes, len, false);
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_SUCCESS);
|
|
Packit |
4e8bc4 |
} while (buffer.response.message.header.response.keylen != 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_illegal(void) {
|
|
Packit |
4e8bc4 |
uint8_t cmd = 0x25;
|
|
Packit |
4e8bc4 |
while (cmd != 0x00) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras response;
|
|
Packit |
4e8bc4 |
char bytes[1024];
|
|
Packit |
4e8bc4 |
} buffer;
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
|
|
Packit |
4e8bc4 |
cmd, NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(buffer.bytes, len, false);
|
|
Packit |
4e8bc4 |
safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
|
|
Packit |
4e8bc4 |
validate_response_header(&buffer.response, cmd,
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND);
|
|
Packit |
4e8bc4 |
++cmd;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
volatile bool hickup_thread_running;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static void *binary_hickup_recv_verification_thread(void *arg) {
|
|
Packit |
4e8bc4 |
protocol_binary_response_no_extras *response = malloc(65*1024);
|
|
Packit |
4e8bc4 |
if (response != NULL) {
|
|
Packit |
4e8bc4 |
while (safe_recv_packet(response, 65*1024)) {
|
|
Packit |
4e8bc4 |
/* Just validate the packet format */
|
|
Packit |
4e8bc4 |
validate_response_header(response,
|
|
Packit |
4e8bc4 |
response->message.header.response.opcode,
|
|
Packit |
4e8bc4 |
response->message.header.response.status);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
free(response);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
hickup_thread_running = false;
|
|
Packit |
4e8bc4 |
allow_closed_read = false;
|
|
Packit |
4e8bc4 |
return NULL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
|
|
Packit |
4e8bc4 |
off_t offset = 0;
|
|
Packit |
4e8bc4 |
char *key[256];
|
|
Packit |
4e8bc4 |
uint64_t value = 0xfeedfacedeadbeef;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
while (hickup_thread_running &&
|
|
Packit |
4e8bc4 |
offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
|
|
Packit |
4e8bc4 |
union {
|
|
Packit |
4e8bc4 |
protocol_binary_request_no_extras request;
|
|
Packit |
4e8bc4 |
char bytes[65 * 1024];
|
|
Packit |
4e8bc4 |
} command;
|
|
Packit |
4e8bc4 |
uint8_t cmd = (uint8_t)(rand() & 0xff);
|
|
Packit |
4e8bc4 |
size_t len;
|
|
Packit |
4e8bc4 |
size_t keylen = (rand() % 250) + 1;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
switch (cmd) {
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_ADD:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_ADDQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_REPLACE:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_REPLACEQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SET:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SETQ:
|
|
Packit |
4e8bc4 |
len = storage_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen , &value, sizeof(value),
|
|
Packit |
4e8bc4 |
0, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_APPEND:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_APPENDQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_PREPEND:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_PREPENDQ:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen, &value, sizeof(value));
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_FLUSH:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_FLUSHQ:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_NOOP:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DELETE:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DELETEQ:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DECREMENT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_DECREMENTQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_INCREMENT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_INCREMENTQ:
|
|
Packit |
4e8bc4 |
len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen, 1, 0, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_VERSION:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_VERSION,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GET:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETK:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETKQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GETQ:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_TOUCH:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GAT:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATK:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_GATKQ:
|
|
Packit |
4e8bc4 |
len = touch_command(command.bytes, sizeof(command.bytes), cmd,
|
|
Packit |
4e8bc4 |
key, keylen, 10);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_STAT:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes),
|
|
Packit |
4e8bc4 |
PROTOCOL_BINARY_CMD_STAT,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SASL_AUTH:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_SASL_STEP:
|
|
Packit |
4e8bc4 |
/* Ignoring SASL */
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_QUITQ:
|
|
Packit |
4e8bc4 |
case PROTOCOL_BINARY_CMD_QUIT:
|
|
Packit |
4e8bc4 |
/* I don't want to pass on the quit commands ;-) */
|
|
Packit |
4e8bc4 |
cmd |= 0xf0;
|
|
Packit |
4e8bc4 |
/* FALLTHROUGH */
|
|
Packit |
4e8bc4 |
default:
|
|
Packit |
4e8bc4 |
len = raw_command(command.bytes, sizeof(command.bytes),
|
|
Packit |
4e8bc4 |
cmd, NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ((len + offset) < buffersize) {
|
|
Packit |
4e8bc4 |
memcpy(((char*)buffer) + offset, command.bytes, len);
|
|
Packit |
4e8bc4 |
offset += len;
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
safe_send(buffer, offset, true);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_binary_pipeline_hickup(void)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
size_t buffersize = 65 * 1024;
|
|
Packit |
4e8bc4 |
void *buffer = malloc(buffersize);
|
|
Packit |
4e8bc4 |
int ii;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
pthread_t tid;
|
|
Packit |
4e8bc4 |
int ret;
|
|
Packit |
4e8bc4 |
allow_closed_read = true;
|
|
Packit |
4e8bc4 |
hickup_thread_running = true;
|
|
Packit |
4e8bc4 |
if ((ret = pthread_create(&tid, NULL,
|
|
Packit |
4e8bc4 |
binary_hickup_recv_verification_thread, NULL)) != 0) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
|
|
Packit |
4e8bc4 |
free(buffer);
|
|
Packit |
4e8bc4 |
return TEST_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Allow the thread to start */
|
|
Packit |
4e8bc4 |
usleep(250);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
srand((int)time(NULL));
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < 2; ++ii) {
|
|
Packit |
4e8bc4 |
test_binary_pipeline_hickup_chunk(buffer, buffersize);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* send quitq to shut down the read thread ;-) */
|
|
Packit |
4e8bc4 |
size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
|
|
Packit |
4e8bc4 |
NULL, 0, NULL, 0);
|
|
Packit |
4e8bc4 |
safe_send(buffer, len, false);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
pthread_join(tid, NULL);
|
|
Packit |
4e8bc4 |
free(buffer);
|
|
Packit |
4e8bc4 |
return TEST_PASS;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static enum test_return test_issue_101(void) {
|
|
Packit |
4e8bc4 |
enum { max = 2 };
|
|
Packit |
4e8bc4 |
enum test_return ret = TEST_PASS;
|
|
Packit |
4e8bc4 |
struct conn *conns[max];
|
|
Packit |
4e8bc4 |
int ii = 0;
|
|
Packit |
4e8bc4 |
pid_t child = 0;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (getenv("SKIP_TEST_101") != NULL) {
|
|
Packit |
4e8bc4 |
return TEST_SKIP;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
const char *command = "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
|
|
Packit |
4e8bc4 |
size_t cmdlen = strlen(command);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
server_pid = start_server(&port, false, 1000);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < max; ++ii) {
|
|
Packit |
4e8bc4 |
conns[ii] = NULL;
|
|
Packit |
4e8bc4 |
conns[ii] = connect_server("127.0.0.1", port, true, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(conns[ii]);
|
|
Packit |
4e8bc4 |
assert(conns[ii]->sock > 0);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Send command on the connection until it blocks */
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < max; ++ii) {
|
|
Packit |
4e8bc4 |
bool more = true;
|
|
Packit |
4e8bc4 |
do {
|
|
Packit |
4e8bc4 |
ssize_t err = conns[ii]->write(conns[ii], command, cmdlen);
|
|
Packit |
4e8bc4 |
if (err == -1) {
|
|
Packit |
4e8bc4 |
switch (errno) {
|
|
Packit |
4e8bc4 |
case EINTR:
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case ENOMEM:
|
|
Packit |
4e8bc4 |
case EWOULDBLOCK:
|
|
Packit |
4e8bc4 |
more = false;
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
default:
|
|
Packit |
4e8bc4 |
ret = TEST_FAIL;
|
|
Packit |
4e8bc4 |
goto cleanup;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} while (more);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
child = fork();
|
|
Packit |
4e8bc4 |
if (child == (pid_t)-1) {
|
|
Packit |
4e8bc4 |
abort();
|
|
Packit |
4e8bc4 |
} else if (child > 0) {
|
|
Packit |
4e8bc4 |
int stat;
|
|
Packit |
4e8bc4 |
pid_t c;
|
|
Packit |
4e8bc4 |
while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
|
|
Packit |
4e8bc4 |
assert(c == child);
|
|
Packit |
4e8bc4 |
assert(stat == 0);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
con = connect_server("127.0.0.1", port, false, enable_ssl);
|
|
Packit |
4e8bc4 |
assert(con);
|
|
Packit |
4e8bc4 |
ret = test_binary_noop();
|
|
Packit |
4e8bc4 |
exit(0);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
cleanup:
|
|
Packit |
4e8bc4 |
/* close all connections */
|
|
Packit |
4e8bc4 |
for (ii = 0; ii < max; ++ii) {
|
|
Packit |
4e8bc4 |
struct conn *c = conns[ii];
|
|
Packit |
4e8bc4 |
if (c == NULL) continue;
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
if (c->ssl) {
|
|
Packit |
4e8bc4 |
SSL_shutdown(c->ssl);
|
|
Packit |
4e8bc4 |
SSL_free(c->ssl);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
if (c->ssl_ctx)
|
|
Packit |
4e8bc4 |
SSL_CTX_free(c->ssl_ctx);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
if (c->sock > 0) close(c->sock);
|
|
Packit |
4e8bc4 |
free(conns[ii]);
|
|
Packit |
4e8bc4 |
conns[ii] = NULL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
assert(kill(server_pid, SIGTERM) == 0);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return ret;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
typedef enum test_return (*TEST_FUNC)(void);
|
|
Packit |
4e8bc4 |
struct testcase {
|
|
Packit |
4e8bc4 |
const char *description;
|
|
Packit |
4e8bc4 |
TEST_FUNC function;
|
|
Packit |
4e8bc4 |
};
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
struct testcase testcases[] = {
|
|
Packit |
4e8bc4 |
{ "cache_create", cache_create_test },
|
|
Packit |
4e8bc4 |
{ "cache_constructor", cache_constructor_test },
|
|
Packit |
4e8bc4 |
{ "cache_constructor_fail", cache_fail_constructor_test },
|
|
Packit |
4e8bc4 |
{ "cache_destructor", cache_destructor_test },
|
|
Packit |
4e8bc4 |
{ "cache_reuse", cache_reuse_test },
|
|
Packit |
4e8bc4 |
{ "cache_redzone", cache_redzone_test },
|
|
Packit |
4e8bc4 |
{ "stats_prefix_find", test_stats_prefix_find },
|
|
Packit |
4e8bc4 |
{ "stats_prefix_record_get", test_stats_prefix_record_get },
|
|
Packit |
4e8bc4 |
{ "stats_prefix_record_delete", test_stats_prefix_record_delete },
|
|
Packit |
4e8bc4 |
{ "stats_prefix_record_set", test_stats_prefix_record_set },
|
|
Packit |
4e8bc4 |
{ "stats_prefix_dump", test_stats_prefix_dump },
|
|
Packit |
4e8bc4 |
{ "issue_161", test_issue_161 },
|
|
Packit |
4e8bc4 |
{ "strtol", test_safe_strtol },
|
|
Packit |
4e8bc4 |
{ "strtoll", test_safe_strtoll },
|
|
Packit |
4e8bc4 |
{ "strtoul", test_safe_strtoul },
|
|
Packit |
4e8bc4 |
{ "strtoull", test_safe_strtoull },
|
|
Packit |
4e8bc4 |
{ "issue_44", test_issue_44 },
|
|
Packit |
4e8bc4 |
{ "vperror", test_vperror },
|
|
Packit |
4e8bc4 |
{ "issue_101", test_issue_101 },
|
|
Packit |
4e8bc4 |
/* The following tests all run towards the same server */
|
|
Packit |
4e8bc4 |
{ "start_server", start_memcached_server },
|
|
Packit |
4e8bc4 |
{ "issue_92", test_issue_92 },
|
|
Packit |
4e8bc4 |
{ "issue_102", test_issue_102 },
|
|
Packit |
4e8bc4 |
{ "binary_noop", test_binary_noop },
|
|
Packit |
4e8bc4 |
{ "binary_quit", test_binary_quit },
|
|
Packit |
4e8bc4 |
{ "binary_quitq", test_binary_quitq },
|
|
Packit |
4e8bc4 |
{ "binary_set", test_binary_set },
|
|
Packit |
4e8bc4 |
{ "binary_setq", test_binary_setq },
|
|
Packit |
4e8bc4 |
{ "binary_add", test_binary_add },
|
|
Packit |
4e8bc4 |
{ "binary_addq", test_binary_addq },
|
|
Packit |
4e8bc4 |
{ "binary_replace", test_binary_replace },
|
|
Packit |
4e8bc4 |
{ "binary_replaceq", test_binary_replaceq },
|
|
Packit |
4e8bc4 |
{ "binary_delete", test_binary_delete },
|
|
Packit |
4e8bc4 |
{ "binary_deleteq", test_binary_deleteq },
|
|
Packit |
4e8bc4 |
{ "binary_get", test_binary_get },
|
|
Packit |
4e8bc4 |
{ "binary_getq", test_binary_getq },
|
|
Packit |
4e8bc4 |
{ "binary_getk", test_binary_getk },
|
|
Packit |
4e8bc4 |
{ "binary_getkq", test_binary_getkq },
|
|
Packit |
4e8bc4 |
{ "binary_gat", test_binary_gat },
|
|
Packit |
4e8bc4 |
{ "binary_gatq", test_binary_gatq },
|
|
Packit |
4e8bc4 |
{ "binary_gatk", test_binary_gatk },
|
|
Packit |
4e8bc4 |
{ "binary_gatkq", test_binary_gatkq },
|
|
Packit |
4e8bc4 |
{ "binary_incr", test_binary_incr },
|
|
Packit |
4e8bc4 |
{ "binary_incrq", test_binary_incrq },
|
|
Packit |
4e8bc4 |
{ "binary_decr", test_binary_decr },
|
|
Packit |
4e8bc4 |
{ "binary_decrq", test_binary_decrq },
|
|
Packit |
4e8bc4 |
{ "binary_version", test_binary_version },
|
|
Packit |
4e8bc4 |
{ "binary_flush", test_binary_flush },
|
|
Packit |
4e8bc4 |
{ "binary_flushq", test_binary_flushq },
|
|
Packit |
4e8bc4 |
{ "binary_append", test_binary_append },
|
|
Packit |
4e8bc4 |
{ "binary_appendq", test_binary_appendq },
|
|
Packit |
4e8bc4 |
{ "binary_prepend", test_binary_prepend },
|
|
Packit |
4e8bc4 |
{ "binary_prependq", test_binary_prependq },
|
|
Packit |
4e8bc4 |
{ "binary_stat", test_binary_stat },
|
|
Packit |
4e8bc4 |
{ "binary_illegal", test_binary_illegal },
|
|
Packit |
4e8bc4 |
{ "binary_pipeline_hickup", test_binary_pipeline_hickup },
|
|
Packit |
4e8bc4 |
{ "shutdown", shutdown_memcached_server },
|
|
Packit |
4e8bc4 |
{ "stop_server", stop_memcached_server },
|
|
Packit |
4e8bc4 |
{ NULL, NULL }
|
|
Packit |
4e8bc4 |
};
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
/* Stub out function defined in memcached.c */
|
|
Packit |
4e8bc4 |
void STATS_LOCK(void);
|
|
Packit |
4e8bc4 |
void STATS_UNLOCK(void);
|
|
Packit |
4e8bc4 |
void STATS_LOCK(void)
|
|
Packit |
4e8bc4 |
{}
|
|
Packit |
4e8bc4 |
void STATS_UNLOCK(void)
|
|
Packit |
4e8bc4 |
{}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
int main(int argc, char **argv)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
int exitcode = 0;
|
|
Packit |
4e8bc4 |
int ii = 0, num_cases = 0;
|
|
Packit |
4e8bc4 |
#ifdef TLS
|
|
Packit |
4e8bc4 |
if (getenv("SSL_TEST") != NULL) {
|
|
Packit |
4e8bc4 |
SSLeay_add_ssl_algorithms();
|
|
Packit |
4e8bc4 |
SSL_load_error_strings();
|
|
Packit |
4e8bc4 |
enable_ssl = true;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
/* Stats prefix test is sensitive to the choice of hash function */
|
|
Packit |
4e8bc4 |
hash_init(JENKINS_HASH);
|
|
Packit |
4e8bc4 |
stats_prefix_init(':');
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
for (num_cases = 0; testcases[num_cases].description; num_cases++) {
|
|
Packit |
4e8bc4 |
/* Just counting */
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
printf("1..%d\n", num_cases);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
for (ii = 0; testcases[ii].description != NULL; ++ii) {
|
|
Packit |
4e8bc4 |
fflush(stdout);
|
|
Packit |
4e8bc4 |
#ifndef DEBUG
|
|
Packit |
4e8bc4 |
/* the test program shouldn't run longer than 10 minutes... */
|
|
Packit |
4e8bc4 |
alarm(600);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
enum test_return ret = testcases[ii].function();
|
|
Packit |
4e8bc4 |
if (ret == TEST_SKIP) {
|
|
Packit |
4e8bc4 |
fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
|
|
Packit |
4e8bc4 |
} else if (ret == TEST_PASS) {
|
|
Packit |
4e8bc4 |
fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
|
|
Packit |
4e8bc4 |
exitcode = 1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
fflush(stdout);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return exitcode;
|
|
Packit |
4e8bc4 |
}
|