Merge in trunk. Updates to manual/update to latest libtest.
[awesomized/libmemcached] / tests / mem_udp.cc
1 /* libMemcached Functions Test
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 */
8
9 /*
10 Sample test application.
11 */
12
13 #include "config.h"
14
15 #include "libmemcached/common.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <signal.h>
26 #include <unistd.h>
27 #include <time.h>
28
29 #include <libtest/server.h>
30 #include <libtest/test.hpp>
31
32 #define SERVERS_TO_CREATE 5
33
34 #ifndef __INTEL_COMPILER
35 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
36 #endif
37
38 /**
39 @note This should be testing to see if the server really supports the binary protocol.
40 */
41 static test_return_t pre_binary(memcached_st *memc)
42 {
43 memcached_return_t rc= MEMCACHED_FAILURE;
44 memcached_st *memc_clone;
45 memcached_server_instance_st instance;
46
47 memc_clone= memcached_clone(NULL, memc);
48 test_true(memc_clone);
49 // The memcached_version needs to be done on a clone, because the server
50 // will not toggle protocol on an connection.
51 memcached_version(memc_clone);
52
53 instance= memcached_server_instance_by_position(memc_clone, 0);
54
55 if (instance->major_version >= 1 && instance->minor_version > 2)
56 {
57 rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
58 test_true(rc == MEMCACHED_SUCCESS);
59 test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
60 }
61
62 memcached_free(memc_clone);
63
64 return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED;
65 }
66
67 static void increment_request_id(uint16_t *id)
68 {
69 (*id)++;
70 if ((*id & UDP_REQUEST_ID_THREAD_MASK) != 0)
71 *id= 0;
72 }
73
74 static uint16_t *get_udp_request_ids(memcached_st *memc)
75 {
76 uint16_t *ids= (uint16_t*)malloc(sizeof(uint16_t) * memcached_server_count(memc));
77 assert(ids);
78
79 for (uint32_t x= 0; x < memcached_server_count(memc); x++)
80 {
81 memcached_server_instance_st instance=
82 memcached_server_instance_by_position(memc, x);
83
84 ids[x]= get_udp_datagram_request_id((struct udp_datagram_header_st *) ((memcached_server_instance_st )instance)->write_buffer);
85 }
86
87 return ids;
88 }
89
90 static test_return_t post_udp_op_check(memcached_st *memc, uint16_t *expected_req_ids)
91 {
92 (void)memc;
93 (void)expected_req_ids;
94 #if 0
95 memcached_server_st *cur_server = memcached_server_list(memc);
96 uint16_t *cur_req_ids = get_udp_request_ids(memc);
97
98 for (size_t x= 0; x < memcached_server_count(memc); x++)
99 {
100 test_true(cur_server[x].cursor_active == 0);
101 test_true(cur_req_ids[x] == expected_req_ids[x]);
102 }
103 free(expected_req_ids);
104 free(cur_req_ids);
105
106 #endif
107 return TEST_SUCCESS;
108 }
109
110 /*
111 ** There is a little bit of a hack here, instead of removing
112 ** the servers, I just set num host to 0 and them add then new udp servers
113 **/
114 static test_return_t init_udp(memcached_st *memc)
115 {
116 memcached_version(memc);
117 #if 0
118 memcached_server_instance_st instance=
119 memcached_server_instance_by_position(memc, 0);
120
121 /* For the time being, only support udp test for >= 1.2.6 && < 1.3 */
122 if (instance->major_version != 1 || instance->minor_version != 2
123 || instance->micro_version < 6)
124 return TEST_SKIPPED;
125
126 uint32_t num_hosts= memcached_server_count(memc);
127 memcached_server_st servers[num_hosts];
128 memcpy(servers, memcached_server_list(memc), sizeof(memcached_server_st) * num_hosts);
129 for (uint32_t x= 0; x < num_hosts; x++)
130 {
131 memcached_server_instance_st set_instance=
132 memcached_server_instance_by_position(memc, x);
133
134 memcached_server_free(((memcached_server_write_instance_st)set_instance));
135 }
136
137 memc->number_of_hosts= 0;
138 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1);
139 for (uint32_t x= 0; x < num_hosts; x++)
140 {
141 memcached_server_instance_st set_instance=
142 memcached_server_instance_by_position(memc, x);
143
144 test_true(memcached_server_add_udp(memc, servers[x].hostname, servers[x].port) == MEMCACHED_SUCCESS);
145 test_true(set_instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
146 }
147 #endif
148
149 return TEST_SKIPPED;
150 }
151
152 static test_return_t binary_init_udp(memcached_st *memc)
153 {
154 test_return_t test_rc;
155 test_rc= pre_binary(memc);
156
157 if (test_rc != TEST_SUCCESS)
158 return test_rc;
159
160 return init_udp(memc);
161 }
162
163 /* Make sure that I cant add a tcp server to a udp client */
164 static test_return_t add_tcp_server_udp_client_test(memcached_st *memc)
165 {
166 (void)memc;
167 #if 0
168 memcached_server_st server;
169 memcached_server_instance_st instance=
170 memcached_server_instance_by_position(memc, 0);
171 memcached_server_clone(&server, &memc->hosts[0]);
172 test_true(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
173 test_true(memcached_server_add(memc, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
174 #endif
175 return TEST_SUCCESS;
176 }
177
178 /* Make sure that I cant add a udp server to a tcp client */
179 static test_return_t add_udp_server_tcp_client_test(memcached_st *memc)
180 {
181 (void)memc;
182 #if 0
183 memcached_server_st server;
184 memcached_server_instance_st instance=
185 memcached_server_instance_by_position(memc, 0);
186 memcached_server_clone(&server, &memc->hosts[0]);
187 test_true(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
188
189 memcached_st tcp_client;
190 memcached_create(&tcp_client);
191 test_true(memcached_server_add_udp(&tcp_client, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
192 #endif
193
194 return TEST_SUCCESS;
195 }
196
197 static test_return_t set_udp_behavior_test(memcached_st *memc)
198 {
199
200 memcached_quit(memc);
201 memc->number_of_hosts= 0;
202 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, memc->distribution);
203 test_true(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1) == MEMCACHED_SUCCESS);
204 test_true(memc->flags.use_udp);
205 test_true(memc->flags.no_reply);
206
207 test_true(memcached_server_count(memc) == 0);
208
209 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,0);
210 test_true(! (memc->flags.use_udp));
211 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY,0);
212 test_true(! (memc->flags.no_reply));
213
214 return TEST_SUCCESS;
215 }
216
217 static test_return_t udp_set_test(memcached_st *memc)
218 {
219 unsigned int num_iters= 1025; //request id rolls over at 1024
220
221 for (size_t x= 0; x < num_iters;x++)
222 {
223 memcached_return_t rc;
224 const char *key= "foo";
225 const char *value= "when we sanitize";
226 uint16_t *expected_ids= get_udp_request_ids(memc);
227 unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
228 memcached_server_instance_st instance=
229 memcached_server_instance_by_position(memc, server_key);
230 size_t init_offset= instance->write_buffer_offset;
231
232 rc= memcached_set(memc, key, strlen(key),
233 value, strlen(value),
234 (time_t)0, (uint32_t)0);
235 test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
236 /** NB, the check below assumes that if new write_ptr is less than
237 * the original write_ptr that we have flushed. For large payloads, this
238 * maybe an invalid assumption, but for the small payload we have it is OK
239 */
240 if (rc == MEMCACHED_SUCCESS ||
241 instance->write_buffer_offset < init_offset)
242 increment_request_id(&expected_ids[server_key]);
243
244 if (rc == MEMCACHED_SUCCESS)
245 {
246 test_true(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
247 }
248 else
249 {
250 test_true(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
251 test_true(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
252 }
253 test_true(post_udp_op_check(memc, expected_ids) == TEST_SUCCESS);
254 }
255 return TEST_SUCCESS;
256 }
257
258 static test_return_t udp_buffered_set_test(memcached_st *memc)
259 {
260 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
261 return udp_set_test(memc);
262 }
263
264 static test_return_t udp_set_too_big_test(memcached_st *memc)
265 {
266 memcached_return_t rc;
267 const char *key= "bar";
268 char value[MAX_UDP_DATAGRAM_LENGTH];
269 uint16_t *expected_ids= get_udp_request_ids(memc);
270 rc= memcached_set(memc, key, strlen(key),
271 value, MAX_UDP_DATAGRAM_LENGTH,
272 (time_t)0, (uint32_t)0);
273 test_true(rc == MEMCACHED_WRITE_FAILURE);
274
275 return post_udp_op_check(memc,expected_ids);
276 }
277
278 static test_return_t udp_delete_test(memcached_st *memc)
279 {
280 unsigned int num_iters= 1025; //request id rolls over at 1024
281
282 for (size_t x= 0; x < num_iters;x++)
283 {
284 memcached_return_t rc;
285 const char *key= "foo";
286 uint16_t *expected_ids=get_udp_request_ids(memc);
287 unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
288 memcached_server_instance_st instance=
289 memcached_server_instance_by_position(memc, server_key);
290 size_t init_offset= instance->write_buffer_offset;
291
292 rc= memcached_delete(memc, key, strlen(key), 0);
293 test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
294
295 if (rc == MEMCACHED_SUCCESS || instance->write_buffer_offset < init_offset)
296 increment_request_id(&expected_ids[server_key]);
297 if (rc == MEMCACHED_SUCCESS)
298 {
299 test_true(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
300 }
301 else
302 {
303 test_true(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
304 test_true(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
305 }
306 test_true(post_udp_op_check(memc,expected_ids) == TEST_SUCCESS);
307 }
308 return TEST_SUCCESS;
309 }
310
311 static test_return_t udp_buffered_delete_test(memcached_st *memc)
312 {
313 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
314 return udp_delete_test(memc);
315 }
316
317 static test_return_t udp_verbosity_test(memcached_st *memc)
318 {
319 memcached_return_t rc;
320 uint16_t *expected_ids= get_udp_request_ids(memc);
321
322 for (size_t x= 0; x < memcached_server_count(memc); x++)
323 {
324 increment_request_id(&expected_ids[x]);
325 }
326
327 rc= memcached_verbosity(memc,3);
328 test_true(rc == MEMCACHED_SUCCESS);
329 return post_udp_op_check(memc,expected_ids);
330 }
331
332 static test_return_t udp_quit_test(memcached_st *memc)
333 {
334 uint16_t *expected_ids= get_udp_request_ids(memc);
335 memcached_quit(memc);
336 return post_udp_op_check(memc, expected_ids);
337 }
338
339 static test_return_t udp_flush_test(memcached_st *memc)
340 {
341 memcached_return_t rc;
342 uint16_t *expected_ids= get_udp_request_ids(memc);
343
344 for (size_t x= 0; x < memcached_server_count(memc); x++)
345 {
346 increment_request_id(&expected_ids[x]);
347 }
348
349 rc= memcached_flush(memc,0);
350 test_true(rc == MEMCACHED_SUCCESS);
351 return post_udp_op_check(memc,expected_ids);
352 }
353
354 static test_return_t udp_incr_test(memcached_st *memc)
355 {
356 memcached_return_t rc;
357 const char *key= "incr";
358 const char *value= "1";
359 rc= memcached_set(memc, key, strlen(key),
360 value, strlen(value),
361 (time_t)0, (uint32_t)0);
362
363 test_true(rc == MEMCACHED_SUCCESS);
364 uint16_t *expected_ids= get_udp_request_ids(memc);
365 unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
366 increment_request_id(&expected_ids[server_key]);
367 uint64_t newvalue;
368 rc= memcached_increment(memc, key, strlen(key), 1, &newvalue);
369 test_true(rc == MEMCACHED_SUCCESS);
370 return post_udp_op_check(memc, expected_ids);
371 }
372
373 static test_return_t udp_decr_test(memcached_st *memc)
374 {
375 memcached_return_t rc;
376 const char *key= "decr";
377 const char *value= "1";
378 rc= memcached_set(memc, key, strlen(key),
379 value, strlen(value),
380 (time_t)0, (uint32_t)0);
381
382 test_true(rc == MEMCACHED_SUCCESS);
383 uint16_t *expected_ids= get_udp_request_ids(memc);
384 unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
385 increment_request_id(&expected_ids[server_key]);
386 uint64_t newvalue;
387 rc= memcached_decrement(memc, key, strlen(key), 1, &newvalue);
388 test_true(rc == MEMCACHED_SUCCESS);
389 return post_udp_op_check(memc, expected_ids);
390 }
391
392
393 static test_return_t udp_stat_test(memcached_st *memc)
394 {
395 memcached_stat_st * rv= NULL;
396 memcached_return_t rc;
397 char args[]= "";
398 uint16_t *expected_ids = get_udp_request_ids(memc);
399 rv = memcached_stat(memc, args, &rc);
400 free(rv);
401 test_true(rc == MEMCACHED_NOT_SUPPORTED);
402 return post_udp_op_check(memc, expected_ids);
403 }
404
405 static test_return_t udp_version_test(memcached_st *memc)
406 {
407 memcached_return_t rc;
408 uint16_t *expected_ids = get_udp_request_ids(memc);
409 rc = memcached_version(memc);
410 test_true(rc == MEMCACHED_NOT_SUPPORTED);
411 return post_udp_op_check(memc, expected_ids);
412 }
413
414 static test_return_t udp_get_test(memcached_st *memc)
415 {
416 memcached_return_t rc;
417 const char *key= "foo";
418 size_t vlen;
419 uint16_t *expected_ids = get_udp_request_ids(memc);
420 char *val= memcached_get(memc, key, strlen(key), &vlen, (uint32_t)0, &rc);
421 test_true(rc == MEMCACHED_NOT_SUPPORTED);
422 test_true(val == NULL);
423 return post_udp_op_check(memc, expected_ids);
424 }
425
426 static test_return_t udp_mixed_io_test(memcached_st *memc)
427 {
428 test_st current_op;
429 test_st mixed_io_ops [] ={
430 {"udp_set_test", 0,
431 (test_callback_fn*)udp_set_test},
432 {"udp_set_too_big_test", 0,
433 (test_callback_fn*)udp_set_too_big_test},
434 {"udp_delete_test", 0,
435 (test_callback_fn*)udp_delete_test},
436 {"udp_verbosity_test", 0,
437 (test_callback_fn*)udp_verbosity_test},
438 {"udp_quit_test", 0,
439 (test_callback_fn*)udp_quit_test},
440 {"udp_flush_test", 0,
441 (test_callback_fn*)udp_flush_test},
442 {"udp_incr_test", 0,
443 (test_callback_fn*)udp_incr_test},
444 {"udp_decr_test", 0,
445 (test_callback_fn*)udp_decr_test},
446 {"udp_version_test", 0,
447 (test_callback_fn*)udp_version_test}
448 };
449
450 for (size_t x= 0; x < 500; x++)
451 {
452 current_op= mixed_io_ops[random() % 9];
453 test_true(current_op.test_fn(memc) == TEST_SUCCESS);
454 }
455 return TEST_SUCCESS;
456 }
457
458 test_st udp_setup_server_tests[] ={
459 {"set_udp_behavior_test", 0, (test_callback_fn*)set_udp_behavior_test},
460 {"add_tcp_server_udp_client_test", 0, (test_callback_fn*)add_tcp_server_udp_client_test},
461 {"add_udp_server_tcp_client_test", 0, (test_callback_fn*)add_udp_server_tcp_client_test},
462 {0, 0, 0}
463 };
464
465 test_st upd_io_tests[] ={
466 {"udp_set_test", 0, (test_callback_fn*)udp_set_test},
467 {"udp_buffered_set_test", 0, (test_callback_fn*)udp_buffered_set_test},
468 {"udp_set_too_big_test", 0, (test_callback_fn*)udp_set_too_big_test},
469 {"udp_delete_test", 0, (test_callback_fn*)udp_delete_test},
470 {"udp_buffered_delete_test", 0, (test_callback_fn*)udp_buffered_delete_test},
471 {"udp_verbosity_test", 0, (test_callback_fn*)udp_verbosity_test},
472 {"udp_quit_test", 0, (test_callback_fn*)udp_quit_test},
473 {"udp_flush_test", 0, (test_callback_fn*)udp_flush_test},
474 {"udp_incr_test", 0, (test_callback_fn*)udp_incr_test},
475 {"udp_decr_test", 0, (test_callback_fn*)udp_decr_test},
476 {"udp_stat_test", 0, (test_callback_fn*)udp_stat_test},
477 {"udp_version_test", 0, (test_callback_fn*)udp_version_test},
478 {"udp_get_test", 0, (test_callback_fn*)udp_get_test},
479 {"udp_mixed_io_test", 0, (test_callback_fn*)udp_mixed_io_test},
480 {0, 0, 0}
481 };
482
483 collection_st collection[] ={
484 {"udp_setup", (test_callback_fn*)init_udp, 0, udp_setup_server_tests},
485 {"udp_io", (test_callback_fn*)init_udp, 0, upd_io_tests},
486 {"udp_binary_io", (test_callback_fn*)binary_init_udp, 0, upd_io_tests},
487 {0, 0, 0, 0}
488 };
489
490 #define SERVERS_TO_CREATE 5
491
492 #include "libmemcached_world.h"
493
494 void get_world(Framework *world)
495 {
496 world->collections= collection;
497
498 world->_create= (test_callback_create_fn*)world_create;
499 world->_destroy= (test_callback_fn*)world_destroy;
500
501 world->item._startup= (test_callback_fn*)world_test_startup;
502 world->item._flush= (test_callback_fn*)world_flush;
503 world->item.set_pre((test_callback_fn*)world_pre_run);
504 world->item.set_post((test_callback_fn*)world_post_run);
505 world->_on_error= (test_callback_error_fn*)world_on_error;
506
507 world->collection_startup= (test_callback_fn*)world_container_startup;
508 world->collection_shutdown= (test_callback_fn*)world_container_shutdown;
509
510 world->runner= &defualt_libmemcached_runner;
511 }