testing: let retry's sleeping duration grow faster
[awesomized/libmemcached] / test / tests / memcached / regression / lp_000-447-342.cpp
1 #include "test/lib/common.hpp"
2 #include "test/lib/MemcachedCluster.hpp"
3 #include "test/fixtures/callbacks.hpp"
4 #include "libmemcached/instance.hpp"
5
6 #define NUM_KEYS 100U
7
8 TEST_CASE("memcached_regression_lp447342") {
9 auto test = MemcachedCluster::network();
10 auto memc = &test.memc;
11
12 REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 2));
13
14 array<string, NUM_KEYS> str;
15 array<char *, NUM_KEYS> chr;
16 array<size_t, NUM_KEYS> len;
17
18 for (auto i = 0U; i < NUM_KEYS; ++i) {
19 str[i] = random_ascii_string(random_num(12, 16)) + to_string(i);
20 chr[i] = str[i].data();
21 len[i] = str[i].length();
22 REQUIRE_SUCCESS(memcached_set(memc, chr[i], len[i], chr[i], len[i], 0, 0));
23 }
24
25 /*
26 ** We are using the quit command to store the replicas, so we need
27 ** to ensure that all of them are processed before we can continue.
28 ** In the test we go directly from storing the object to trying to
29 ** receive the object from all of the different servers, so we
30 ** could end up in a race condition (the memcached server hasn't yet
31 ** processed the quiet command from the replication set when it process
32 ** the request from the other client (created by the clone)). As a
33 ** workaround for that we call memcached_quit to send the quit command
34 ** to the server and wait for the response ;-) If you use the test code
35 ** as an example for your own code, please note that you shouldn't need
36 ** to do this ;-)
37 */
38
39 memcached_quit(memc);
40
41 REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS));
42
43 size_t counter = 0;
44 memcached_execute_fn cb[] = {&callback_counter};
45 REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1));
46 REQUIRE(counter == NUM_KEYS);
47
48 memcached_quit(memc);
49
50 /*
51 * Don't do the following in your code. I am abusing the internal details
52 * within the library, and this is not a supported interface.
53 * This is to verify correct behavior in the library. Fake that two servers
54 * are dead..
55 */
56 auto instance_one= memcached_server_instance_by_position(memc, 0);
57 auto instance_two= memcached_server_instance_by_position(memc, 2);
58 in_port_t port0= instance_one->port();
59 in_port_t port2= instance_two->port();
60
61 const_cast<memcached_instance_st*>(instance_one)->port(0);
62 const_cast<memcached_instance_st*>(instance_two)->port(0);
63
64 REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS));
65
66 counter = 0;
67 REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1));
68 REQUIRE(counter == NUM_KEYS);
69
70 /* restore the memc handle */
71 const_cast<memcached_instance_st*>(instance_one)->port(port0);
72 const_cast<memcached_instance_st*>(instance_two)->port(port2);
73
74 memcached_quit(memc);
75
76 for (auto i = 0U; i < NUM_KEYS; ++i) {
77 if (i & 1U) {
78 REQUIRE_SUCCESS(memcached_delete(memc, chr[i], len[i], 0));
79 }
80 }
81
82 memcached_quit(memc);
83
84 const_cast<memcached_instance_st*>(instance_one)->port(0);
85 const_cast<memcached_instance_st*>(instance_two)->port(0);
86
87 /* now retry the command, this time we should have cache misses */
88 REQUIRE_SUCCESS(memcached_mget(memc, chr.data(), len.data(), NUM_KEYS));
89
90 counter = 0;
91 REQUIRE_SUCCESS(memcached_fetch_execute(memc, cb, &counter, 1));
92 REQUIRE(counter == NUM_KEYS>>1U);
93 }