Extend pool API for fetch/release. Fix concurrency issue in test case.
[awesomized/libmemcached] / tests / mem_functions.cc
index a205b5658412a17da51796feb2d16588fda06c1a..cca23464e01ac16d9b63aa21e2c5cdef6ca3395d 100644 (file)
@@ -52,6 +52,7 @@
 #include <cerrno>
 #include <memory>
 #include <pthread.h>
+#include <semaphore.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -73,6 +74,7 @@
 #include "tests/debug.h"
 #include "tests/deprecated.h"
 #include "tests/error_conditions.h"
+#include "tests/exist.h"
 #include "tests/ketama.h"
 #include "tests/namespace.h"
 #include "tests/parser.h"
@@ -571,9 +573,11 @@ static test_return_t cas2_test(memcached_st *memc)
     test_compare(MEMCACHED_SUCCESS, rc);
   }
 
-  rc= memcached_mget(memc, keys, key_length, 3);
+  test_compare(MEMCACHED_SUCCESS, 
+               memcached_mget(memc, keys, key_length, 3));
 
   results= memcached_result_create(memc, &results_obj);
+  test_true(results);
 
   results= memcached_fetch_result(memc, &results_obj, &rc);
   test_true(results);
@@ -616,9 +620,11 @@ static test_return_t cas_test(memcached_st *memc)
                     (time_t)0, (uint32_t)0);
   test_compare(MEMCACHED_SUCCESS, rc);
 
-  rc= memcached_mget(memc, keys, keylengths, 1);
+  test_compare(MEMCACHED_SUCCESS,
+               memcached_mget(memc, keys, keylengths, 1));
 
   results= memcached_result_create(memc, &results_obj);
+  test_true(results);
 
   results= memcached_fetch_result(memc, &results_obj, &rc);
   test_true(results);
@@ -819,12 +825,12 @@ static test_return_t bad_key_test(memcached_st *memc)
   const char *key= "foo bad";
   uint32_t flags;
   memcached_st *memc_clone;
-  size_t max_keylen= 0xffff;
 
-  // Just skip if we are in binary mode.
   uint64_t query_id= memcached_query_id(memc);
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL))
-    return TEST_SKIPPED;
+  
+  // Just skip if we are in binary mode.
+  test_skip(false, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL));
+
   test_compare(query_id, memcached_query_id(memc)); // We should not increase the query_id for memcached_behavior_get()
 
   memc_clone= memcached_clone(NULL, memc);
