Merge in all of libtest.
authorBrian Aker <brian@tangent.org>
Tue, 19 Jul 2011 05:27:46 +0000 (22:27 -0700)
committerBrian Aker <brian@tangent.org>
Tue, 19 Jul 2011 05:27:46 +0000 (22:27 -0700)
12 files changed:
libtest/error.h
libtest/gearmand.cc
libtest/include.am
libtest/memcached.cc
libtest/server.cc
libtest/server.h
libtest/stream.h
libtest/string.hpp [new file with mode: 0644]
libtest/test.cc
libtest/test.hpp
libtest/unittest.cc
tests/include.am

index a40868b3c1ba41cc8d0c1dd5ccf250aeb4a803ac..ca6c575d068fcd265b34bcccc2376e24c161feba 100644 (file)
@@ -1,9 +1,40 @@
-/* uTest Copyright (C) 2011 Data Differential, http://datadifferential.com/
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  libtest
+ *
+ *  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.
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
  */
 
+
 #pragma once
 
 enum test_return_t {
index c729d8ed836a763a69897acf819107a262155ac1..f526e015f4c0648690dd19c225bc8596029c96b4 100644 (file)
 #include <libtest/common.h>
 #include <libtest/gearmand.h>
 
-#include "util/instance.h"
-#include "util/operation.h"
+#include "util/instance.hpp"
+#include "util/operation.hpp"
 
-using namespace gearman_util;
+using namespace datadifferential;
 using namespace libtest;
 
 #include <cassert>
@@ -54,16 +54,13 @@ using namespace libtest;
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <libtest/server.h>
-#include <libtest/wait.h>
-
 #include <libgearman/gearman.h>
 
 #ifndef __INTEL_COMPILER
 #pragma GCC diagnostic ignored "-Wold-style-cast"
 #endif
 
-class GetPid : public Instance::Finish
+class GetPid : public util::Instance::Finish
 {
 private:
   pid_t _pid;
@@ -91,10 +88,10 @@ public:
     if (_pid < 1)
     {
       _pid= -1;
-      return true;
+      return false;
     }
 
-    return false;
+    return true;
   }
 };
 
@@ -110,20 +107,29 @@ public:
 
   pid_t get_pid(bool error_is_ok)
   {
+    if (not pid_file().empty())
+    {
+      Wait wait(pid_file(), 0);
+
+      if (error_is_ok and not wait.successful())
+      {
+        Error << "Pidfile was not found:" << pid_file();
+        return -1;
+      }
+    }
+
     GetPid *get_instance_pid;
-    Instance instance(hostname(), port());
+    util::Instance instance(hostname(), port());
     instance.set_finish(get_instance_pid= new GetPid);
 
-    instance.push(new Operation(test_literal_param("getpid\r\n"), true));
+    instance.push(new util::Operation(test_literal_param("getpid\r\n"), true));
 
-    if (not instance.run() and not error_is_ok)
+    if (error_is_ok and instance.run() == false)
     {
       Error << "Failed to obtain pid of server";
     }
 
-    _pid= get_instance_pid->pid();
-
-    return _pid;
+    return get_instance_pid->pid();
   }
 
   bool ping()
