1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 * Gearmand client and server library.
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include <libtest/test.hpp>
41 #include "libmemcached/common.h"
42 #include <tests/replication.h>
44 test_return_t
replication_set_test(memcached_st
*memc
)
46 memcached_return_t rc
;
47 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
48 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 0);
50 rc
= memcached_set(memc
, "bubba", 5, "0", 1, 0, 0);
51 test_true(rc
== MEMCACHED_SUCCESS
);
54 ** We are using the quiet commands to store the replicas, so we need
55 ** to ensure that all of them are processed before we can continue.
56 ** In the test we go directly from storing the object to trying to
57 ** receive the object from all of the different servers, so we
58 ** could end up in a race condition (the memcached server hasn't yet
59 ** processed the quiet command from the replication set when it process
60 ** the request from the other client (created by the clone)). As a
61 ** workaround for that we call memcached_quit to send the quit command
62 ** to the server and wait for the response ;-) If you use the test code
63 ** as an example for your own code, please note that you shouldn't need
69 ** "bubba" should now be stored on all of our servers. We don't have an
70 ** easy to use API to address each individual server, so I'll just iterate
71 ** through a bunch of "master keys" and I should most likely hit all of the
74 for (int x
= 'a'; x
<= 'z'; ++x
)
76 const char key
[2]= { (char)x
, 0 };
79 char *val
= memcached_get_by_key(memc_clone
, key
, 1, "bubba", 5,
81 test_true(rc
== MEMCACHED_SUCCESS
);
82 test_true(val
!= NULL
);
86 memcached_free(memc_clone
);
91 test_return_t
replication_get_test(memcached_st
*memc
)
93 memcached_return_t rc
;
96 * Don't do the following in your code. I am abusing the internal details
97 * within the library, and this is not a supported interface.
98 * This is to verify correct behavior in the library
100 for (uint32_t host
= 0; host
< memcached_server_count(memc
); ++host
)
102 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
103 memcached_server_instance_st instance
=
104 memcached_server_instance_by_position(memc_clone
, host
);
106 ((memcached_server_write_instance_st
)instance
)->port
= 0;
108 for (int x
= 'a'; x
<= 'z'; ++x
)
110 const char key
[2]= { (char)x
, 0 };
113 char *val
= memcached_get_by_key(memc_clone
, key
, 1, "bubba", 5,
115 test_true(rc
== MEMCACHED_SUCCESS
);
116 test_true(val
!= NULL
);
120 memcached_free(memc_clone
);
126 test_return_t
replication_mget_test(memcached_st
*memc
)
128 memcached_return_t rc
;
129 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
130 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 0);
132 const char *keys
[]= { "bubba", "key1", "key2", "key3" };
133 size_t len
[]= { 5, 4, 4, 4 };
135 for (size_t x
= 0; x
< 4; ++x
)
137 rc
= memcached_set(memc
, keys
[x
], len
[x
], "0", 1, 0, 0);
138 test_true(rc
== MEMCACHED_SUCCESS
);
142 ** We are using the quiet commands to store the replicas, so we need
143 ** to ensure that all of them are processed before we can continue.
144 ** In the test we go directly from storing the object to trying to
145 ** receive the object from all of the different servers, so we
146 ** could end up in a race condition (the memcached server hasn't yet
147 ** processed the quiet command from the replication set when it process
148 ** the request from the other client (created by the clone)). As a
149 ** workaround for that we call memcached_quit to send the quit command
150 ** to the server and wait for the response ;-) If you use the test code
151 ** as an example for your own code, please note that you shouldn't need
154 memcached_quit(memc
);
157 * Don't do the following in your code. I am abusing the internal details
158 * within the library, and this is not a supported interface.
159 * This is to verify correct behavior in the library
161 memcached_result_st result_obj
;
162 for (uint32_t host
= 0; host
< memc_clone
->number_of_hosts
; host
++)
164 memcached_st
*new_clone
= memcached_clone(NULL
, memc
);
165 memcached_server_instance_st instance
=
166 memcached_server_instance_by_position(new_clone
, host
);
167 ((memcached_server_write_instance_st
)instance
)->port
= 0;
169 for (int x
= 'a'; x
<= 'z'; ++x
)
171 char key
[2]= { (char)x
, 0 };
173 rc
= memcached_mget_by_key(new_clone
, key
, 1, keys
, len
, 4);
174 test_true(rc
== MEMCACHED_SUCCESS
);
176 memcached_result_st
*results
= memcached_result_create(new_clone
, &result_obj
);
180 while ((results
= memcached_fetch_result(new_clone
, &result_obj
, &rc
)) != NULL
)
184 test_true(hits
== 4);
185 memcached_result_free(&result_obj
);
188 memcached_free(new_clone
);
191 memcached_free(memc_clone
);
196 test_return_t
replication_randomize_mget_test(memcached_st
*memc
)
198 memcached_result_st result_obj
;
199 memcached_return_t rc
;
200 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
201 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 3);
202 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
, 1);
204 const char *keys
[]= { "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
205 size_t len
[]= { 4, 4, 4, 4, 4, 4, 4 };
207 for (size_t x
= 0; x
< 7; ++x
)
209 rc
= memcached_set(memc
, keys
[x
], len
[x
], "1", 1, 0, 0);
210 test_true(rc
== MEMCACHED_SUCCESS
);
213 memcached_quit(memc
);
215 for (size_t x
= 0; x
< 7; ++x
)
217 const char key
[2]= { (char)x
, 0 };
219 rc
= memcached_mget_by_key(memc_clone
, key
, 1, keys
, len
, 7);
220 test_true(rc
== MEMCACHED_SUCCESS
);
222 memcached_result_st
*results
= memcached_result_create(memc_clone
, &result_obj
);
226 while ((results
= memcached_fetch_result(memc_clone
, &result_obj
, &rc
)) != NULL
)
230 test_true(hits
== 7);
231 memcached_result_free(&result_obj
);
233 memcached_free(memc_clone
);
237 test_return_t
replication_delete_test(memcached_st
*memc
)
239 memcached_return_t rc
;
240 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
241 /* Delete the items from all of the servers except 1 */
242 uint64_t repl
= memcached_behavior_get(memc
,
243 MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
);
244 memcached_behavior_set(memc
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, --repl
);
246 const char *keys
[]= { "bubba", "key1", "key2", "key3" };
247 size_t len
[]= { 5, 4, 4, 4 };
249 for (size_t x
= 0; x
< 4; ++x
)
251 rc
= memcached_delete_by_key(memc
, keys
[0], len
[0], keys
[x
], len
[x
], 0);
252 test_true(rc
== MEMCACHED_SUCCESS
);
256 * Don't do the following in your code. I am abusing the internal details
257 * within the library, and this is not a supported interface.
258 * This is to verify correct behavior in the library
260 uint32_t hash
= memcached_generate_hash(memc
, keys
[0], len
[0]);
261 for (uint32_t x
= 0; x
< (repl
+ 1); ++x
)
263 memcached_server_instance_st instance
=
264 memcached_server_instance_by_position(memc_clone
, x
);
266 ((memcached_server_write_instance_st
)instance
)->port
= 0;
267 if (++hash
== memc_clone
->number_of_hosts
)
271 memcached_result_st result_obj
;
272 for (uint32_t host
= 0; host
< memc_clone
->number_of_hosts
; ++host
)
274 for (size_t x
= 'a'; x
<= 'z'; ++x
)
276 const char key
[2]= { (char)x
, 0 };
278 rc
= memcached_mget_by_key(memc_clone
, key
, 1, keys
, len
, 4);
279 test_true(rc
== MEMCACHED_SUCCESS
);
281 memcached_result_st
*results
= memcached_result_create(memc_clone
, &result_obj
);
285 while ((results
= memcached_fetch_result(memc_clone
, &result_obj
, &rc
)) != NULL
)
289 test_true(hits
== 4);
290 memcached_result_free(&result_obj
);
293 memcached_free(memc_clone
);
298 test_return_t
replication_randomize_mget_fail_test(memcached_st
*memc
)
300 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
301 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 3);
303 for (int x
= int(MEMCACHED_SUCCESS
); x
< int(MEMCACHED_MAXIMUM_RETURN
); ++x
)
305 const char *key
= memcached_strerror(NULL
, memcached_return_t(x
));
306 memcached_return_t rc
= memcached_set(memc
,
308 key
, strlen(key
), 0, 0);
309 test_true(rc
== MEMCACHED_SUCCESS
);
312 memcached_flush_buffers(memc
);
314 // We need to now cause a failure in one server, never do this in your own
316 close(memc_clone
->servers
[1].fd
);
317 memc_clone
->servers
[1].port
= 1;
318 memc_clone
->servers
[1].address_info_next
= NULL
;
320 for (int x
= int(MEMCACHED_SUCCESS
); x
< int(MEMCACHED_MAXIMUM_RETURN
); ++x
)
322 const char *key
= memcached_strerror(NULL
, memcached_return_t(x
));
323 memcached_return_t rc
;
326 char *value
= memcached_get(memc_clone
, key
, strlen(key
), &value_length
, &flags
, &rc
);
327 test_true(rc
== MEMCACHED_SUCCESS
);
328 test_compare(strlen(key
), value_length
);
329 test_strcmp(key
, value
);
332 memcached_free(memc_clone
);