@@ -838,7 +844,7 @@ static test_return_t bad_key_test(memcached_st *memc)
   /* All keys are valid in the binary protocol (except for length) */
   if (not memcached_behavior_get(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL))
   {
-    query_id= memcached_query_id(memc_clone);
+    uint64_t before_query_id= memcached_query_id(memc_clone);
     {
       size_t string_length;
       char *string= memcached_get(memc_clone, key, strlen(key),
@@ -847,6 +853,7 @@ static test_return_t bad_key_test(memcached_st *memc)
       test_zero(string_length);
       test_false(string);
     }
+    test_compare(before_query_id +1, memcached_query_id(memc_clone));
 
     query_id= memcached_query_id(memc_clone);
     test_compare(MEMCACHED_SUCCESS,
@@ -879,8 +886,6 @@ static test_return_t bad_key_test(memcached_st *memc)
                  memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1));
     test_compare(query_id +1, memcached_query_id(memc_clone));
 
-    max_keylen= 250;
-
     /* The following test should be moved to the end of this function when the
        memcached server is updated to allow max size length of the keys in the
        binary protocol
@@ -889,21 +894,18 @@ static test_return_t bad_key_test(memcached_st *memc)
                  memcached_callback_set(memc_clone, MEMCACHED_CALLBACK_NAMESPACE, NULL));
 
     std::vector <char> longkey;
-    longkey.insert(longkey.end(), max_keylen +1, 'a');
-    if (longkey.size())
+    longkey.insert(longkey.end(), MEMCACHED_MAX_KEY, 'a');
+    test_compare(longkey.size(), size_t(MEMCACHED_MAX_KEY));
     {
       size_t string_length;
-      char *string= memcached_get(memc_clone, &longkey[0], max_keylen,
-                                  &string_length, &flags, &rc);
+      // We subtract 1
+      test_null(memcached_get(memc_clone, &longkey[0], longkey.size() -1, &string_length, &flags, &rc));
       test_compare(MEMCACHED_NOTFOUND, rc);
       test_zero(string_length);
-      test_false(string);
 
-      string= memcached_get(memc_clone, &longkey[0], max_keylen +1,
-                            &string_length, &flags, &rc);
+      test_null(memcached_get(memc_clone, &longkey[0], longkey.size(), &string_length, &flags, &rc));
       test_compare(MEMCACHED_BAD_KEY_PROVIDED, rc);
       test_zero(string_length);
-      test_false(string);
     }
   }
 
@@ -992,12 +994,11 @@ static memcached_return_t delete_trigger(memcached_st *,
 static test_return_t delete_through(memcached_st *memc)
 {
   memcached_trigger_delete_key_fn callback;
-  memcached_return_t rc;
 
   callback= (memcached_trigger_delete_key_fn)delete_trigger;
 
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_DELETE_TRIGGER, *(void**)&callback);
-  test_compare(MEMCACHED_SUCCESS, rc);
+  test_compare(MEMCACHED_SUCCESS, 
+               memcached_callback_set(memc, MEMCACHED_CALLBACK_DELETE_TRIGGER, *(void**)&callback));
 
   return TEST_SUCCESS;
 }
@@ -1266,6 +1267,7 @@ static test_return_t mget_end(memcached_st *memc)
   // this should indicate end
   string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
   test_compare(MEMCACHED_END, rc);
+  test_null(string);
 
   // now get just one
   rc= memcached_mget(memc, keys, lengths, 1);
@@ -1282,6 +1284,7 @@ static test_return_t mget_end(memcached_st *memc)
   // this should indicate end
   string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
   test_compare(MEMCACHED_END, rc);
+  test_null(string);
 
   return TEST_SUCCESS;
 }
@@ -3307,6 +3310,7 @@ static test_return_t mget_read_result(memcached_st *memc)
   {
     memcached_result_st results_obj;
     memcached_result_st *results= memcached_result_create(memc, &results_obj);
+    test_true(results);
 
     memcached_return_t rc;
     while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
@@ -3377,6 +3381,8 @@ static test_return_t mget_read_partial_result(memcached_st *memc)
   {
     memcached_result_st results_obj;
     memcached_result_st *results= memcached_result_create(memc, &results_obj);
+    test_true(results);
+    test_false(memcached_is_allocated(results));
 
     memcached_return_t rc;
     while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
@@ -3518,13 +3524,8 @@ static test_return_t pre_nonblock_binary(memcached_st *memc)
 
 static test_return_t pre_murmur(memcached_st *memc)
 {
-#ifdef HAVE_MURMUR_HASH
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR);
+  test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR));
   return TEST_SUCCESS;
-#else
-  (void) memc;
-  return TEST_SKIPPED;
-#endif
 }
 
 static test_return_t pre_jenkins(memcached_st *memc)
@@ -3551,25 +3552,20 @@ static test_return_t pre_crc(memcached_st *memc)
 
 static test_return_t pre_hsieh(memcached_st *memc)
 {
-#ifdef HAVE_HSIEH_HASH
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_HSIEH);
+  test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_HSIEH));
   return TEST_SUCCESS;
-#else
-  (void) memc;
-  return TEST_SKIPPED;
-#endif
 }
 
 static test_return_t pre_hash_fnv1_64(memcached_st *memc)
 {
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR);
+  test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR));
 
   return TEST_SUCCESS;
 }
 
 static test_return_t pre_hash_fnv1a_64(memcached_st *memc)
 {
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_64);
+  test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_64));
 
   return TEST_SUCCESS;
 }
@@ -3736,6 +3732,7 @@ static test_return_t selection_of_namespace_tests(memcached_st *memc)
 
   /* Make sure be default none exists */
   value= (char*)memcached_callback_get(memc, MEMCACHED_CALLBACK_NAMESPACE, &rc);
+  test_null(value);
   test_compare_got(MEMCACHED_FAILURE, rc, memcached_strerror(NULL, rc));
 
   /* Test a clean set */
@@ -3807,6 +3804,7 @@ static test_return_t set_namespace(memcached_st *memc)
 
   /* Make sure be default none exists */
   value= (char*)memcached_callback_get(memc, MEMCACHED_CALLBACK_NAMESPACE, &rc);
+  test_null(value);
   test_compare_got(MEMCACHED_FAILURE, rc, memcached_strerror(NULL, rc));
 
   /* Test a clean set */
@@ -4007,13 +4005,12 @@ static test_return_t pre_settimer(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
-static test_return_t poll_timeout(memcached_st *memc)
+static test_return_t MEMCACHED_BEHAVIOR_POLL_TIMEOUT_test(memcached_st *memc)
 {
   const uint64_t timeout= 100; // Not using, just checking that it sets
 
   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, timeout);
 
-
   test_compare(timeout, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT));
 
   return TEST_SUCCESS;
@@ -4027,12 +4024,12 @@ static test_return_t noreply_test(memcached_st *memc)
                memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1));
   test_compare(MEMCACHED_SUCCESS, 
                memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1));
