1 /* LibMemcached
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  * Summary:
9  *
10  */
11 
12 /*
13   Sample test application.
14 */
15 #include <mem_config.h>
16 
17 #include <libtest/test.hpp>
18 
19 #include <libmemcached-1.0/memcached.h>
20 
21 #include <cstdio>
22 #include <cstdlib>
23 #include <stdint.h>
24 #include <cstring>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <ctime>
30 #include <clients/generator.h>
31 #include <clients/execute.h>
32 
33 #include <libtest/server.h>
34 
35 #include <tests/debug.h>
36 
37 #include "tests/libmemcached-1.0/generate.h"
38 
39 using namespace libtest;
40 
41 /* Number of items generated for tests */
42 #define GLOBAL_COUNT 100000
43 
44 /* Number of times to run the test loop */
45 #define TEST_COUNTER 500000
46 
47 static pairs_st *global_pairs;
48 static char *global_keys[GLOBAL_COUNT];
49 static size_t global_keys_length[GLOBAL_COUNT];
50 
cleanup_pairs_TEST(memcached_st *)51 static test_return_t cleanup_pairs_TEST(memcached_st *)
52 {
53   pairs_free(global_pairs);
54 
55   return TEST_SUCCESS;
56 }
57 
generate_pairs_TEST(memcached_st *)58 static test_return_t generate_pairs_TEST(memcached_st *)
59 {
60   global_pairs= pairs_generate(GLOBAL_COUNT, 400);
61 
62   for (ptrdiff_t x= 0; x < GLOBAL_COUNT; x++)
63   {
64     global_keys[x]= global_pairs[x].key;
65     global_keys_length[x]=  global_pairs[x].key_length;
66   }
67 
68   return TEST_SUCCESS;
69 }
70 
drizzle_TEST(memcached_st * memc)71 static test_return_t drizzle_TEST(memcached_st *memc)
72 {
73 infinite:
74   for (ptrdiff_t x= 0; x < TEST_COUNTER; x++)
75   {
76     memcached_return_t rc;
77 
78     uint32_t test_bit= (uint32_t)(random() % GLOBAL_COUNT);
79     uint8_t which= (uint8_t)(random() % 2);
80 
81     if (which == 0)
82     {
83       size_t return_value_length;
84       uint32_t flags;
85       char* return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
86                                         &return_value_length, &flags, &rc);
87       if (rc == MEMCACHED_SUCCESS && return_value)
88       {
89         free(return_value);
90       }
91       else if (rc == MEMCACHED_NOTFOUND)
92       {
93         continue;
94       }
95       else
96       {
97         test_compare(MEMCACHED_SUCCESS, rc);
98       }
99     }
100     else
101     {
102       rc= memcached_set(memc, global_pairs[test_bit].key,
103                         global_pairs[test_bit].key_length,
104                         global_pairs[test_bit].value,
105                         global_pairs[test_bit].value_length,
106                         0, 0);
107       if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
108       {
109         test_compare(MEMCACHED_SUCCESS, rc);
110       }
111     }
112   }
113 
114   if (getenv("MEMCACHED_ATOM_BURIN_IN"))
115   {
116     goto infinite;
117   }
118 
119   return TEST_SUCCESS;
120 }
121 
pre_nonblock(memcached_st * memc)122 static test_return_t pre_nonblock(memcached_st *memc)
123 {
124   test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0));
125 
126   return TEST_SUCCESS;
127 }
128 
129 /*
130   Set the value, then quit to make sure it is flushed.
131   Come back in and test that add fails.
132 */
add_test(memcached_st * memc)133 static test_return_t add_test(memcached_st *memc)
134 {
135   const char *key= "foo";
136   const char *value= "when we sanitize";
137 
138   memcached_return_t rc= memcached_set(memc, key, strlen(key),
139                                        value, strlen(value),
140                                        time_t(0), uint32_t(0));
141   test_true_got(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc));
142   memcached_quit(memc);
143   rc= memcached_add(memc, key, strlen(key),
144                     value, strlen(value),
145                     (time_t)0, (uint32_t)0);
146 
147   if (rc == MEMCACHED_CONNECTION_FAILURE)
148   {
149     print_servers(memc);
150   }
151 
152   /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
153   if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK))
154   {
155     test_true(rc == MEMCACHED_NOTSTORED or rc == MEMCACHED_STORED);
156   }
157   else
158   {
159     test_compare_got(MEMCACHED_NOTSTORED, rc, memcached_strerror(NULL, rc));
160   }
161 
162   return TEST_SUCCESS;
163 }
164 
165 /*
166  * repeating add_tests many times
167  * may show a problem in timing
168  */
many_adds(memcached_st * memc)169 static test_return_t many_adds(memcached_st *memc)
170 {
171   test_true(memc);
172   for (ptrdiff_t x= 0; x < TEST_COUNTER; x++)
173   {
174     test_compare_got(TEST_SUCCESS, add_test(memc), x);
175   }
176   return TEST_SUCCESS;
177 }
178 
179 test_st smash_tests[] ={
180   {"generate_pairs", true, (test_callback_fn*)generate_pairs_TEST },
181   {"drizzle", true, (test_callback_fn*)drizzle_TEST },
182   {"cleanup", true, (test_callback_fn*)cleanup_pairs_TEST },
183   {"many_adds", true, (test_callback_fn*)many_adds },
184   {0, 0, 0}
185 };
186 
187 #define BENCHMARK_TEST_LOOP 20000
188 
189 struct benchmark_state_st
190 {
191   bool create_init;
192   bool clone_init;
193   memcached_st *create;
194   memcached_st *clone;
195 } benchmark_state;
196 
memcached_create_benchmark(memcached_st *)197 static test_return_t memcached_create_benchmark(memcached_st *)
198 {
199   benchmark_state.create_init= true;
200 
201   for (ptrdiff_t x= 0; x < BENCHMARK_TEST_LOOP; x++)
202   {
203     memcached_st *ptr= memcached_create(&benchmark_state.create[x]);
204 
205     test_true(ptr);
206   }
207 
208   return TEST_SUCCESS;
209 }
210 
memcached_clone_benchmark(memcached_st * memc)211 static test_return_t memcached_clone_benchmark(memcached_st *memc)
212 {
213   benchmark_state.clone_init= true;
214 
215   for (ptrdiff_t x= 0; x < BENCHMARK_TEST_LOOP; x++)
216   {
217     memcached_st *ptr= memcached_clone(&benchmark_state.clone[x], memc);
218 
219     test_true(ptr);
220   }
221 
222   return TEST_SUCCESS;
223 }
224 
pre_allocate(memcached_st *)225 static test_return_t pre_allocate(memcached_st *)
226 {
227   memset(&benchmark_state, 0, sizeof(benchmark_state));
228 
229   benchmark_state.create= (memcached_st *)calloc(BENCHMARK_TEST_LOOP, sizeof(memcached_st));
230   test_true(benchmark_state.create);
231   benchmark_state.clone= (memcached_st *)calloc(BENCHMARK_TEST_LOOP, sizeof(memcached_st));
232   test_true(benchmark_state.clone);
233 
234   return TEST_SUCCESS;
235 }
236 
post_allocate(memcached_st *)237 static test_return_t post_allocate(memcached_st *)
238 {
239   for (ptrdiff_t x= 0; x < BENCHMARK_TEST_LOOP; x++)
240   {
241     if (benchmark_state.create_init)
242     {
243       memcached_free(&benchmark_state.create[x]);
244     }
245 
246     if (benchmark_state.clone_init)
247     {
248       memcached_free(&benchmark_state.clone[x]);
249     }
250   }
251 
252   free(benchmark_state.create);
253   free(benchmark_state.clone);
254 
255   return TEST_SUCCESS;
256 }
257 
258 
259 test_st micro_tests[] ={
260   {"memcached_create", 1, (test_callback_fn*)memcached_create_benchmark },
261   {"memcached_clone", 1, (test_callback_fn*)memcached_clone_benchmark },
262   {0, 0, 0}
263 };
264 
265 
266 collection_st collection[] ={
267   {"smash", 0, 0, smash_tests},
268   {"smash_nonblock", (test_callback_fn*)pre_nonblock, 0, smash_tests},
269   {"micro-benchmark", (test_callback_fn*)pre_allocate, (test_callback_fn*)post_allocate, micro_tests},
270   {0, 0, 0, 0}
271 };
272 
273 
274 #include "tests/libmemcached_world.h"
275 
get_world(libtest::Framework * world)276 void get_world(libtest::Framework* world)
277 {
278   world->collections(collection);
279 
280   world->create((test_callback_create_fn*)world_create);
281   world->destroy((test_callback_destroy_fn*)world_destroy);
282 
283   world->set_runner(new LibmemcachedRunner);
284 }
285