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