@@ -138,7 +144,7 @@ public:
 
     if (gearman_success(gearman_client_add_server(client, hostname().c_str(), port())))
     {
-      gearman_return_t rc= gearman_client_echo(client, gearman_literal_param("This is my echo test"));
+      gearman_return_t rc= gearman_client_echo(client, test_literal_param("This is my echo test"));
 
       if (gearman_success(rc))
       {
index b7cddea607ad3afcc35be7a359f041956ec4f5fa..4a51fa46e037d653f65839e524a51234f7e0c840 100644 (file)
@@ -41,6 +41,7 @@ noinst_HEADERS+= \
                 libtest/stats.h \
                 libtest/stream.h \
                 libtest/strerror.h \
+                libtest/string.hpp \
                 libtest/test.h \
                 libtest/test.hpp \
                 libtest/visibility.h \
index e3d90947a2c0e1b99a5395dbb94f0942d27122f4..3b63c0fc485e08f63c077879ff844e0ae203dae8 100644 (file)
@@ -77,29 +77,30 @@ public:
     {
       Wait wait(pid_file(), 0);
 
-      if (not wait.successful())
+      if (error_is_ok and not wait.successful())
       {
         Error << "Pidfile was not found:" << pid_file();
         return -1;
       }
     }
 
+    pid_t local_pid;
     memcached_return_t rc;
     if (has_socket())
     {
-      _pid= libmemcached_util_getpid(socket().c_str(), port(), &rc);
+      local_pid= libmemcached_util_getpid(socket().c_str(), port(), &rc);
     }
     else
     {
-      _pid= libmemcached_util_getpid(hostname().c_str(), port(), &rc);
+      local_pid= libmemcached_util_getpid(hostname().c_str(), port(), &rc);
     }
 
-    if ((memcached_failed(rc) or _pid < 1) and not error_is_ok)
+    if (error_is_ok and ((memcached_failed(rc) or local_pid < 1)))
     {
-      Error << "libmemcached_util_getpid(" << memcached_strerror(NULL, rc) << ") pid: " << _pid << " for:" << *this;
+      Error << "libmemcached_util_getpid(" << memcached_strerror(NULL, rc) << ") pid: " << local_pid << " for:" << *this;
     }
 
-    return _pid;
+    return local_pid;
   }
 
   bool ping()
index ed7e87f11672ffe0c547d4a4d7d8e85b4a7231c2..f547d455abb56384606540f879c6b49f58ea5725 100644 (file)
@@ -116,7 +116,7 @@ Server::Server(const std::string& host_arg, const in_port_t port_arg, bool is_so
 
 Server::~Server()
 {
-  if (has_pid() and not kill())
+  if (has_pid() and not kill(_pid))
   {
     Error << "Unable to kill:" << *this;
   }
@@ -138,7 +138,7 @@ bool Server::cycle()
   pid_t current_pid;
   while (--limit and (current_pid= get_pid()) != -1)
   {
-    if (kill())
+    if (kill(current_pid))
     {
       Log << "Killed existing server," << *this << " with pid:" << current_pid;
       nap();
@@ -174,9 +174,9 @@ bool Server::command(std::string& command_arg)
 bool Server::start()
 {
   // If we find that we already have a pid then kill it.
-  if (has_pid() and not kill())
+  if (has_pid() and not kill(_pid))
   {
-    Error << "Could not kill() existing server during start()";
+    Error << "Could not kill() existing server during start() pid:" << _pid;
     return false;
   }
   assert(not has_pid());
@@ -219,7 +219,7 @@ bool Server::start()
   }
 
   // A failing get_pid() at this point is considered an error
-  _pid= get_pid(false);
+  _pid= get_pid(true);
 
   return has_pid();
 }
@@ -396,9 +396,9 @@ bool Server::is_valgrind() const
   return bool(getenv("LIBTEST_MANUAL_VALGRIND"));
 }
 
-bool Server::kill()
+bool Server::kill(pid_t pid_arg)
 {
-  if (has_pid() and kill_pid(_pid)) // If we kill it, reset
+  if (check_pid(pid_arg) and kill_pid(pid_arg)) // If we kill it, reset
   {
     if (broken_pid_file() and not pid_file().empty())
     {
@@ -463,7 +463,7 @@ void server_startup_st::shutdown(bool remove)
   {
     for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
     {
-      if ((*iter)->has_pid() and not (*iter)->kill())
+      if ((*iter)->has_pid() and not (*iter)->kill((*iter)->pid()))
       {
         Error << "Unable to kill:" <<  *(*iter);
       }
@@ -488,7 +488,7 @@ bool server_startup_st::is_valgrind() const
 
 bool server_startup(server_startup_st& construct, const std::string& server_type, in_port_t try_port, int argc, const char *argv[])
 {
-  Logn();
+  Outn();
 
   // Look to see if we are being provided ports to use
   {
@@ -557,10 +557,10 @@ bool server_startup(server_startup_st& construct, const std::string& server_type
 
   if (construct.is_debug())
   {
-    Log << "Pausing for startup, hit return when ready.";
+    Out << "Pausing for startup, hit return when ready.";
     std::string gdb_command= server->base_command();
     std::string options;
-    Log << "run " << server->args(options);
+    Out << "run " << server->args(options);
     getchar();
   }
   else if (not server->start())
@@ -571,7 +571,7 @@ bool server_startup(server_startup_st& construct, const std::string& server_type
   }
   else
   {
-    Log << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
+    Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
   }
 
   construct.push_server(server);
@@ -582,14 +582,15 @@ bool server_startup(server_startup_st& construct, const std::string& server_type
     set_default_port(server->port());
   }
 
-  Logn();
+  Outn();
 
   return true;
 }
 
 bool server_startup_st::start_socket_server(const std::string& server_type, const in_port_t try_port, int argc, const char *argv[])
 {
-  Logn();
+  (void)try_port;
+  Outn();
 
   Server *server= NULL;
   if (0)
@@ -635,10 +636,10 @@ bool server_startup_st::start_socket_server(const std::string& server_type, cons
 
   if (is_debug())
   {
-    Log << "Pausing for startup, hit return when ready.";
+    Out << "Pausing for startup, hit return when ready.";
     std::string gdb_command= server->base_command();
     std::string options;
-    Log << "run " << server->args(options);
+    Out << "run " << server->args(options);
     getchar();
   }
   else if (not server->start())
@@ -649,14 +650,14 @@ bool server_startup_st::start_socket_server(const std::string& server_type, cons
   }
   else
   {
-    Log << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
+    Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
   }
 
   push_server(server);
 
   set_default_socket(server->socket().c_str());
 
-  Logn();
+  Outn();
 
   return true;
 }
index f13cad0781c302f12aca53fdab500b8136d189c4..7a915bb9bdf18c213ce63f2dda6b528a0b68882f 100644 (file)
@@ -28,9 +28,9 @@ private:
   std::string _log_file;
   std::string _base_command; // executable command which include libtool, valgrind, gdb, etc
   std::string _running; // Current string being used for system()
+  pid_t _pid;
 
 protected:
-  pid_t _pid;
   in_port_t _port;
   std::string _hostname;
   std::string _extra_args;
@@ -92,7 +92,7 @@ public:
 
   virtual bool ping()= 0;
 
-  virtual pid_t get_pid(bool error_is_ok= true)= 0;
+  virtual pid_t get_pid(bool error_is_ok= false)= 0;
 
   virtual bool build(int argc, const char *argv[])= 0;
 
@@ -130,6 +130,11 @@ public:
     return (_pid > 1);
   }
 
+  bool check_pid(pid_t pid_arg) const
+  {
+    return (pid_arg > 1);
+  }
+
   bool is_socket() const
   {
     return _hostname[0] == '/';
@@ -142,7 +147,7 @@ public:
 
   std::string log_and_pid();
 
-  bool kill();
+  bool kill(pid_t pid_arg);
   bool start();
   bool command(std::string& command_arg);
 
index 0b503a04c6f4092ac6565eaea6de94ad1ce75b35..ed5a03e541ed0e6090a9a6711c87132dc6dbe1e8 100644 (file)
@@ -182,6 +182,8 @@ public:
 
 #define Out stream::cout(NULL, __LINE__, __func__)
 
+#define Outn() stream::cout(NULL, __LINE__, __func__) << " "
+
 #define Log stream::clog(NULL, __LINE__, __func__)
 
 #define Logn() stream::clog(NULL, __LINE__, __func__) << " "
diff --git a/libtest/string.hpp b/libtest/string.hpp
new file mode 100644 (file)
index 0000000..f747eef
--- /dev/null
@@ -0,0 +1,44 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  libtest
+ *
+ *  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
+
+#include "util/string.hpp"
+
+#define test_literal_param util_literal_param
+#define test_literal_param_size util_literal_param_size
+#define test_string_make_from_cstr util_string_make_from_cstr
+#define test_array_length util_array_length
index 63cf9cbc8a7a0256b0af14fd2e51de1187948ea3..5b1a20156d083bfe3e76d52753084d2124214fae 100644 (file)
@@ -94,15 +94,15 @@ void set_default_socket(const char *socket)
 
 static void stats_print(Stats *stats)
 {
-  Log << "\tTotal Collections\t\t\t\t" << stats->collection_total;
-  Log << "\tFailed Collections\t\t\t\t" << stats->collection_failed;
-  Log << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped;
-  Log << "\tSucceeded Collections\t\t\t\t" << stats->collection_success;
-  Logn();
-  Log << "Total\t\t\t\t" << stats->total;
-  Log << "\tFailed\t\t\t" << stats->failed;
-  Log << "\tSkipped\t\t\t" << stats->skipped;
-  Log << "\tSucceeded\t\t" << stats->success;
+  Out << "\tTotal Collections\t\t\t\t" << stats->collection_total;
+  Out << "\tFailed Collections\t\t\t\t" << stats->collection_failed;
+  Out << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped;
+  Out << "\tSucceeded Collections\t\t\t\t" << stats->collection_success;
+  Outn();
+  Out << "Total\t\t\t\t" << stats->total;
+  Out << "\tFailed\t\t\t" << stats->failed;
+  Out << "\tSkipped\t\t\t" << stats->skipped;
+  Out << "\tSucceeded\t\t" << stats->success;
 }
 
 static long int timedif(struct timeval a, struct timeval b)
@@ -194,7 +194,7 @@ int main(int argc, char *argv[])
 
   if (collection_to_run)
   {
-    Log << "Only testing " <<  collection_to_run;
+    Out << "Only testing " <<  collection_to_run;
   }
 
   char *wildcard= NULL;
@@ -228,13 +228,13 @@ int main(int argc, char *argv[])
 
     case TEST_FATAL:
     case TEST_FAILURE:
-      Error << next->name << " [ failed ]";
+      Out << next->name << " [ failed ]";
       failed= true;
       set_shutdown(SHUTDOWN_GRACEFUL);
       goto cleanup;
 
     case TEST_SKIPPED:
-      Log << next->name << " [ skipping ]";
+      Out << next->name << " [ skipping ]";
       skipped= true;
       goto cleanup;
 
@@ -242,7 +242,7 @@ int main(int argc, char *argv[])
       test_assert(0, "Allocation failure, or unknown return");
     }
 
-    Log << "Collection: " << next->name;
+    Out << "Collection: " << next->name;
 
     for (test_st *run= next->tests; run->name; run++)
     {
@@ -296,7 +296,7 @@ int main(int argc, char *argv[])
       switch (return_code)
       {
       case TEST_SUCCESS:
-        Log << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
+        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
         stats.success++;
         break;
 
@@ -304,13 +304,13 @@ int main(int argc, char *argv[])
       case TEST_FAILURE:
         stats.failed++;
         failed= true;
-        Log << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
         break;
 
       case TEST_SKIPPED:
         stats.skipped++;
         skipped= true;
-        Log << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+        Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
         break;
 
       case TEST_MEMORY_ALLOCATION_FAILURE:
@@ -344,7 +344,7 @@ cleanup:
     }
 
     world->shutdown(creators_ptr);
-    Logn();
+    Outn();
   }
 
   if (not is_shutdown())
@@ -356,28 +356,28 @@ cleanup:
   shutdown_t status= get_shutdown();
   if (status == SHUTDOWN_FORCED)
   {
-    Log << "Tests were aborted.";
+    Out << "Tests were aborted.";
     exit_code= EXIT_FAILURE;
   }
   else if (stats.collection_failed)
   {
-    Log << "Some test failed.";
+    Out << "Some test failed.";
     exit_code= EXIT_FAILURE;
   }
   else if (stats.collection_skipped)
   {
-    Log << "Some tests were skipped.";
+    Out << "Some tests were skipped.";
   }
   else
   {
-    Log << "All tests completed successfully.";
+    Out << "All tests completed successfully.";
   }
 
   stats_print(&stats);
 
   delete world;
 
-  Logn(); // Generate a blank to break up the messages if make check/test has been run
+  Outn(); // Generate a blank to break up the messages if make check/test has been run
 
   return exit_code;
 }
index b2c89722d856e2e98dd43c892493c78768a7c557..eed030cb9d764b8c9c89a426a8854ffa0a0d0672 100644 (file)
@@ -60,6 +60,7 @@
 #include <libtest/get.h>
 #include <libtest/stream.h>
 #include <libtest/cmdline.h>
+#include <libtest/string.hpp>
 
 #pragma once
 
@@ -77,13 +78,3 @@ void set_default_socket(const char *socket);
 
 LIBTEST_API
 bool test_is_local(void);
-
-#ifdef __cplusplus
-#define test_literal_param(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
-#else
-#define test_literal_param(X) (X), ((size_t)((sizeof(X) - 1)))
-#endif
-
-#define test_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
-
-#define test_array_length(__array) sizeof(__array)/sizeof(&__array)
index 1e3241ed82bc165a1cb0a05dfea4225a3b2cccc8..1528106b7974443e94fa172a25c5019cbbb6a078 100644 (file)
@@ -132,7 +132,7 @@ static test_return_t memcached_cycle_test(void *object)
   server_startup_st *servers= (server_startup_st*)object;
   test_true(servers);
 
-#if !defined(MEMCACHED_BINARY) && !defined(HAVE_LIBMEMCACHED)
+#if !defined(MEMCACHED_BINARY) || !defined(HAVE_LIBMEMCACHED)
   return TEST_SKIPPED;
 #endif
 
@@ -147,7 +147,7 @@ static test_return_t memcached_socket_cycle_test(void *object)
   server_startup_st *servers= (server_startup_st*)object;
   test_true(servers);
 
-#if !defined(MEMCACHED_BINARY) && !defined(HAVE_LIBMEMCACHED)
+#if !defined(MEMCACHED_BINARY) || !defined(HAVE_LIBMEMCACHED)
   return TEST_SKIPPED;
 #endif
 
index 62cd960f1cb9e2fafbcd13760f962d027c7018d5..6c263765bdb507bc329a6ed62261264fe895685b 100644 (file)
@@ -329,7 +329,34 @@ valgrind-memslap: clients/memslap
        $(VALGRIND_COMMAND) $(MEMSLAP_COMMAND)
 
 PHONY += valgrind
-valgrind: tests/testapp tests/testhashkit valgrind-mem valgrind-hash valgrind-memcat valgrind-memcp valgrind-memrm valgrind-memerror valgrind-memdump valgrind-memflush valgrind-memstat
+valgrind: valgrind-mem valgrind-hash valgrind-memcat valgrind-memcp valgrind-memrm valgrind-memerror valgrind-memdump valgrind-memflush valgrind-memstat
+
+helgrind-cycle: tests/cycle
+       $(HELGRIND_COMMAND)  $(CYCLE_COMMAND)
+
+helgrind-mem: tests/testapp
+       $(HELGRIND_COMMAND)  $(MEM_COMMAND)
+
+helgrind-atom: tests/atomsmasher
+       $(HELGRIND_COMMAND)  $(ATOM_COMMAND)
+
+helgrind-udp: tests/testudp
+       $(HELGRIND_COMMAND)  $(UDP_COMMAND)
+
+helgrind-plus: tests/testplus
+       $(HELGRIND_COMMAND)  $(TESTPLUS_COMMAND)
+
+helgrind-hash: tests/testhashkit
+       $(HELGRIND_COMMAND) $(HASH_COMMAND)
+
+helgrind-hashplus: tests/hashplus
+       $(HELGRIND_COMMAND) $(HASHPLUS_COMMAND)
+
+helgrind-memslap: clients/memslap
+       $(HELGRIND_COMMAND) $(MEMSLAP_COMMAND)
+
+PHONY += helgrind
+helgrind: helgrind-mem helgrind-hash helgrind-memcat helgrind-memcp helgrind-memrm helgrind-memerror helgrind-memdump helgrind-memflush helgrind-memstat
 
 PHONY += cachegrind
 CLEANFILES += tests/cachegrind.out