tests/testudp
tests/var/
unittests/unittests
+libtest/wait
+docs/text
+docs/changes
+tests/cycle
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * libmcachedd client library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <cstdio>
+
+#ifdef NDEBUG
+#define assert(__expr, __mesg) ((void)0)
+#else
+
+#define assert_msg(__expr, __mesg) \
+do \
+{ \
+ if (not (__expr)) \
+ { \
+ fprintf(stderr, "\nAssertion \"%s\" failed for function \"%s\" likely for %s, at %s:%d\n", #__expr, __func__, (#__mesg), __FILE__, __LINE__);\
+ abort(); \
+ } \
+} while (0)
+
+#endif
memcached_return_t memcached_purge(memcached_server_write_instance_st ptr);
LIBMEMCACHED_LOCAL
-memcached_server_st *memcached_server_create_with(const memcached_st *memc,
- memcached_server_write_instance_st host,
- const char *hostname,
- in_port_t port,
- uint32_t weight,
- memcached_connection_t type);
+ memcached_server_st *__server_create_with(const memcached_st *memc,
+ memcached_server_write_instance_st host,
+ const char *hostname,
+ in_port_t port,
+ uint32_t weight,
+ memcached_connection_t type);
static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool binary)
int err;
socklen_t len= sizeof (err);
(void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
- ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+ memcached_set_errno(*ptr, (err == 0) ? get_socket_errno() : err, MEMCACHED_AT);
}
else
{
- ptr->cached_errno= get_socket_errno();
+ memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
}
WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
- return memcached_set_errno(*ptr, errno, NULL);
+ memcached_set_errno(*ptr, errno, NULL);
+ return MEMCACHED_CONNECTION_FAILURE;
}
struct sockaddr_un servAddr;
default:
WATCHPOINT_ERRNO(errno);
- return memcached_set_errno(*ptr, errno, MEMCACHED_AT);
+ memcached_set_errno(*ptr, errno, MEMCACHED_AT);
+ return MEMCACHED_CONNECTION_FAILURE;
}
}
} while (0);
memcached_return_t rc= MEMCACHED_NO_SERVERS;
if (ptr->fd != INVALID_SOCKET)
+ {
return MEMCACHED_SUCCESS;
+ }
LIBMEMCACHED_MEMCACHED_CONNECT_START();
char message[MAX_ERROR_LENGTH];
};
+static void _set(memcached_server_st& server, memcached_st& memc)
+{
+ if (server.error_messages && server.error_messages->query_id != server.root->query_id)
+ {
+ memcached_error_free(server);
+ }
+
+ if (memc.error_messages == NULL)
+ return;
+
+ memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t));
+ if (not error) // Bad business if this happens
+ return;
+
+ memcpy(error, memc.error_messages, sizeof(memcached_error_t));
+ error->next= server.error_messages;
+ server.error_messages= error;
+}
+
static void _set(memcached_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
{
(void)at;
if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
{
- memcached_error_free(&memc);
+ memcached_error_free(memc);
}
// For memory allocation we use our error since it is a bit more specific
return rc;
_set(*self.root, &error_host, rc, at);
+ _set(self, (*self.root));
return rc;
}
return rc;
_set(*self.root, &error_host, rc, at);
+ _set(self, *self.root);
return rc;
}
memcached_string_t error_host= { hostname_port_message, size };
- self.cached_errno= local_errno; // Store in the actual server
-
memcached_return_t rc= MEMCACHED_ERRNO;
if (not self.root)
return rc;
_set(*self.root, &error_host, rc, at, local_errno);
+ _set(self, (*self.root));
return rc;
}
memcached_string_t error_host= { hostname_port_message, size };
- self.cached_errno= local_errno; // Store in the actual server
-
memcached_return_t rc= MEMCACHED_ERRNO;
if (not self.root)
return rc;
_set(*self.root, &error_host, rc, at, local_errno);
+ _set(self, (*self.root));
return rc;
}
}
}
-void memcached_error_free(memcached_st *self)
+void memcached_error_free(memcached_st& self)
{
- if (not self)
- return;
+ _error_free(self.error_messages);
+ self.error_messages= NULL;
+}
- _error_free(self->error_messages);
- self->error_messages= NULL;
+void memcached_error_free(memcached_server_st& self)
+{
+ _error_free(self.error_messages);
+ self.error_messages= NULL;
}
const char *memcached_last_error_message(memcached_st *memc)
return memc->error_messages->local_errno;
}
+
+const char *memcached_server_error(memcached_server_instance_st server)
+{
+ if (not server)
+ return memcached_strerror(server->root, MEMCACHED_INVALID_ARGUMENTS);
+
+ if (not server->error_messages)
+ return memcached_strerror(server->root, MEMCACHED_SUCCESS);
+
+ if (not server->error_messages->size)
+ return memcached_strerror(server->root, server->error_messages->rc);
+
+ return server->error_messages->message;
+}
+
+
+memcached_error_t *memcached_error_copy(const memcached_server_st& server)
+{
+ if (not server.error_messages)
+ return NULL;
+
+ memcached_error_t *error= (memcached_error_t *)libmemcached_malloc(server.root, sizeof(memcached_error_t));
+ memcpy(error, server.error_messages, sizeof(memcached_error_t));
+ error->next= NULL;
+
+ return error;
+}
+
+memcached_return_t memcached_server_error_return(memcached_server_instance_st ptr)
+{
+ if (ptr and ptr->error_messages)
+ {
+ return ptr->error_messages->rc;
+ }
+
+ return MEMCACHED_FAILURE;
+}
extern "C" {
#endif
-LIBMEMCACHED_LOCAL
- void memcached_error_free(memcached_st *error);
-
LIBMEMCACHED_API
const char *memcached_last_error_message(memcached_st *memc);
LIBMEMCACHED_API
int memcached_last_error_errno(memcached_st *memc);
+LIBMEMCACHED_API
+ const char *memcached_server_error(memcached_server_instance_st ptr);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_server_error_return(memcached_server_instance_st ptr);
+
#ifdef __cplusplus
} // extern "C"
#endif
LIBMEMCACHED_LOCAL
bool memcached_has_current_error(memcached_st &memc);
+LIBMEMCACHED_LOCAL
+void memcached_error_free(memcached_st&);
+
+LIBMEMCACHED_LOCAL
+void memcached_error_free(memcached_server_st&);
+
+LIBMEMCACHED_LOCAL
+memcached_error_t *memcached_error_copy(const memcached_server_st&);
+
#endif
memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
{
if (not list)
+ {
return MEMCACHED_SUCCESS;
+ }
uint32_t count= memcached_server_list_count(list);
memcached_server_write_instance_st instance;
if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
- or ((list[x].type == MEMCACHED_CONNECTION_UDP)
- and ! (ptr->flags.use_udp)) )
+ or ((list[x].type == MEMCACHED_CONNECTION_UDP) and not (ptr->flags.use_udp)) )
{
return MEMCACHED_INVALID_HOST_PROTOCOL;
}
instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
WATCHPOINT_ASSERT(instance);
- if (not memcached_server_create_with(ptr, instance, list[x].hostname,
- list[x].port, list[x].weight, list[x].type))
+ if (not __server_create_with(ptr, instance, list[x].hostname,
+ list[x].port, list[x].weight, list[x].type))
{
return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
}
if (not hostname)
hostname= "localhost";
- return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP);
+ return server_add(ptr, hostname, port, weight, hostname[0] == '/' ? MEMCACHED_CONNECTION_UNIX_SOCKET : MEMCACHED_CONNECTION_TCP);
}
static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
/* TODO: Check return type */
memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
- if (not memcached_server_create_with(ptr, instance, hostname, port, weight, type))
+ if (not __server_create_with(ptr, instance, hostname, port, weight, type))
{
return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
}
libmemcached/memcached/README.txt
noinst_HEADERS+= \
+ libmemcached/assert.hpp \
libmemcached/byteorder.h \
libmemcached/common.h \
libmemcached/do.hpp \
int err;
socklen_t len= sizeof (err);
(void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
- ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+ memcached_set_errno(*ptr, (err == 0) ? get_socket_errno() : err, MEMCACHED_AT);
}
else
{
- ptr->cached_errno= get_socket_errno();
+ memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
}
memcached_quit_server(ptr, true);
}
}
- ptr->cached_errno= get_socket_errno();
memcached_quit_server(ptr, true);
- return memcached_set_error(*ptr, MEMCACHED_FAILURE, MEMCACHED_AT);
+ return memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
}
memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr)
if (sent_length == SOCKET_ERROR)
{
- ptr->cached_errno= get_socket_errno();
+ memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
#if 0 // @todo I should look at why we hit this bit of code hard frequently
WATCHPOINT_ERRNO(get_socket_errno());
WATCHPOINT_NUMBER(get_socket_errno());
memcached_array_free(ptr->prefix_key);
ptr->prefix_key= NULL;
- memcached_error_free(ptr);
+ memcached_error_free(*ptr);
if (ptr->sasl.callbacks)
{
#pragma once
+#include <libmemcached/util/pid.h>
#include <libmemcached/util/flush.h>
#include <libmemcached/util/ping.h>
#include <libmemcached/util/pool.h>
if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
{
memcached_quit_server(ptr, true);
- return memcached_set_error(*ptr, rrc, MEMCACHED_AT);
+ return memcached_set_error(*ptr, MEMCACHED_IN_PROGRESS, MEMCACHED_AT);
}
else if (memcached_failed(rrc))
{
while (*endptr != '\r' && *endptr != '\n') endptr++;
- /*
- Yes, we could make this "efficent" but to do that we would need
- to maintain more state for the size of the buffer. Why waste
- memory in the struct, which is important, for something that
- rarely should happen?
- */
- char *rel_ptr= (char *)libmemcached_realloc(ptr->root,
- ptr->cached_server_error,
- (size_t) (endptr - startptr + 1));
-
- if (rel_ptr == NULL)
- {
- /* If we happened to have some memory, we just null it since we don't know the size */
- if (ptr->cached_server_error)
- ptr->cached_server_error[0]= 0;
- return MEMCACHED_SERVER_ERROR;
- }
- ptr->cached_server_error= rel_ptr;
-
- memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
- ptr->cached_server_error[endptr - startptr]= 0;
- return MEMCACHED_SERVER_ERROR;
+ return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
}
else if (buffer[1] == 'T')
{
self->number_of_hosts= 0;
self->cursor_active= 0;
self->port= port;
- self->cached_errno= 0;
self->fd= -1;
self->io_bytes_sent= 0;
self->server_failure_counter= 0;
self->micro_version= UINT8_MAX;
self->minor_version= UINT8_MAX;
self->type= type;
+ self->error_messages= NULL;
self->read_ptr= self->read_buffer;
- self->cached_server_error= NULL;
self->read_buffer_length= 0;
self->read_data_length= 0;
self->write_buffer_offset= 0;
return self;
}
-memcached_server_st *memcached_server_create_with(const memcached_st *memc,
- memcached_server_write_instance_st self,
- const char *hostname, in_port_t port,
- uint32_t weight, memcached_connection_t type)
+memcached_server_st *__server_create_with(const memcached_st *memc,
+ memcached_server_write_instance_st self,
+ const char *hostname, in_port_t port,
+ uint32_t weight, memcached_connection_t type)
{
self= _server_create(self, memc);
return self;
}
-void memcached_server_free(memcached_server_st *self)
+void __server_free(memcached_server_st *self)
{
- if (not self)
- return;
-
memcached_quit_server(self, false);
- if (self->cached_server_error)
- free(self->cached_server_error);
-
if (self->address_info)
+ {
freeaddrinfo(self->address_info);
+ }
+
+ memcached_error_free(*self);
if (memcached_is_allocated(self))
{
}
}
+void memcached_server_free(memcached_server_st *self)
+{
+ if (not self)
+ return;
+
+ if (memcached_server_list_count(self))
+ {
+ memcached_server_list_free(self);
+ return;
+ }
+
+ __server_free(self);
+}
+
/*
If we do not have a valid object to clone from, we toss an error.
*/
if (not source)
return NULL;
- destination= memcached_server_create_with(source->root, destination,
- source->hostname, source->port, source->weight,
- source->type);
+ destination= __server_create_with(source->root, destination,
+ source->hostname, source->port, source->weight,
+ source->type);
if (not destination)
{
- destination->cached_errno= source->cached_errno;
-
- if (source->cached_server_error)
- destination->cached_server_error= strdup(source->cached_server_error);
+ if (source->error_messages)
+ {
+ destination->error_messages= memcached_error_copy(*source);
+ }
}
return destination;
if (not self)
return;
- self->cached_server_error[0]= 0;
+ memcached_error_free(*self);
}
memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self)
return self->last_disconnected_server;
}
-void memcached_server_list_free(memcached_server_list_st self)
-{
- if (not self)
- return;
-
- for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
- {
- if (self[x].address_info)
- {
- freeaddrinfo(self[x].address_info);
- self[x].address_info= NULL;
- }
- }
-
- libmemcached_free(self->root, self);
-}
-
uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
{
WATCHPOINT_ASSERT(servers);
return self->cursor_active;
}
-const char *memcached_server_error(memcached_server_instance_st ptr)
-{
- return ptr ? ptr->cached_server_error : NULL;
-}
-
const char *memcached_server_type(memcached_server_instance_st ptr)
{
if (ptr)
uint32_t number_of_hosts;
uint32_t cursor_active;
in_port_t port;
- int cached_errno;
memcached_socket_t fd;
uint32_t io_bytes_sent; /* # bytes sent since last read */
uint32_t server_failure_counter;
uint8_t minor_version; // ditto
memcached_connection_t type;
char *read_ptr;
- char *cached_server_error;
size_t read_buffer_length;
size_t read_data_length;
size_t write_buffer_offset;
time_t next_retry;
memcached_st *root;
uint64_t limit_maxbytes;
+ struct memcached_error_t *error_messages;
char read_buffer[MEMCACHED_MAX_BUFFER];
char write_buffer[MEMCACHED_MAX_BUFFER];
char hostname[NI_MAXHOST];
LIBMEMCACHED_API
in_port_t memcached_server_port(memcached_server_instance_st self);
-LIBMEMCACHED_API
-const char *memcached_server_error(memcached_server_instance_st ptr);
-
LIBMEMCACHED_API
const char *memcached_server_type(memcached_server_instance_st ptr);
+LIBMEMCACHED_LOCAL
+void __server_free(memcached_server_st *);
#ifdef __cplusplus
} // extern "C"
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
*
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
*
- * Summary:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
+
#include <libmemcached/common.h>
+#include <libmemcached/assert.hpp>
memcached_server_list_st
memcached_server_list_append_with_weight(memcached_server_list_st ptr,
uint32_t count;
memcached_server_list_st new_host_list;
- if (hostname == NULL || error == NULL)
- return NULL;
+ memcached_return_t unused;
+ if (error == NULL)
+ error= &unused;
+
+ if (hostname == NULL)
+ {
+ hostname= "localhost";
+ }
if (hostname[0] == '/')
+ {
port = 0;
- else if (! port)
+ }
+ else if (not port)
+ {
port= MEMCACHED_DEFAULT_PORT;
+ }
/* Increment count for hosts */
count= 1;
}
new_host_list= (memcached_server_write_instance_st)realloc(ptr, sizeof(memcached_server_st) * count);
- if (!new_host_list)
+ if (not new_host_list)
{
- ptr->cached_errno= errno;
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ *error= memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
return NULL;
}
/* @todo Check return type */
- if (not memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET))
+ if (not __server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET))
{
- ptr->cached_errno= errno;
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ *error= memcached_set_errno(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
return NULL;
}
+#if 0
// Handset allocated since
new_host_list->options.is_allocated= true;
+#endif
/* Backwards compatibility hack */
memcached_servers_set_count(new_host_list, count);
{
self->servers= list;
}
+
+void memcached_server_list_free(memcached_server_list_st self)
+{
+ if (not self)
+ return;
+
+ for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
+ {
+ assert_msg(not memcached_is_allocated(&self[x]), "You have called memcached_server_list_free(), but you did not pass it a valid memcached_server_list_st");
+ __server_free(&self[x]);
+ }
+
+ libmemcached_free(self->root, self);
+}
stat_instance= stats +x;
+ stat_instance->pid= -1;
stat_instance->root= self;
instance= memcached_server_instance_fetch(self, x);
libmemcached/memcached_util.h \
libmemcached/util.h \
libmemcached/util/flush.h \
+ libmemcached/util/pid.h \
libmemcached/util/ping.h \
libmemcached/util/pool.h \
libmemcached/util/version.h
libmemcached_libmemcachedutil_la_SOURCES= \
libmemcached/util/flush.cc \
+ libmemcached/util/pid.cc \
libmemcached/util/ping.cc \
libmemcached/util/pool.cc \
libmemcached/util/version.cc
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Summary: connects to a host, and determines what its pid is
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
+
+
+// Never look at the stat object directly.
+
+
+pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+ memcached_st *memc_ptr= memcached_create(NULL);
+
+ pid_t pid= -1;
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ if (memcached_success(memcached_version(memc_ptr)))
+ {
+ memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc);
+ if (stat and stat->pid > 0)
+ {
+ pid= stat->pid;
+ }
+
+ memcached_stat_free(memc_ptr, stat);
+ }
+ }
+ memcached_free(memc_ptr);
+
+ if (ret)
+ {
+ *ret= rc;
+ }
+
+ return pid;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret);
+
+#ifdef __cplusplus
+}
+#endif
+
rc= memcached_version(memc_ptr);
}
+ if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc_ptr, 0);
+
+ if (instance and instance->error_messages)
+ {
+ rc= memcached_server_error_return(instance);
+ }
+ }
memcached_free(memc_ptr);
if (ret)
*ret= rc;
}
- return rc == MEMCACHED_SUCCESS;
+ return memcached_success(rc);
}
#define test_failed(__test_return_t) ((__test_return_t) != TEST_SUCCESS)
+#define test_success(__test_return_t) ((__test_return_t) == TEST_SUCCESS)
return TEST_SUCCESS;
}
+
+void* Framework::create(test_return_t* arg)
+{
+ if (_create)
+ {
+ return _create(arg);
+ }
+
+ return NULL;
+}
+
test_callback_create_fn *_create;
test_callback_fn *_destroy;
- void* create(test_return_t* arg)
- {
- if (_create)
- {
- return _create(arg);
- }
-
- return NULL;
- }
+ void* create(test_return_t* arg);
test_return_t destroy(void*);
CLEANFILES+= \
tests/var/log/* \
+ tests/var/run/* \
tests/var/tmp/*
noinst_HEADERS+= \
libtest/failed.h \
libtest/framework.h \
libtest/get.h \
+ libtest/killpid.h \
libtest/runner.h \
libtest/server.h \
libtest/stats.h \
libtest/strerror.h \
libtest/test.h \
libtest/test.hpp \
- libtest/visibility.h
+ libtest/visibility.h \
+ libtest/wait.h
noinst_LTLIBRARIES+= libtest/libserver.la
-libtest_libserver_la_SOURCES= libtest/memcached.cc
+libtest_libserver_la_SOURCES= \
+ libtest/killpid.cc \
+ libtest/memcached.cc \
+ libtest/server.cc
noinst_LTLIBRARIES+= libtest/libtest.la
libtest_libtest_la_SOURCES=\
libtest_libtest_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} -DBUILDING_LIBTEST
libtest_libtest_la_CPPFLAGS= ${AM_CPPFLAGS}
-tests/var: tests/var/log tests/var/tmp
+clearn-var:
+ @rm -f tests/var/log/*
+ @rm -f tests/var/run/*
+ @rm -f tests/var/tmp/*
+
+
+tests/var: tests/var/log tests/var/tmp tests/var/run clearn-var
$(mkdir_p) tests/var
tests/var/log:
tests/var/tmp:
$(mkdir_p) tests/var/tmp
+
+tests/var/run:
+ $(mkdir_p) tests/var/run
+
+noinst_PROGRAMS+= libtest/wait
+
+libtest_wait_SOURCES= libtest/wait.cc
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+#include <libtest/killpid.h>
+
+bool kill_pid(pid_t pid_arg)
+{
+ if ((kill(pid_arg, SIGTERM) == -1))
+ {
+ switch (errno)
+ {
+ case EPERM:
+ perror(__func__);
+ std::cerr << __func__ << " -> Does someone else have a process running locally for " << int(pid_arg) << "?" << std::endl;
+ return false;
+
+ case ESRCH:
+ perror(__func__);
+ std::cerr << "Process " << int(pid_arg) << " not found." << std::endl;
+ return false;
+
+ default:
+ case EINVAL:
+ perror(__func__);
+ return false;
+ }
+ }
+
+ int status= 0;
+ pid_t pid= waitpid(pid_arg, &status, 0);
+ if (pid == -1)
+ {
+ switch (errno)
+ {
+ case ECHILD:
+ return true;
+ }
+ std::cerr << std::endl << "Error occured while waitpid(" << strerror(errno) << ") on pid " << int(pid_arg) << std::endl;
+ return false;
+ }
+
+ if (WIFEXITED(status))
+ return true;
+
+ if (WCOREDUMP(status))
+ return true;
+
+ return false;
+}
+
+
+void kill_file(const std::string &filename)
+{
+ FILE *fp;
+
+ if (filename.empty())
+ return;
+
+ if ((fp= fopen(filename.c_str(), "r")))
+ {
+ char pid_buffer[1024];
+
+ char *ptr= fgets(pid_buffer, sizeof(pid_buffer), fp);
+ fclose(fp);
+
+ if (ptr)
+ {
+ pid_t pid= (pid_t)atoi(pid_buffer);
+ if (pid != 0)
+ {
+ kill_pid(pid);
+ unlink(filename.c_str()); // If this happens we may be dealing with a dead server that left its pid file.
+ }
+ }
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+bool kill_pid(pid_t pid_arg);
+
+void kill_file(const std::string &filename);
#define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
-#include <config.h>
-
-#include <iso646.h>
-
-#include <assert.h>
+#include <libtest/common.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
#include <limits.h>
#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <sys/time.h>
-#include <time.h>
#include <unistd.h>
-#include <errno.h>
+#include <iostream>
#include <libmemcached/memcached.h>
#include <libmemcached/util.h>
#include <libtest/server.h>
+#include <libtest/killpid.h>
+#include <libtest/wait.h>
+
+#include <boost/lexical_cast.hpp>
+
+
+#define CERR_PREFIX std::endl << __FILE__ << ":" << __LINE__ << " "
static void global_sleep(void)
{
#endif
}
-static bool wait_for_file(const char *filename)
-{
- uint32_t timeout= 6;
- uint32_t waited;
- uint32_t this_wait;
- uint32_t retry;
+#define SOCKET_FILE "/tmp/memcached.socket"
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- if ((! access(filename, R_OK)) || (waited >= timeout))
- {
- return true;
- }
-
- this_wait= retry * retry / 3 + 1;
- sleep(this_wait);
- }
-
- return false;
-}
-
-static void kill_file(const char *file_buffer)
+static bool cycle_server(server_st& server)
{
- FILE *fp;
-
- while ((fp= fopen(file_buffer, "r")))
+ while (1)
{
- char pid_buffer[1024];
-
- if (fgets(pid_buffer, sizeof(pid_buffer), fp) != NULL)
+ if (libmemcached_util_ping(server.hostname, server.port(), NULL))
{
- pid_t pid= (pid_t)atoi(pid_buffer);
- if (pid != 0)
+ // First we try to kill it, and on fail of that we flush it.
+ pid_t pid= libmemcached_util_getpid(server.hostname, server.port(), NULL);
+
+ if (pid > 0 and kill_pid(pid))
{
- if (kill(pid, SIGTERM) == -1)
- {
- remove(file_buffer); // If this happens we may be dealing with a dead server that left its pid file.
- }
- else
- {
- uint32_t counter= 3;
- while ((kill(pid, 0) == 0) && --counter)
- {
- global_sleep();
- }
- }
+ std::cerr << CERR_PREFIX << "Killed existing server," << server << " with pid:" << pid << std::endl;
+ continue;
+ }
+ else if (libmemcached_util_flush(server.hostname, server.port(), NULL)) // If we can flush it, we will just use it
+ {
+ std::cerr << CERR_PREFIX << "Found server on port " << int(server.port()) << ", flushed it!" << std::endl;
+ server.set_used();
+ return true;
+ } // No idea what is wrong here, so we need to find a different port
+ else
+ {
+ return false;
}
}
- global_sleep();
-
- fclose(fp);
+ break;
}
+
+ return true;
}
-void server_startup(server_startup_st *construct)
+bool server_startup(server_startup_st *construct)
{
- if ((construct->server_list= getenv("MEMCACHED_SERVERS")))
+ if (getenv(((char *)"MEMCACHED_SERVERS")))
{
- printf("servers %s\n", construct->server_list);
+ construct->server_list= getenv(((char *)"MEMCACHED_SERVERS"));
+ printf("servers %s\n", construct->server_list.c_str());
construct->count= 0;
}
else
{
+ std::string server_config_string;
+
+ uint32_t port_base= 0;
+ for (uint32_t x= 0; x < (construct->count -1); x++)
{
- char server_string_buffer[8096];
- char *end_ptr;
- end_ptr= server_string_buffer;
+ server_st &server= construct->server[x];
- uint32_t port_base= 0;
- for (uint32_t x= 0; x < construct->count; x++)
{
- int status;
+ char *var;
+ char variable_buffer[1024];
+
+ snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
- snprintf(construct->pid_file[x], FILENAME_MAX, "/tmp/memcached.pidXXXXXX");
- int fd;
- if ((fd= mkstemp(construct->pid_file[x])) == -1)
+ if ((var= getenv(variable_buffer)))
{
- perror("mkstemp");
- return;
+ server.set_port((in_port_t)atoi(var));
}
- close(fd);
-
+ else
{
- char *var;
- char variable_buffer[1024];
-
- snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
+ server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
- if ((var= getenv(variable_buffer)))
- {
- construct->port[x]= (in_port_t)atoi(var);
- }
- else
+ while (not cycle_server(server))
{
- do {
- construct->port[x]= (in_port_t)(x + TEST_PORT_BASE + port_base);
-
- if (libmemcached_util_ping("localhost", construct->port[x], NULL))
- {
- if (libmemcached_util_flush("localhost", construct->port[x], NULL))
- {
- fprintf(stderr, "Found server on port %d, flushed it!\n", (int)construct->port[x]);
- construct->is_used[x]= true;
- } // If we can flush it, we will just use it
- else
- {
- fprintf(stderr, "Found server on port %d, could not flush it, so trying next port.\n", (int)construct->port[x]);
- port_base++;
- construct->port[x]= 0;
- }
- }
- } while (construct->port[x] == 0);
+ std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl;
+ port_base++;
+ server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
}
}
+ }
+ if (server.is_used())
+ {
+ std::cerr << std::endl << "Using server at : " << server << std::endl;
+ }
+ else
+ {
char buffer[FILENAME_MAX];
if (x == 0)
{
- snprintf(buffer, sizeof(buffer), "%s -d -P %s -t 1 -p %u -U %u -m 128",
- MEMCACHED_BINARY, construct->pid_file[x], construct->port[x], construct->port[x]);
+ snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u -m 128",
+ MEMCACHED_BINARY, server.port(), server.port());
}
else
{
- snprintf(buffer, sizeof(buffer), "%s -d -P %s -t 1 -p %u -U %u",
- MEMCACHED_BINARY, construct->pid_file[x], construct->port[x], construct->port[x]);
+ snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u",
+ MEMCACHED_BINARY, server.port(), server.port());
}
- if (construct->is_used[x])
+ int status= system(buffer);
+ if (status == -1)
{
- fprintf(stderr, "USING SERVER: %s\n", buffer);
+ std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
+ return false;
}
- else
+ fprintf(stderr, "STARTING SERVER: %s\n", buffer);
+
+ int count= 30;
+ memcached_return_t rc;
+ while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count)
{
- if (libmemcached_util_ping("localhost", construct->port[x], NULL))
- {
- fprintf(stderr, "Server on port %u already exists\n", construct->port[x]);
- }
- else
- {
- status= system(buffer);
- fprintf(stderr, "STARTING SERVER: %s status:%d\n", buffer, status);
- }
+ global_sleep();
}
- size_t remaining_length= sizeof(server_string_buffer) - (size_t)(end_ptr -server_string_buffer);
- int count= snprintf(end_ptr, remaining_length, "--server=localhost:%u ", construct->port[x]);
-
- if ((size_t)count >= remaining_length or count < 0)
+ if (memcached_failed(rc))
{
- fprintf(stderr, "server names grew to be larger then buffer allowed\n");
- abort();
+ std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl;
+ return false;
}
- end_ptr+= count;
- }
- *end_ptr= 0;
-
- for (uint32_t x= 0; x < construct->count; x++)
- {
- if (! wait_for_file(construct->pid_file[x]))
+ server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc));
+ if (not server.has_pid())
{
- abort();
+ std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl;
+ return false;
}
}
- for (uint32_t x= 0; x < construct->count; x++)
+ server_config_string+= "--server=";
+ server_config_string+= server.hostname;
+ server_config_string+= ":";
+ server_config_string+= boost::lexical_cast<std::string>(server.port());
+ server_config_string+= " ";
+ fprintf(stderr, " Port %d\n", server.port());
+ }
+
+ {
+ server_st &server= construct->server[construct->count -1];
+
{
- uint32_t counter= 3000; // Absurd, just to catch run away process
+ std::string socket_file;
+ char *var;
- if (construct->is_used[x])
- continue;
+ server.set_hostname(SOCKET_FILE);
- while (construct->pids[x] <= 0 && --counter)
+ if ((var= getenv("LIBMEMCACHED_SOCKET")))
+ {
+ socket_file+= var;
+ }
+ else
{
- FILE *file= fopen(construct->pid_file[x], "r");
- if (file)
+ if (not cycle_server(server))
{
- char pid_buffer[1024];
- char *found= fgets(pid_buffer, sizeof(pid_buffer), file);
-
- if (found)
- {
- construct->pids[x]= atoi(pid_buffer);
- fclose(file);
-
- if (construct->pids[x] > 0)
- break;
- }
- fclose(file);
+ std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl;
+ return false;
}
+ }
+ }
- switch (errno)
- {
- default:
- fprintf(stderr, "Could not open pid file %s -> fopen(%s) -> %s:%d\n", construct->pid_file[x], strerror(errno), __FILE__, __LINE__);
- abort();
-
- case ENOENT:
- case EINTR:
- case EACCES:
- case EINPROGRESS:
- break;
-
- case ENOTCONN:
- continue;
- }
+ if (server.is_used())
+ {
+ std::cerr << std::endl << "Using server at : " << server << std::endl;
+ }
+ else
+ {
+ char buffer[FILENAME_MAX];
+ snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE);
- // Safety 3rd, check to see if the file has gone away
- if (! wait_for_file(construct->pid_file[x]))
- {
- abort();
- }
+ int status= system(buffer);
+ if (status == -1)
+ {
+ std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
+ return false;
}
+ fprintf(stderr, "STARTING SERVER: %s\n", buffer);
- bool was_started= false;
- if (construct->pids[x] > 0)
+ int count= 30;
+ memcached_return_t rc;
+ while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count)
{
- counter= 30;
- while (--counter)
- {
- if (kill(construct->pids[x], 0) == 0)
- {
- was_started= true;
- break;
- }
- global_sleep();
- }
+ global_sleep();
}
- if (was_started == false)
+ if (memcached_failed(rc))
{
- fprintf(stderr, "Failed to open buffer %s(%d)\n", construct->pid_file[x], construct->pids[x]);
- for (uint32_t y= 0; y < construct->count; y++)
- {
- if (construct->pids[y] > 0)
- kill(construct->pids[y], SIGTERM);
- }
- abort();
+ std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl;
+ return false;
+ }
+
+ server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc));
+ if (not server.has_pid())
+ {
+ std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl;
+ return false;
}
}
- construct->server_list= strndup(server_string_buffer, strlen(server_string_buffer) -1);
+ {
+ set_default_socket(server.hostname);
+ server_config_string+= "--socket=\"";
+ server_config_string+= server.hostname;
+ server_config_string+= "\" ";
+ }
}
+
+ server_config_string.resize(server_config_string.size() -1); // Remove final space
+ construct->server_list= server_config_string;
}
srandom((unsigned int)time(NULL));
- printf("\n");
+ std::cerr << std::endl;
+ return true;
}
void server_shutdown(server_startup_st *construct)
{
- if (construct->server_list)
+ for (uint32_t x= 0; x < construct->count; x++)
{
- for (uint32_t x= 0; x < construct->count; x++)
- {
- if (construct->is_used[x])
- continue;
-
- kill_file(construct->pid_file[x]);
- }
+ if (construct->server[x].is_used())
+ continue;
- free(construct->server_list);
+ construct->server[x].kill();
}
}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <iostream>
+
+#include <libtest/server.h>
+#include <libtest/killpid.h>
+
+
+std::ostream& operator<<(std::ostream& output, const server_st &arg)
+{
+ if (arg.is_socket())
+ {
+ output << arg.hostname;
+ }
+ else
+ {
+ output << arg.hostname << ":" << arg.port();
+ }
+ return output; // for multiple << operators
+}
+
+server_st::~server_st()
+{
+ if (not _used)
+ {
+ kill();
+ }
+}
+
+void server_st::reset_pid()
+{
+ pid_file[0]= 0;
+ _pid= -1;
+}
+
+bool server_st::kill()
+{
+ if (not has_pid() and pid_file[0] == 0)
+ {
+ return true;
+ }
+
+ if (has_pid())
+ {
+ kill_pid(pid());
+ if (pid_file[0])
+ {
+ unlink(pid_file); // If this happens we may be dealing with a dead server that left its pid file.
+ }
+ reset_pid();
+
+ return true;
+ }
+ else if (pid_file[0])
+ {
+ kill_file(pid_file);
+ reset_pid();
+
+ return true;
+ }
+
+ return false;
+}
#pragma once
+#include <cstring>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string>
#include <unistd.h>
-/*
- Server startup and shutdown functions.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define SERVERS_TO_CREATE 5
-#include <libmemcached/memcached.h>
+struct server_st {
+private:
+ bool _used;
+ pid_t _pid;
+ in_port_t _port;
+ char pid_file[FILENAME_MAX]; // Did we start it, or was it just sitting there?
+public:
-typedef struct server_startup_st server_startup_st;
-#define SERVERS_TO_CREATE 5
+ char hostname[NI_MAXHOST];
+
+ server_st() :
+ _used(false),
+ _pid(-1),
+ _port(0)
+ {
+ pid_file[0]= 0;
+ strncpy(hostname, "localhost", sizeof(hostname));
+ }
+
+ void set_port(in_port_t arg)
+ {
+ _port= arg;
+ }
+
+ in_port_t port() const
+ {
+ return _port;
+ }
+
+ bool has_port() const
+ {
+ return not _port == 0;
+ }
+
+ void set_used()
+ {
+ _used= true;
+ }
+
+ void set_pid(pid_t arg)
+ {
+ _pid= arg;
+ }
+
+ pid_t pid() const
+ {
+ return _pid;
+ }
+
+ bool is_used() const
+ {
+ return _used;
+ }
+
+ ~server_st();
+
+ bool has_pid()
+ {
+ return _pid > 0;
+ }
+
+ bool is_socket() const
+ {
+ return hostname[0] == '/';
+ }
+
+ void set_hostname(const char *arg)
+ {
+ strncpy(hostname, arg, sizeof(hostname));
+ }
+
+ bool kill();
+
+private:
+ void reset_pid();
+};
+
+std::ostream& operator<<(std::ostream& output, const server_st &arg);
struct server_startup_st
{
uint8_t count;
uint8_t udp;
- char *server_list;
- char pid_file[SERVERS_TO_CREATE][FILENAME_MAX];
- in_port_t port[SERVERS_TO_CREATE];
- int pids[SERVERS_TO_CREATE];
- bool is_used[SERVERS_TO_CREATE]; // Did we start it, or was it just sitting there?
+ std::string server_list;
+ server_st server[SERVERS_TO_CREATE];
+
+ server_startup_st() :
+ count(SERVERS_TO_CREATE),
+ udp(0)
+ { }
+
+ ~server_startup_st()
+ { }
};
-void server_startup(server_startup_st *construct);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+bool server_startup(server_startup_st *construct);
void server_shutdown(server_startup_st *construct);
#ifdef __cplusplus
#endif
static in_port_t global_port= 0;
+static char global_socket[1024];
in_port_t default_port()
{
global_port= port;
}
+const char *default_socket()
+{
+ assert(global_socket[0]);
+ return global_socket;
+}
+
+void set_default_socket(const char *socket)
+{
+ strncpy(global_socket, socket, strlen(socket));
+}
+
static void stats_print(Stats *stats)
{
std::cout << "\tTotal Collections\t\t\t\t" << stats->collection_total << std::endl;
int main(int argc, char *argv[])
{
- Framework world;
+ Framework *world= new Framework();
- Stats stats;
-
- get_world(&world);
-
- if (not world.runner)
+ if (not world)
{
- world.runner= &defualt_runners;
+ return EXIT_FAILURE;
}
+ Stats stats;
+
+ get_world(world);
+
test_return_t error;
- void *world_ptr= world.create(&error);
+ void *world_ptr= world->create(&error);
if (test_failed(error))
{
+ std::cerr << "create() failed" << std::endl;
return EXIT_FAILURE;
}
wildcard= argv[2];
}
- for (collection_st *next= world.collections; next->name; next++)
+ for (collection_st *next= world->collections; next->name; next++)
{
test_return_t collection_rc= TEST_SUCCESS;
bool failed= false;
stats.collection_total++;
- collection_rc= world.startup(world_ptr);
+ collection_rc= world->startup(world_ptr);
if (collection_rc == TEST_SUCCESS and next->pre)
{
- collection_rc= world.runner->pre(next->pre, world_ptr);
+ collection_rc= world->runner->pre(next->pre, world_ptr);
}
switch (collection_rc)
std::cerr << "\tTesting " << run->name;
- world.item.startup(world_ptr);
-
- world.item.flush(world_ptr, run);
-
- world.item.pre(world_ptr);
-
test_return_t return_code;
- { // Runner Code
- gettimeofday(&start_time, NULL);
- return_code= world.runner->run(run->test_fn, world_ptr);
- gettimeofday(&end_time, NULL);
- load_time= timedif(end_time, start_time);
+ if (test_success(return_code= world->item.startup(world_ptr)))
+ {
+ if (test_success(return_code= world->item.flush(world_ptr, run)))
+ {
+ // @note pre will fail is SKIPPED is returned
+ if (test_success(return_code= world->item.pre(world_ptr)))
+ {
+ { // Runner Code
+ gettimeofday(&start_time, NULL);
+ return_code= world->runner->run(run->test_fn, world_ptr);
+ gettimeofday(&end_time, NULL);
+ load_time= timedif(end_time, start_time);
+ }
+ }
+
+ // @todo do something if post fails
+ (void)world->item.post(world_ptr);
+ }
+ else
+ {
+ std::cerr << __FILE__ << ":" << __LINE__ << " item.flush(failure)" << std::endl;
+ }
+ }
+ else
+ {
+ std::cerr << __FILE__ << ":" << __LINE__ << " item.startup(failure)" << std::endl;
}
-
- world.item.post(world_ptr);
stats.total++;
std::cerr << "[ " << test_strerror(return_code) << " ]" << std::endl;
- if (test_failed(world.on_error(return_code, world_ptr)))
+ if (test_failed(world->on_error(return_code, world_ptr)))
{
break;
}
}
- if (next->post && world.runner->post)
+ if (next->post and world->runner->post)
{
- (void) world.runner->post(next->post, world_ptr);
+ (void) world->runner->post(next->post, world_ptr);
}
if (failed == 0 and skipped == 0)
}
cleanup:
- world.shutdown(world_ptr);
+ world->shutdown(world_ptr);
}
if (stats.collection_failed || stats.collection_skipped)
std::cout << std::endl << std::endl << "All tests completed successfully." << std::endl << std::endl;
}
- if (test_failed(world.destroy(world_ptr)))
+ if (test_failed(world->destroy(world_ptr)))
{
stats.failed++; // We do this to make our exit code return EXIT_FAILURE
}
stats_print(&stats);
- return stats.failed == 0 ? 0 : 1;
+ delete world;
+
+ return stats.failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
LIBTEST_API
void set_default_port(in_port_t port);
+LIBTEST_API
+ const char* default_socket();
+
+LIBTEST_API
+ void set_default_socket(const char *socket);
+
#ifdef __cplusplus
#define test_literal_param(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
#else
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <cstdlib>
+#include <libtest/wait.h>
+
+int main(int argc, char *argv[])
+{
+ if (argc == 2)
+ {
+ libtest::Wait wait(argv[1]);
+
+ if (wait.successful())
+ return EXIT_SUCCESS;
+ }
+
+ return EXIT_FAILURE;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <string>
+
+namespace libtest {
+
+class Wait
+{
+public:
+
+ Wait(const std::string &filename, uint32_t timeout= 6) :
+ _successful(false)
+ {
+ uint32_t waited;
+ uint32_t this_wait;
+ uint32_t retry;
+
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if ((not access(filename.c_str(), R_OK)) or (waited >= timeout))
+ {
+ _successful= true;
+ break;
+ }
+
+ this_wait= retry * retry / 3 + 1;
+ sleep(this_wait);
+ }
+ }
+
+ bool successful() const
+ {
+ return _successful;
+ }
+
+private:
+ bool _successful;
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ Test that we are cycling the servers we are creating during testing.
+*/
+
+#include <libtest/common.h>
+
+#include <libmemcached/common.h>
+
+
+#include <libtest/server.h>
+
+#define SERVERS_TO_CREATE 5
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+test_st ping[] ={
+ {0, 0, 0}
+};
+
+collection_st collection[] ={
+ {0, 0, 0, 0}
+};
+
+static server_startup_st *world_create(test_return_t *error)
+{
+ server_startup_st *servers= new server_startup_st();
+
+ server_startup(servers);
+
+ *error= TEST_SUCCESS;
+
+ return servers;
+}
+
+static test_return_t world_destroy(server_startup_st *servers)
+{
+ server_shutdown(servers);
+ delete servers;
+
+ return TEST_SUCCESS;
+}
+
+
+
+void get_world(Framework *world)
+{
+ world->collections= collection;
+
+ world->_create= (test_callback_create_fn*)world_create;
+ world->_destroy= (test_callback_fn*)world_destroy;
+}
+
(void)ptr;
server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, NULL);
- test_true(server_list == NULL);
+ test_true(server_list);
+ memcached_server_list_free(server_list);
server_list= memcached_server_list_append_with_weight(NULL, "localhost", 0, 0, NULL);
- test_true(server_list == NULL);
+ test_true(server_list);
+ memcached_server_list_free(server_list);
server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, &rc);
- test_true(server_list == NULL);
+ test_true(server_list);
+ memcached_server_list_free(server_list);
return TEST_SUCCESS;
}
// Look for memory leak
test_return_t regression_bug_728286(memcached_st *)
{
- memcached_server_st *servers = memcached_servers_parse("1.2.3.4:99");
+ memcached_server_st *servers= memcached_servers_parse("1.2.3.4:99");
assert(servers);
memcached_server_free(servers);
noinst_PROGRAMS+= \
tests/atomsmasher \
+ tests/cycle \
tests/hash_plus \
- tests/startservers \
tests/testapp \
tests/testhashkit \
tests/testplus \
tests/testudp
+# Cycle should always run first
+tests_cycle_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
+tests_cycle_SOURCES= tests/cycle.cc
+tests_cycle_DEPENDENCIES= $(TESTS_LDADDS)
+tests_cycle_LDADD= $(tests_cycle_DEPENDENCIES)
+check_PROGRAMS+= tests/cycle
+
+
tests_testapp_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
tests_testapp_SOURCES= \
tests/basic.cc \
$(TESTS_LDADDS) \
libhashkit/libhashkit.la \
libmemcached/libmemcachedinternal.la
+check_PROGRAMS+= tests/testapp
tests_testplus_SOURCES= tests/plus.cpp
tests_testplus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX)
tests_testplus_LDADD= $(tests_testplus_DEPENDENCIES) $(LIBSASL)
check_PROGRAMS+= tests/testplus
-tests_atomsmasher_SOURCES= tests/atomsmasher.cc
-tests_atomsmasher_SOURCES+= clients/generator.cc clients/execute.cc
+tests_atomsmasher_SOURCES= \
+ tests/atomsmasher.cc \
+ clients/generator.cc \
+ clients/execute.cc
tests_atomsmasher_DEPENDENCIES= $(TESTS_LDADDS)
-
tests_atomsmasher_LDADD= $(tests_atomsmasher_DEPENDENCIES) $(LIBSASL)
tests_testudp_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
tests_testudp_SOURCES= tests/mem_udp.cc
tests_testudp_DEPENDENCIES= $(TESTS_LDADDS)
-
tests_testudp_LDADD= $(tests_testudp_DEPENDENCIES) $(LIBSASL)
-
-tests_startservers_SOURCES= tests/start.cc
-tests_startservers_DEPENDENCIES= $(TESTS_LDADDS)
-tests_startservers_LDADD= $(tests_startservers_DEPENDENCIES) $(LIBSASL)
+check_PROGRAMS+= tests/testudp
tests_testhashkit_SOURCES = tests/hashkit_functions.cc
tests_testhashkit_DEPENDENCIES = libtest/libtest.la libhashkit/libhashkit.la
tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES)
+check_PROGRAMS+= tests/testhashkit
tests_hash_plus_SOURCES= tests/hash_plus.cc
tests_hash_plus_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
test: check
-check-local: tests/var $(TEST_DOCS) test-mem test-hash memcapable
+check-local: tests/var $(TEST_DOCS) memcapable
@echo "Tests completed"
-test-x: check-local test-plus test-memcat test-memcp test-memrm test-memerror test-memdump test-memflush test-memstat
+test-x: tests/var test-plus test-memcat test-memcp test-memrm test-memerror test-memdump test-memflush test-memstat
@echo "Tests completed"
memcapable: clients/memcapable
HASHPLUS_COMMAND= tests/hashplus $(COLLECTION) $(SUITE)
+CYCLE_COMMAND= tests/cycle $(COLLECTION) $(SUITE)
+
ATOM_COMMAND= tests/atomsmasher $(COLLECTION) $(SUITE)
UDP_COMMAND= tests/testudp $(COLLECTION) $(SUITE)
HASH_COMMAND= tests/testhashkit $(COLLECTION) $(SUITE)
-test-mem: tests/testapp
+test-mem: tests/var tests/testapp
$(MEM_COMMAND)
-test-udp: tests/testudp
+test-udp: tests/var tests/testudp
$(UDP_COMMAND)
-test-atom: tests/atomsmasher
+test-atom: tests/var tests/atomsmasher
$(ATOM_COMMAND)
-test-plus: tests/testplus
+test-plus: tests/var tests/testplus
$(TESTPLUS_COMMAND)
-test-hash: tests/testhashkit
+test-hash: tests/var tests/testhashkit
$(HASH_COMMAND)
-test-hashplus: tests/hashplus
+test-hashplus: tests/var tests/hashplus
$(HASHPLUS_COMMAND)
+test-cycle: tests/var tests/cycle
+ $(CYCLE_COMMAND)
+
pahole-mem: tests/testapp
$(PAHOLE_COMMAND) $(MEM_COMMAND)
gdb-hashplus: tests/hashplus
$(DEBUG_COMMAND) $(HASHPLUS_COMMAND)
+gdb-cycle: tests/cycle
+ $(DEBUG_COMMAND) $(CYCLE_COMMAND)
+
gdb-memslap: clients/memslap
$(DEBUG_COMMAND) $(MEMSLAP_COMMAND)
*
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
+#pragma once
+
+#include <cassert>
/* The structure we use for the test system */
struct libmemcached_test_container_st
libmemcached_test_container_st() :
parent(NULL),
memc(NULL)
- {
- memset(&construct, 0, sizeof(server_startup_st));
- }
+ { }
};
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Prototypes for functions we will pass to test framework */
libmemcached_test_container_st *world_create(test_return_t *error);
test_return_t world_test_startup(libmemcached_test_container_st *);
{
global_container.construct.count= SERVERS_TO_CREATE;
global_container.construct.udp= 0;
- server_startup(&global_container.construct);
+ if (not server_startup(&global_container.construct))
+ {
+ *error= TEST_FAILURE;
+ return NULL;
+ }
*error= TEST_SUCCESS;
char buffer[BUFSIZ];
test_compare_got(MEMCACHED_SUCCESS,
- libmemcached_check_configuration(container->construct.server_list, strlen(container->construct.server_list),
+ libmemcached_check_configuration(container->construct.server_list.c_str(), container->construct.server_list.size(),
buffer, sizeof(buffer)),
buffer);
- container->parent= memcached(container->construct.server_list, strlen(container->construct.server_list));
+ assert(not container->parent);
+ container->parent= memcached(container->construct.server_list.c_str(), container->construct.server_list.size());
test_true(container->parent);
return TEST_SUCCESS;
test_return_t world_test_startup(libmemcached_test_container_st *container)
{
+ assert(container);
+ assert(not container->memc);
+ assert(container->parent);
container->memc= memcached_clone(NULL, container->parent);
test_true(container->memc);
test_return_t world_flush(libmemcached_test_container_st *container)
{
+ assert(container->memc);
memcached_flush(container->memc, 0);
memcached_quit(container->memc);
test_return_t world_pre_run(libmemcached_test_container_st *container)
{
+ assert(container->memc);
for (uint32_t loop= 0; loop < memcached_server_list_count(container->memc->servers); loop++)
{
memcached_server_instance_st instance=
test_return_t world_on_error(test_return_t test_state, libmemcached_test_container_st *container)
{
(void)test_state;
+ assert(container->memc);
memcached_free(container->memc);
container->memc= NULL;
{
if (func)
{
+ assert(container);
+ assert(container->memc);
return func(container->memc);
}
else
memcached_server_instance_by_position(memc, 0);
if ((instance->major_version >= 1 && (instance->minor_version == 2 && instance->micro_version >= 4))
- || instance->minor_version > 2)
+ or instance->minor_version > 2)
{
return TEST_SUCCESS;
}
static test_return_t pre_unix_socket(memcached_st *memc)
{
- memcached_return_t rc;
struct stat buf;
memcached_servers_reset(memc);
+ const char *socket_file= default_socket();
- if (stat("/tmp/memcached.socket", &buf))
- return TEST_SKIPPED;
+ test_skip(0, stat(socket_file, &buf));
- rc= memcached_server_add_unix_socket_with_weight(memc, "/tmp/memcached.socket", 0);
+ test_compare(MEMCACHED_SUCCESS,
+ memcached_server_add_unix_socket_with_weight(memc, socket_file, 0));
- return ( rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_FAILURE );
+ return TEST_SUCCESS;
}
static test_return_t pre_nodelay(memcached_st *memc)
static test_return_t test_server_failure(memcached_st *memc)
{
+ if (memcached_server_count(memc) < 2)
+ return TEST_SKIPPED;
+
memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 0);
memcached_st *local_memc= memcached_create(NULL);
static test_return_t test_cull_servers(memcached_st *memc)
{
- uint32_t count = memcached_server_count(memc);
+ uint32_t count= memcached_server_count(memc);
+
+ if (count < 2)
+ {
+ return TEST_SKIPPED;
+ }
// Do not do this in your code, it is not supported.
memc->servers[1].options.is_dead= true;
{"libmemcached_check_configuration_with_filename", 0, (test_callback_fn*)libmemcached_check_configuration_with_filename_test },
{"number_options", 0, (test_callback_fn*)parser_number_options_test },
{"randomly generated options", 0, (test_callback_fn*)random_statement_build_test },
- {"prefix_key", 0, (test_callback_fn*)parser_key_prefix_test },
+ {"namespace", 0, (test_callback_fn*)parser_key_prefix_test },
{"server", 0, (test_callback_fn*)server_test },
{"bad server strings", 0, (test_callback_fn*)servers_bad_test },
{"server with weights", 0, (test_callback_fn*)server_with_weight_test },
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <libtest/server.h>
-
-int main(void)
-{
- server_startup_st construct;
-
- memset(&construct, 0, sizeof(server_startup_st));
-
- construct.count= 4;
-
- server_startup(&construct);
-
- return EXIT_SUCCESS;
-}