-  test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY) == 1);
-  test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS) == 1);
-  test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS) == 1);
+  test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY));
+  test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS));
+  test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS));
 
   memcached_return_t ret;
-  for (int count=0; count < 5; ++count)
+  for (int count= 0; count < 5; ++count)
   {
     for (size_t x= 0; x < 100; ++x)
     {
@@ -4161,10 +4158,9 @@ static test_return_t noreply_test(memcached_st *memc)
 static test_return_t analyzer_test(memcached_st *memc)
 {
   memcached_return_t rc;
-  memcached_stat_st *memc_stat;
   memcached_analysis_st *report;
 
-  memc_stat= memcached_stat(memc, NULL, &rc);
+  memcached_stat_st *memc_stat= memcached_stat(memc, NULL, &rc);
   test_compare(MEMCACHED_SUCCESS, rc);
   test_true(memc_stat);
 
@@ -4196,68 +4192,85 @@ static test_return_t dump_test(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
-struct test_pool_context_st {
-  memcached_pool_st* pool;
-  memcached_st* mmc;
-};
-
-static void* connection_release(void *arg)
-{
-  test_pool_context_st *resource= static_cast<test_pool_context_st *>(arg);
-
-  usleep(250);
-  // Release all of the memc we are holding
-  assert(memcached_success(memcached_pool_push(resource->pool, resource->mmc)));
-  return arg;
-}
 
 #define POOL_SIZE 10
 static test_return_t connection_pool_test(memcached_st *memc)
 {
   memcached_pool_st* pool= memcached_pool_create(memc, 5, POOL_SIZE);
-  test_true(pool != NULL);
+  test_true(pool);
   memcached_st *mmc[POOL_SIZE];
-  memcached_return_t rc;
 
   // Fill up our array that we will store the memc that are in the pool
   for (size_t x= 0; x < POOL_SIZE; ++x)
   {
-    mmc[x]= memcached_pool_pop(pool, false, &rc);
-    test_true(mmc[x] != NULL);
+    memcached_return_t rc;
+    mmc[x]= memcached_pool_fetch(pool, NULL, &rc);
     test_compare(MEMCACHED_SUCCESS, rc);
+    test_true(mmc[x]);
   }
 
   // All memc should be gone
-  test_true(memcached_pool_pop(pool, false, &rc) == NULL);
-  test_compare(MEMCACHED_SUCCESS, rc);
+  {
+    memcached_return_t rc;
+    test_null(memcached_pool_fetch(pool, NULL, &rc));
+    test_compare(MEMCACHED_NOTFOUND, rc);
+  }
 
-  pthread_t tid;
-  test_pool_context_st item= { pool, mmc[9] };
+  // Release them..
+  for (size_t x= 0; x < POOL_SIZE; ++x)
+  {
+    if (mmc[x])
+    {
+      test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[x]));
+    }
+  }
+  test_true(memcached_pool_destroy(pool) == memc);
 
-  pthread_create(&tid, NULL, connection_release, &item);
-  mmc[9]= memcached_pool_pop(pool, true, &rc);
-  test_compare(MEMCACHED_SUCCESS, rc);
-  pthread_join(tid, NULL);
-  test_true(mmc[9]);
-  const char *key= "key";
-  size_t keylen= strlen(key);
+  return TEST_SUCCESS;
+}
+
+static test_return_t connection_pool2_test(memcached_st *memc)
+{
+  memcached_pool_st* pool= memcached_pool_create(memc, 5, POOL_SIZE);
+  test_true(pool);
+  memcached_st *mmc[POOL_SIZE];
+
+  // Fill up our array that we will store the memc that are in the pool
+  for (size_t x= 0; x < POOL_SIZE; ++x)
+  {
+    memcached_return_t rc;
+    mmc[x]= memcached_pool_fetch(pool, NULL, &rc);
+    test_compare(MEMCACHED_SUCCESS, rc);
+    test_true(mmc[x]);
+  }
+
+  // All memc should be gone
+  {
+    memcached_return_t rc;
+    test_null(memcached_pool_fetch(pool, NULL, &rc));
+    test_compare(MEMCACHED_NOTFOUND, rc);
+  }
 
   // verify that I can do ops with all connections
   test_compare(MEMCACHED_SUCCESS,
-               memcached_set(mmc[0], key, keylen, "0", 1, 0, 0));
+               memcached_set(mmc[0],
+                             test_literal_param("key"),
+                             "0", 1, 0, 0));
 
   for (uint64_t x= 0; x < POOL_SIZE; ++x)
   {
     uint64_t number_value;
     test_compare(MEMCACHED_SUCCESS,
-                 memcached_increment(mmc[x], key, keylen, 1, &number_value));
+                 memcached_increment(mmc[x], 
+                                     test_literal_param("key"),
+                                     1, &number_value));
     test_compare(number_value, (x+1));
   }
 
   // Release them..
   for (size_t x= 0; x < POOL_SIZE; ++x)
   {
-    test_compare(MEMCACHED_SUCCESS, memcached_pool_push(pool, mmc[x]));
+    test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[x]));
   }
 
 
