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