Update for testig memcached_light
authorBrian Aker <brian@tangent.org>
Fri, 2 Mar 2012 07:05:55 +0000 (23:05 -0800)
committerBrian Aker <brian@tangent.org>
Fri, 2 Mar 2012 07:05:55 +0000 (23:05 -0800)
12 files changed:
configure.ac
example/include.am
example/memcached_light.cc
example/t/include.am
example/t/memcached_light.cc
libtest/memcached.cc
libtest/memcached.h
libtest/server.cc
libtest/server_container.cc
libtest/unittest.cc
util/include.am
util/log.hpp [new file with mode: 0644]

index 8bb9a60a37199fb22dcad18e9b6e1e7f1693fd32..caec223bca9a56c963790b3144dde7c8ba99a8f1 100644 (file)
@@ -209,6 +209,9 @@ AC_DEFINE([GEARMAND_BLOBSLAP_WORKER], [0], [Support for Gearman Blobslap worker]
 AC_DEFINE([HAVE_LIBPQ], [0], [Support for Postgres])
 AC_DEFINE([HAVE_LIBCURL], [0], [Support for libcurl])
 
+AC_DEFINE([HAVE_MEMCACHED_LIGHT_BINARY], [1], [Support for memcached_light])
+AC_DEFINE([MEMCACHED_LIGHT_BINARY], ["example/memcached_light"], [Support for memcached_light])
+
 AC_CHECK_HEADERS_ONCE(winsock2.h poll.h sys/wait.h fnmatch.h)
 AM_CONDITIONAL(BUILD_POLL, test "x$ac_cv_header_poll_h" = "xno")
 AM_CONDITIONAL(BUILD_WIN32_WRAPPERS, test "x$ac_cv_header_winsock2_h" = "xyes")
index 0abd2c3bc4801f69c93ef0c0b7161cdea49b240d..bf620d0c2d4344c5f4dcffa5050546e91c0e678d 100644 (file)
@@ -15,7 +15,9 @@ example_memcached_light_SOURCES= \
                                 example/byteorder.cc \
                                 example/interface_v0.cc \
                                 example/interface_v1.cc \
-                                example/memcached_light.cc
+                                example/memcached_light.cc \
+                                util/daemon.cc \
+                                util/pidfile.cc
 
 example_memcached_light_LDADD= libmemcached/libmemcachedprotocol.la \
                                $(LIBEVENT_LDFLAGS)
index 791d259be24379ecda39bb81916197198c7bc3b7..4bf828250e27787b8a6b3e105da0ea7d46260a63 100644 (file)
 #include "example/storage.h"
 #include "example/memcached_light.h"
 
+#include "util/daemon.hpp"
+#include "util/log.hpp"
+#include "util/pidfile.hpp"
+
+using namespace datadifferential;
+
 #include <event.h>
 
 #include <cassert>
@@ -60,14 +66,17 @@ struct connection
 static int maxconns= 1024;
 
 static struct connection *socket_userdata_map;
-static struct event_base *event_base;
+static struct event_base *event_base= NULL;
 
 struct options_st {
-  char *pid_file;
+  std::string pid_file;
+  std::string service;
+  std::string log_file;
   bool is_verbose;
+  bool opt_daemon;
 
   options_st() :
-    pid_file(NULL),
+    service("9999"),
     is_verbose(false)
   {
   }
@@ -185,11 +194,7 @@ static void accept_handler(memcached_socket_t fd, short, void *arg)
   }
 }
 