@@ -4265,22 +4278,137 @@ static test_return_t connection_pool_test(memcached_st *memc)
    * of the connections in the pool. It should however be enabled
    * when I push the item into the pool
    */
-  mmc[0]= memcached_pool_pop(pool, false, &rc);
+  mmc[0]= memcached_pool_fetch(pool, NULL, NULL);
   test_true(mmc[0]);
 
-  rc= memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK, 9999);
-  test_compare(MEMCACHED_SUCCESS, rc);
+  test_compare(MEMCACHED_SUCCESS,
+               memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK, 9999));
 
-  mmc[1]= memcached_pool_pop(pool, false, &rc);
-  test_true(mmc[1]);
+  {
+    memcached_return_t rc;
+    mmc[1]= memcached_pool_fetch(pool, NULL, &rc);
+    test_true(mmc[1]);
+    test_compare(MEMCACHED_SUCCESS, rc);
+  }
 
   test_compare(UINT64_C(9999), memcached_behavior_get(mmc[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK));
-  test_compare(MEMCACHED_SUCCESS, memcached_pool_push(pool, mmc[1]));
-  test_compare(MEMCACHED_SUCCESS, memcached_pool_push(pool, mmc[0]));
+  test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[1]));
+  test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[0]));
+
+  {
+    memcached_return_t rc;
+    mmc[0]= memcached_pool_fetch(pool, NULL, &rc);
+    test_true(mmc[0]);
+    test_compare(MEMCACHED_SUCCESS, rc);
+  }
 
