From: Brian Aker Date: Thu, 26 Jan 2012 07:12:47 +0000 (-0800) Subject: This fixes memcached_dump(), and creates a couple of additional tests for memcached_s... X-Git-Tag: 1.0.4^2~3^2 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=7f3f3d165c47d2722cc7a57b618cee7ed14557b3;p=awesomized%2Flibmemcached This fixes memcached_dump(), and creates a couple of additional tests for memcached_stat_execute(). --- diff --git a/libmemcached-1.0/return.h b/libmemcached-1.0/return.h index b63953a5..65dc63af 100644 --- a/libmemcached-1.0/return.h +++ b/libmemcached-1.0/return.h @@ -68,6 +68,7 @@ static inline bool memcached_fatal(memcached_return_t rc) rc != MEMCACHED_E2BIG && rc != MEMCACHED_END && rc != MEMCACHED_ITEM && + rc != MEMCACHED_ERROR && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_NOTSTORED && rc != MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE && diff --git a/libmemcached-1.0/types/return.h b/libmemcached-1.0/types/return.h index e57442e4..f4ec9b08 100644 --- a/libmemcached-1.0/types/return.h +++ b/libmemcached-1.0/types/return.h @@ -47,8 +47,8 @@ enum memcached_return_t { MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_CLIENT_ERROR, - MEMCACHED_SERVER_ERROR, - MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE, // DEPRECATED + MEMCACHED_SERVER_ERROR, // Server returns "SERVER_ERROR" + MEMCACHED_ERROR, // Server returns "ERROR" MEMCACHED_DATA_EXISTS, MEMCACHED_DATA_DOES_NOT_EXIST, MEMCACHED_NOTSTORED, @@ -86,7 +86,8 @@ enum memcached_return_t { MEMCACHED_IN_PROGRESS, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE, - MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */ + MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */ + MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE= MEMCACHED_ERROR }; #ifndef __cplusplus diff --git a/libmemcached/dump.cc b/libmemcached/dump.cc index 899a4c3e..5ba4ce16 100644 --- a/libmemcached/dump.cc +++ b/libmemcached/dump.cc @@ -46,91 +46,90 @@ static memcached_return_t ascii_dump(memcached_st *memc, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) { - for (uint32_t server_key= 0; server_key < memcached_server_count(memc); server_key++) + /* MAX_NUMBER_OF_SLAB_CLASSES is defined to 200 in Memcached 1.4.10 */ + for (uint32_t x= 0; x < 200; x++) { - memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, server_key); + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + int buffer_length= snprintf(buffer, sizeof(buffer), "%u", x); + if (size_t(buffer_length) >= sizeof(buffer) or buffer_length < 0) + { + return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); + } - bool exit_slab_loop= false; - /* MAX_NUMBER_OF_SLAB_CLASSESdefined to 200 in Memcached 1.4.10 */ - for (uint32_t x= 0; x < 200 and (exit_slab_loop == false); x++) + // @NOTE the hard coded zero means "no limit" + libmemcached_io_vector_st vector[]= { - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int buffer_length= snprintf(buffer, sizeof(buffer), "%u", x); - if (size_t(buffer_length) >= sizeof(buffer) or buffer_length < 0) - { - return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); - } + { memcached_literal_param("stats cachedump ") }, + { buffer, buffer_length }, + { memcached_literal_param(" 0\r\n") } + }; - libmemcached_io_vector_st vector[]= - { - { memcached_literal_param("stats cachedump ") }, - { buffer, buffer_length }, - { memcached_literal_param(" 0 0\r\n") } - }; + // Send message to all servers + for (uint32_t server_key= 0; server_key < memcached_server_count(memc); server_key++) + { + memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, server_key); memcached_return_t vdo_rc; if (memcached_success((vdo_rc= memcached_vdo(instance, vector, 3, true)))) { - while (1) + // We have sent the message to the server successfully + } + else + { + return memcached_set_error(*instance, vdo_rc, MEMCACHED_AT); + } + } + + // Collect the returned items + memcached_server_write_instance_st instance; + while ((instance= memcached_io_get_readable_server(memc))) + { + memcached_return_t response_rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + if (response_rc == MEMCACHED_ITEM) + { + char *string_ptr, *end_ptr; + + string_ptr= buffer; + string_ptr+= 5; /* Move past ITEM */ + + for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {} ; + + char *key= string_ptr; + key[(size_t)(end_ptr-string_ptr)]= 0; + + for (uint32_t callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++) { - memcached_return_t response_rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, response_rc)); - if (response_rc == MEMCACHED_ITEM) - { - char *string_ptr, *end_ptr; - - string_ptr= buffer; - string_ptr+= 5; /* Move past ITEM */ - - for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {} ; - - char *key= string_ptr; - key[(size_t)(end_ptr-string_ptr)]= 0; - - for (uint32_t callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++) - { - memcached_return_t callback_rc= (*callback[callback_counter])(memc, key, (size_t)(end_ptr-string_ptr), context); - if (callback_rc != MEMCACHED_SUCCESS) - { - // @todo build up a message for the error from the value - memcached_set_error(*instance, callback_rc, MEMCACHED_AT); - break; - } - } - } - else if (response_rc == MEMCACHED_END) - { - // No additional items were found - exit_slab_loop= true; - break; - } - else if (response_rc == MEMCACHED_SERVER_ERROR or response_rc == MEMCACHED_CLIENT_ERROR) - { - /* If we try to request stats cachedump for a slab class that is too big - * the server will return an incorrect error message: - * "MEMCACHED_SERVER_ERROR failed to allocate memory" - * This isn't really a fatal error, so let's just skip it. I want to - * fix the return value from the memcached server to a CLIENT_ERROR, - * so let's add support for that as well right now. - */ - exit_slab_loop= true; - break; - } - else + memcached_return_t callback_rc= (*callback[callback_counter])(memc, key, (size_t)(end_ptr-string_ptr), context); + if (callback_rc != MEMCACHED_SUCCESS) { - memcached_set_error(*instance, response_rc, MEMCACHED_AT); - exit_slab_loop= true; + // @todo build up a message for the error from the value + memcached_set_error(*instance, callback_rc, MEMCACHED_AT); break; } } } + else if (response_rc == MEMCACHED_END) + { + // All items have been returned + } + else if (response_rc == MEMCACHED_SERVER_ERROR or response_rc == MEMCACHED_CLIENT_ERROR or response_rc == MEMCACHED_ERROR) + { + /* If we try to request stats cachedump for a slab class that is too big + * the server will return an incorrect error message: + * "MEMCACHED_SERVER_ERROR failed to allocate memory" + * This isn't really a fatal error, so let's just skip it. I want to + * fix the return value from the memcached server to a CLIENT_ERROR, + * so let's add support for that as well right now. + */ + assert(response_rc == MEMCACHED_SUCCESS); // Just fail + return response_rc; + } else { - exit_slab_loop= true; - memcached_set_error(*instance, vdo_rc, MEMCACHED_AT); + // IO error of some sort must have occurred + return memcached_set_error(*instance, response_rc, MEMCACHED_AT); } - fprintf(stderr, "Was able to request %u slab\n", x); } } diff --git a/libmemcached/response.cc b/libmemcached/response.cc index 7af52ce4..ac1fb057 100644 --- a/libmemcached/response.cc +++ b/libmemcached/response.cc @@ -319,6 +319,11 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta return MEMCACHED_PROTOCOL_ERROR; } #endif + // ERROR + else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R') + { + return MEMCACHED_ERROR; + } // EXISTS else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S') { @@ -781,6 +786,7 @@ memcached_return_t memcached_response(memcached_server_write_instance_st ptr, rc != MEMCACHED_DELETED and rc != MEMCACHED_E2BIG and rc != MEMCACHED_END and + rc != MEMCACHED_ERROR and rc != MEMCACHED_ITEM and rc != MEMCACHED_NOTFOUND and rc != MEMCACHED_NOTSTORED and diff --git a/libmemcached/server.cc b/libmemcached/server.cc index a86f09ad..2f415844 100644 --- a/libmemcached/server.cc +++ b/libmemcached/server.cc @@ -241,18 +241,28 @@ memcached_return_t memcached_server_execute(memcached_st *ptr, memcached_server_execute_fn callback, void *context) { + if (callback == NULL) + { + return MEMCACHED_INVALID_ARGUMENTS; + } + + bool some_errors= false;; for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); - unsigned int iferror= (*callback)(ptr, instance, context); - - if (iferror) + memcached_return_t rc= (*callback)(ptr, instance, context); + if (rc == MEMCACHED_INVALID_ARGUMENTS) + { + return rc; + } + else if (memcached_fatal(rc)) { - continue; + some_errors= true; } } + (void)some_errors; return MEMCACHED_SUCCESS; } diff --git a/libmemcached/stats.cc b/libmemcached/stats.cc index d5d1c234..49dfab01 100644 --- a/libmemcached/stats.cc +++ b/libmemcached/stats.cc @@ -81,7 +81,7 @@ struct local_context }; -static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value) +static memcached_return_t set_data(memcached_stat_st *memc_stat, const char *key, const char *value) { if (strlen(key) < 1) @@ -127,7 +127,7 @@ static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char else if (not strcmp("rusage_user", key)) { char *walk_ptr; - for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++) {}; + for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {}; *walk_ptr= 0; walk_ptr++; memc_stat->rusage_user_seconds= strtoul(value, (char **)NULL, 10); @@ -136,7 +136,7 @@ static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char else if (not strcmp("rusage_system", key)) { char *walk_ptr; - for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++) {}; + for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {}; *walk_ptr= 0; walk_ptr++; memc_stat->rusage_system_seconds= strtoul(value, (char **)NULL, 10); @@ -402,15 +402,6 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, return rc; } - if (memc_stat) - { - if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) - { - WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); - WATCHPOINT_ASSERT(0); - } - } - if (check && check->func) { size_t key_length= strlen(buffer); @@ -420,6 +411,15 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, buffer+key_length+1, strlen(buffer+key_length+1), check->context); } + + if (memc_stat) + { + if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) + { + WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); + WATCHPOINT_ASSERT(0); + } + } } while (1); /* @@ -448,40 +448,50 @@ static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, if (memcached_success(rc)) { char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - while ((rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL)) == MEMCACHED_STAT) + while ((rc= memcached_response(instance, buffer, sizeof(buffer), NULL)) == MEMCACHED_STAT) { - char *string_ptr, *end_ptr; - char *key, *value; - - string_ptr= buffer; + char *string_ptr= buffer; string_ptr+= 5; /* Move past STAT */ + + char *end_ptr; for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {}; - key= string_ptr; - key[(size_t)(end_ptr-string_ptr)]= 0; + char *key= string_ptr; + key[size_t(end_ptr-string_ptr)]= 0; string_ptr= end_ptr + 1; for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++) {}; - value= string_ptr; + char *value= string_ptr; value[(size_t)(end_ptr -string_ptr)]= 0; - if (memc_stat) - { - unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) - { - WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); - WATCHPOINT_ASSERT(0); - } - } +#if 0 + bool check_bool= bool(check); + bool check_func_bool= bool(check) ? bool(check->func) : false; + fprintf(stderr, "%s:%d %s %s %d:%d\n", __FILE__, __LINE__, key, value, check_bool, check_func_bool); +#endif - if (check && check->func) + if (check and check->func) { check->func(instance, key, strlen(key), value, strlen(value), check->context); } + + if (memc_stat) + { + if((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) + { + WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); + WATCHPOINT_ASSERT(0); + } + } } } + if (rc == MEMCACHED_ERROR) + { + return MEMCACHED_INVALID_ARGUMENTS; + } + if (rc == MEMCACHED_END) { return MEMCACHED_SUCCESS; @@ -552,6 +562,13 @@ memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_retu temp_return= ascii_stats_fetch(stat_instance, args, args_length, instance, NULL); } + // Special case where "args" is invalid + if (temp_return == MEMCACHED_INVALID_ARGUMENTS) + { + rc= MEMCACHED_INVALID_ARGUMENTS; + break; + } + if (memcached_failed(temp_return)) { rc= MEMCACHED_SOME_ERRORS; @@ -619,8 +636,10 @@ char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *, memcached_return_t *error) { - if (not ptr) + if (ptr == NULL) + { return NULL; + } char **list= static_cast(libmemcached_malloc(ptr, sizeof(memcached_stat_keys))); if (not list) @@ -658,9 +677,9 @@ static memcached_return_t call_stat_fn(memcached_st *ptr, void *context) { memcached_return_t rc; - struct local_context *check= (struct local_context *)context; + local_context *check= (struct local_context *)context; - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { rc= binary_stats_fetch(NULL, check->args, check->args_length, instance, check); } @@ -676,7 +695,7 @@ memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, { memcached_version(memc); - struct local_context check(func, context, args, args ? strlen(args) : 0); + local_context check(func, context, args, args ? strlen(args) : 0); return memcached_server_execute(memc, call_stat_fn, (void *)&check); } diff --git a/libmemcached/strerror.cc b/libmemcached/strerror.cc index b70a60b9..7cd2ff2f 100644 --- a/libmemcached/strerror.cc +++ b/libmemcached/strerror.cc @@ -74,8 +74,8 @@ const char *memcached_strerror(memcached_st *, memcached_return_t rc) case MEMCACHED_WRITE_FAILURE: return "WRITE FAILURE"; - case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: // DEPRECATED - return "CONNECTION SOCKET CREATE FAILURE"; + case MEMCACHED_ERROR: + return "ERROR was returned by server"; case MEMCACHED_DATA_EXISTS: return "CONNECTION DATA EXISTS"; diff --git a/tests/libmemcached-1.0/dump.cc b/tests/libmemcached-1.0/dump.cc index 1421bd47..c0f8658a 100644 --- a/tests/libmemcached-1.0/dump.cc +++ b/tests/libmemcached-1.0/dump.cc @@ -35,6 +35,10 @@ */ #include + +#include +#include + #include #include @@ -45,21 +49,41 @@ using namespace libtest; #include "tests/libmemcached-1.0/dump.h" static memcached_return_t callback_dump_counter(const memcached_st *, - const char *key, - size_t length, + const char*, // key, + size_t, // length, void *context) { size_t *counter= (size_t *)context; +#if 0 std::cerr.write(key, length); std::cerr << std::endl; - +#endif *counter= *counter +1; return MEMCACHED_SUCCESS; } +static memcached_return_t item_counter(memcached_server_instance_st , + const char *key, size_t key_length, + const char *value, size_t, // value_length, + void *context) +{ + if ((key_length == (sizeof("curr_items") -1)) and (strncmp("curr_items", key, (sizeof("curr_items") -1)) == 0)) + { + uint64_t* counter= (uint64_t*)context; + unsigned long number_value= strtoul(value, (char **)NULL, 10); + if (number_value == ULONG_MAX) + { + return MEMCACHED_FAILURE; + } + *counter= *counter +number_value; + } + + return MEMCACHED_SUCCESS; +} + test_return_t memcached_dump_TEST(memcached_st *memc) { test_skip(false, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); @@ -68,6 +92,12 @@ test_return_t memcached_dump_TEST(memcached_st *memc) memcached_dump_fn callbacks[1]; callbacks[0]= &callback_dump_counter; + uint64_t counter= 0; + test_compare_got(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, NULL, item_counter, &counter), + memcached_last_error_message(memc)); + test_zero(counter); + test_compare_got(MEMCACHED_SUCCESS, memcached_dump(memc, callbacks, &count, 1), memcached_last_error_message(memc)); return TEST_SUCCESS; @@ -95,6 +125,12 @@ test_return_t memcached_dump_TEST2(memcached_st *memc) } memcached_quit(memc); + uint64_t counter= 0; + test_compare_got(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, NULL, item_counter, &counter), + memcached_last_error_message(memc)); + test_true_got(counter > 0, counter); + size_t count= 0; memcached_dump_fn callbacks[1]; callbacks[0]= &callback_dump_counter; @@ -103,9 +139,7 @@ test_return_t memcached_dump_TEST2(memcached_st *memc) memcached_dump(memc, callbacks, &count, 1), memcached_last_error_message(memc)); -#if 0 test_compare(size_t(memcached_dump_TEST2_COUNT), count); -#endif return TEST_SUCCESS; } diff --git a/tests/libmemcached-1.0/include.am b/tests/libmemcached-1.0/include.am index fe7f3479..373fc6e7 100644 --- a/tests/libmemcached-1.0/include.am +++ b/tests/libmemcached-1.0/include.am @@ -19,6 +19,7 @@ noinst_HEADERS+= \ tests/ketama_test_cases.h \ tests/ketama_test_cases_spy.h \ tests/libmemcached-1.0/dump.h \ + tests/libmemcached-1.0/stat.h \ tests/namespace.h \ tests/parser.h \ tests/pool.h \ @@ -60,6 +61,7 @@ tests_libmemcached_1_0_testapp_SOURCES= \ tests/libmemcached-1.0/namespace.cc \ tests/libmemcached-1.0/parser.cc \ tests/libmemcached-1.0/server_add.cc \ + tests/libmemcached-1.0/stat.cc \ tests/libmemcached-1.0/touch.cc \ tests/libmemcached-1.0/virtual_buckets.cc diff --git a/tests/libmemcached-1.0/mem_functions.cc b/tests/libmemcached-1.0/mem_functions.cc index 4127fa77..a3143893 100644 --- a/tests/libmemcached-1.0/mem_functions.cc +++ b/tests/libmemcached-1.0/mem_functions.cc @@ -79,6 +79,7 @@ #include "tests/namespace.h" #include "tests/parser.h" #include "tests/libmemcached-1.0/dump.h" +#include "tests/libmemcached-1.0/stat.h" #include "tests/touch.h" #include "tests/callbacks.h" #include "tests/pool.h" @@ -486,7 +487,7 @@ static test_return_t memcached_return_t_TEST(memcached_st *memc) { uint32_t values[] = { 851992627U, 2337886783U, 4109241422U, 4001849190U, 982370485U, 1263635348U, 4242906218U, 3829656100U, - 1891735253U, 334139633U, 2257084983U, 3088286104U, + 1891735253U, 334139633U, 2257084983U, 3351789013U, 13199785U, 2542027183U, 1097051614U, 199566778U, 2748246961U, 2465192557U, 1664094137U, 2405439045U, 1842224848U, 692413798U, 3479807801U, 919913813U, @@ -5661,6 +5662,12 @@ test_st touch_tests[] ={ {0, 0, 0} }; +test_st memcached_stat_tests[] ={ + {"memcached_stat() INVALID ARG", 0, (test_callback_fn*)memcached_stat_TEST}, + {"memcached_stat()", 0, (test_callback_fn*)memcached_stat_TEST2}, + {0, 0, 0} +}; + test_st behavior_tests[] ={ {"libmemcached_string_behavior()", false, (test_callback_fn*)libmemcached_string_behavior_test}, {"libmemcached_string_distribution()", false, (test_callback_fn*)libmemcached_string_distribution_test}, @@ -5998,6 +6005,7 @@ collection_st collection[] ={ {"memcached_server_get_last_disconnect", 0, 0, memcached_server_get_last_disconnect_tests}, {"touch", 0, 0, touch_tests}, {"touch", (test_callback_fn*)pre_binary, 0, touch_tests}, + {"memcached_stat()", 0, 0, memcached_stat_tests}, {0, 0, 0, 0} }; diff --git a/tests/libmemcached-1.0/stat.cc b/tests/libmemcached-1.0/stat.cc new file mode 100644 index 00000000..209b70a6 --- /dev/null +++ b/tests/libmemcached-1.0/stat.cc @@ -0,0 +1,109 @@ +/* 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 + +#include +#include + +#include + +#include +#include + +using namespace libtest; + +#include "tests/libmemcached-1.0/stat.h" + +static memcached_return_t item_counter(memcached_server_instance_st , + const char *key, size_t key_length, + const char *value, size_t, // value_length, + void *context) +{ + if ((key_length == (sizeof("curr_items") -1)) and (strncmp("curr_items", key, (sizeof("curr_items") -1)) == 0)) + { + uint64_t* counter= (uint64_t*)context; + unsigned long number_value= strtoul(value, (char **)NULL, 10); + if (number_value == ULONG_MAX) + { + return MEMCACHED_FAILURE; + } + *counter= *counter +number_value; + } + + return MEMCACHED_SUCCESS; +} + +test_return_t memcached_stat_TEST(memcached_st *memc) +{ + uint64_t counter= 0; + test_compare_got(MEMCACHED_INVALID_ARGUMENTS, + memcached_stat_execute(memc, "BAD_ARG_VALUE", item_counter, &counter), + memcached_last_error_message(memc)); + + return TEST_SUCCESS; +} + +#define memcached_dump_TEST2_COUNT 64 +test_return_t memcached_stat_TEST2(memcached_st *memc) +{ + test_skip(false, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); + + /* The dump test relies on there being at least 32 items in memcached */ + for (uint32_t x= 0; x < memcached_dump_TEST2_COUNT; x++) + { + char key[1024]; + + int length= snprintf(key, sizeof(key), "%s%u", __func__, x); + + test_true(length > 0); + + test_compare_hint(MEMCACHED_SUCCESS, + memcached_set(memc, key, length, + NULL, 0, // Zero length values + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); + } + memcached_quit(memc); + + uint64_t counter= 0; + test_compare_got(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, NULL, item_counter, &counter), + memcached_last_error_message(memc)); + test_true_got(counter > 0, counter); + + return TEST_SUCCESS; +} diff --git a/tests/libmemcached-1.0/stat.h b/tests/libmemcached-1.0/stat.h new file mode 100644 index 00000000..3b85ba9c --- /dev/null +++ b/tests/libmemcached-1.0/stat.h @@ -0,0 +1,40 @@ +/* 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 memcached_stat_TEST(memcached_st *); +test_return_t memcached_stat_TEST2(memcached_st *);