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 "apr.h" 18#include "apr_general.h" 19#include "apr_pools.h" 20#include "apr_errno.h" 21#include "apr_dbm.h" 22#include "apr_uuid.h" 23#include "apr_strings.h" 24#include "abts.h" 25#include "testutil.h" 26 27#define NUM_TABLE_ROWS 1024 28 29typedef struct { 30 apr_datum_t key; 31 apr_datum_t val; 32 int deleted; 33 int visited; 34} dbm_table_t; 35 36static dbm_table_t *generate_table(void) 37{ 38 unsigned int i; 39 apr_uuid_t uuid; 40 dbm_table_t *table = apr_pcalloc(p, sizeof(*table) * NUM_TABLE_ROWS); 41 42 for (i = 0; i < NUM_TABLE_ROWS/2; i++) { 43 apr_uuid_get(&uuid); 44 table[i].key.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); 45 table[i].key.dsize = sizeof(uuid.data); 46 table[i].val.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH); 47 table[i].val.dsize = APR_UUID_FORMATTED_LENGTH; 48 apr_uuid_format(table[i].val.dptr, &uuid); 49 } 50 51 for (; i < NUM_TABLE_ROWS; i++) { 52 apr_uuid_get(&uuid); 53 table[i].val.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); 54 table[i].val.dsize = sizeof(uuid.data); 55 table[i].key.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH); 56 table[i].key.dsize = APR_UUID_FORMATTED_LENGTH; 57 apr_uuid_format(table[i].key.dptr, &uuid); 58 } 59 60 return table; 61} 62 63static void test_dbm_store(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) 64{ 65 apr_status_t rv; 66 unsigned int i = NUM_TABLE_ROWS - 1; 67 68 for (; i >= NUM_TABLE_ROWS/2; i--) { 69 rv = apr_dbm_store(db, table[i].key, table[i].val); 70 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 71 table[i].deleted = FALSE; 72 } 73 74 for (i = 0; i < NUM_TABLE_ROWS/2; i++) { 75 rv = apr_dbm_store(db, table[i].key, table[i].val); 76 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 77 table[i].deleted = FALSE; 78 } 79} 80 81static void test_dbm_fetch(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) 82{ 83 apr_status_t rv; 84 unsigned int i; 85 apr_datum_t val; 86 87 for (i = 0; i < NUM_TABLE_ROWS; i++) { 88 memset(&val, 0, sizeof(val)); 89 rv = apr_dbm_fetch(db, table[i].key, &val); 90 if (!table[i].deleted) { 91 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 92 ABTS_INT_EQUAL(tc, table[i].val.dsize, val.dsize); 93 ABTS_INT_EQUAL(tc, 0, memcmp(table[i].val.dptr, val.dptr, val.dsize)); 94 apr_dbm_freedatum(db, val); 95 } else { 96 ABTS_INT_EQUAL(tc, 0, val.dsize); 97 } 98 } 99} 100 101static void test_dbm_delete(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) 102{ 103 apr_status_t rv; 104 unsigned int i; 105 106 for (i = 0; i < NUM_TABLE_ROWS; i++) { 107 /* XXX: random */ 108 if (i & 1) 109 continue; 110 rv = apr_dbm_delete(db, table[i].key); 111 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 112 table[i].deleted = TRUE; 113 } 114} 115 116static void test_dbm_exists(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) 117{ 118 unsigned int i; 119 int cond; 120 121 for (i = 0; i < NUM_TABLE_ROWS; i++) { 122 cond = apr_dbm_exists(db, table[i].key); 123 if (table[i].deleted) { 124 ABTS_TRUE(tc, cond == 0); 125 } else { 126 ABTS_TRUE(tc, cond != 0); 127 } 128 } 129} 130 131static void test_dbm_traversal(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) 132{ 133 apr_status_t rv; 134 unsigned int i; 135 apr_datum_t key; 136 137 rv = apr_dbm_firstkey(db, &key); 138 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 139 140 do { 141 if (key.dptr == NULL || key.dsize == 0) 142 break; 143 144 for (i = 0; i < NUM_TABLE_ROWS; i++) { 145 if (table[i].key.dsize != key.dsize) 146 continue; 147 if (memcmp(table[i].key.dptr, key.dptr, key.dsize)) 148 continue; 149 ABTS_INT_EQUAL(tc, 0, table[i].deleted); 150 ABTS_INT_EQUAL(tc, 0, table[i].visited); 151 table[i].visited++; 152 } 153 154 rv = apr_dbm_nextkey(db, &key); 155 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 156 } while (1); 157 158 for (i = 0; i < NUM_TABLE_ROWS; i++) { 159 if (table[i].deleted) 160 continue; 161 ABTS_INT_EQUAL(tc, 1, table[i].visited); 162 table[i].visited = 0; 163 } 164} 165 166static void test_dbm(abts_case *tc, void *data) 167{ 168 apr_dbm_t *db; 169 apr_status_t rv; 170 dbm_table_t *table; 171 const char *type = data; 172 const char *file = apr_pstrcat(p, "data/test-", type, NULL); 173 174 rv = apr_dbm_open_ex(&db, type, file, APR_DBM_RWCREATE, APR_OS_DEFAULT, p); 175 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 176 177 if (rv != APR_SUCCESS) 178 return; 179 180 table = generate_table(); 181 182 test_dbm_store(tc, db, table); 183 test_dbm_fetch(tc, db, table); 184 test_dbm_delete(tc, db, table); 185 test_dbm_exists(tc, db, table); 186 test_dbm_traversal(tc, db, table); 187 188 apr_dbm_close(db); 189 190 rv = apr_dbm_open_ex(&db, type, file, APR_DBM_READONLY, APR_OS_DEFAULT, p); 191 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 192 193 if (rv != APR_SUCCESS) 194 return; 195 196 test_dbm_exists(tc, db, table); 197 test_dbm_traversal(tc, db, table); 198 test_dbm_fetch(tc, db, table); 199 200 apr_dbm_close(db); 201} 202 203abts_suite *testdbm(abts_suite *suite) 204{ 205 suite = ADD_SUITE(suite); 206 207#if APU_HAVE_GDBM 208 abts_run_test(suite, test_dbm, "gdbm"); 209#endif 210#if APU_HAVE_NDBM 211 abts_run_test(suite, test_dbm, "ndbm"); 212#endif 213#if APU_HAVE_SDBM 214 abts_run_test(suite, test_dbm, "sdbm"); 215#endif 216#if APU_HAVE_DB 217 abts_run_test(suite, test_dbm, "db"); 218#endif 219 220 return suite; 221} 222