-  mmc[0]= memcached_pool_pop(pool, false, &rc);
   test_compare(UINT64_C(9999), memcached_behavior_get(mmc[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK));
-  test_compare(MEMCACHED_SUCCESS, memcached_pool_push(pool, mmc[0]));
+  test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[0]));
+
+  test_true(memcached_pool_destroy(pool) == memc);
+
+  return TEST_SUCCESS;
+}
+
+struct test_pool_context_st {
+  volatile memcached_return_t rc;
+  memcached_pool_st* pool;
+  memcached_st* mmc;
+  sem_t _lock;
+
+  test_pool_context_st(memcached_pool_st *pool_arg, memcached_st *memc_arg):
+    rc(MEMCACHED_FAILURE),
+    pool(pool_arg),
+    mmc(memc_arg)
+  {
+    sem_init(&_lock, 0, 0);
+  }
+
+  void wait()
+  {
+    sem_wait(&_lock);
+  }
+
+  void release()
+  {
+    sem_post(&_lock);
+  }
+
+  ~test_pool_context_st()
+  {
+    sem_destroy(&_lock);
+  }
+};
+
+static void* connection_release(void *arg)
+{
+  test_pool_context_st *resource= static_cast<test_pool_context_st *>(arg);
+  assert(resource);
+  if (resource == NULL)
+  {
+    abort();
+  }
+
+  // Release all of the memc we are holding 
+  resource->rc= memcached_pool_release(resource->pool, resource->mmc);
+  resource->release();
+
+  pthread_exit(arg);
+}
+
+static test_return_t connection_pool3_test(memcached_st *memc)
+{
+  memcached_pool_st* pool= memcached_pool_create(memc, 1, 1);
+  test_true(pool);
+
+  memcached_st *pool_memc;
+  {
+    memcached_return_t rc;
+    pool_memc= memcached_pool_fetch(pool, NULL, &rc);
+    test_compare(MEMCACHED_SUCCESS, rc);
+    test_true(pool_memc);
+  }
+
+  /*
+    @note This comment was written to describe what was believed to be the original authors intent.
+
+    This portion of the test creates a thread that will wait until told to free a memcached_st
+    that will be grabbed by the main thread.
+
+    It is believed that this tests whether or not we are handling ownership correctly.
+  */
+  pthread_t tid;
+  test_pool_context_st item(pool, pool_memc);
+
+  test_zero(pthread_create(&tid, NULL, connection_release, &item));
+  item.wait();
+
+  memcached_return_t rc;
+  memcached_st *pop_memc;
+  int counter= 5;
+  do
+  {
+    struct timespec relative_time= { 0, 0 };
+    pop_memc= memcached_pool_fetch(pool, &relative_time, &rc);
+
+    if (memcached_failed(rc))
+    {
+      test_null(pop_memc);
+    }
+  } while (rc == MEMCACHED_TIMEOUT and --counter);
+
+  if (memcached_failed(rc)) // Cleanup thread since we will exit once we test.
+  {
+    pthread_join(tid, NULL);
+    test_compare(MEMCACHED_SUCCESS, rc);
+  }
+
+  {
+    int pthread_ret= pthread_join(tid, NULL);
+    test_true(pthread_ret == 0 or pthread_ret == ESRCH);
+  }
+  test_compare(MEMCACHED_SUCCESS, rc);
+  test_true(pool_memc == pop_memc);
 
   test_true(memcached_pool_destroy(pool) == memc);
 
@@ -4428,26 +4556,21 @@ static test_return_t hash_sanity_test (memcached_st *memc)
 
 static test_return_t hsieh_avaibility_test (memcached_st *memc)
 {
-  memcached_return_t expected_rc= MEMCACHED_INVALID_ARGUMENTS;
-#ifdef HAVE_HSIEH_HASH
-  expected_rc= MEMCACHED_SUCCESS;
-#endif
-  memcached_return_t rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH,
-                                                (uint64_t)MEMCACHED_HASH_HSIEH);
-  test_true(rc == expected_rc);
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_HSIEH));
+
+  test_compare(MEMCACHED_SUCCESS, 
+               memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH,
+                                      (uint64_t)MEMCACHED_HASH_HSIEH));
 
   return TEST_SUCCESS;
 }
 
 static test_return_t murmur_avaibility_test (memcached_st *memc)
 {
-  memcached_return_t expected_rc= MEMCACHED_INVALID_ARGUMENTS;
-#ifdef HAVE_MURMUR_HASH
-  expected_rc= MEMCACHED_SUCCESS;
-#endif
-  memcached_return_t rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH,
-                                                (uint64_t)MEMCACHED_HASH_MURMUR);
-  test_true(rc == expected_rc);
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_MURMUR));
+
+  test_compare(MEMCACHED_SUCCESS,
+               memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR));
 
   return TEST_SUCCESS;
 }
@@ -4459,10 +4582,8 @@ static test_return_t one_at_a_time_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_DEFAULT);
-    test_true(one_at_a_time_values[x] == hash_val);
+    test_compare(one_at_a_time_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_DEFAULT));
   }
 
   return TEST_SUCCESS;
