unit tests for hash table.

git-svn-id: file:///svn/unbound/trunk@179 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards
2007-03-14 14:30:30 +00:00
parent 06b25ffa5a
commit af41706579
8 changed files with 414 additions and 101 deletions
+3 -2
View File
@@ -66,8 +66,9 @@ static void lock_error(struct checked_lock* lock,
log_err("lock error (description follows)");
log_err("Created at %s %s:%d", lock->create_func,
lock->create_file, lock->create_line);
log_err("Previously %s %s:%d", lock->holder_func,
lock->holder_file, lock->holder_line);
if(lock->holder_func && lock->holder_file)
log_err("Previously %s %s:%d", lock->holder_func,
lock->holder_file, lock->holder_line);
log_err("At %s %s:%d", func, file, line);
log_err("Error for %s lock: %s",
(lock->type==check_lock_mutex)?"mutex": (
+257
View File
@@ -0,0 +1,257 @@
/*
* testcode/unitlruhash.c - unit test for lruhash table.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* Tests the locking LRU keeping hash table implementation.
*/
#include "config.h"
#include "testcode/unitmain.h"
#include "util/log.h"
#include "util/storage/lruhash.h"
/* --- test representation --- */
/** structure contains test key */
struct testkey {
/** the key id */
int id;
/** the entry */
struct lruhash_entry entry;
};
/** structure contains test data */
struct testdata {
/** data value */
int data;
};
/** sizefunc for lruhash */
static size_t test_sizefunc(void*, void*);
/** comparefunc for lruhash */
static int test_compfunc(void*, void*);
/** delkey for lruhash */
static void test_delkey(void*, void*);
/** deldata for lruhash */
static void test_deldata(void*, void*);
/* --- end test representation --- */
/** hash func, very bad to improve collisions. */
static hashvalue_t myhash(int id) {return id & 0x0f;}
/** allocate new key, fill in hash. */
static struct testkey* newkey(int id) {
struct testkey* k = (struct testkey*)calloc(1, sizeof(struct testkey));
k->id = id;
k->entry.hash = myhash(id);
k->entry.key = k;
lock_rw_init(&k->entry.lock);
return k;
}
/** new data el */
static struct testdata* newdata(int val) {
struct testdata* d = (struct testdata*)calloc(1,
sizeof(struct testdata));
d->data = val;
return d;
}
/** delete key */
static void delkey(struct testkey* k) {
lock_rw_destroy(&k->entry.lock); free(k);}
/** delete data */
static void deldata(struct testdata* d) {free(d);}
/** test bin_find_entry function and bin_overflow_remove */
static void
test_bin_find_entry(struct lruhash* table)
{
struct testkey* k = newkey(12);
struct testdata* d = newdata(128);
struct testkey* k2 = newkey(12 + 1024);
struct testkey* k3 = newkey(14);
struct testkey* k4 = newkey(12 + 1024*2);
hashvalue_t h = myhash(12);
struct lruhash_bin bin;
bin_init(&bin, 1);
/* remove from empty list */
bin_overflow_remove(&bin, &k->entry);
/* find in empty list */
unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
/* insert */
lock_quick_lock(&bin.lock);
bin.overflow_list = &k->entry;
lock_quick_unlock(&bin.lock);
/* find, hash not OK. */
unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
/* find, hash OK, but cmp not */
unit_assert( k->entry.hash == k2->entry.hash );
unit_assert( bin_find_entry(table, &bin, h, k2) == NULL );
/* find, hash OK, and cmp too */
unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
/* remove the element */
lock_quick_lock(&bin.lock);
bin_overflow_remove(&bin, &k->entry);
lock_quick_unlock(&bin.lock);
unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
/* prepend two different elements; so the list is long */
/* one has the same hash, but different cmp */
lock_quick_lock(&bin.lock);
unit_assert( k->entry.hash == k4->entry.hash );
k4->entry.overflow_next = &k->entry;
k3->entry.overflow_next = &k4->entry;
bin.overflow_list = &k3->entry;
lock_quick_unlock(&bin.lock);
/* find, hash not OK. */
unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
/* find, hash OK, but cmp not */
unit_assert( k->entry.hash == k2->entry.hash );
unit_assert( bin_find_entry(table, &bin, h, k2) == NULL );
/* find, hash OK, and cmp too */
unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
/* remove middle element */
unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4)
== &k4->entry );
lock_quick_lock(&bin.lock);
bin_overflow_remove(&bin, &k4->entry);
lock_quick_unlock(&bin.lock);
unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4) == NULL);
/* remove last element */
lock_quick_lock(&bin.lock);
bin_overflow_remove(&bin, &k->entry);
lock_quick_unlock(&bin.lock);
unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
lock_quick_destroy(&bin.lock);
delkey(k);
delkey(k2);
delkey(k3);
delkey(k4);
deldata(d);
}
/** test lru_front lru_remove */
static void test_lru(struct lruhash* table)
{
struct testkey* k = newkey(12);
struct testkey* k2 = newkey(14);
lock_quick_lock(&table->lock);
unit_assert( table->lru_start == NULL && table->lru_end == NULL);
lru_remove(table, &k->entry);
unit_assert( table->lru_start == NULL && table->lru_end == NULL);
/* add one */
lru_front(table, &k->entry);
unit_assert( table->lru_start == &k->entry &&
table->lru_end == &k->entry);
/* remove it */
lru_remove(table, &k->entry);
unit_assert( table->lru_start == NULL && table->lru_end == NULL);
/* add two */
lru_front(table, &k->entry);
unit_assert( table->lru_start == &k->entry &&
table->lru_end == &k->entry);
lru_front(table, &k2->entry);
unit_assert( table->lru_start == &k2->entry &&
table->lru_end == &k->entry);
/* remove first in list */
lru_remove(table, &k2->entry);
unit_assert( table->lru_start == &k->entry &&
table->lru_end == &k->entry);
lru_front(table, &k2->entry);
unit_assert( table->lru_start == &k2->entry &&
table->lru_end == &k->entry);
/* remove last in list */
lru_remove(table, &k->entry);
unit_assert( table->lru_start == &k2->entry &&
table->lru_end == &k2->entry);
/* empty the list */
lru_remove(table, &k2->entry);
unit_assert( table->lru_start == NULL && table->lru_end == NULL);
lock_quick_unlock(&table->lock);
delkey(k);
delkey(k2);
}
void lruhash_test()
{
/* start very very small array, so it can do lots of table_grow() */
/* also small in size so that reclaim has to be done quickly. */
struct lruhash* table = lruhash_create(2, 1024,
test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
test_bin_find_entry(table);
test_lru(table);
/* hashtable tests go here */
lruhash_delete(table);
}
static size_t test_sizefunc(void* ATTR_UNUSED(key), void* ATTR_UNUSED(data))
{
return sizeof(struct testkey) + sizeof(struct testdata);
}
static int test_compfunc(void* key1, void* key2)
{
struct testkey* k1 = (struct testkey*)key1;
struct testkey* k2 = (struct testkey*)key2;
if(k1->id == k2->id)
return 0;
if(k1->id > k2->id)
return 1;
return -1;
}
static void test_delkey(void* key, void* ATTR_UNUSED(arg))
{
delkey((struct testkey*)key);
}
static void test_deldata(void* data, void* ATTR_UNUSED(arg))
{
deldata((struct testdata*)data);
}
+4 -4
View File
@@ -41,11 +41,10 @@
#include "config.h"
#include "util/log.h"
#include "testcode/unitmain.h"
/** number of tests done */
int testcount = 0;
/** test bool x, exits on failure, increases testcount. */
#define unit_assert(x) testcount++; log_assert(x);
#include "util/alloc.h"
/** test alloc code */
@@ -55,7 +54,6 @@ alloc_test() {
struct alloc_cache major, minor1, minor2;
int i;
checklock_start();
alloc_init(&major, NULL);
alloc_init(&minor1, &major);
alloc_init(&minor2, &major);
@@ -84,7 +82,6 @@ alloc_test() {
alloc_clear(&minor2);
unit_assert(major.num_quar == 11);
alloc_clear(&major);
checklock_stop();
}
#include "util/net_help.h"
@@ -148,9 +145,12 @@ main(int argc, char* argv[])
return 1;
}
printf("Start of %s unit test.\n", PACKAGE_STRING);
checklock_start();
net_test();
alloc_test();
msgreply_test();
lruhash_test();
checklock_stop();
printf("%d tests succeeded\n", testcount);
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* testcode/unitmain.h - unit test main program for unbound.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* Declarations useful for the unit tests.
*/
#ifndef TESTCODE_UNITMAIN_H
#define TESTCODE_UNITMAIN_H
#include "util/log.h"
/** number of tests done */
extern int testcount;
/** test bool x, exits on failure, increases testcount. */
#define unit_assert(x) do {testcount++; log_assert(x);} while(0)
/** unit test lruhashtable implementation */
void lruhash_test();
#endif /* TESTCODE_UNITMAIN_H */