Add in better testing for gdb.
authorBrian Aker <brian@tangent.org>
Mon, 5 Mar 2012 00:44:37 +0000 (16:44 -0800)
committerBrian Aker <brian@tangent.org>
Mon, 5 Mar 2012 00:44:37 +0000 (16:44 -0800)
28 files changed:
.bzrignore
example/interface_v0.cc
example/interface_v1.cc
example/memcached_light.cc
example/memcached_light.h
example/t/include.am
example/t/memcached_light.cc
libtest/abort.cc [new file with mode: 0644]
libtest/cmdline.cc
libtest/cmdline.h
libtest/include.am
libtest/memcached.cc
libtest/run.gdb
libtest/server.cc
libtest/server.h
libtest/test.hpp
libtest/tmpfile.cc [new file with mode: 0644]
libtest/tmpfile.hpp [new file with mode: 0644]
libtest/unittest.cc
tests/libmemcached-1.0/all_tests.h
tests/libmemcached-1.0/include.am
tests/libmemcached-1.0/mem_functions.cc
tests/libmemcached-1.0/mem_functions.h
tests/libmemcached-1.0/memcached_get.cc [new file with mode: 0644]
tests/libmemcached-1.0/memcached_get.h [new file with mode: 0644]
tests/libmemcached-1.0/setup_and_teardowns.cc
tests/libmemcached-1.0/setup_and_teardowns.h
util/log.hpp

index d3ff77afe4b4b5c579c74e54a557c2ad09bab1d4..a3cc73e5df7e401c53abda212eb6279cf8093b80 100644 (file)
@@ -144,3 +144,4 @@ tmp_chroot
 unittests/unittests
 tests/libmemcached-1.0/testsocket
 example/t/memcached_light
+libtest/abort
index cc2f17d274fb9a71df32c87017912173bc51db9d..e4f5c9013c76a972d05872e50c6eb96ea621afb3 100644 (file)
 #include <example/byteorder.h>
 #include "example/memcached_light.h"
 #include "example/storage.h"
