From: Michael Wallner Date: Tue, 15 Sep 2020 15:09:28 +0000 (+0200) Subject: testing: flush tests X-Git-Tag: 1.1.0-beta1~236^2~63 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=718975776a47a5c65c9f89010e8959103d1e3555;p=m6w6%2Flibmemcached testing: flush tests --- diff --git a/testing/lib/MemcachedCluster.cpp b/testing/lib/MemcachedCluster.cpp index efb1a2de..910aca3c 100644 --- a/testing/lib/MemcachedCluster.cpp +++ b/testing/lib/MemcachedCluster.cpp @@ -47,6 +47,19 @@ MemcachedCluster::MemcachedCluster(Cluster &&cluster_) init(); } +MemcachedCluster::MemcachedCluster(MemcachedCluster &&mc) + : cluster{Server{}} +{ + *this = move(mc); +} + +MemcachedCluster &MemcachedCluster::operator=(MemcachedCluster &&mc) { + cluster = move(mc.cluster); + memcached_clone(&memc, &mc.memc); + returns = ReturnMatcher{&memc}; + return *this; +} + MemcachedCluster MemcachedCluster::mixed() { return MemcachedCluster{}; } @@ -70,15 +83,13 @@ void MemcachedCluster::enableBinaryProto(bool enable) { MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, enable)); } -MemcachedCluster::MemcachedCluster(MemcachedCluster &&mc) - : cluster{Server{}} -{ - *this = move(mc); +void MemcachedCluster::enableBuffering(bool enable) { + REQUIRE(MEMCACHED_SUCCESS == memcached_behavior_set(&memc, + MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, enable)); } -MemcachedCluster &MemcachedCluster::operator=(MemcachedCluster &&mc) { - cluster = move(mc.cluster); - memcached_clone(&memc, &mc.memc); - returns = ReturnMatcher{&memc}; - return *this; +void MemcachedCluster::enableReplication() { + REQUIRE(MEMCACHED_SUCCESS == memcached_behavior_set(&memc, + MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, memcached_server_count(&memc))); } + diff --git a/testing/lib/MemcachedCluster.hpp b/testing/lib/MemcachedCluster.hpp index ea6aa346..ee2dfdd2 100644 --- a/testing/lib/MemcachedCluster.hpp +++ b/testing/lib/MemcachedCluster.hpp @@ -23,6 +23,8 @@ public: MemcachedCluster &operator=(MemcachedCluster &&mc); void enableBinaryProto(bool enable = true); + void enableBuffering(bool enable = true); + void enableReplication(); void flush(); static MemcachedCluster mixed(); diff --git a/testing/tests/memcached/regression/lp434484.cpp b/testing/tests/memcached/regression/lp434484.cpp new file mode 100644 index 00000000..48fd1af3 --- /dev/null +++ b/testing/tests/memcached/regression/lp434484.cpp @@ -0,0 +1,16 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +TEST_CASE("memcached_regression_lp434484") { + MemcachedCluster test; + auto memc = &test.memc; + + test.enableBinaryProto(); + + REQUIRE_RC(MEMCACHED_NOTFOUND, memcached_append(memc, S(__func__), S(__func__), 0, 0)); + + vector blob; + blob.resize(2048 * 1024); + REQUIRE_RC(MEMCACHED_E2BIG, memcached_set(memc, S(__func__), blob.data(), blob.size(), 0, 0)); + +} diff --git a/testing/tests/memcached/regression/lp434843.cpp b/testing/tests/memcached/regression/lp434843.cpp new file mode 100644 index 00000000..87f85399 --- /dev/null +++ b/testing/tests/memcached/regression/lp434843.cpp @@ -0,0 +1,48 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +static memcached_return_t callback_counter(const memcached_st *, memcached_result_st *, void *context) { + auto *counter= reinterpret_cast(context); + *counter = *counter + 1; + + return MEMCACHED_SUCCESS; +} + +#define NUM_KEYS 1024 + +TEST_CASE("memcached_regression_lp434843") { + MemcachedCluster test{Cluster{Server{MEMCACHED_BINARY, {"-p", random_port_string}}, 1}}; + auto memc = &test.memc; + auto buffering = GENERATE(0, 1); + + test.enableBinaryProto(); + test.enableBuffering(buffering); + + INFO("buffering: " << buffering); + + size_t counter = 0; + memcached_execute_fn cb[] = {&callback_counter}; + + array str; + array chr; + array len; + + for (auto i = 0; i < NUM_KEYS; ++i) { + str[i] = random_ascii_string(random_num(24, 32)); + chr[i] = str[i].data(); + len[i] = str[i].length(); + } + + REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS)); + REQUIRE_RC(MEMCACHED_NOTFOUND, memcached_fetch_execute(memc, cb, &counter, 1)); + REQUIRE(counter == 0); + + for (auto i = 0; i < NUM_KEYS; ++i) { + char data[1024]; + REQUIRE_SUCCESS(memcached_add(memc, chr[i], len[i], data, sizeof(data), 0, 0)); + } + + REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS)); + REQUIRE_SUCCESS( memcached_fetch_execute(memc, cb, &counter, 1)); + REQUIRE(counter == NUM_KEYS); +} diff --git a/testing/tests/memcached/regression/lp442914.cpp b/testing/tests/memcached/regression/lp442914.cpp new file mode 100644 index 00000000..e833f318 --- /dev/null +++ b/testing/tests/memcached/regression/lp442914.cpp @@ -0,0 +1,39 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +#include + +/* Original Comment: + * The test case isn't obvious so I should probably document why + * it works the way it does. Bug 442914 was caused by a bug + * in the logic in memcached_purge (it did not handle the case + * where the number of bytes sent was equal to the watermark). + * In this test case, create messages so that we hit that case + * and then disable noreply mode and issue a new command to + * verify that it isn't stuck. If we change the format for the + * delete command or the watermarks, we need to update this + * test.... + */ + +TEST_CASE("memcached_regression_lp442914") { + MemcachedCluster test{Cluster{Server{MEMCACHED_BINARY, {"-p", random_port_string}}, 1}}; + auto memc = &test.memc; + + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1)); + + + for (auto x = 0; x < 250; ++x) { + stringstream ss; + ss << setfill('0') << setw(250) << x; + REQUIRE_SUCCESS(memcached_delete(memc, ss.str().c_str(), ss.str().length(), 0)); + } + + stringstream key; + key << setfill('0') << setw(37) << 251; + REQUIRE_SUCCESS(memcached_delete(memc, key.str().c_str(), key.str().length(), 0)); + + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 0)); + + REQUIRE_RC(MEMCACHED_NOTFOUND, memcached_delete(memc, key.str().c_str(), key.str().length(), 0)); +} diff --git a/testing/tests/memcached/regression/lp447342.cpp b/testing/tests/memcached/regression/lp447342.cpp new file mode 100644 index 00000000..1ff33fe7 --- /dev/null +++ b/testing/tests/memcached/regression/lp447342.cpp @@ -0,0 +1,100 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +#include "libmemcached/instance.hpp" + +static memcached_return_t callback_counter(const memcached_st *, memcached_result_st *, void *context) { + auto *counter= reinterpret_cast(context); + *counter = *counter + 1; + + return MEMCACHED_SUCCESS; +} + +#define NUM_KEYS 100U + +TEST_CASE("memcached_regression_lp447342") { + auto test = MemcachedCluster::mixed(); + auto memc = &test.memc; + + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 2)); + + array str; + array chr; + array len; + + for (auto i = 0U; i < NUM_KEYS; ++i) { + str[i] = random_ascii_string(random_num(24, 32)); + chr[i] = str[i].data(); + len[i] = str[i].length(); + REQUIRE_SUCCESS(memcached_set(memc, chr[i], len[i], chr[i], len[i], 0, 0)); + } + + /* + ** We are using the qiet command to store the replicas, so we need + ** to ensure that all of them are processed before we can continue. + ** In the test we go directly from storing the object to trying to + ** receive the object from all of the different servers, so we + ** could end up in a race condition (the memcached server hasn't yet + ** processed the quiet command from the replication set when it process + ** the request from the other client (created by the clone)). As a + ** workaround for that we call memcached_quit to send the quit command + ** to the server and wait for the response ;-) If you use the test code + ** as an example for your own code, please note that you shouldn't need + ** to do this ;-) + */ + + memcached_quit(memc); + + REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS)); + + size_t counter = 0; + memcached_execute_fn cb[] = {&callback_counter}; + REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1)); + REQUIRE(counter == NUM_KEYS); + + memcached_quit(memc); + + /* + * Don't do the following in your code. I am abusing the internal details + * within the library, and this is not a supported interface. + * This is to verify correct behavior in the library. Fake that two servers + * are dead.. + */ + auto instance_one= memcached_server_instance_by_position(memc, 0); + auto instance_two= memcached_server_instance_by_position(memc, 2); + in_port_t port0= instance_one->port(); + in_port_t port2= instance_two->port(); + + const_cast(instance_one)->port(0); + const_cast(instance_two)->port(0); + + REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS)); + + counter = 0; + REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1)); + REQUIRE(counter == NUM_KEYS); + + /* restore the memc handle */ + const_cast(instance_one)->port(port0); + const_cast(instance_two)->port(port2); + + memcached_quit(memc); + + for (auto i = 0U; i < NUM_KEYS; ++i) { + if (i & 1U) { + REQUIRE_SUCCESS(memcached_delete(memc, chr[i], len[i], 0)); + } + } + + memcached_quit(memc); + + const_cast(instance_one)->port(0); + const_cast(instance_two)->port(0); + + /* now retry the command, this time we should have cache misses */ + REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS)); + + counter = 0; + REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1)); + REQUIRE(counter == NUM_KEYS>>1U); +} diff --git a/testing/tests/memcached/regression/lp490486.cpp b/testing/tests/memcached/regression/lp490486.cpp new file mode 100644 index 00000000..cc7dd9aa --- /dev/null +++ b/testing/tests/memcached/regression/lp490486.cpp @@ -0,0 +1,52 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +#define NUM_KEYS 20480U + +static memcached_return_t callback_counter(const memcached_st *, memcached_result_st *, void *context) { + auto *counter= reinterpret_cast(context); + *counter = *counter + 1; + + return MEMCACHED_SUCCESS; +} + +TEST_CASE("memcached_regression_lp490486") { + MemcachedCluster test{Cluster{Server{MEMCACHED_BINARY, {"-p", random_port_string}}, 1}}; + auto memc = &test.memc; + + test.enableBinaryProto(); + + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, 1000)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 3600)); + + array str; + array chr; + array len; + + for (auto i = 0U; i < NUM_KEYS; ++i) { + char blob[1024]; + + str[i] = random_ascii_string(36); + chr[i] = str[i].data(); + len[i] = str[i].length(); + + REQUIRE_SUCCESS(memcached_set(memc, chr[i], len[i], blob, sizeof(blob), 0, 0)); + } + + size_t counter = 0; + memcached_return_t rc; + memcached_execute_fn cb[] = {&callback_counter}; + REQUIRE_SUCCESS(memcached_mget_execute(memc, chr.data(), len.data(), NUM_KEYS, cb, &counter, 1)); + + do { + char key_buf[MEMCACHED_MAX_KEY]; + size_t key_len; + + Malloced value(memcached_fetch(memc, key_buf, &key_len, nullptr, nullptr, &rc)); + counter += !!*value; + } while(rc == MEMCACHED_SUCCESS); + + REQUIRE_RC(MEMCACHED_END, rc); + REQUIRE(counter == NUM_KEYS); +} diff --git a/testing/tests/memcached/regression/lp996813.cpp b/testing/tests/memcached/regression/lp996813.cpp new file mode 100644 index 00000000..540cb046 --- /dev/null +++ b/testing/tests/memcached/regression/lp996813.cpp @@ -0,0 +1,27 @@ +#include "testing/lib/common.hpp" +#include "testing/lib/MemcachedCluster.hpp" + +TEST_CASE("memcached_regression_lp996813") { + MemcachedPtr memc_ptr; + auto memc = *memc_ptr; + LoneReturnMatcher test{memc}; + + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, 1)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 300)); + REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 30)); + + // We will never connect to these servers + in_port_t base_port = 11211; + for (size_t x = 0; x < 17; x++) { + REQUIRE_SUCCESS(memcached_server_add(memc, "10.2.3.4", base_port + x)); + } + + REQUIRE(6U == memcached_generate_hash(memc, S("SZ6hu0SHweFmpwpc0w2R"))); + REQUIRE(1U == memcached_generate_hash(memc, S("SQCK9eiCf53YxHWnYA.o"))); + REQUIRE(9U == memcached_generate_hash(memc, S("SUSDkGXuuZC9t9VhMwa."))); + REQUIRE(0U == memcached_generate_hash(memc, S("SnnqnJARfaCNT679iAF_"))); +}