-/**
- * Create a socket and bind it to a specific port number
- * @param port the port number to bind to
- */
-static int server_socket(const char *port)
+static bool server_socket(util::log_info_st& log_file, const std::string& service)
 {
   struct addrinfo *ai;
   struct addrinfo hints;
@@ -199,19 +204,23 @@ static int server_socket(const char *port)
   hints.ai_family= AF_UNSPEC;
   hints.ai_socktype= SOCK_STREAM;
 
-  int error= getaddrinfo("127.0.0.1", port, &hints, &ai);
+  int error= getaddrinfo("127.0.0.1", service.c_str(), &hints, &ai);
   if (error != 0)
   {
     if (error != EAI_SYSTEM)
     {
-      std::cerr << "getaddrinfo(): " << gai_strerror(error) << std::endl;
+      std::string buffer("getaddrinfo: ");
+      buffer+= gai_strerror(error);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
     }
     else
     {
-      std::cerr << "getaddrinfo(): " << strerror(errno) << std::endl;
+      std::string buffer("getaddrinfo: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
     }
 
-    return 0;
+    return false;
   }
 
   struct linger ling= {0, 0};
@@ -221,7 +230,9 @@ static int server_socket(const char *port)
     memcached_socket_t sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     if (sock == INVALID_SOCKET)
     {
-      std::cerr << "Failed to create socket: " << strerror(errno) << std::endl;
+      std::string buffer("Failed to create socket: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       continue;
     }
 
@@ -238,7 +249,9 @@ static int server_socket(const char *port)
     flags= fcntl(sock, F_GETFL, 0);
     if (flags == -1)
     {
-      std::cerr << "Failed to get socket flags: " << strerror(errno) << std::endl;
+      std::string buffer("Failed to get socket flags: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       closesocket(sock);
       continue;
     }
@@ -247,7 +260,9 @@ static int server_socket(const char *port)
     {
       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
       {
-        std::cerr << "Failed to set socket to nonblocking mode: " << strerror(errno) << std::endl;
+        std::string buffer("Failed to set socket to nonblocking mode: ");
+        buffer+= strerror(errno);
+        log_file.write(util::VERBOSE_ERROR, buffer.c_str());
         closesocket(sock);
         continue;
       }
@@ -288,14 +303,18 @@ static int server_socket(const char *port)
 
     if (listen(sock, 1024) == SOCKET_ERROR)
     {
-      std::cerr << "listen(): " << strerror(errno) << std::endl;
+      std::string buffer("listen(): ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       closesocket(sock);
       continue;
     }
 
     if (global_options.is_verbose)
     {
-      std::cout << "Listening to " << port << std::endl;
+      std::string buffer("Listening to: ");
+      buffer+= global_options.service;
+      log_file.write(util::VERBOSE_NOTICE, buffer.c_str());
     }
 
     server_sockets[num_server_sockets++]= sock;
@@ -303,7 +322,7 @@ static int server_socket(const char *port)
 
   freeaddrinfo(ai);
 
-  return (num_server_sockets > 0) ? 0 : 1;
+  return (num_server_sockets > 0) ? true : false;
 }
 
 /**
@@ -414,13 +433,6 @@ int main(int argc, char **argv)
 {
   memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
 
-  event_base= event_init();
-  if (event_base == NULL)
-  {
-    std::cerr << "Failed to create an instance of libevent" << std::endl;
-    return EXIT_FAILURE;
-  }
-
   /*
    * We need to initialize the handlers manually due to a bug in the
    * warnings generated by struct initialization in gcc (all the way up to 4.4)
@@ -432,27 +444,31 @@ int main(int argc, char **argv)
     enum long_option_t {
       OPT_HELP,
       OPT_VERBOSE,
+      OPT_DAEMON,
       OPT_PROTOCOL_VERSION,
       OPT_VERSION,
       OPT_PORT,
       OPT_MAX_CONNECTIONS,
+      OPT_LOGFILE,
       OPT_PIDFILE
     };
 
     static struct option long_options[]=
     {
-      {"help", no_argument, NULL, OPT_HELP},
-      {"port", required_argument, NULL, OPT_PORT},
-      {"verbose", no_argument, NULL, OPT_VERBOSE},
-      {"protocol", required_argument, NULL, OPT_PROTOCOL_VERSION},
-      {"version", no_argument, NULL, OPT_VERSION},
-      {"max-connections", required_argument, NULL, OPT_MAX_CONNECTIONS},
-      {"pid-file", required_argument, NULL, OPT_PIDFILE},
+      { "help", no_argument, NULL, OPT_HELP },
+      { "port", required_argument, NULL, OPT_PORT },
+      { "verbose", no_argument, NULL, OPT_VERBOSE },
+      { "daemon", no_argument, NULL, OPT_DAEMON },
+      { "protocol", no_argument, NULL, OPT_PROTOCOL_VERSION },
+      { "version", no_argument, NULL, OPT_VERSION },
+      { "max-connections", required_argument, NULL, OPT_MAX_CONNECTIONS },
+      { "pid-file", required_argument, NULL, OPT_PIDFILE },
+      { "log-file", required_argument, NULL, OPT_LOGFILE },
       {0, 0, 0, 0}
     };
 
+    bool opt_help= false;
     int option_index;
-    bool has_port= false;
     bool done= false;
     while (done == false)
     {
@@ -467,16 +483,26 @@ int main(int argc, char **argv)
         break;
 
       case OPT_PIDFILE:
-        global_options.pid_file= strdup(optarg);
+        global_options.pid_file= optarg;
+        break;
+
+      case OPT_LOGFILE:
+        global_options.log_file= optarg;
         break;
 
       case OPT_VERBOSE:
         global_options.is_verbose= true;
         break;
 
+      case OPT_VERSION:
+        break;
+
+      case OPT_DAEMON:
+        global_options.opt_daemon= true;
+        break;
+
       case OPT_PORT:
-        has_port= true;
-        (void)server_socket(optarg);
+        global_options.service= optarg;
         break;
 
       case OPT_MAX_CONNECTIONS:
@@ -484,12 +510,8 @@ int main(int argc, char **argv)
         break;
 
       case OPT_HELP:  /* FALLTHROUGH */
-        std::cout << "Usage: " << argv[0] << std::endl;
-        for (struct option *ptr_option= long_options; ptr_option->name; ptr_option++)
-        {
-          std::cout << "\t" << ptr_option->name << std::endl;
-        }
-        return EXIT_SUCCESS;
+        opt_help= true;
+        break;
 
       default:
         {
@@ -499,42 +521,47 @@ int main(int argc, char **argv)
       }
     }
 
-    if (has_port == false)
+    if (opt_help)
     {
-      (void)server_socket("9999");
+      std::cout << "Usage: " << argv[0] << std::endl;
+      for (struct option *ptr_option= long_options; ptr_option->name; ptr_option++)
+      {
+        std::cout << "\t" << ptr_option->name << std::endl;
+      }
+      return EXIT_SUCCESS;
     }
   }
 
-  if (! initialize_storage())
+  if (global_options.opt_daemon)
+  {
+    util::daemonize(false, true);
+  }
+
+  if (initialize_storage() == false)
   {
     /* Error message already printed */
     return EXIT_FAILURE;
   }
 
-  if (global_options.pid_file)
-  {
-    FILE *pid_file;
-    uint32_t pid;
+  util::Pidfile _pid_file(global_options.pid_file);
 
-    pid_file= fopen(global_options.pid_file, "w+");
+  if (_pid_file.create() == false)
+  {
+    std::cerr << "Failed to create pid-file" <<  _pid_file.error_message() << std::endl;
+    return EXIT_FAILURE;
+  }
 
-    if (pid_file == NULL)
-    {
-      perror(strerror(get_socket_errno()));
-      abort();
-    }
+  util::log_info_st log_file(argv[0], global_options.log_file, false);
+  log_file.write(util::VERBOSE_NOTICE, "starting log");
 
-    pid= (uint32_t)getpid();
-    if (global_options.is_verbose)
-    {
-      std::cout << "pid:" << pid << std::endl;
-    }
-    fclose(pid_file);
+  if (server_socket(log_file, global_options.service) == false)
+  {
+    return EXIT_FAILURE;
   }
 
   if (num_server_sockets == 0)
   {
-    std::cerr << "No server sockets are available" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
     return EXIT_FAILURE;
   }
 
@@ -550,20 +577,27 @@ int main(int argc, char **argv)
   struct memcached_protocol_st *protocol_handle;
   if ((protocol_handle= memcached_protocol_create_instance()) == NULL)
   {
-    std::cerr << "Failed to allocate protocol handle" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
     return EXIT_FAILURE;
   }
 
   socket_userdata_map= (struct connection*)calloc((size_t)(maxconns), sizeof(struct connection));
   if (socket_userdata_map == NULL)
   {
-    std::cerr << "Failed to allocate room for connections" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "Failed to allocate room for connections");
     return EXIT_FAILURE;
   }
 
   memcached_binary_protocol_set_callbacks(protocol_handle, interface);
   memcached_binary_protocol_set_pedantic(protocol_handle, true);
 
+  event_base= event_init();
+  if (event_base == NULL)
+  {
+    std::cerr << "Failed to create an instance of libevent" << std::endl;
+    return EXIT_FAILURE;
+  }
+
   for (int xx= 0; xx < num_server_sockets; ++xx)
   {
     struct connection *conn= &socket_userdata_map[server_sockets[xx]];
@@ -574,13 +608,36 @@ int main(int argc, char **argv)
     event_base_set(event_base, &conn->event);
     if (event_add(&conn->event, 0) == -1)
     {
-      std::cerr << "Failed to add event for " << server_sockets[xx] << std::endl;
+      log_file.write(util::VERBOSE_ERROR, "Failed to add event");
       closesocket(server_sockets[xx]);
     }
   }
 
+  if (global_options.opt_daemon)
+  {
+    if (util::daemon_is_ready(true) == false)
+    {
+      log_file.write(util::VERBOSE_ERROR, "Failed for util::daemon_is_ready()");
+      return EXIT_FAILURE;
+    }
+  }
+
+
   /* Serve all of the clients */
-  event_base_loop(event_base, 0);
+  switch (event_base_loop(event_base, 0) == -1)
+  {
+  case -1:
+    log_file.write(util::VERBOSE_ERROR, "event_base_loop() failed");
+    break;
+
+  case 1:
+    log_file.write(util::VERBOSE_ERROR, "event_base_loop(), no events were registered");
+    break;
+
+  default:
+    break;
+  }
+  log_file.write(util::VERBOSE_NOTICE, "exiting");
 
   /* NOTREACHED */
   return EXIT_SUCCESS;
index 82ba9404a9bd7e52e5da71d8de2e165b678f0508..3cb5b809785fafb335deab4e5d3d5a506214f4a6 100644 (file)
@@ -14,8 +14,8 @@ MEMCACHED_LIGHT_TESTS_LDADDS= \
                               libtest/libtest.la
 example_t_memcached_light_SOURCES= example/t/memcached_light.cc
 example_t_memcached_light_CXXFLAGS = $(AM_CXXFLAGS)
-example_t_memcached_light_DEPENDENCIES= $(MEMCACHED_LIGHT_TESTS_LDADDS)
-example_t_memcached_light_LDADD= $(example_t_memcached_light_DEPENDENCIES)
+example_t_memcached_light_DEPENDENCIES= $(MEMCACHED_LIGHT_TESTS_LDADDS) example/memcached_light
+example_t_memcached_light_LDADD= $(MEMCACHED_LIGHT_TESTS_LDADDS)
 check_PROGRAMS+= example/t/memcached_light
 noinst_PROGRAMS+= example/t/memcached_light
 
index ae99651868c1756743b50e688ab54536de29c4e1..44f2770c8f0030969e01b083cb3f81cf4490a789 100644 (file)
@@ -1,8 +1,8 @@
 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
  * 
- *  Test memslap
+ *  Test memcat
  *
- *  Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *  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
@@ -50,85 +50,127 @@ using namespace libtest;
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #endif
 
-static std::string executable;
+static std::string executable("example/memcached_light");
 
 static test_return_t help_TEST(void *)
 {
-  const char *memcached_light_args[]= { "--help", 0 };
-  Application memcached_light_app(executable, true);
+  const char *args[]= { "--help", 0 };
 
-  test_compare(Application::SUCCESS, memcached_light_app.run(memcached_light_args));
-  test_compare(Application::SUCCESS, memcached_light_app.wait());
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
 
   return TEST_SUCCESS;
 }
 
-static test_return_t basic_TEST(void *)
+static test_return_t verbose_TEST(void *)
 {
-  test_skip(false, true);
+  const char *args[]= { "--help", "--verbose", 0 };
 
-  char port_buffer[1024];
-  snprintf(port_buffer, sizeof(port_buffer), "--port=%d", int(libtest::default_port()));
-  const char *memcached_light_args[]= { port_buffer, 0 };
-  Application memcached_light_app(executable, true);
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
 
-  test_compare(Application::SUCCESS, memcached_light_app.run(memcached_light_args));
+  return TEST_SUCCESS;
+}
 
-  char instance_buffer[1024];
-  int instance_buffer_length= snprintf(instance_buffer, sizeof(instance_buffer), "--BINARY --server=localhost:%d", int(libtest::default_port()));
-  memcached_st *memc= memcached(instance_buffer, instance_buffer_length);
+static test_return_t daemon_TEST(void *)
+{
+  const char *args[]= { "--help", "--daemon", 0 };
 
-#if 0
-  for (size_t x= 0; x < 24; x++)
-  {
-    char id_buffer[1024];
-    int length= snprintf(id_buffer, sizeof(id_buffer), "%u", uint32_t(x));
-    test_compare_hint(MEMCACHED_NOTFOUND, memcached_delete(memc, id_buffer, length, 0),
-                      id_buffer);
-  }
-#endif
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
 
-  // We fail since we are just outright killing it.
-  test_compare(Application::FAILURE, memcached_light_app.wait());
+  return TEST_SUCCESS;
+}
+
+static test_return_t protocol_TEST(void *)
+{
+  const char *args[]= { "--help", "--protocol", 0 };
 
-  memcached_free(memc);
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
 
   return TEST_SUCCESS;
 }
 
-test_st help_TESTS[] ={
-  {"--help", true, help_TEST },
-  {0, 0, 0}
-};
+static test_return_t version_TEST(void *)
+{
+  const char *args[]= { "--help", "--version", 0 };
+
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t port_TEST(void *)
+{
+  const char *args[]= { "--help", "--port=9090", 0 };
+
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+  return TEST_SUCCESS;
+}
 
-test_st basic_TESTS[] ={
-  {"--port", true, basic_TEST },
+static test_return_t pid_file_TEST(void *)
+{
+  const char *args[]= { "--help", "--pid-file=/tmp/foo.pid", 0 };
+
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t log_file_TEST(void *)
+{
+  const char *args[]= { "--help", "--log-file=/tmp/foo.log", 0 };
+
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t max_connections_file_TEST(void *)
+{
+  const char *args[]= { "--help", "--max-connections=/tmp/foo.max_connections", 0 };
+
+  test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+  return TEST_SUCCESS;
+}
+
+test_st cmdline_option_TESTS[] ={
+  {"--help", true, help_TEST },
+  {"--verbose", true, verbose_TEST },
+  {"--daemon", true, daemon_TEST },
+  {"--protocol", true, protocol_TEST },
+  {"--version", true, version_TEST },
+  {"--port", true, port_TEST },
+  {"--pid-file", true, pid_file_TEST },
+  {"--log-file", true, log_file_TEST },
+  {"--max-connections", true, max_connections_file_TEST },
   {0, 0, 0}
 };
 
 collection_st collection[] ={
-  {"--help", 0, 0, help_TESTS },
-  {"basics", 0, 0, basic_TESTS },
+  {"command line options", 0, 0, cmdline_option_TESTS },
   {0, 0, 0, 0}
 };
 
 static void *world_create(server_startup_st& servers, test_return_t& error)
 {
-  if (HAVE_MEMCACHED_BINARY == 0)
+  if (HAVE_MEMCACHED_LIGHT_BINARY == 0)
   {
     error= TEST_SKIPPED;
     return NULL;
   }
 
+  if (server_startup(servers, "memcached-light", libtest::default_port(), 0, NULL) == 0)
+  {
+    error= TEST_FAILURE;
+  }
+
   return &servers;
 }
 
 
 void get_world(Framework *world)
 {
-  executable= "./example/memcached_light";
   world->collections= collection;
   world->_create= world_create;
 }
 
-
index 271e2c3baca27864a50397b3c1b1f4a43b2cffe4..6f81dd6c790b696974ab087ad9cb16f4d93ae526 100644 (file)
@@ -85,7 +85,7 @@ public:
   pid_t get_pid(bool error_is_ok)
   {
     // Memcached is slow to start, so we need to do this
-    if (not pid_file().empty())
+    if (pid_file().empty() == false)
     {
       if (error_is_ok and not wait_for_pidfile())
       {
@@ -222,6 +222,107 @@ public:
   bool build(size_t argc, const char *argv[]);
 };
 
+class MemcachedLight : public libtest::Server
+{
+
+public:
+  MemcachedLight(const std::string& host_arg, const in_port_t port_arg):
+    libtest::Server(host_arg, port_arg)
+  {
+    set_pid_file();
+  }
+
+  pid_t get_pid(bool error_is_ok)
+  {
+    // Memcached is slow to start, so we need to do this
+    if (not pid_file().empty())
+    {
+      if (error_is_ok and not wait_for_pidfile())
+      {
+        Error << "Pidfile was not found:" << pid_file();
+        return -1;
+      }
+    }
+
+    bool success= false;
+    std::stringstream error_message;
+    pid_t local_pid= get_pid_from_file(pid_file(), error_message);
+    if (local_pid > 0)
+    {
+      if (::kill(local_pid, 0) > 0)
+      {
+        success= true;
+      }
+    }
+
+    if (error_is_ok and ((success or not is_pid_valid(local_pid))))
+    {
+      Error << "kill(" << " pid: " << local_pid << " errno:" << strerror(errno) << " for:" << *this;
+    }
+
+    return local_pid;
+  }
+
+  bool ping()
+  {
+    // Memcached is slow to start, so we need to do this
+    if (not pid_file().empty())
+    {
+      if (not wait_for_pidfile())
+      {
+        Error << "Pidfile was not found:" << pid_file();
+        return false;
+      }
+    }
+
+    std::stringstream error_message;
+    pid_t local_pid= get_pid_from_file(pid_file(), error_message);
+    if (local_pid > 0)
+    {
+      if (::kill(local_pid, 0) == 0)
+      {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  const char *name()
+  {
+    return "memcached_light";
+  };
+
+  const char *executable()
+  {
+    return MEMCACHED_LIGHT_BINARY;
+  }
+
+  const char *daemon_file_option()
+  {
+    return "--daemon";
+  }
+
+  virtual void port_option(Application& app, in_port_t arg)
+  {
+    char buffer[1024];
+    snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
+    app.add_option(buffer);
+  }
+
+  bool has_port_option() const
+  {
+    return true;
+  }
+
+  bool is_libtool()
+  {
+    return true;
+  }
+
+  bool build(size_t argc, const char *argv[]);
+};
+
 class MemcachedSaSL : public Memcached
 {
 public:
@@ -330,7 +431,17 @@ bool Memcached::build(size_t argc, const char *argv[])
     add_option(sasl());
   }
 
-  for (int x= 1 ; x < argc ; x++)
+  for (int x= 0 ; x < argc ; x++)
+  {
+    add_option(argv[x]);
+  }
+
+  return true;
+}
+
+bool MemcachedLight::build(size_t argc, const char *argv[])
+{
+  for (int x= 0 ; x < argc ; x++)
   {
     add_option(argv[x]);
   }
@@ -350,6 +461,11 @@ libtest::Server *build_memcached_socket(const std::string& socket_file, const in
   return new Memcached(socket_file, try_port, true);
 }
 
+libtest::Server *build_memcached_light(const std::string& hostname, const in_port_t try_port)
+{
+  return new MemcachedLight(hostname, try_port);
+}
+
 
 libtest::Server *build_memcached_sasl(const std::string& hostname, const in_port_t try_port, const std::string& username, const std::string &password)
 {
index a08996140189c69648823700d6306faa5ad96125..4594d5b6abe44ca76defa5e9a21c9e85f185402c 100644 (file)
@@ -25,6 +25,8 @@ namespace libtest {
 
 libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port);
 
+libtest::Server *build_memcached_light(const std::string& socket_file, const in_port_t try_port);
+
 libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port);
 
 libtest::Server *build_memcached_sasl(const std::string& hostname, const in_port_t try_port, const std::string& username, const std::string& password);
index 66575e74300725dd93b9327be6e339d3682cb649..8ca6b53e60ee812082735ff2361f44f070ed469a 100644 (file)
@@ -186,10 +186,16 @@ bool Server::start()
     // If we happen to have a pid file, lets try to kill it
     if (pid_file().empty() == false)
     {
-      Error << "We are going to kill it off";
-      kill_file(pid_file());
+      if (kill_file(pid_file()) == false)
+      {
+        fatal_message("Failed to kill off server after startup occurred, when pinging failed");
+      }
+      Error << "Failed to ping() server started, having pid_file. exec:" << _running;
+    }
+    else
+    {
+      Error << "Failed to ping() server started. exec:" << _running;
     }
-    Error << "Failed to ping() server started with:" << _running;
     _running.clear();
     return false;
   }
index 244f80e6b4fb7545642132bd36cda7653977a587..6d0c785e7de5f20d5d2d06d549ed7545e5b749ff 100644 (file)
@@ -195,11 +195,20 @@ bool server_startup(server_startup_st& construct, const std::string& server_type
       }
     }
   }
+  else if (server_type.compare("memcached-light") == 0)
+  {
+    if (MEMCACHED_LIGHT_BINARY)
+    {
+      if (HAVE_LIBMEMCACHED)
+      {
+        server= build_memcached_light("localhost", try_port);
+      }
+    }
+  }
 
   if (server == NULL)
   {
-    Error << "Failure occured while creating server: " <<  server_type;
-    return false;
+    fatal_message("Launching of an unknown server was attempted");
   }
 
   /*
index 53fb605fd658cca034db7b6f5f7be3563855f275..95ab7ce1b632fc0391ce20078fad370d4a009cc5 100644 (file)
@@ -241,6 +241,18 @@ static test_return_t gearmand_cycle_test(void *object)
   return TEST_SUCCESS;
 }
 
+static test_return_t memcached_light_cycle_TEST(void *object)
+{
+  server_startup_st *servers= (server_startup_st*)object;
+  test_true(servers);
+
+  test_skip(true, bool(HAVE_MEMCACHED_LIGHT_BINARY));
+
+  test_true(server_startup(*servers, "memcached-light", get_free_port(), 0, NULL));
+
+  return TEST_SUCCESS;
+}
+
 static test_return_t memcached_cycle_test(void *object)
 {
   server_startup_st *servers= (server_startup_st*)object;
@@ -565,6 +577,7 @@ static test_return_t check_for_libmemcached(void *)
 
 test_st memcached_tests[] ={
   {"memcached startup-shutdown", 0, memcached_cycle_test },
+  {"memcached-light startup-shutdown", 0, memcached_light_cycle_TEST },
   {"memcached(socket file) startup-shutdown", 0, memcached_socket_cycle_test },
   {"memcached_sasl() startup-shutdown", 0, memcached_sasl_test },
   {"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test },
index 6f848f381ed9067c50ecca17bc6e4cf36a390c16..2dcf1c4347eecf49c1852920c389f4f3ccdccbc0 100644 (file)
@@ -14,6 +14,7 @@ noinst_HEADERS+= \
                 util/daemon.hpp \
                 util/instance.hpp \
                 util/logfile.hpp \
+                util/log.hpp \
                 util/operation.hpp \
                 util/signal.hpp \
                 util/string.hpp \
diff --git a/util/log.hpp b/util/log.hpp
new file mode 100644 (file)
index 0000000..b7f257d
--- /dev/null
@@ -0,0 +1,198 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  libtest
+ *
+ *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 3 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#pragma once
+
+#include <cerrno>
+#include <cstdio>
+#include <fcntl.h>
+#include <iostream>
+#include <string>
+#include <syslog.h>
+
+#define UTIL_MAX_ERROR_SIZE 2048
+
+namespace datadifferential {
+namespace util {
+
+/** Verbosity levels.
+ */
+enum verbose_t
+{
+  // Logging this will cause shutdown
+  VERBOSE_FATAL= LOG_EMERG, // syslog:LOG_EMERG
+
+  VERBOSE_ALERT= LOG_ALERT, // syslog:LOG_ALERT
+  VERBOSE_CRITICAL= LOG_CRIT, //  syslog:LOG_CRIT
+
+  VERBOSE_ERROR= LOG_ERR, // syslog:LOG_ERR
+
+  VERBOSE_WARN= LOG_WARNING, // syslog:LOG_WARNING
+
+  VERBOSE_NOTICE= LOG_NOTICE, // syslog:LOG_NOTICE
+
+  VERBOSE_INFO= LOG_INFO, // syslog:LOG_INFO
+
+  VERBOSE_DEBUG= LOG_DEBUG // syslog:LOG_DEBUG
+};
+
+
+struct log_info_st
+{
+  std::string name;
+  std::string filename;
+  int fd;
+  bool opt_syslog;
+  bool opt_file;
+  bool init_success;
+
+  log_info_st(const std::string& name_arg, const std::string &filename_arg, bool syslog_arg) :
+    name(name_arg),
+    filename(filename_arg),
+    fd(-1),
+    opt_syslog(syslog_arg),
+    opt_file(false),
+    init_success(false)
+  {
+    if (opt_syslog)
+    {
+      openlog(name.c_str(), LOG_PID | LOG_NDELAY, LOG_USER);
+    }
+
+    init();
+  }
+
+  void init()
+  {
+    if (filename.size())
+    {
+      if (filename.compare("stderr") == 0)
+      {
+        fd= STDERR_FILENO;
+      }
+      else
+      {
+        fd= open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
+        if (fd == -1)
+        {
+          if (opt_syslog)
+          {
+            char buffer[1024];
+            getcwd(buffer, sizeof(buffer));
+            syslog(LOG_ERR, "Could not open log file \"%.*s\", from \"%s\", open failed with (%s)", 
+                   int(filename.size()), filename.c_str(), 
+                   buffer,
+                   strerror(errno));
+          }
+          std::cerr << "Could not open log file for writing, switching to stderr." << std::endl;
+
+          fd= STDERR_FILENO;
+        }
+      }
+
+      opt_file= true;
+    }
+
+    init_success= true;
+  }
+
+  bool initialized() const
+  {
+    return init_success;
+  }
+
+  int file() const
+  {
+    return fd;
+  }
+
+  void write(verbose_t verbose, const char *mesg)
+  {
+    if (opt_file)
+    {
+      char buffer[UTIL_MAX_ERROR_SIZE];
+      int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %s\n", verbose_name(verbose), mesg);
+      if (::write(file(), buffer, buffer_length) == -1)
+      {
+        std::cerr << "Could not write to log file." << std::endl;
+        syslog(LOG_EMERG, "gearmand could not open log file %s, got error %s", filename.c_str(), strerror(errno));
+      }
+
+    }
+
+    if (opt_syslog)
+    {
+      syslog(int(verbose), "%7s %s", verbose_name(verbose), mesg);
+    }
+  }
+
+  ~log_info_st()
+  {
+    if (fd != -1 and fd != STDERR_FILENO)
+    {
+      close(fd);
+    }
+
+    if (opt_syslog)
+    {
+      closelog();
+    }
+  }
+
+private:
+  const char *verbose_name(verbose_t verbose)
+  {
+    switch (verbose)
+    {
+    case VERBOSE_FATAL:
+      return "FATAL";
+
+    case VERBOSE_ALERT:
+      return "ALERT";
+
+    case VERBOSE_CRITICAL:
+      return "CRITICAL";
+
+    case VERBOSE_ERROR:
+      return "ERROR";
+
+    case VERBOSE_WARN:
+      return "WARNING";
+
+    case VERBOSE_NOTICE:
+      return "NOTICE";
+
+    case VERBOSE_INFO:
+      return "INFO";
+
+    case VERBOSE_DEBUG:
+      return "DEBUG";
+
+    default:
+      break;
+    }
+
+    return "UNKNOWN";
+  }
+};
+
+} // namespace util
+} // namespace datadifferential