+#include "util/log.hpp"
+
+
+using namespace datadifferential;
+
+static util::log_info_st *log_file= NULL;
 
 static protocol_binary_response_status noop_command_handler(const void *cookie,
                                                             protocol_binary_request_header *header,
@@ -121,18 +127,22 @@ static protocol_binary_response_status delete_command_handler(const void *cookie
   response.message.header.response.opcode= header->request.opcode;
   response.message.header.response.opaque= header->request.opaque;
 
-  if (!delete_item(key, keylen))
+  if (delete_item(key, keylen) == false)
   {
+    log_file->write(util::VERBOSE_NOTICE, "%s not found: %.*s", __func__, keylen, key);
     response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
     return response_handler(cookie, header, (protocol_binary_response_header*)&response);
   }
   else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
   {
+    log_file->write(util::VERBOSE_NOTICE, "%s not found: %.*s", __func__, keylen, key);
     /* DELETEQ doesn't want success response */
     response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
     return response_handler(cookie, header, (protocol_binary_response_header*)&response);
   }
 
+  log_file->write(util::VERBOSE_NOTICE, "%s deleted: %.*s", __func__, keylen, key);
+
   return PROTOCOL_BINARY_RESPONSE_SUCCESS;
 }
 
@@ -516,8 +526,10 @@ static protocol_binary_response_status stat_command_handler(const void *cookie,
 
 memcached_binary_protocol_callback_st interface_v0_impl;
 
-void initialize_interface_v0_handler(void)
+void initialize_interface_v0_handler(util::log_info_st& arg)
 {
+  log_file= &arg;
+
   interface_v0_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V0;
   interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
   interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
index a4364918146b91c740b91d9d5bdaa20f35f79ace..08d093885aa7097f4e50ba7f2d9f2fbfb2e0e665 100644 (file)
@@ -9,19 +9,23 @@
  * command is being sent.
  */
 #include "config.h"
-#include <assert.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
 #include <sys/types.h>
-#include <stdio.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
 
 #include <libmemcachedprotocol-0.0/handler.h>
 #include <example/byteorder.h>
 #include "example/memcached_light.h"
 #include "example/storage.h"
+#include "util/log.hpp"
+
+static datadifferential::util::log_info_st *log_file= NULL;
 
 static protocol_binary_response_status add_handler(const void *cookie,
                                                    const void *key,
@@ -390,8 +394,9 @@ static protocol_binary_response_status version_handler(const void *cookie,
 
 memcached_binary_protocol_callback_st interface_v1_impl;
 
-void initialize_interface_v1_handler(void)
+void initialize_interface_v1_handler(datadifferential::util::log_info_st& arg)
 {
+  log_file= &arg;
   memset(&interface_v1_impl, 0, sizeof(memcached_binary_protocol_callback_st));
 
   interface_v1_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V1;
index 61c5314da950ce4d5fe42882355bede0185fd0ae..e7f952eacee1a1d3633cdfbbdcc0313eb63873f8 100644 (file)
@@ -433,13 +433,6 @@ int main(int argc, char **argv)
 {
   memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
 
-  /*
-   * 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)
-   */
-  initialize_interface_v0_handler();
-  initialize_interface_v1_handler();
-
   {
     enum long_option_t {
       OPT_HELP,
@@ -554,6 +547,14 @@ int main(int argc, char **argv)
   util::log_info_st log_file(argv[0], global_options.log_file, false);
   log_file.write(util::VERBOSE_NOTICE, "starting log");
 
+  /*
+   * 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)
+   */
+  initialize_interface_v0_handler(log_file);
+  initialize_interface_v1_handler(log_file);
+
+
   if (server_socket(log_file, global_options.service) == false)
   {
     return EXIT_FAILURE;
index 12c4ea79a222acff47de291045f061ee7ba7174a..6abb8744910a4726f9ad608320a7646b83b6880a 100644 (file)
@@ -1,5 +1,44 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Memcached Light interface definitions
+ *
+ *  Copyright (C) 2012 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.
+ *
+ */
+
 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
 #pragma once
 
-extern void initialize_interface_v0_handler(void);
-extern void initialize_interface_v1_handler(void);
+#include "util/log.hpp"
+
+void initialize_interface_v0_handler(datadifferential::util::log_info_st&);
+void initialize_interface_v1_handler(datadifferential::util::log_info_st&);
index 3cb5b809785fafb335deab4e5d3d5a506214f4a6..b9b7556d2eff083463515c232034cfa0ea2c45ac 100644 (file)
@@ -12,12 +12,25 @@ MEMCACHED_LIGHT_TESTS_LDADDS= \
                               libmemcached/libmemcached.la \
                               libmemcached/libmemcachedutil.la \
                               libtest/libtest.la
-example_t_memcached_light_SOURCES= example/t/memcached_light.cc
+
+example_t_memcached_light_SOURCES=
+example_t_memcached_light_LDADD=
+
+example_t_memcached_light_SOURCES+= example/t/memcached_light.cc
+example_t_memcached_light_SOURCES+= tests/libmemcached-1.0/memcached_get.cc
+example_t_memcached_light_SOURCES+= tests/libmemcached-1.0/setup_and_teardowns.cc
 example_t_memcached_light_CXXFLAGS = $(AM_CXXFLAGS)
 example_t_memcached_light_DEPENDENCIES= $(MEMCACHED_LIGHT_TESTS_LDADDS) example/memcached_light
-example_t_memcached_light_LDADD= $(MEMCACHED_LIGHT_TESTS_LDADDS)
+example_t_memcached_light_LDADD+= $(MEMCACHED_LIGHT_TESTS_LDADDS)
+example_t_memcached_light_LDADD+= $(LIBUUID_LDFLAGS)
 check_PROGRAMS+= example/t/memcached_light
 noinst_PROGRAMS+= example/t/memcached_light
 
-test-memcached_light: example/t/memcached_light
+test-memcached_light: example/t/memcached_light example/memcached_light
        @example/t/memcached_light
+
+gdb-memcached_light: example/t/memcached_light example/memcached_light
+       @$(DEBUG_COMMAND) example/t/memcached_light
+
+valgrind-memcached_light: example/t/memcached_light example/memcached_light
+       $(VALGRIND_COMMAND) example/t/memcached_light
index 44f2770c8f0030969e01b083cb3f81cf4490a789..bcfce0a52a19e3bdc350fe28ad64c9c562698510 100644 (file)
@@ -44,6 +44,8 @@
 #include <libtest/test.hpp>
 #include <libmemcached/memcached.h>
 
+#include "tests/libmemcached-1.0/memcached_get.h"
+
 using namespace libtest;
 
 #ifndef __INTEL_COMPILER
@@ -133,6 +135,39 @@ static test_return_t max_connections_file_TEST(void *)
   return TEST_SUCCESS;
 }
 
+typedef test_return_t (*libmemcached_test_callback_fn)(memcached_st *);
+
+static test_return_t _runner_default(libmemcached_test_callback_fn func, void *object)
+{
+  if (func)
+  {
+    test_true(object);
+    test_return_t ret;
+    try {
+      ret= func((memcached_st*)object);
+    }
+    catch (std::exception& e)
+    {
+      libtest::Error << e.what();
+      return TEST_FAILURE;
+    }
+
+    return ret;
+  }
+
+  return TEST_SUCCESS;
+}
+
+class MemcachedLightRunner : public libtest::Runner {
+public:
+  test_return_t run(test_callback_fn* func, void *object)
+  {
+    return _runner_default(libmemcached_test_callback_fn(func), object);
+  }
+};
+
+static MemcachedLightRunner defualt_libmemcached_runner;
+
 test_st cmdline_option_TESTS[] ={
   {"--help", true, help_TEST },
   {"--verbose", true, verbose_TEST },
@@ -146,8 +181,21 @@ test_st cmdline_option_TESTS[] ={
   {0, 0, 0}
 };
 
+/* Clean the server before beginning testing */
+test_st basic_TESTS[] ={
+#if 0
+  {"memcached_get()", true, (test_callback_fn*)get_test },
+  {"memcached_get() test 2", false, (test_callback_fn*)get_test2 },
+  {"memcached_get() test 3", false, (test_callback_fn*)get_test3 },
+  {"memcached_get() test 4", false, (test_callback_fn*)get_test4 },
+  {"memcached_get() test 5", false, (test_callback_fn*)get_test5 },
+#endif
+  {0, 0, 0}
+};
+
 collection_st collection[] ={
   {"command line options", 0, 0, cmdline_option_TESTS },
+  {"basic", 0, 0, basic_TESTS },
   {0, 0, 0, 0}
 };
 
@@ -164,13 +212,32 @@ static void *world_create(server_startup_st& servers, test_return_t& error)
     error= TEST_FAILURE;
   }
 
-  return &servers;
+
+  char buffer[1024];
+  int length= snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(libtest::default_port()));
+  fatal_assert(length > 0);
+
+  memcached_st *memc= memcached(buffer, length);
+
+  fatal_assert(memc);
+
+  return (void*)memc;
+}
+
+static bool world_destroy(void *object)
+{
+  memcached_st *memc= (memcached_st*)object;
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
 }
 
 
 void get_world(Framework *world)
 {
-  world->collections= collection;
   world->_create= world_create;
+  world->_destroy= world_destroy;
+  world->collections= collection;
+  world->set_runner(&defualt_libmemcached_runner);
 }
 
diff --git a/libtest/abort.cc b/libtest/abort.cc
new file mode 100644 (file)
index 0000000..05dfa26
--- /dev/null
@@ -0,0 +1,11 @@
+#include <cstdlib>
+
+int main(void)
+{
+  if (1)
+  {
+    abort();
+  }
+
+  return 0;
+}
index 6807c338af6fe20e69efffdff9be152e05ae9b09..22f0399d697d2a9e23e1614d2787a7b711bac85e 100644 (file)
@@ -26,6 +26,7 @@ using namespace libtest;
 #include <cstdlib>
 #include <cstring>
 #include <fcntl.h>
+#include <fstream>
 #include <memory>
 #include <spawn.h>
 #include <sstream>
@@ -56,7 +57,7 @@ extern "C" {
 
 namespace {
 
-  std::string print_argv(char * * & built_argv, const size_t& argc, const pid_t& pid)
+  std::string print_argv(char * * & built_argv, const size_t& argc)
   {
     std::stringstream arg_buffer;
 
@@ -68,6 +69,18 @@ namespace {
     return arg_buffer.str();
   }
 
+  std::string print_argv(char** argv)
+  {
+    std::stringstream arg_buffer;
+
+    for (char** ptr= argv; *ptr; ptr++)
+    {
+      arg_buffer << *ptr << " ";
+    }
+
+    return arg_buffer.str();
+  }
+
   static Application::error_t int_to_error_t(int arg)
   {
     switch (arg)
@@ -89,6 +102,8 @@ namespace libtest {
 
 Application::Application(const std::string& arg, const bool _use_libtool_arg) :
   _use_libtool(_use_libtool_arg),
+  _use_valgrind(false),
+  _use_gdb(false),
   _argc(0),
   _exectuble(arg),
   built_argv(NULL),
@@ -102,6 +117,19 @@ Application::Application(const std::string& arg, const bool _use_libtool_arg) :
       }
     }
 
+    // Find just the name of the application with no path
+    {
+      size_t found= arg.find_last_of("/\\");
+      if (found)
+      {
+        _exectuble_name= arg.substr(found +1);
+      }
+      else
+      {
+        _exectuble_name= arg;
+      }
+    }
+
     if (_use_libtool and getenv("PWD"))
     {
       _exectuble_with_path+= getenv("PWD");
@@ -133,13 +161,66 @@ Application::error_t Application::run(const char *args[])
   create_argv(args);
 
   int spawn_ret;
-  if (_use_libtool)
+  if (_use_gdb)
   {
-    spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL);
+    std::string gdb_run_file= create_tmpfile(_exectuble_name);
+    std::fstream file_stream;
+    file_stream.open(gdb_run_file.c_str(), std::fstream::out | std::fstream::trunc);
+
+    _gdb_filename= create_tmpfile(_exectuble_name);
+    file_stream 
+      << "set logging redirect on" << std::endl
+      << "set logging file " << _gdb_filename << std::endl
+      << "set logging overwrite on" << std::endl
+      << "set logging on" << std::endl
+      << "set environment LIBTEST_IN_GDB=1" << std::endl
+      << "run " << arguments() << std::endl
+      << "thread apply all bt" << std::endl
+      << "quit" << std::endl;
+
+    fatal_assert(file_stream.good());
+    file_stream.close();
+
+    if (_use_libtool)
+    {
+      // libtool --mode=execute gdb -f -x binary
+      char *argv[]= {
+        const_cast<char *>(libtool()),
+        const_cast<char *>("--mode=execute"),
+        const_cast<char *>("gdb"),
+        const_cast<char *>("-batch"),
+        const_cast<char *>("-f"),
+        const_cast<char *>("-x"),
+        const_cast<char *>(gdb_run_file.c_str()), 
+        const_cast<char *>(_exectuble_with_path.c_str()), 
+        0};
+
+      spawn_ret= posix_spawnp(&_pid, libtool(), &file_actions, NULL, argv, NULL);
+    }
+    else
+    {
+      // gdb binary
+      char *argv[]= {
+        const_cast<char *>("gdb"),
+        const_cast<char *>("-batch"),
+        const_cast<char *>("-f"),
+        const_cast<char *>("-x"),
+        const_cast<char *>(gdb_run_file.c_str()), 
+        const_cast<char *>(_exectuble_with_path.c_str()), 
+        0};
+      spawn_ret= posix_spawnp(&_pid, "gdb", &file_actions, NULL, argv, NULL);
+    }
   }
   else
   {
-    spawn_ret= posix_spawnp(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL);
+    if (_use_libtool)
+    {
+      spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL);
+    }
+    else
+    {
+      spawn_ret= posix_spawnp(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL);
+    }
   }
 
   posix_spawn_file_actions_destroy(&file_actions);
@@ -237,10 +318,12 @@ Application::error_t Application::wait()
     }
   }
 
+#if 0
   if (exit_code == Application::INVALID)
   {
-    Error << print_argv(built_argv, _argc, _pid);
+    Error << print_argv(built_argv, _argc);
   }
+#endif
 
   return exit_code;
 }
@@ -341,6 +424,18 @@ void Application::create_argv(const char *args[])
     _argc+= 2; // +2 for libtool --mode=execute
   }
 
+  /*
+    valgrind --error-exitcode=1 --leak-check=yes --show-reachable=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
+  */
+  if (_use_valgrind)
+  {
+    _argc+= 7;
+  }
+  else if (_use_gdb) // gdb
+  {
+    _argc+= 1;
+  }
+
   for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++)
   {
     _argc++;
@@ -368,6 +463,25 @@ void Application::create_argv(const char *args[])
     built_argv[x++]= strdup(libtool());
     built_argv[x++]= strdup("--mode=execute");
   }
+
+  if (_use_valgrind)
+  {
+    /*
+      valgrind --error-exitcode=1 --leak-check=yes --show-reachable=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
+    */
+    built_argv[x++]= strdup("valgrind");
+    built_argv[x++]= strdup("--error-exitcode=1");
+    built_argv[x++]= strdup("--leak-check=yes");
+    built_argv[x++]= strdup("--show-reachable=yes");
+    built_argv[x++]= strdup("--track-fds=yes");
+    built_argv[x++]= strdup("--malloc-fill=A5");
+    built_argv[x++]= strdup("--free-fill=DE");
+  }
+  else if (_use_gdb)
+  {
+    built_argv[x++]= strdup("gdb");
+  }
+
   built_argv[x++]= strdup(_exectuble_with_path.c_str());
 
   for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++)
@@ -391,7 +505,21 @@ void Application::create_argv(const char *args[])
 
 std::string Application::print()
 {
-  return print_argv(built_argv, _argc, _pid);
+  return print_argv(built_argv, _argc);
+}
+
+std::string Application::arguments()
+{
+  std::stringstream arg_buffer;
+
+  for (size_t x= 1 + _use_libtool ? 2 : 0;
+       x < _argc and built_argv[x];
+       x++)
+  {
+    arg_buffer << built_argv[x] << " ";
+  }
+
+  return arg_buffer.str();
 }
 
 void Application::delete_argv()
index 39ba35a2fb8784bf84ee0adb3fdcde88ab3a0a8f..f6da62bea260d02aeae9f1bdddff693cb09588c0 100644 (file)
@@ -95,15 +95,36 @@ public:
 
   std::string print();
 
+  void use_valgrind(bool arg= true)
+  {
+    _use_valgrind= arg;
+  }
+
+  void use_gdb(bool arg= true)
+  {
+    _use_gdb= arg;
+  }
+
+  std::string arguments();
+
+  std::string gdb_filename()
+  {
+    return  _gdb_filename;
+  }
+
 private:
   void create_argv(const char *args[]);
   void delete_argv();
 
 private:
   const bool _use_libtool;
+  bool _use_valgrind;
+  bool _use_gdb;
   size_t _argc;
+  std::string _exectuble_name;
   std::string _exectuble;
   std::string _exectuble_with_path;
+  std::string _gdb_filename;
   Options _options;
   Pipe stdin_fd;
   Pipe stdout_fd;
index 76392eca803336dfc76a9a4b336f3a3de841a381..92dc7d2776f61744852faafaf682619929a5b09d 100644 (file)
@@ -79,8 +79,8 @@ noinst_HEADERS+= \
                 libtest/killpid.h \
                 libtest/libtool.hpp \
                 libtest/memcached.h \
-                libtest/runner.h \
                 libtest/port.h \
+                libtest/runner.h \
                 libtest/server.h \
                 libtest/server_container.h \
                 libtest/signal.h \
@@ -91,6 +91,7 @@ noinst_HEADERS+= \
                 libtest/string.hpp \
                 libtest/test.h \
                 libtest/test.hpp \
+                libtest/tmpfile.hpp \
                 libtest/vchar.hpp \
                 libtest/visibility.h \
                 libtest/wait.h
@@ -117,6 +118,7 @@ libtest_libtest_la_SOURCES= \
                            libtest/socket.cc \
                            libtest/strerror.cc \
                            libtest/test.cc \
+                           libtest/tmpfile.cc \
                            libtest/vchar.cc
 
 libtest_libtest_la_CXXFLAGS=
@@ -199,7 +201,7 @@ tmp_chroot/var/run: tmp_chroot/var
        @$(mkdir_p) tmp_chroot/var/run
 
 
-libtest_unittest_DEPENDENCIES+= libtest/libtest.la libtest_tmp_dir
+libtest_unittest_DEPENDENCIES+= libtest/libtest.la libtest_tmp_dir libtest/abort libtest/wait
 libtest_unittest_LDADD+= libtest/libtest.la
 libtest_unittest_SOURCES= libtest/unittest.cc
 check_PROGRAMS+= libtest/unittest
@@ -226,3 +228,6 @@ noinst_PROGRAMS+= libtest/skiptest
 
 libtest_wait_SOURCES= libtest/wait.cc
 noinst_PROGRAMS+= libtest/wait
+
+libtest_abort_SOURCES= libtest/abort.cc
+noinst_PROGRAMS+= libtest/abort
index 6f81dd6c790b696974ab087ad9cb16f4d93ae526..c5358bf53fa5da4bdf4b6b7c68f777bddd87c873 100644 (file)
@@ -123,7 +123,7 @@ public:
     // Memcached is slow to start, so we need to do this
     if (not pid_file().empty())
     {
-      if (not wait_for_pidfile())
+      if (wait_for_pidfile() == false)
       {
         Error << "Pidfile was not found:" << pid_file();
         return -1;
@@ -320,6 +320,22 @@ public:
     return true;
   }
 
+  void log_file_option(Application& app, const std::string& arg)
+  {
+    if (arg.empty() == false)
+    {
+      std::string buffer("--log-file=");
+      buffer+= arg;
+      app.add_option("--verbose");
+      app.add_option(buffer);
+    }
+  }
+
+  bool has_log_file_option() const
+  {
+    return true;
+  }
+
   bool build(size_t argc, const char *argv[]);
 };
 
index 320407a23012715afb8d63f03c3dcaae9fc67e03..86b5fe07a31abaf17d6c8f237383cc2e3e11eec5 100644 (file)
@@ -1,2 +1,6 @@
+set logging on
+set logging overwrite on
 set environment LIBTEST_IN_GDB=1
 run
+thread apply all bt
+quit
index 8ca6b53e60ee812082735ff2361f44f070ed469a..e554039a1c523d8dea88c4c869f89f067af85ed8 100644 (file)
@@ -138,6 +138,19 @@ bool Server::start()
   }
 
   Application app(executable(), is_libtool());
+
+  if (is_debug())
+  {
+    app.use_gdb();
+  }
+  else if (getenv("TESTS_ENVIRONMENT"))
+  {
+    if (strstr(getenv("TESTS_ENVIRONMENT"), "gdb"))
+    {
+      app.use_gdb();
+    }
+  }
+
   if (args(app) == false)
   {
     Error << "Could not build command()";
@@ -293,8 +306,7 @@ bool Server::set_log_file()
   int fd;
   if ((fd= mkstemp(file_buffer)) == -1)
   {
-    perror(file_buffer);
-    return false;
+    libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", file_buffer, strerror(errno));
   }
   close(fd);
 
@@ -307,13 +319,9 @@ bool Server::args(Application& app)
 {
 
   // Set a log file if it was requested (and we can)
-  if (getenv("LIBTEST_LOG") and has_log_file_option())
+  if (has_log_file_option())
   {
-    if (not set_log_file())
-    {
-      return false;
-    }
-
+    set_log_file();
     log_file_option(app, _log_file);
   }
 
index b193fb8ffd21f617d79a178a0477f4e17bb090c0..df2bbee814774d9ceb8146e0d5e1d97859f3794f 100644 (file)
@@ -78,7 +78,7 @@ public:
     }
   }
 
-  bool has_log_file_option() const
+  virtual bool has_log_file_option() const
   {
     return false;
   }
index c0d9193806320f017dcda8171998ce80cedbd601..eb1b56c079415e50b8d572262af380fdd5e235e3 100644 (file)
@@ -60,3 +60,4 @@
 #include <libtest/binaries.h>
 #include <libtest/http.hpp>
 #include <libtest/cpu.hpp>
+#include <libtest/tmpfile.hpp>
diff --git a/libtest/tmpfile.cc b/libtest/tmpfile.cc
new file mode 100644 (file)
index 0000000..1bbacda
--- /dev/null
@@ -0,0 +1,46 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  libtest
+ *
+ *  Copyright (C) 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
+ */
+
+
+#include <libtest/common.h>
+
+namespace libtest {
+
+std::string create_tmpfile(const std::string& name)
+{
+  char file_buffer[FILENAME_MAX];
+  file_buffer[0]= 0;
+
+  int length= snprintf(file_buffer, sizeof(file_buffer), "var/tmp/%s.XXXXXX", name.c_str());
+  fatal_assert(length > 0);
+
+  int fd;
+  if ((fd= mkstemp(file_buffer)) == -1)
+  {
+    libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", file_buffer, strerror(errno));
+  }
+  close(fd);
+  unlink(file_buffer);
+
+  return file_buffer;
+}
+
+} // namespace libtest
diff --git a/libtest/tmpfile.hpp b/libtest/tmpfile.hpp
new file mode 100644 (file)
index 0000000..5ab50c4
--- /dev/null
@@ -0,0 +1,31 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  libtest
+ *
+ *  Copyright (C) 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 <libtest/common.h>
+
+namespace libtest {
+
+std::string create_tmpfile(const std::string&);
+
+} // namespace libtest
+
index 33309a7c1fc216f18a37411901efde3b67d68654..bffa4ecbf6544cd50b694bd13b14d3c234a99893 100644 (file)
@@ -322,6 +322,29 @@ static test_return_t application_true_BINARY(void *)
   return TEST_SUCCESS;
 }
 
+static test_return_t application_gdb_true_BINARY2(void *)
+{
+  Application true_app("true");
+  true_app.use_gdb();
+
+  test_compare(Application::SUCCESS, true_app.run());
+  test_compare(Application::SUCCESS, true_app.wait());
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t application_gdb_true_BINARY(void *)
+{
+  Application true_app("true");
+  true_app.use_gdb();
+
+  const char *args[]= { "--fubar", 0 };
+  test_compare(Application::SUCCESS, true_app.run(args));
+  test_compare(Application::SUCCESS, true_app.wait());
+
+  return TEST_SUCCESS;
+}
+
 static test_return_t application_true_fubar_BINARY(void *)
 {
   Application true_app("true");
@@ -334,6 +357,18 @@ static test_return_t application_true_fubar_BINARY(void *)
   return TEST_SUCCESS;
 }
 
+static test_return_t application_doesnotexist_BINARY(void *)
+{
+  Application true_app("doesnotexist");
+
+  const char *args[]= { "--fubar", 0 };
+  test_compare(Application::SUCCESS, true_app.run(args));
+  test_compare(Application::INVALID, true_app.wait());
+  test_compare(0, true_app.stdout_result().size());
+
+  return TEST_SUCCESS;
+}
+
 static test_return_t application_true_fubar_eq_doh_BINARY(void *)
 {
   Application true_app("true");
@@ -502,14 +537,49 @@ static test_return_t wait_services_BINARY2(void *)
   return TEST_SUCCESS;
 }
 
-static test_return_t application_wait_services_BINARY2(void *)
+static test_return_t wait_services_appliction_TEST(void *)
 {
   test_skip(0, access("/etc/services", R_OK ));
 
-  libtest::Application("libtest/wait", true);
+  libtest::Application wait_app("libtest/wait", true);
+  wait_app.use_gdb();
+
   const char *args[]= { "/etc/services", 0 };
+  test_compare(Application::SUCCESS, wait_app.run(args));
+  test_compare(Application::SUCCESS, wait_app.wait());
 
-  test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
+  return TEST_SUCCESS;
+}
+
+static test_return_t gdb_wait_services_appliction_TEST(void *)
+{
+  test_skip(0, access("/etc/services", R_OK ));
+
+  libtest::Application wait_app("libtest/wait", true);
+  wait_app.use_gdb();
+
+  const char *args[]= { "/etc/services", 0 };
+  test_compare(Application::SUCCESS, wait_app.run(args));
+  test_compare(Application::SUCCESS, wait_app.wait());
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t gdb_abort_services_appliction_TEST(void *)
+{
+  libtest::Application abort_app("libtest/abort", true);
+  abort_app.use_gdb();
+
+  test_compare(Application::SUCCESS, abort_app.run());
+  test_compare(Application::SUCCESS, abort_app.wait());
+
+  std::string gdb_filename= abort_app.gdb_filename();
+  const char *args[]= { "SIGABRT", gdb_filename.c_str(), 0 };
+  test_compare(EXIT_SUCCESS, exec_cmdline("grep", args));
+
+  // Sanity test
+  args[0]= "THIS_WILL_NOT_BE_FOUND";
+  test_compare(EXIT_FAILURE, exec_cmdline("grep", args));
 
   return TEST_SUCCESS;
 }
@@ -541,6 +611,21 @@ static test_return_t number_of_cpus_TEST(void *)
   return TEST_SUCCESS;
 }
 
+static test_return_t create_tmpfile_TEST(void *)
+{
+  std::string tmp= create_tmpfile(__func__);
+
+  Application touch_app("touch");
+  const char *args[]= { tmp.c_str(), 0 };
+  test_compare(Application::SUCCESS, touch_app.run(args));
+  test_compare(Application::SUCCESS, touch_app.wait());
+
+  test_compare_hint(0, access(tmp.c_str(), R_OK), strerror(errno));
+  test_compare_hint(0, unlink(tmp.c_str()), strerror(errno));
+
+  return TEST_SUCCESS;
+}
+
 static test_return_t fatal_message_TEST(void *)
 {
   test_compare(fatal_calls++, fatal::disabled_counter());
@@ -640,6 +725,9 @@ test_st cmdline_tests[] ={
   {"wait --quiet --version", 0, wait_version_BINARY },
   {"wait --quiet /etc/services", 0, wait_services_BINARY },
   {"wait /etc/services", 0, wait_services_BINARY2 },
+  {"wait /etc/services", 0, wait_services_appliction_TEST },
+  {"gdb wait /etc/services", 0, gdb_wait_services_appliction_TEST },
+  {"gdb abort", 0, gdb_abort_services_appliction_TEST },
   {0, 0, 0}
 };
 
@@ -660,10 +748,18 @@ test_st number_of_cpus_TESTS[] ={
   {0, 0, 0}
 };
 
+test_st create_tmpfile_TESTS[] ={
+  {"libtest::create_tmpfile()", 0, create_tmpfile_TEST },
+  {0, 0, 0}
+};
+
 test_st application_tests[] ={
   {"vchar_t", 0, vchar_t_TEST },
   {"true", 0, application_true_BINARY },
+  {"gbd true --fubar", 0, application_gdb_true_BINARY },
+  {"gbd true", 0, application_gdb_true_BINARY2 },
   {"true --fubar", 0, application_true_fubar_BINARY },
+  {"doesnotexist --fubar", 0, application_doesnotexist_BINARY },
   {"true --fubar=doh", 0, application_true_fubar_eq_doh_BINARY },
   {"true --fubar=doh add_option()", 0, application_true_fubar_eq_doh_option_BINARY },
   {"echo fubar", 0, application_echo_fubar_BINARY },
@@ -710,6 +806,7 @@ collection_st collection[] ={
   {"get_free_port()", 0, 0, get_free_port_TESTS },
   {"fatal", disable_fatal_exception, enable_fatal_exception, fatal_message_TESTS },
   {"number_of_cpus()", 0, 0, number_of_cpus_TESTS },
+  {"create_tmpfile()", 0, 0, create_tmpfile_TESTS },
   {0, 0, 0, 0}
 };
 
index 47db429d85e2b09112debd455d7d6d91d381ea92..c54a5071047d4b8ac7827c4260dede7b7e96c751 100644 (file)
@@ -37,6 +37,8 @@
 
 #pragma once
 
+#include <tests/libmemcached-1.0/memcached_get.h>
+
 
 /* Clean the server before beginning testing */
 test_st tests[] ={
index 48a03695468003e5b58ddb85a3226144cd987111..a320a9a511cae0111e77167d31cb4e5ce26f1ad6 100644 (file)
@@ -25,6 +25,7 @@ noinst_HEADERS+= \
                 tests/libmemcached-1.0/generate.h \
                 tests/libmemcached-1.0/haldenbrand.h \
                 tests/libmemcached-1.0/mem_functions.h \
+                tests/libmemcached-1.0/memcached_get.h \
                 tests/libmemcached-1.0/setup_and_teardowns.h \
                 tests/libmemcached-1.0/stat.h \
                 tests/namespace.h \
@@ -67,6 +68,7 @@ tests_libmemcached_1_0_testapp_SOURCES= \
                                        tests/libmemcached-1.0/haldenbrand.cc \
                                        tests/libmemcached-1.0/ketama.cc \
                                        tests/libmemcached-1.0/mem_functions.cc \
+                                       tests/libmemcached-1.0/memcached_get.cc \
                                        tests/libmemcached-1.0/namespace.cc \
                                        tests/libmemcached-1.0/parser.cc \
                                        tests/libmemcached-1.0/pool.cc \
@@ -113,6 +115,7 @@ tests_libmemcached_1_0_testsocket_SOURCES= \
                                           tests/libmemcached-1.0/haldenbrand.cc \
                                           tests/libmemcached-1.0/ketama.cc \
                                           tests/libmemcached-1.0/mem_functions.cc \
+                                          tests/libmemcached-1.0/memcached_get.cc \
                                           tests/libmemcached-1.0/namespace.cc \
                                           tests/libmemcached-1.0/parser.cc \
                                           tests/libmemcached-1.0/pool.cc \
index a878b2dfd0644e4a84e6c4fb92a31b2617c7c831..8a1951e66ac62cd47ed4377935b03c710632e1d4 100644 (file)
@@ -192,16 +192,6 @@ private:
     std::vector<size_t> _lengths;
 };
 
-static memcached_return_t return_value_based_on_buffering(memcached_st *memc)
-{
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS))
-  {
-    return MEMCACHED_BUFFERED;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
 static memcached_st * create_single_instance_memcached(const memcached_st *original_memc, const char *options)
 {
   /*
@@ -1185,62 +1175,6 @@ test_return_t read_through(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
-test_return_t get_test(memcached_st *memc)
-{
-  uint64_t query_id= memcached_query_id(memc);
-  memcached_return_t rc= memcached_delete(memc,
-                                          test_literal_param(__func__),
-                                          time_t(0));
-  test_true_hint(rc == MEMCACHED_BUFFERED or rc == MEMCACHED_NOTFOUND, memcached_last_error_message(memc));
-  test_compare(query_id +1, memcached_query_id(memc));
-
-  size_t string_length;
-  uint32_t flags;
-  char *string= memcached_get(memc,
-                        test_literal_param(__func__),
-                        &string_length, &flags, &rc);
-
-  test_compare_got(MEMCACHED_NOTFOUND, rc, memcached_last_error_message(memc));
-  test_false(string_length);
-  test_false(string);
-
-  return TEST_SUCCESS;
-}
-
-test_return_t get_test2(memcached_st *memc)
-{
-  const char *value= "when we sanitize";
-
-  uint64_t query_id= memcached_query_id(memc);
-  test_compare(return_value_based_on_buffering(memc),
-               memcached_set(memc,
-                             test_literal_param(__func__),
-                             value, strlen(value),
-                             time_t(0), uint32_t(0)));
-  test_compare(query_id +1, memcached_query_id(memc));
-
-  query_id= memcached_query_id(memc);
-  test_true(query_id);
-
-  uint32_t flags;
-  size_t string_length;
-  memcached_return_t rc;
-  char *string= memcached_get(memc,
-                              test_literal_param(__func__),
-                              &string_length, &flags, &rc);
-  test_compare(query_id +1, memcached_query_id(memc));
-
-  test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc));
-  test_compare_got(MEMCACHED_SUCCESS, memcached_last_error(memc), memcached_last_error_message(memc));
-  test_true(string);
-  test_compare(strlen(value), string_length);
-  test_memcmp(string, value, string_length);
-
-  free(string);
-
-  return TEST_SUCCESS;
-}
-
 test_return_t set_test2(memcached_st *memc)
 {
   for (uint32_t x= 0; x < 10; x++)
@@ -1285,126 +1219,6 @@ test_return_t set_test3(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
-test_return_t get_test3(memcached_st *memc)
-{
-  size_t value_length= 8191;
-
-  libtest::vchar_t value;
-  value.reserve(value_length);
-  for (uint32_t x= 0; x < value_length; x++)
-  {
-    value.push_back(char(x % 127));
-  }
-
-  test_compare_hint(return_value_based_on_buffering(memc),
-                    memcached_set(memc,
-                                  test_literal_param(__func__),
-                                  &value[0], value.size(),
-                                  time_t(0), uint32_t(0)),
-                    memcached_last_error_message(memc));
-
-  size_t string_length;
-  uint32_t flags;
-  memcached_return_t rc;
-  char *string= memcached_get(memc,
-                              test_literal_param(__func__),
-                              &string_length, &flags, &rc);
-
-  test_compare(MEMCACHED_SUCCESS, rc);
-  test_true(string);
-  test_compare(value.size(), string_length);
-  test_memcmp(string, &value[0], string_length);
-
-  free(string);
-
-  return TEST_SUCCESS;
-}
-
-test_return_t get_test4(memcached_st *memc)
-{
-  size_t value_length= 8191;
-
-  libtest::vchar_t value;
-  value.reserve(value_length);
-  for (uint32_t x= 0; x < value_length; x++)
-  {
-    value.push_back(char(x % 127));
-  }
-
-  test_compare_hint(return_value_based_on_buffering(memc),
-                    memcached_set(memc,
-                                  test_literal_param(__func__),
-                                  &value[0], value.size(),
-                                  time_t(0), uint32_t(0)),
-                    memcached_last_error_message(memc));
-
-  for (uint32_t x= 0; x < 10; x++)
-  {
-    uint32_t flags;
-    size_t string_length;
-    memcached_return_t rc;
-    char *string= memcached_get(memc,
-                                test_literal_param(__func__),
-                                &string_length, &flags, &rc);
-
-    test_compare(MEMCACHED_SUCCESS, rc);
-    test_true(string);
-    test_compare(value.size(), string_length);
-    test_memcmp(string, &value[0], string_length);
-    free(string);
-  }
-
-  return TEST_SUCCESS;
-}
-
-/*
- * This test verifies that memcached_read_one_response doesn't try to
- * dereference a NIL-pointer if you issue a multi-get and don't read out all
- * responses before you execute a storage command.
- */
-test_return_t get_test5(memcached_st *memc)
-{
-  /*
-  ** Request the same key twice, to ensure that we hash to the same server
-  ** (so that we have multiple response values queued up) ;-)
-  */
-  const char *keys[]= { "key", "key" };
-  size_t lengths[]= { 3, 3 };
-  uint32_t flags;
-  size_t rlen;
-
-  test_compare_hint(return_value_based_on_buffering(memc),
-                    memcached_set(memc, keys[0], lengths[0],
-                                  keys[0], lengths[0],
-                                  time_t(0), uint32_t(0)),
-                    memcached_last_error_message(memc));
-  test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, lengths, test_array_length(keys)));
-
-  memcached_result_st results_obj;
-  memcached_result_st *results= memcached_result_create(memc, &results_obj);
-  test_true(results);
-
-  memcached_return_t rc;
-  results= memcached_fetch_result(memc, &results_obj, &rc);
-  test_true(results);
-
-  memcached_result_free(&results_obj);
-
-  /* Don't read out the second result, but issue a set instead.. */
-  test_compare(MEMCACHED_SUCCESS, memcached_set(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0));
-
-  char *val= memcached_get_by_key(memc, keys[0], lengths[0], "yek", 3,
-                                  &rlen, &flags, &rc);
-  test_false(val);
-  test_compare(MEMCACHED_NOTFOUND, rc);
-  val= memcached_get(memc, keys[0], lengths[0], &rlen, &flags, &rc);
-  test_true(val);
-  test_compare(MEMCACHED_SUCCESS, rc);
-  free(val);
-
-  return TEST_SUCCESS;
-}
-
 test_return_t mget_end(memcached_st *memc)
 {
   const char *keys[]= { "foo", "foo2" };
index 7126f7fcb4b4ed9d36286ffa46d2b4fa7ec33480..d632dd4bb1d1ce88ce70675fa1d5322503333b48 100644 (file)
@@ -78,11 +78,6 @@ test_return_t fnv1a_32_run (memcached_st *);
 test_return_t fnv1a_64_run (memcached_st *);
 test_return_t get_stats(memcached_st *memc);
 test_return_t get_stats_keys(memcached_st *memc);
-test_return_t get_test(memcached_st *memc);
-test_return_t get_test2(memcached_st *memc);
-test_return_t get_test3(memcached_st *memc);
-test_return_t get_test4(memcached_st *memc);
-test_return_t get_test5(memcached_st *memc);
 test_return_t getpid_connection_failure_test(memcached_st *memc);
 test_return_t getpid_test(memcached_st *memc);
 test_return_t hash_sanity_test (memcached_st *memc);
diff --git a/tests/libmemcached-1.0/memcached_get.cc b/tests/libmemcached-1.0/memcached_get.cc
new file mode 100644 (file)
index 0000000..2636ecd
--- /dev/null
@@ -0,0 +1,222 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2012 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 <libtest/test.hpp>
+
+/*
+  Test cases
+*/
+
+#include <libmemcached-1.0/memcached.h>
+#include "tests/libmemcached-1.0/memcached_get.h"
+#include "tests/libmemcached-1.0/setup_and_teardowns.h"
+
+test_return_t get_test(memcached_st *memc)
+{
+  uint64_t query_id= memcached_query_id(memc);
+  memcached_return_t rc= memcached_delete(memc,
+                                          test_literal_param(__func__),
+                                          time_t(0));
+  test_true_hint(rc == MEMCACHED_BUFFERED or rc == MEMCACHED_NOTFOUND, memcached_last_error_message(memc));
+  test_compare(query_id +1, memcached_query_id(memc));
+
+  size_t string_length;
+  uint32_t flags;
+  char *string= memcached_get(memc,
+                        test_literal_param(__func__),
+                        &string_length, &flags, &rc);
+
+  test_compare_got(MEMCACHED_NOTFOUND, rc, memcached_last_error_message(memc));
+  test_false(string_length);
+  test_false(string);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t get_test2(memcached_st *memc)
+{
+  const char *value= "when we sanitize";
+
+  uint64_t query_id= memcached_query_id(memc);
+  test_compare(return_value_based_on_buffering(memc),
+               memcached_set(memc,
+                             test_literal_param(__func__),
+                             value, strlen(value),
+                             time_t(0), uint32_t(0)));
+  test_compare(query_id +1, memcached_query_id(memc));
+
+  query_id= memcached_query_id(memc);
+  test_true(query_id);
+
+  uint32_t flags;
+  size_t string_length;
+  memcached_return_t rc;
+  char *string= memcached_get(memc,
+                              test_literal_param(__func__),
+                              &string_length, &flags, &rc);
+  test_compare(query_id +1, memcached_query_id(memc));
+
+  test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc));
+  test_compare_got(MEMCACHED_SUCCESS, memcached_last_error(memc), memcached_last_error_message(memc));
+  test_true(string);
+  test_compare(strlen(value), string_length);
+  test_memcmp(string, value, string_length);
+
+  free(string);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t get_test3(memcached_st *memc)
+{
+  size_t value_length= 8191;
+
+  libtest::vchar_t value;
+  value.reserve(value_length);
+  for (uint32_t x= 0; x < value_length; x++)
+  {
+    value.push_back(char(x % 127));
+  }
+
+  test_compare_hint(return_value_based_on_buffering(memc),
+                    memcached_set(memc,
+                                  test_literal_param(__func__),
+                                  &value[0], value.size(),
+                                  time_t(0), uint32_t(0)),
+                    memcached_last_error_message(memc));
+
+  size_t string_length;
+  uint32_t flags;
+  memcached_return_t rc;
+  char *string= memcached_get(memc,
+                              test_literal_param(__func__),
+                              &string_length, &flags, &rc);
+
+  test_compare(MEMCACHED_SUCCESS, rc);
+  test_true(string);
+  test_compare(value.size(), string_length);
+  test_memcmp(string, &value[0], string_length);
+
+  free(string);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t get_test4(memcached_st *memc)
+{
+  size_t value_length= 8191;
+
+  libtest::vchar_t value;
+  value.reserve(value_length);
+  for (uint32_t x= 0; x < value_length; x++)
+  {
+    value.push_back(char(x % 127));
+  }
+
+  test_compare_hint(return_value_based_on_buffering(memc),
+                    memcached_set(memc,
+                                  test_literal_param(__func__),
+                                  &value[0], value.size(),
+                                  time_t(0), uint32_t(0)),
+                    memcached_last_error_message(memc));
+
+  for (uint32_t x= 0; x < 10; x++)
+  {
+    uint32_t flags;
+    size_t string_length;
+    memcached_return_t rc;
+    char *string= memcached_get(memc,
+                                test_literal_param(__func__),
+                                &string_length, &flags, &rc);
+
+    test_compare(MEMCACHED_SUCCESS, rc);
+    test_true(string);
+    test_compare(value.size(), string_length);
+    test_memcmp(string, &value[0], string_length);
+    free(string);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/*
+ * This test verifies that memcached_read_one_response doesn't try to
+ * dereference a NIL-pointer if you issue a multi-get and don't read out all
+ * responses before you execute a storage command.
+ */
+test_return_t get_test5(memcached_st *memc)
+{
+  /*
+  ** Request the same key twice, to ensure that we hash to the same server
+  ** (so that we have multiple response values queued up) ;-)
+  */
+  const char *keys[]= { "key", "key" };
+  size_t lengths[]= { 3, 3 };
+  uint32_t flags;
+  size_t rlen;
+
+  test_compare_hint(return_value_based_on_buffering(memc),
+                    memcached_set(memc, keys[0], lengths[0],
+                                  keys[0], lengths[0],
+                                  time_t(0), uint32_t(0)),
+                    memcached_last_error_message(memc));
+  test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, lengths, test_array_length(keys)));
+
+  memcached_result_st results_obj;
+  memcached_result_st *results= memcached_result_create(memc, &results_obj);
+  test_true(results);
+
+  memcached_return_t rc;
+  results= memcached_fetch_result(memc, &results_obj, &rc);
+  test_true(results);
+
+  memcached_result_free(&results_obj);
+
+  /* Don't read out the second result, but issue a set instead.. */
+  test_compare(MEMCACHED_SUCCESS, memcached_set(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0));
+
+  char *val= memcached_get_by_key(memc, keys[0], lengths[0], "yek", 3,
+                                  &rlen, &flags, &rc);
+  test_false(val);
+  test_compare(MEMCACHED_NOTFOUND, rc);
+  val= memcached_get(memc, keys[0], lengths[0], &rlen, &flags, &rc);
+  test_true(val);
+  test_compare(MEMCACHED_SUCCESS, rc);
+  free(val);
+
+  return TEST_SUCCESS;
+}
diff --git a/tests/libmemcached-1.0/memcached_get.h b/tests/libmemcached-1.0/memcached_get.h
new file mode 100644 (file)
index 0000000..46e8def
--- /dev/null
@@ -0,0 +1,44 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2012 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
+
+test_return_t get_test(memcached_st*);
+test_return_t get_test2(memcached_st*);
+test_return_t get_test3(memcached_st*);
+test_return_t get_test4(memcached_st*);
+test_return_t get_test5(memcached_st*);
+
index 84f57abe2cc85b0c44218fe5d3353a314a4df8e1..9bf0e92a838fca9cbab14ac07fed51d20c322955 100644 (file)
 
 #include <sys/stat.h>
 
+
+memcached_return_t return_value_based_on_buffering(memcached_st *memc)
+{
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS))
+  {
+    return MEMCACHED_BUFFERED;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
 /**
   @note This should be testing to see if the server really supports the binary protocol.
 */
index e141685fff5e19be6a86c58a24867226c54af783..fa6fbdf2860fb8ad68c026cb673713f8f148339c 100644 (file)
@@ -37,6 +37,8 @@
 
 #pragma once
 
+memcached_return_t return_value_based_on_buffering(memcached_st*);
+
 test_return_t pre_behavior_ketama(memcached_st*);
 test_return_t pre_behavior_ketama_weighted(memcached_st*);
 test_return_t pre_binary(memcached_st*);
index 885133a2b66cd0d785175586fdf84013be4d2734..1442faa3e00946f52d000ad6bbd815a7f46c4de9 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <cerrno>
+#include <cstdarg>
 #include <cstdio>
 #include <fcntl.h>
 #include <iostream>
@@ -124,23 +125,32 @@ struct log_info_st
     return fd;
   }
 
-  void write(verbose_t verbose, const char *mesg)
+  void write(verbose_t verbose, const char *format, ...)
   {
-    if (opt_file)
+    if (opt_file or opt_syslog)
     {
-      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)
+      va_list args;
+      va_start(args, format);
+      char mesg[BUFSIZ];
+      int mesg_length= vsnprintf(mesg, sizeof(mesg), format, args);
+      va_end(args);
+
+      if (opt_file)
       {
-        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));
-      }
+        char buffer[UTIL_MAX_ERROR_SIZE];
+        int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %.*s\n", verbose_name(verbose), mesg_length, 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);
+      if (opt_syslog)
+      {
+        syslog(int(verbose), "%7s %.*s", verbose_name(verbose), mesg_length, mesg);
+      }
     }
   }