]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr-util/test/testmemcache.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr-util / test / testmemcache.c
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  */
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  */
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;
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
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
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
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 */
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
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 */
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 */
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
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  */
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
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 }