1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "testutil.h"
18 #include "apr.h"
19 #include "apu.h"
20 #include "apr_general.h"
21 #include "apr_strings.h"
22 #include "apr_hash.h"
23 #include "apr_memcache.h"
24 #include "apr_network_io.h"
25 
26 #if APR_HAVE_STDLIB_H
27 #include <stdlib.h>		/* for exit() */
28 #endif
29 
30 #define HOST "localhost"
31 #define PORT 11211
32 
33 /* the total number of items to use for set/get testing */
34 #define TDATA_SIZE 3000
35 
36 /* some smaller subset of TDATA_SIZE used for multiget testing */
37 #define TDATA_SET 100
38 
39 /* our custom hash function just returns this all the time */
40 #define HASH_FUNC_RESULT 510
41 
42 /* all keys will be prefixed with this */
43 const char prefix[] = "testmemcache";
44 
45 /* text for values we store */
46 const char txt[] =
47 "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at"
48 "lacus in ligula hendrerit consectetuer. Vestibulum tristique odio"
49 "iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non,"
50 "neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum"
51 "nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat"
52 "tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis"
53 "tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in,"
54 "convallis id, iaculis feugiat cras amet.";
55 
56 /*
57  * this datatype is for our custom server determination function. this might
58  * be useful if you don't want to rely on simply hashing keys to determine
59  * where a key belongs, but instead want to write something fancy, or use some
60  * other kind of configuration data, i.e. a hash plus some data about a
61  * namespace, or whatever. see my_server_func, and test_memcache_user_funcs
62  * for the examples.
63  */
64 typedef struct {
65   const char *someval;
66   apr_uint32_t which_server;
67 } my_hash_server_baton;
68 
69 
70 /* this could do something fancy and return some hash result.
71  * for simplicity, just return the same value, so we can test it later on.
72  * if you wanted to use some external hashing library or functions for
73  * consistent hashing, for example, this would be a good place to do it.
74  */
my_hash_func(void * baton,const char * data,apr_size_t data_len)75 static apr_uint32_t my_hash_func(void *baton, const char *data,
76                                  apr_size_t data_len)
77 {
78 
79   return HASH_FUNC_RESULT;
80 }
81 
82 /*
83  * a fancy function to determine which server to use given some kind of data
84  * and a hash value. this example actually ignores the hash value itself
85  * and pulls some number from the *baton, which is a struct that has some
86  * kind of meaningful stuff in it.
87  */
my_server_func(void * baton,apr_memcache_t * mc,const apr_uint32_t hash)88 static apr_memcache_server_t *my_server_func(void *baton,
89                                              apr_memcache_t *mc,
90                                              const apr_uint32_t hash)
91 {
92   apr_memcache_server_t *ms = NULL;
93   my_hash_server_baton *mhsb = (my_hash_server_baton *)baton;
94 
95   if(mc->ntotal == 0) {
96     return NULL;
97   }
98 
99   if(mc->ntotal < mhsb->which_server) {
100     return NULL;
101   }
102 
103   ms = mc->live_servers[mhsb->which_server - 1];
104 
105   return ms;
106 }
107 
108 apr_uint16_t firsttime = 0;
randval(apr_uint32_t high)109 static int randval(apr_uint32_t high)
110 {
111     apr_uint32_t i = 0;
112     double d = 0;
113 
114     if (firsttime == 0) {
115 	srand((unsigned) (getpid()));
116 	firsttime = 1;
117     }
118 
119     d = (double) rand() / ((double) RAND_MAX + 1);
120     i = (int) (d * (high - 0 + 1));
121 
122     return i > 0 ? i : 1;
123 }
124 
125 /*
126  * general test to make sure we can create the memcache struct and add
127  * some servers, but not more than we tell it we can add
128  */
129 
test_memcache_create(abts_case * tc,void * data)130 static void test_memcache_create(abts_case * tc, void *data)
131 {
132   apr_pool_t *pool = p;
133   apr_status_t rv;
134   apr_memcache_t *memcache;
135   apr_memcache_server_t *server, *s;
136   apr_uint32_t max_servers = 10;
137   apr_uint32_t i;
138   apr_uint32_t hash;
139 
140   rv = apr_memcache_create(pool, max_servers, 0, &memcache);
141   ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
142 
143   for (i = 1; i <= max_servers; i++) {
144     apr_port_t port;
145 
146     port = PORT + i;
147     rv =
148       apr_memcache_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, &server);
149     ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
150 
151     rv = apr_memcache_add_server(memcache, server);
152     ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
153 
154     s = apr_memcache_find_server(memcache, HOST, port);
155     ABTS_PTR_EQUAL(tc, server, s);
156 
157     rv = apr_memcache_disable_server(memcache, s);
158     ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS);
159 
160     rv = apr_memcache_enable_server(memcache, s);
161     ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS);
162 
163     hash = apr_memcache_hash(memcache, prefix, strlen(prefix));
164     ABTS_ASSERT(tc, "hash failed", hash > 0);
165 
166     s = apr_memcache_find_server_hash(memcache, hash);
167     ABTS_PTR_NOTNULL(tc, s);
168   }
169 
170   rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
171   ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
172 
173   rv = apr_memcache_add_server(memcache, server);
174   ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS);
175 
176 }
177 
178 /* install our own custom hashing and server selection routines. */
179 
create_test_hash(apr_pool_t * p,apr_hash_t * h)180 static int create_test_hash(apr_pool_t *p, apr_hash_t *h)
181 {
182   int i;
183 
184   for (i = 0; i < TDATA_SIZE; i++) {
185     char *k, *v;
186 
187     k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL);
188     v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt)));
189 
190     apr_hash_set(h, k, APR_HASH_KEY_STRING, v);
191   }
192 
193   return i;
194 }
195 
test_memcache_user_funcs(abts_case * tc,void * data)196 static void test_memcache_user_funcs(abts_case * tc, void *data)
197 {
198   apr_pool_t *pool = p;
199   apr_status_t rv;
200   apr_memcache_t *memcache;
201   apr_memcache_server_t *found;
202   apr_uint32_t max_servers = 10;
203   apr_uint32_t hres;
204   apr_uint32_t i;
205   my_hash_server_baton *baton =
206     apr_pcalloc(pool, sizeof(my_hash_server_baton));
207 
208   rv = apr_memcache_create(pool, max_servers, 0, &memcache);
209   ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
210 
211   /* as noted above, install our custom hash function, and call
212    * apr_memcache_hash. the return value should be our predefined number,
213    * and our function just ignores the other args, for simplicity.
214    */
215   memcache->hash_func = my_hash_func;
216 
217   hres = apr_memcache_hash(memcache, "whatever", sizeof("whatever") - 1);
218   ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres);
219 
220   /* add some servers */
221   for(i = 1; i <= 10; i++) {
222     apr_memcache_server_t *ms;
223 
224     rv = apr_memcache_server_create(pool, HOST, i, 0, 1, 1, 60, &ms);
225     ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
226 
227     rv = apr_memcache_add_server(memcache, ms);
228     ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
229   }
230 
231   /*
232    * set 'which_server' in our server_baton to find the third server
233    * which should have the same port.
234    */
235   baton->which_server = 3;
236   memcache->server_func = my_server_func;
237   memcache->server_baton = baton;
238   found = apr_memcache_find_server_hash(memcache, 0);
239   ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server);
240 }
241 
242 /* test non data related commands like stats and version */
test_memcache_meta(abts_case * tc,void * data)243 static void test_memcache_meta(abts_case * tc, void *data)
244 {
245     apr_pool_t *pool = p;
246     apr_memcache_t *memcache;
247     apr_memcache_server_t *server;
248     apr_memcache_stats_t *stats;
249     char *result;
250     apr_status_t rv;
251 
252     rv = apr_memcache_create(pool, 1, 0, &memcache);
253     ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
254 
255     rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
256     ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
257 
258     rv = apr_memcache_add_server(memcache, server);
259     ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
260 
261     rv = apr_memcache_version(server, pool, &result);
262     ABTS_PTR_NOTNULL(tc, result);
263 
264     rv = apr_memcache_stats(server, p, &stats);
265     ABTS_PTR_NOTNULL(tc, stats);
266 
267     ABTS_STR_NEQUAL(tc, stats->version, result, 5);
268 
269     /*
270      * no way to know exactly what will be in most of these, so
271      * just make sure there is something.
272      */
273 
274     ABTS_ASSERT(tc, "pid", stats->pid >= 0);
275     ABTS_ASSERT(tc, "time", stats->time >= 0);
276     /* ABTS_ASSERT(tc, "pointer_size", stats->pointer_size >= 0); */
277     ABTS_ASSERT(tc, "rusage_user", stats->rusage_user >= 0);
278     ABTS_ASSERT(tc, "rusage_system", stats->rusage_system >= 0);
279 
280     ABTS_ASSERT(tc, "curr_items", stats->curr_items >= 0);
281     ABTS_ASSERT(tc, "total_items", stats->total_items >= 0);
282     ABTS_ASSERT(tc, "bytes", stats->bytes >= 0);
283 
284     ABTS_ASSERT(tc, "curr_connections", stats->curr_connections >= 0);
285     ABTS_ASSERT(tc, "total_connections", stats->total_connections >= 0);
286     ABTS_ASSERT(tc, "connection_structures",
287                 stats->connection_structures >= 0);
288 
289     ABTS_ASSERT(tc, "cmd_get", stats->cmd_get >= 0);
290     ABTS_ASSERT(tc, "cmd_set", stats->cmd_set >= 0);
291     ABTS_ASSERT(tc, "get_hits", stats->get_hits >= 0);
292     ABTS_ASSERT(tc, "get_misses", stats->get_misses >= 0);
293 
294     /* ABTS_ASSERT(tc, "evictions", stats->evictions >= 0); */
295 
296     ABTS_ASSERT(tc, "bytes_read", stats->bytes_read >= 0);
297     ABTS_ASSERT(tc, "bytes_written", stats->bytes_written >= 0);
298     ABTS_ASSERT(tc, "limit_maxbytes", stats->limit_maxbytes >= 0);
299 
300     /* ABTS_ASSERT(tc, "threads", stats->threads >= 0); */
301 }
302 
303 /* test add and replace calls */
304 
test_memcache_addreplace(abts_case * tc,void * data)305 static void test_memcache_addreplace(abts_case * tc, void *data)
306 {
307  apr_pool_t *pool = p;
308  apr_status_t rv;
309  apr_memcache_t *memcache;
310  apr_memcache_server_t *server;
311  apr_hash_t *tdata;
312  apr_hash_index_t *hi;
313  char *result;
314  apr_size_t len;
315 
316   rv = apr_memcache_create(pool, 1, 0, &memcache);
317   ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
318 
319   rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
320   ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
321 
322   rv = apr_memcache_add_server(memcache, server);
323   ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
324 
325   tdata = apr_hash_make(p);
326   create_test_hash(pool, tdata);
327 
328   for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
329     const void *k;
330     void *v;
331     const char *key;
332 
333     apr_hash_this(hi, &k, NULL, &v);
334     key = k;
335 
336     /* doesn't exist yet, fail */
337     rv = apr_memcache_replace(memcache, key, v, strlen(v) - 1, 0, 27);
338     ABTS_ASSERT(tc, "replace should have failed", rv != APR_SUCCESS);
339 
340     /* doesn't exist yet, succeed */
341     rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
342     ABTS_ASSERT(tc, "add failed", rv == APR_SUCCESS);
343 
344     /* exists now, succeed */
345     rv = apr_memcache_replace(memcache, key, "new", sizeof("new") - 1, 0, 27);
346     ABTS_ASSERT(tc, "replace failed", rv == APR_SUCCESS);
347 
348     /* make sure its different */
349     rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
350     ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
351     ABTS_STR_NEQUAL(tc, result, "new", 3);
352 
353     /* exists now, fail */
354     rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
355     ABTS_ASSERT(tc, "add should have failed", rv != APR_SUCCESS);
356 
357     /* clean up */
358     rv = apr_memcache_delete(memcache, key, 0);
359     ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
360   }
361 }
362 
363 /* basic tests of the increment and decrement commands */
test_memcache_incrdecr(abts_case * tc,void * data)364 static void test_memcache_incrdecr(abts_case * tc, void *data)
365 {
366  apr_pool_t *pool = p;
367  apr_status_t rv;
368  apr_memcache_t *memcache;
369  apr_memcache_server_t *server;
370  apr_uint32_t new;
371  char *result;
372  apr_size_t len;
373  apr_uint32_t i;
374 
375   rv = apr_memcache_create(pool, 1, 0, &memcache);
376   ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
377 
378   rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
379   ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
380 
381   rv = apr_memcache_add_server(memcache, server);
382   ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
383 
384   rv = apr_memcache_set(memcache, prefix, "271", sizeof("271") - 1, 0, 27);
385   ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
386 
387   for( i = 1; i <= TDATA_SIZE; i++) {
388     apr_uint32_t expect;
389 
390     rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
391     ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
392 
393     expect = i + atoi(result);
394 
395     rv = apr_memcache_incr(memcache, prefix, i, &new);
396     ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS);
397 
398     ABTS_INT_EQUAL(tc, expect, new);
399 
400     rv = apr_memcache_decr(memcache, prefix, i, &new);
401     ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS);
402     ABTS_INT_EQUAL(tc, atoi(result), new);
403 
404   }
405 
406   rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
407   ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
408 
409   ABTS_INT_EQUAL(tc, 271, atoi(result));
410 
411   rv = apr_memcache_delete(memcache, prefix, 0);
412   ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
413 }
414 
415 /* test the multiget functionality */
test_memcache_multiget(abts_case * tc,void * data)416 static void test_memcache_multiget(abts_case * tc, void *data)
417 {
418   apr_pool_t *pool = p;
419   apr_pool_t *tmppool;
420   apr_status_t rv;
421   apr_memcache_t *memcache;
422   apr_memcache_server_t *server;
423   apr_hash_t *tdata, *values;
424   apr_hash_index_t *hi;
425   apr_uint32_t i;
426 
427   rv = apr_memcache_create(pool, 1, 0, &memcache);
428   ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
429 
430   rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
431   ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
432 
433   rv = apr_memcache_add_server(memcache, server);
434   ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
435 
436   values = apr_hash_make(p);
437   tdata = apr_hash_make(p);
438 
439   create_test_hash(pool, tdata);
440 
441   for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
442     const void *k;
443     void *v;
444     const char *key;
445 
446     apr_hash_this(hi, &k, NULL, &v);
447     key = k;
448 
449     rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
450     ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
451   }
452 
453   rv = apr_pool_create(&tmppool, pool);
454   for (i = 0; i < TDATA_SET; i++)
455     apr_memcache_add_multget_key(pool,
456                                  apr_pstrcat(pool, prefix,
457                                              apr_itoa(pool, i), NULL),
458                                  &values);
459 
460   rv = apr_memcache_multgetp(memcache,
461                              tmppool,
462                              pool,
463                              values);
464 
465   ABTS_ASSERT(tc, "multgetp failed", rv == APR_SUCCESS);
466   ABTS_ASSERT(tc, "multgetp returned too few results",
467               apr_hash_count(values) == TDATA_SET);
468 
469   for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
470     const void *k;
471     const char *key;
472 
473     apr_hash_this(hi, &k, NULL, NULL);
474     key = k;
475 
476     rv = apr_memcache_delete(memcache, key, 0);
477     ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
478   }
479 
480 }
481 
482 /* test setting and getting */
483 
test_memcache_setget(abts_case * tc,void * data)484 static void test_memcache_setget(abts_case * tc, void *data)
485 {
486     apr_pool_t *pool = p;
487     apr_status_t rv;
488     apr_memcache_t *memcache;
489     apr_memcache_server_t *server;
490     apr_hash_t *tdata;
491     apr_hash_index_t *hi;
492     char *result;
493     apr_size_t len;
494 
495     rv = apr_memcache_create(pool, 1, 0, &memcache);
496     ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
497 
498     rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
499     ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
500 
501     rv = apr_memcache_add_server(memcache, server);
502     ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
503 
504     tdata = apr_hash_make(pool);
505 
506     create_test_hash(pool, tdata);
507 
508     for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
509 	const void *k;
510 	void *v;
511         const char *key;
512 
513 	apr_hash_this(hi, &k, NULL, &v);
514         key = k;
515 
516 	rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
517 	ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
518 	rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
519 	ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
520     }
521 
522     rv = apr_memcache_getp(memcache, pool, "nothere3423", &result, &len, NULL);
523 
524     ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS);
525 
526     for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
527 	const void *k;
528 	const char *key;
529 
530 	apr_hash_this(hi, &k, NULL, NULL);
531 	key = k;
532 
533 	rv = apr_memcache_delete(memcache, key, 0);
534 	ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
535     }
536 }
537 
538 /* use apr_socket stuff to see if there is in fact a memcached server
539  * running on PORT.
540  */
check_mc(void)541 static apr_status_t check_mc(void)
542 {
543   apr_pool_t *pool = p;
544   apr_status_t rv;
545   apr_socket_t *sock = NULL;
546   apr_sockaddr_t *sa;
547   struct iovec vec[2];
548   apr_size_t written;
549   char buf[128];
550   apr_size_t len;
551 
552   rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool);
553   if(rv != APR_SUCCESS) {
554     return rv;
555   }
556 
557   rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool);
558   if(rv != APR_SUCCESS) {
559     return rv;
560   }
561 
562   rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC);
563   if (rv != APR_SUCCESS) {
564     return rv;
565   }
566 
567   rv = apr_socket_connect(sock, sa);
568   if (rv != APR_SUCCESS) {
569     return rv;
570   }
571 
572   rv = apr_socket_timeout_set(sock, -1);
573   if (rv != APR_SUCCESS) {
574     return rv;
575   }
576 
577   vec[0].iov_base = "version";
578   vec[0].iov_len  = sizeof("version") - 1;
579 
580   vec[1].iov_base = "\r\n";
581   vec[1].iov_len  = sizeof("\r\n") -1;
582 
583   rv = apr_socket_sendv(sock, vec, 2, &written);
584   if (rv != APR_SUCCESS) {
585     return rv;
586   }
587 
588   len = sizeof(buf);
589   rv = apr_socket_recv(sock, buf, &len);
590   if(rv != APR_SUCCESS) {
591     return rv;
592   }
593 
594   if(strncmp(buf, "VERSION", sizeof("VERSION")-1) != 0) {
595     rv = APR_EGENERAL;
596   }
597 
598   apr_socket_close(sock);
599   return rv;
600 }
601 
testmemcache(abts_suite * suite)602 abts_suite *testmemcache(abts_suite * suite)
603 {
604     apr_status_t rv;
605     suite = ADD_SUITE(suite);
606     /* check for a running memcached on the typical port before
607      * trying to run the tests. succeed if we don't find one.
608      */
609     rv = check_mc();
610     if (rv == APR_SUCCESS) {
611       abts_run_test(suite, test_memcache_create, NULL);
612       abts_run_test(suite, test_memcache_user_funcs, NULL);
613       abts_run_test(suite, test_memcache_meta, NULL);
614       abts_run_test(suite, test_memcache_setget, NULL);
615       abts_run_test(suite, test_memcache_multiget, NULL);
616       abts_run_test(suite, test_memcache_addreplace, NULL);
617       abts_run_test(suite, test_memcache_incrdecr, NULL);
618     }
619     else {
620         abts_log_message("Error %d occurred attempting to reach memcached "
621                          "on %s:%d.  Skipping apr_memcache tests...",
622                          rv, HOST, PORT);
623     }
624 
625     return suite;
626 }
627