@@ -4475,10 +4596,8 @@ static test_return_t md5_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MD5);
-    test_true(md5_values[x] == hash_val);
+    test_compare(md5_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MD5));
   }
 
   return TEST_SUCCESS;
@@ -4491,10 +4610,8 @@ static test_return_t crc_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_CRC);
-    test_true(crc_values[x] == hash_val);
+    test_compare(crc_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_CRC));
   }
 
   return TEST_SUCCESS;
@@ -4502,15 +4619,15 @@ static test_return_t crc_run (memcached_st *)
 
 static test_return_t fnv1_64_run (memcached_st *)
 {
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_FNV1_64));
+
   uint32_t x;
   const char **ptr;
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_64);
-    test_true(fnv1_64_values[x] == hash_val);
+    test_compare(fnv1_64_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_64));
   }
 
   return TEST_SUCCESS;
@@ -4518,15 +4635,15 @@ static test_return_t fnv1_64_run (memcached_st *)
 
 static test_return_t fnv1a_64_run (memcached_st *)
 {
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_FNV1A_64));
+
   uint32_t x;
   const char **ptr;
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_64);
-    test_true(fnv1a_64_values[x] == hash_val);
+    test_compare(fnv1a_64_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_64));
   }
 
   return TEST_SUCCESS;
@@ -4539,10 +4656,8 @@ static test_return_t fnv1_32_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_32);
-    test_true(fnv1_32_values[x] == hash_val);
+    test_compare(fnv1_32_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_32));
   }
 
   return TEST_SUCCESS;
@@ -4555,10 +4670,8 @@ static test_return_t fnv1a_32_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_32);
-    test_true(fnv1a_32_values[x] == hash_val);
+    test_compare(fnv1a_32_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_32));
   }
 
   return TEST_SUCCESS;
@@ -4566,15 +4679,15 @@ static test_return_t fnv1a_32_run (memcached_st *)
 
 static test_return_t hsieh_run (memcached_st *)
 {
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_HSIEH));
+
   uint32_t x;
   const char **ptr;
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_HSIEH);
-    test_true(hsieh_values[x] == hash_val);
+    test_compare(hsieh_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_HSIEH));
   }
 
   return TEST_SUCCESS;
@@ -4582,6 +4695,8 @@ static test_return_t hsieh_run (memcached_st *)
 
 static test_return_t murmur_run (memcached_st *)
 {
+  test_skip(true, libhashkit_has_algorithm(HASHKIT_HASH_MURMUR));
+
 #ifdef WORDS_BIGENDIAN
   (void)murmur_values;
   return TEST_SKIPPED;
@@ -4591,10 +4706,8 @@ static test_return_t murmur_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MURMUR);
-    test_true(murmur_values[x] == hash_val);
+    test_compare(murmur_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MURMUR));
   }
 
   return TEST_SUCCESS;
@@ -4608,24 +4721,20 @@ static test_return_t jenkins_run (memcached_st *)
 
   for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
   {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_JENKINS);
-    test_true(jenkins_values[x] == hash_val);
+    test_compare(jenkins_values[x],
+                 memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_JENKINS));
   }
 
   return TEST_SUCCESS;
 }
 
-static uint32_t hash_md5_test_function(const char *string, size_t string_length, void *context)
+static uint32_t hash_md5_test_function(const char *string, size_t string_length, void *)
 {
-  (void)context;
   return libhashkit_md5(string, string_length);
 }
 
-static uint32_t hash_crc_test_function(const char *string, size_t string_length, void *context)
+static uint32_t hash_crc_test_function(const char *string, size_t string_length, void *)
 {
-  (void)context;
   return libhashkit_crc32(string, string_length);
 }
 
@@ -5579,7 +5688,7 @@ static test_return_t regression_bug_655423(memcached_st *memc)
 
     test_compare(MEMCACHED_SUCCESS, rc);
     test_true(value);
-    test_compare(100UL, value_length);
+    test_compare(100LLU, value_length);
     free(value);
   }
 
