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