1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "testutil.h"
18251876Speter#include "apr.h"
19251876Speter#include "apu.h"
20251876Speter#include "apr_general.h"
21251876Speter#include "apr_strings.h"
22251876Speter#include "apr_hash.h"
23251876Speter#include "apr_memcache.h"
24251876Speter#include "apr_network_io.h"
25251876Speter
26251876Speter#if APR_HAVE_STDLIB_H
27251876Speter#include <stdlib.h>		/* for exit() */
28251876Speter#endif
29251876Speter
30251876Speter#define HOST "localhost"
31251876Speter#define PORT 11211
32251876Speter
33251876Speter/* the total number of items to use for set/get testing */
34251876Speter#define TDATA_SIZE 3000
35251876Speter
36251876Speter/* some smaller subset of TDATA_SIZE used for multiget testing */
37251876Speter#define TDATA_SET 100
38251876Speter
39251876Speter/* our custom hash function just returns this all the time */
40251876Speter#define HASH_FUNC_RESULT 510
41251876Speter
42251876Speter/* all keys will be prefixed with this */
43251876Speterconst char prefix[] = "testmemcache";
44251876Speter
45251876Speter/* text for values we store */
46251876Speterconst char txt[] =
47251876Speter"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at"
48251876Speter"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio"
49251876Speter"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non,"
50251876Speter"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum"
51251876Speter"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat"
52251876Speter"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis"
53251876Speter"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in,"
54251876Speter"convallis id, iaculis feugiat cras amet.";
55251876Speter
56251876Speter/*
57251876Speter * this datatype is for our custom server determination function. this might
58251876Speter * be useful if you don't want to rely on simply hashing keys to determine
59251876Speter * where a key belongs, but instead want to write something fancy, or use some
60251876Speter * other kind of configuration data, i.e. a hash plus some data about a
61251876Speter * namespace, or whatever. see my_server_func, and test_memcache_user_funcs
62251876Speter * for the examples.
63251876Speter */
64251876Spetertypedef struct {
65251876Speter  const char *someval;
66251876Speter  apr_uint32_t which_server;
67251876Speter} my_hash_server_baton;
68251876Speter
69251876Speter
70251876Speter/* this could do something fancy and return some hash result.
71251876Speter * for simplicity, just return the same value, so we can test it later on.
72251876Speter * if you wanted to use some external hashing library or functions for
73251876Speter * consistent hashing, for example, this would be a good place to do it.
74251876Speter */
75251876Speterstatic apr_uint32_t my_hash_func(void *baton, const char *data,
76251876Speter                                 apr_size_t data_len)
77251876Speter{
78251876Speter
79251876Speter  return HASH_FUNC_RESULT;
80251876Speter}
81251876Speter
82251876Speter/*
83251876Speter * a fancy function to determine which server to use given some kind of data
84251876Speter * and a hash value. this example actually ignores the hash value itself
85251876Speter * and pulls some number from the *baton, which is a struct that has some
86251876Speter * kind of meaningful stuff in it.
87251876Speter */
88251876Speterstatic apr_memcache_server_t *my_server_func(void *baton,
89251876Speter                                             apr_memcache_t *mc,
90251876Speter                                             const apr_uint32_t hash)
91251876Speter{
92251876Speter  apr_memcache_server_t *ms = NULL;
93251876Speter  my_hash_server_baton *mhsb = (my_hash_server_baton *)baton;
94251876Speter
95251876Speter  if(mc->ntotal == 0) {
96251876Speter    return NULL;
97251876Speter  }
98251876Speter
99251876Speter  if(mc->ntotal < mhsb->which_server) {
100251876Speter    return NULL;
101251876Speter  }
102251876Speter
103251876Speter  ms = mc->live_servers[mhsb->which_server - 1];
104251876Speter
105251876Speter  return ms;
106251876Speter}
107251876Speter
108251876Speterapr_uint16_t firsttime = 0;
109251876Speterstatic int randval(apr_uint32_t high)
110251876Speter{
111251876Speter    apr_uint32_t i = 0;
112251876Speter    double d = 0;
113251876Speter
114251876Speter    if (firsttime == 0) {
115251876Speter	srand((unsigned) (getpid()));
116251876Speter	firsttime = 1;
117251876Speter    }
118251876Speter
119251876Speter    d = (double) rand() / ((double) RAND_MAX + 1);
120251876Speter    i = (int) (d * (high - 0 + 1));
121251876Speter
122251876Speter    return i > 0 ? i : 1;
123251876Speter}
124251876Speter
125251876Speter/*
126251876Speter * general test to make sure we can create the memcache struct and add
127251876Speter * some servers, but not more than we tell it we can add
128251876Speter */
129251876Speter
130251876Speterstatic void test_memcache_create(abts_case * tc, void *data)
131251876Speter{
132251876Speter  apr_pool_t *pool = p;
133251876Speter  apr_status_t rv;
134251876Speter  apr_memcache_t *memcache;
135251876Speter  apr_memcache_server_t *server, *s;
136251876Speter  apr_uint32_t max_servers = 10;
137251876Speter  apr_uint32_t i;
138251876Speter  apr_uint32_t hash;
139251876Speter
140251876Speter  rv = apr_memcache_create(pool, max_servers, 0, &memcache);
141251876Speter  ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
142251876Speter
143251876Speter  for (i = 1; i <= max_servers; i++) {
144251876Speter    apr_port_t port;
145251876Speter
146251876Speter    port = PORT + i;
147251876Speter    rv =
148251876Speter      apr_memcache_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, &server);
149251876Speter    ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
150251876Speter
151251876Speter    rv = apr_memcache_add_server(memcache, server);
152251876Speter    ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
153251876Speter
154251876Speter    s = apr_memcache_find_server(memcache, HOST, port);
155251876Speter    ABTS_PTR_EQUAL(tc, server, s);
156251876Speter
157251876Speter    rv = apr_memcache_disable_server(memcache, s);
158251876Speter    ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS);
159251876Speter
160251876Speter    rv = apr_memcache_enable_server(memcache, s);
161251876Speter    ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS);
162251876Speter
163251876Speter    hash = apr_memcache_hash(memcache, prefix, strlen(prefix));
164251876Speter    ABTS_ASSERT(tc, "hash failed", hash > 0);
165251876Speter
166251876Speter    s = apr_memcache_find_server_hash(memcache, hash);
167251876Speter    ABTS_PTR_NOTNULL(tc, s);
168251876Speter  }
169251876Speter
170251876Speter  rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
171251876Speter  ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
172251876Speter
173251876Speter  rv = apr_memcache_add_server(memcache, server);
174251876Speter  ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS);
175251876Speter
176251876Speter}
177251876Speter
178251876Speter/* install our own custom hashing and server selection routines. */
179251876Speter
180251876Speterstatic int create_test_hash(apr_pool_t *p, apr_hash_t *h)
181251876Speter{
182251876Speter  int i;
183251876Speter
184251876Speter  for (i = 0; i < TDATA_SIZE; i++) {
185251876Speter    char *k, *v;
186251876Speter
187251876Speter    k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL);
188251876Speter    v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt)));
189251876Speter
190251876Speter    apr_hash_set(h, k, APR_HASH_KEY_STRING, v);
191251876Speter  }
192251876Speter
193251876Speter  return i;
194251876Speter}
195251876Speter
196251876Speterstatic void test_memcache_user_funcs(abts_case * tc, void *data)
197251876Speter{
198251876Speter  apr_pool_t *pool = p;
199251876Speter  apr_status_t rv;
200251876Speter  apr_memcache_t *memcache;
201251876Speter  apr_memcache_server_t *found;
202251876Speter  apr_uint32_t max_servers = 10;
203251876Speter  apr_uint32_t hres;
204251876Speter  apr_uint32_t i;
205251876Speter  my_hash_server_baton *baton =
206251876Speter    apr_pcalloc(pool, sizeof(my_hash_server_baton));
207251876Speter
208251876Speter  rv = apr_memcache_create(pool, max_servers, 0, &memcache);
209251876Speter  ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
210251876Speter
211251876Speter  /* as noted above, install our custom hash function, and call
212251876Speter   * apr_memcache_hash. the return value should be our predefined number,
213251876Speter   * and our function just ignores the other args, for simplicity.
214251876Speter   */
215251876Speter  memcache->hash_func = my_hash_func;
216251876Speter
217251876Speter  hres = apr_memcache_hash(memcache, "whatever", sizeof("whatever") - 1);
218251876Speter  ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres);
219251876Speter
220251876Speter  /* add some servers */
221251876Speter  for(i = 1; i <= 10; i++) {
222251876Speter    apr_memcache_server_t *ms;
223251876Speter
224251876Speter    rv = apr_memcache_server_create(pool, HOST, i, 0, 1, 1, 60, &ms);
225251876Speter    ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
226251876Speter
227251876Speter    rv = apr_memcache_add_server(memcache, ms);
228251876Speter    ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
229251876Speter  }
230251876Speter
231251876Speter  /*
232251876Speter   * set 'which_server' in our server_baton to find the third server
233251876Speter   * which should have the same port.
234251876Speter   */
235251876Speter  baton->which_server = 3;
236251876Speter  memcache->server_func = my_server_func;
237251876Speter  memcache->server_baton = baton;
238251876Speter  found = apr_memcache_find_server_hash(memcache, 0);
239251876Speter  ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server);
240251876Speter}
241251876Speter
242251876Speter/* test non data related commands like stats and version */
243251876Speterstatic void test_memcache_meta(abts_case * tc, void *data)
244251876Speter{
245251876Speter    apr_pool_t *pool = p;
246251876Speter    apr_memcache_t *memcache;
247251876Speter    apr_memcache_server_t *server;
248251876Speter    apr_memcache_stats_t *stats;
249251876Speter    char *result;
250251876Speter    apr_status_t rv;
251251876Speter
252251876Speter    rv = apr_memcache_create(pool, 1, 0, &memcache);
253251876Speter    ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
254251876Speter
255251876Speter    rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
256251876Speter    ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
257251876Speter
258251876Speter    rv = apr_memcache_add_server(memcache, server);
259251876Speter    ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
260251876Speter
261251876Speter    rv = apr_memcache_version(server, pool, &result);
262251876Speter    ABTS_PTR_NOTNULL(tc, result);
263251876Speter
264251876Speter    rv = apr_memcache_stats(server, p, &stats);
265251876Speter    ABTS_PTR_NOTNULL(tc, stats);
266251876Speter
267251876Speter    ABTS_STR_NEQUAL(tc, stats->version, result, 5);
268251876Speter
269251876Speter    /*
270251876Speter     * no way to know exactly what will be in most of these, so
271251876Speter     * just make sure there is something.
272251876Speter     */
273251876Speter
274251876Speter    ABTS_ASSERT(tc, "pid", stats->pid >= 0);
275251876Speter    ABTS_ASSERT(tc, "time", stats->time >= 0);
276251876Speter    /* ABTS_ASSERT(tc, "pointer_size", stats->pointer_size >= 0); */
277251876Speter    ABTS_ASSERT(tc, "rusage_user", stats->rusage_user >= 0);
278251876Speter    ABTS_ASSERT(tc, "rusage_system", stats->rusage_system >= 0);
279251876Speter
280251876Speter    ABTS_ASSERT(tc, "curr_items", stats->curr_items >= 0);
281251876Speter    ABTS_ASSERT(tc, "total_items", stats->total_items >= 0);
282251876Speter    ABTS_ASSERT(tc, "bytes", stats->bytes >= 0);
283251876Speter
284251876Speter    ABTS_ASSERT(tc, "curr_connections", stats->curr_connections >= 0);
285251876Speter    ABTS_ASSERT(tc, "total_connections", stats->total_connections >= 0);
286251876Speter    ABTS_ASSERT(tc, "connection_structures",
287251876Speter                stats->connection_structures >= 0);
288251876Speter
289251876Speter    ABTS_ASSERT(tc, "cmd_get", stats->cmd_get >= 0);
290251876Speter    ABTS_ASSERT(tc, "cmd_set", stats->cmd_set >= 0);
291251876Speter    ABTS_ASSERT(tc, "get_hits", stats->get_hits >= 0);
292251876Speter    ABTS_ASSERT(tc, "get_misses", stats->get_misses >= 0);
293251876Speter
294251876Speter    /* ABTS_ASSERT(tc, "evictions", stats->evictions >= 0); */
295251876Speter
296251876Speter    ABTS_ASSERT(tc, "bytes_read", stats->bytes_read >= 0);
297251876Speter    ABTS_ASSERT(tc, "bytes_written", stats->bytes_written >= 0);
298251876Speter    ABTS_ASSERT(tc, "limit_maxbytes", stats->limit_maxbytes >= 0);
299251876Speter
300251876Speter    /* ABTS_ASSERT(tc, "threads", stats->threads >= 0); */
301251876Speter}
302251876Speter
303251876Speter/* test add and replace calls */
304251876Speter
305251876Speterstatic void test_memcache_addreplace(abts_case * tc, void *data)
306251876Speter{
307251876Speter apr_pool_t *pool = p;
308251876Speter apr_status_t rv;
309251876Speter apr_memcache_t *memcache;
310251876Speter apr_memcache_server_t *server;
311251876Speter apr_hash_t *tdata;
312251876Speter apr_hash_index_t *hi;
313251876Speter char *result;
314251876Speter apr_size_t len;
315251876Speter
316251876Speter  rv = apr_memcache_create(pool, 1, 0, &memcache);
317251876Speter  ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
318251876Speter
319251876Speter  rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
320251876Speter  ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
321251876Speter
322251876Speter  rv = apr_memcache_add_server(memcache, server);
323251876Speter  ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
324251876Speter
325251876Speter  tdata = apr_hash_make(p);
326251876Speter  create_test_hash(pool, tdata);
327251876Speter
328251876Speter  for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
329251876Speter    const void *k;
330251876Speter    void *v;
331251876Speter    const char *key;
332251876Speter
333251876Speter    apr_hash_this(hi, &k, NULL, &v);
334251876Speter    key = k;
335251876Speter
336251876Speter    /* doesn't exist yet, fail */
337251876Speter    rv = apr_memcache_replace(memcache, key, v, strlen(v) - 1, 0, 27);
338251876Speter    ABTS_ASSERT(tc, "replace should have failed", rv != APR_SUCCESS);
339251876Speter
340251876Speter    /* doesn't exist yet, succeed */
341251876Speter    rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
342251876Speter    ABTS_ASSERT(tc, "add failed", rv == APR_SUCCESS);
343251876Speter
344251876Speter    /* exists now, succeed */
345251876Speter    rv = apr_memcache_replace(memcache, key, "new", sizeof("new") - 1, 0, 27);
346251876Speter    ABTS_ASSERT(tc, "replace failed", rv == APR_SUCCESS);
347251876Speter
348251876Speter    /* make sure its different */
349251876Speter    rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
350251876Speter    ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
351251876Speter    ABTS_STR_NEQUAL(tc, result, "new", 3);
352251876Speter
353251876Speter    /* exists now, fail */
354251876Speter    rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
355251876Speter    ABTS_ASSERT(tc, "add should have failed", rv != APR_SUCCESS);
356251876Speter
357251876Speter    /* clean up */
358251876Speter    rv = apr_memcache_delete(memcache, key, 0);
359251876Speter    ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
360251876Speter  }
361251876Speter}
362251876Speter
363251876Speter/* basic tests of the increment and decrement commands */
364251876Speterstatic void test_memcache_incrdecr(abts_case * tc, void *data)
365251876Speter{
366251876Speter apr_pool_t *pool = p;
367251876Speter apr_status_t rv;
368251876Speter apr_memcache_t *memcache;
369251876Speter apr_memcache_server_t *server;
370251876Speter apr_uint32_t new;
371251876Speter char *result;
372251876Speter apr_size_t len;
373251876Speter apr_uint32_t i;
374251876Speter
375251876Speter  rv = apr_memcache_create(pool, 1, 0, &memcache);
376251876Speter  ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
377251876Speter
378251876Speter  rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
379251876Speter  ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
380251876Speter
381251876Speter  rv = apr_memcache_add_server(memcache, server);
382251876Speter  ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
383251876Speter
384251876Speter  rv = apr_memcache_set(memcache, prefix, "271", sizeof("271") - 1, 0, 27);
385251876Speter  ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
386251876Speter
387251876Speter  for( i = 1; i <= TDATA_SIZE; i++) {
388251876Speter    apr_uint32_t expect;
389251876Speter
390251876Speter    rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
391251876Speter    ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
392251876Speter
393251876Speter    expect = i + atoi(result);
394251876Speter
395251876Speter    rv = apr_memcache_incr(memcache, prefix, i, &new);
396251876Speter    ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS);
397251876Speter
398251876Speter    ABTS_INT_EQUAL(tc, expect, new);
399251876Speter
400251876Speter    rv = apr_memcache_decr(memcache, prefix, i, &new);
401251876Speter    ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS);
402251876Speter    ABTS_INT_EQUAL(tc, atoi(result), new);
403251876Speter
404251876Speter  }
405251876Speter
406251876Speter  rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
407251876Speter  ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
408251876Speter
409251876Speter  ABTS_INT_EQUAL(tc, 271, atoi(result));
410251876Speter
411251876Speter  rv = apr_memcache_delete(memcache, prefix, 0);
412251876Speter  ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
413251876Speter}
414251876Speter
415251876Speter/* test the multiget functionality */
416251876Speterstatic void test_memcache_multiget(abts_case * tc, void *data)
417251876Speter{
418251876Speter  apr_pool_t *pool = p;
419251876Speter  apr_pool_t *tmppool;
420251876Speter  apr_status_t rv;
421251876Speter  apr_memcache_t *memcache;
422251876Speter  apr_memcache_server_t *server;
423251876Speter  apr_hash_t *tdata, *values;
424251876Speter  apr_hash_index_t *hi;
425251876Speter  apr_uint32_t i;
426251876Speter
427251876Speter  rv = apr_memcache_create(pool, 1, 0, &memcache);
428251876Speter  ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
429251876Speter
430251876Speter  rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
431251876Speter  ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
432251876Speter
433251876Speter  rv = apr_memcache_add_server(memcache, server);
434251876Speter  ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
435251876Speter
436253734Speter  values = apr_hash_make(p);
437251876Speter  tdata = apr_hash_make(p);
438251876Speter
439251876Speter  create_test_hash(pool, tdata);
440251876Speter
441251876Speter  for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
442251876Speter    const void *k;
443251876Speter    void *v;
444251876Speter    const char *key;
445251876Speter
446251876Speter    apr_hash_this(hi, &k, NULL, &v);
447251876Speter    key = k;
448251876Speter
449251876Speter    rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
450251876Speter    ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
451251876Speter  }
452251876Speter
453251876Speter  rv = apr_pool_create(&tmppool, pool);
454251876Speter  for (i = 0; i < TDATA_SET; i++)
455251876Speter    apr_memcache_add_multget_key(pool,
456251876Speter                                 apr_pstrcat(pool, prefix,
457251876Speter                                             apr_itoa(pool, i), NULL),
458251876Speter                                 &values);
459251876Speter
460251876Speter  rv = apr_memcache_multgetp(memcache,
461251876Speter                             tmppool,
462251876Speter                             pool,
463251876Speter                             values);
464251876Speter
465251876Speter  ABTS_ASSERT(tc, "multgetp failed", rv == APR_SUCCESS);
466251876Speter  ABTS_ASSERT(tc, "multgetp returned too few results",
467251876Speter              apr_hash_count(values) == TDATA_SET);
468251876Speter
469251876Speter  for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
470251876Speter    const void *k;
471251876Speter    const char *key;
472251876Speter
473251876Speter    apr_hash_this(hi, &k, NULL, NULL);
474251876Speter    key = k;
475251876Speter
476251876Speter    rv = apr_memcache_delete(memcache, key, 0);
477251876Speter    ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
478251876Speter  }
479251876Speter
480251876Speter}
481251876Speter
482251876Speter/* test setting and getting */
483251876Speter
484251876Speterstatic void test_memcache_setget(abts_case * tc, void *data)
485251876Speter{
486251876Speter    apr_pool_t *pool = p;
487251876Speter    apr_status_t rv;
488251876Speter    apr_memcache_t *memcache;
489251876Speter    apr_memcache_server_t *server;
490251876Speter    apr_hash_t *tdata;
491251876Speter    apr_hash_index_t *hi;
492251876Speter    char *result;
493251876Speter    apr_size_t len;
494251876Speter
495251876Speter    rv = apr_memcache_create(pool, 1, 0, &memcache);
496251876Speter    ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
497251876Speter
498251876Speter    rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
499251876Speter    ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
500251876Speter
501251876Speter    rv = apr_memcache_add_server(memcache, server);
502251876Speter    ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
503251876Speter
504251876Speter    tdata = apr_hash_make(pool);
505251876Speter
506251876Speter    create_test_hash(pool, tdata);
507251876Speter
508251876Speter    for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
509251876Speter	const void *k;
510251876Speter	void *v;
511251876Speter        const char *key;
512251876Speter
513251876Speter	apr_hash_this(hi, &k, NULL, &v);
514251876Speter        key = k;
515251876Speter
516251876Speter	rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
517251876Speter	ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
518251876Speter	rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
519251876Speter	ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
520251876Speter    }
521251876Speter
522251876Speter    rv = apr_memcache_getp(memcache, pool, "nothere3423", &result, &len, NULL);
523251876Speter
524251876Speter    ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS);
525251876Speter
526251876Speter    for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
527251876Speter	const void *k;
528251876Speter	const char *key;
529251876Speter
530251876Speter	apr_hash_this(hi, &k, NULL, NULL);
531251876Speter	key = k;
532251876Speter
533251876Speter	rv = apr_memcache_delete(memcache, key, 0);
534251876Speter	ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
535251876Speter    }
536251876Speter}
537251876Speter
538251876Speter/* use apr_socket stuff to see if there is in fact a memcached server
539251876Speter * running on PORT.
540251876Speter */
541251876Speterstatic apr_status_t check_mc(void)
542251876Speter{
543251876Speter  apr_pool_t *pool = p;
544251876Speter  apr_status_t rv;
545251876Speter  apr_socket_t *sock = NULL;
546251876Speter  apr_sockaddr_t *sa;
547251876Speter  struct iovec vec[2];
548251876Speter  apr_size_t written;
549251876Speter  char buf[128];
550251876Speter  apr_size_t len;
551251876Speter
552251876Speter  rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool);
553251876Speter  if(rv != APR_SUCCESS) {
554251876Speter    return rv;
555251876Speter  }
556251876Speter
557251876Speter  rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool);
558251876Speter  if(rv != APR_SUCCESS) {
559251876Speter    return rv;
560251876Speter  }
561251876Speter
562251876Speter  rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC);
563251876Speter  if (rv != APR_SUCCESS) {
564251876Speter    return rv;
565251876Speter  }
566251876Speter
567251876Speter  rv = apr_socket_connect(sock, sa);
568251876Speter  if (rv != APR_SUCCESS) {
569251876Speter    return rv;
570251876Speter  }
571251876Speter
572251876Speter  rv = apr_socket_timeout_set(sock, -1);
573251876Speter  if (rv != APR_SUCCESS) {
574251876Speter    return rv;
575251876Speter  }
576251876Speter
577251876Speter  vec[0].iov_base = "version";
578251876Speter  vec[0].iov_len  = sizeof("version") - 1;
579251876Speter
580251876Speter  vec[1].iov_base = "\r\n";
581251876Speter  vec[1].iov_len  = sizeof("\r\n") -1;
582251876Speter
583251876Speter  rv = apr_socket_sendv(sock, vec, 2, &written);
584251876Speter  if (rv != APR_SUCCESS) {
585251876Speter    return rv;
586251876Speter  }
587251876Speter
588251876Speter  len = sizeof(buf);
589251876Speter  rv = apr_socket_recv(sock, buf, &len);
590251876Speter  if(rv != APR_SUCCESS) {
591251876Speter    return rv;
592251876Speter  }
593251876Speter
594251876Speter  if(strncmp(buf, "VERSION", sizeof("VERSION")-1) != 0) {
595251876Speter    rv = APR_EGENERAL;
596251876Speter  }
597251876Speter
598251876Speter  apr_socket_close(sock);
599251876Speter  return rv;
600251876Speter}
601251876Speter
602251876Speterabts_suite *testmemcache(abts_suite * suite)
603251876Speter{
604251876Speter    apr_status_t rv;
605251876Speter    suite = ADD_SUITE(suite);
606251876Speter    /* check for a running memcached on the typical port before
607253734Speter     * trying to run the tests. succeed if we don't find one.
608251876Speter     */
609251876Speter    rv = check_mc();
610253734Speter    if (rv == APR_SUCCESS) {
611251876Speter      abts_run_test(suite, test_memcache_create, NULL);
612251876Speter      abts_run_test(suite, test_memcache_user_funcs, NULL);
613251876Speter      abts_run_test(suite, test_memcache_meta, NULL);
614251876Speter      abts_run_test(suite, test_memcache_setget, NULL);
615251876Speter      abts_run_test(suite, test_memcache_multiget, NULL);
616251876Speter      abts_run_test(suite, test_memcache_addreplace, NULL);
617251876Speter      abts_run_test(suite, test_memcache_incrdecr, NULL);
618251876Speter    }
619253734Speter    else {
620253734Speter        abts_log_message("Error %d occurred attempting to reach memcached "
621253734Speter                         "on %s:%d.  Skipping apr_memcache tests...",
622253734Speter                         rv, HOST, PORT);
623253734Speter    }
624251876Speter
625251876Speter    return suite;
626251876Speter}
627