@@ -5663,6 +5772,27 @@ static test_return_t regression_bug_490520(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
+
+static test_return_t regression_bug_854604(memcached_st *)
+{
+  char buffer[1024];
+
+  test_compare(MEMCACHED_INVALID_ARGUMENTS, libmemcached_check_configuration(0, 0, buffer, 0));
+
+  test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 0));
+  
+  test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 1));
+  test_compare(buffer[0], 0);
+  
+  test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 10));
+  test_true(strlen(buffer));
+
+  test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, sizeof(buffer)));
+  test_true(strlen(buffer));
+  
+  return TEST_SUCCESS;
+}
+
 static void memcached_die(memcached_st* mc, memcached_return error, const char* what, uint32_t it)
 {
   fprintf(stderr, "Iteration #%u: ", it);
@@ -5827,11 +5957,17 @@ test_st tests[] ={
   {"delete_through", true, (test_callback_fn*)delete_through },
   {"noreply", true, (test_callback_fn*)noreply_test},
   {"analyzer", true, (test_callback_fn*)analyzer_test},
-  {"connectionpool", true, (test_callback_fn*)connection_pool_test },
+  {"memcached_pool_st", true, (test_callback_fn*)connection_pool_test },
+  {"memcached_pool_st #2", true, (test_callback_fn*)connection_pool2_test },
+  {"memcached_pool_st #3", true, (test_callback_fn*)connection_pool3_test },
   {"memcached_pool_test", true, (test_callback_fn*)memcached_pool_test },
   {"test_get_last_disconnect", true, (test_callback_fn*)test_get_last_disconnect},
   {"verbosity", true, (test_callback_fn*)test_verbosity},
   {"memcached_stat_execute", true, (test_callback_fn*)memcached_stat_execute_test},
+  {"memcached_exist(MEMCACHED_NOTFOUND)", true, (test_callback_fn*)memcached_exist_NOTFOUND },
+  {"memcached_exist(MEMCACHED_SUCCESS)", true, (test_callback_fn*)memcached_exist_SUCCESS },
+  {"memcached_exist_by_key(MEMCACHED_NOTFOUND)", true, (test_callback_fn*)memcached_exist_by_key_NOTFOUND },
+  {"memcached_exist_by_key(MEMCACHED_SUCCESS)", true, (test_callback_fn*)memcached_exist_by_key_SUCCESS },
   {0, 0, 0}
 };
 
@@ -5842,6 +5978,7 @@ test_st behavior_tests[] ={
   {"MEMCACHED_BEHAVIOR_CORK", false, (test_callback_fn*)MEMCACHED_BEHAVIOR_CORK_test},
   {"MEMCACHED_BEHAVIOR_TCP_KEEPALIVE", false, (test_callback_fn*)MEMCACHED_BEHAVIOR_TCP_KEEPALIVE_test},
   {"MEMCACHED_BEHAVIOR_TCP_KEEPIDLE", false, (test_callback_fn*)MEMCACHED_BEHAVIOR_TCP_KEEPIDLE_test},
+  {"MEMCACHED_BEHAVIOR_POLL_TIMEOUT", false, (test_callback_fn*)MEMCACHED_BEHAVIOR_POLL_TIMEOUT_test},
   {0, 0, 0}
 };
 
@@ -5968,6 +6105,7 @@ test_st regression_tests[]= {
   {"lp:71231153 poll()", true, (test_callback_fn*)regression_bug_71231153_poll },
   {"lp:655423", true, (test_callback_fn*)regression_bug_655423 },
   {"lp:490520", true, (test_callback_fn*)regression_bug_490520 },
+  {"lp:854604", true, (test_callback_fn*)regression_bug_854604 },
   {0, false, (test_callback_fn*)0}
 };
 
@@ -6126,7 +6264,6 @@ collection_st collection[] ={
   {"ketama_auto_eject_hosts", (test_callback_fn*)pre_behavior_ketama, 0, ketama_auto_eject_hosts},
   {"unix_socket", (test_callback_fn*)pre_unix_socket, 0, tests},
   {"unix_socket_nodelay", (test_callback_fn*)pre_nodelay, 0, tests},
-  {"poll_timeout", (test_callback_fn*)poll_timeout, 0, tests},
   {"gets", (test_callback_fn*)enable_cas, 0, tests},
   {"consistent_crc", (test_callback_fn*)enable_consistent_crc, 0, tests},
   {"consistent_hsieh", (test_callback_fn*)enable_consistent_hsieh, 0, tests},