/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "apr.h" #include "apr_general.h" #include "apr_pools.h" #include "apr_errno.h" #include "apr_dbm.h" #include "apr_uuid.h" #include "apr_strings.h" #include "abts.h" #include "testutil.h" #define NUM_TABLE_ROWS 1024 typedef struct { apr_datum_t key; apr_datum_t val; int deleted; int visited; } dbm_table_t; static dbm_table_t *generate_table(void) { unsigned int i; apr_uuid_t uuid; dbm_table_t *table = apr_pcalloc(p, sizeof(*table) * NUM_TABLE_ROWS); for (i = 0; i < NUM_TABLE_ROWS/2; i++) { apr_uuid_get(&uuid); table[i].key.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); table[i].key.dsize = sizeof(uuid.data); table[i].val.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); table[i].val.dsize = APR_UUID_FORMATTED_LENGTH + 1; apr_uuid_format(table[i].val.dptr, &uuid); } for (; i < NUM_TABLE_ROWS; i++) { apr_uuid_get(&uuid); table[i].val.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); table[i].val.dsize = sizeof(uuid.data); table[i].key.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); table[i].key.dsize = APR_UUID_FORMATTED_LENGTH + 1; apr_uuid_format(table[i].key.dptr, &uuid); } return table; } static void test_dbm_store(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) { apr_status_t rv; unsigned int i = NUM_TABLE_ROWS - 1; for (; i >= NUM_TABLE_ROWS/2; i--) { rv = apr_dbm_store(db, table[i].key, table[i].val); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); table[i].deleted = FALSE; } for (i = 0; i < NUM_TABLE_ROWS/2; i++) { rv = apr_dbm_store(db, table[i].key, table[i].val); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); table[i].deleted = FALSE; } } static void test_dbm_fetch(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) { apr_status_t rv; unsigned int i; apr_datum_t val; for (i = 0; i < NUM_TABLE_ROWS; i++) { memset(&val, 0, sizeof(val)); rv = apr_dbm_fetch(db, table[i].key, &val); if (!table[i].deleted) { ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_SIZE_EQUAL(tc, table[i].val.dsize, val.dsize); ABTS_INT_EQUAL(tc, 0, memcmp(table[i].val.dptr, val.dptr, val.dsize)); apr_dbm_freedatum(db, val); } else { ABTS_SIZE_EQUAL(tc, 0, val.dsize); } } } static void test_dbm_delete(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) { apr_status_t rv; unsigned int i; for (i = 0; i < NUM_TABLE_ROWS; i++) { /* XXX: random */ if (i & 1) continue; rv = apr_dbm_delete(db, table[i].key); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); table[i].deleted = TRUE; } } static void test_dbm_exists(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) { unsigned int i; int cond; for (i = 0; i < NUM_TABLE_ROWS; i++) { cond = apr_dbm_exists(db, table[i].key); if (table[i].deleted) { ABTS_TRUE(tc, cond == 0); } else { ABTS_TRUE(tc, cond != 0); } } } static void test_dbm_traversal(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) { apr_status_t rv; unsigned int i; apr_datum_t key; rv = apr_dbm_firstkey(db, &key); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); do { if (key.dptr == NULL || key.dsize == 0) break; for (i = 0; i < NUM_TABLE_ROWS; i++) { if (table[i].key.dsize != key.dsize) continue; if (memcmp(table[i].key.dptr, key.dptr, key.dsize)) continue; ABTS_INT_EQUAL(tc, 0, table[i].deleted); ABTS_INT_EQUAL(tc, 0, table[i].visited); table[i].visited++; } rv = apr_dbm_nextkey(db, &key); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); } while (1); for (i = 0; i < NUM_TABLE_ROWS; i++) { if (table[i].deleted) continue; ABTS_INT_EQUAL(tc, 1, table[i].visited); table[i].visited = 0; } } static void test_dbm(abts_case *tc, void *data) { apr_dbm_t *db; apr_status_t rv; dbm_table_t *table; const char *type = data; const char *file = apr_pstrcat(p, "data/test-", type, NULL); rv = apr_dbm_open_ex(&db, type, file, APR_DBM_RWCREATE, APR_FPROT_OS_DEFAULT, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); if (rv != APR_SUCCESS) return; table = generate_table(); test_dbm_store(tc, db, table); test_dbm_fetch(tc, db, table); test_dbm_delete(tc, db, table); test_dbm_exists(tc, db, table); test_dbm_traversal(tc, db, table); apr_dbm_close(db); rv = apr_dbm_open_ex(&db, type, file, APR_DBM_READONLY, APR_FPROT_OS_DEFAULT, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); if (rv != APR_SUCCESS) return; test_dbm_exists(tc, db, table); test_dbm_traversal(tc, db, table); test_dbm_fetch(tc, db, table); apr_dbm_close(db); } abts_suite *testdbm(abts_suite *suite) { suite = ADD_SUITE(suite); #if APU_HAVE_GDBM abts_run_test(suite, test_dbm, "gdbm"); #endif #if APU_HAVE_NDBM abts_run_test(suite, test_dbm, "ndbm"); #endif #if APU_HAVE_SDBM abts_run_test(suite, test_dbm, "sdbm"); #endif #if APU_HAVE_DB abts_run_test(suite, test_dbm, "db"); #endif return suite; }