diff --git a/lib/cache.c b/lib/cache.c index b5df162827cc48cda5bae9e2c1a2d273af6f37cc..334dd163fe59c4bce5d2f13f56fd7e627ca3891e 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -30,15 +30,14 @@ /* Key size */ #define KEY_SIZE (sizeof(uint8_t) + KNOT_DNAME_MAXLEN + sizeof(uint16_t)) -#define db_api(cache) (cache->api) int kr_cache_open(struct kr_cache *cache, const namedb_api_t *api, void *opts, mm_ctx_t *mm) { if (!cache) { return kr_error(EINVAL); } - db_api(cache) = (api == NULL) ? namedb_lmdb_api() : api; - int ret = db_api(cache)->init(&cache->db, mm, opts); + cache->api = (api == NULL) ? namedb_lmdb_api() : api; + int ret = cache->api->init(&cache->db, mm, opts); if (ret != 0) { return ret; } @@ -49,8 +48,8 @@ int kr_cache_open(struct kr_cache *cache, const namedb_api_t *api, void *opts, m void kr_cache_close(struct kr_cache *cache) { if (cache && cache->db) { - if (db_api(cache)) { - db_api(cache)->deinit(cache->db); + if (cache->api) { + cache->api->deinit(cache->db); } cache->db = NULL; } @@ -58,7 +57,7 @@ void kr_cache_close(struct kr_cache *cache) int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigned flags) { - if (!cache || !cache->db || !db_api(cache) || !txn ) { + if (!cache || !cache->db || !cache->api || !txn ) { return kr_error(EINVAL); } @@ -68,16 +67,16 @@ int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigne cache->stats.txn_write += 1; } txn->owner = cache; - return db_api(cache)->txn_begin(cache->db, (namedb_txn_t *)txn, flags); + return cache->api->txn_begin(cache->db, (namedb_txn_t *)txn, flags); } int kr_cache_txn_commit(struct kr_cache_txn *txn) { - if (!txn || !txn->owner) { + if (!txn || !txn->owner || !txn->owner->api) { return kr_error(EINVAL); } - int ret = db_api(txn->owner)->txn_commit((namedb_txn_t *)txn); + int ret = txn->owner->api->txn_commit((namedb_txn_t *)txn); if (ret != 0) { kr_cache_txn_abort(txn); } @@ -86,8 +85,8 @@ int kr_cache_txn_commit(struct kr_cache_txn *txn) void kr_cache_txn_abort(struct kr_cache_txn *txn) { - if (txn && txn->owner) { - db_api(txn->owner)->txn_abort((namedb_txn_t *)txn); + if (txn && txn->owner && txn->owner->api) { + txn->owner->api->txn_abort((namedb_txn_t *)txn); } } @@ -105,14 +104,14 @@ static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag, { uint8_t keybuf[KEY_SIZE]; size_t key_len = cache_key(keybuf, tag, name, type); - if (!txn || !txn->owner) { + if (!txn || !txn->owner || !txn->owner->api) { return NULL; } /* Look up and return value */ namedb_val_t key = { keybuf, key_len }; namedb_val_t val = { NULL, 0 }; - int ret = db_api(txn->owner)->find((namedb_txn_t *)txn, &key, &val, 0); + int ret = txn->owner->api->find((namedb_txn_t *)txn, &key, &val, 0); if (ret != KNOT_EOK) { return NULL; } @@ -166,7 +165,7 @@ static void entry_write(struct kr_cache_entry *dst, struct kr_cache_entry *heade int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type, struct kr_cache_entry *header, namedb_val_t data) { - if (!txn || !txn->owner || !name || !tag || !header) { + if (!txn || !txn->owner || !txn->owner->api || !name || !tag || !header) { return kr_error(EINVAL); } @@ -175,11 +174,12 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n size_t key_len = cache_key(keybuf, tag, name, type); namedb_val_t key = { keybuf, key_len }; namedb_val_t entry = { NULL, sizeof(*header) + data.len }; + const namedb_api_t *db_api = txn->owner->api; /* LMDB can do late write and avoid copy */ txn->owner->stats.insert += 1; - if (db_api(txn->owner) == namedb_lmdb_api()) { - int ret = db_api(txn->owner)->insert((namedb_txn_t *)txn, &key, &entry, 0); + if (db_api == namedb_lmdb_api()) { + int ret = db_api->insert((namedb_txn_t *)txn, &key, &entry, 0); if (ret != 0) { return ret; } @@ -191,7 +191,7 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n return kr_error(ENOMEM); } entry_write(entry.data, header, data); - int ret = db_api(txn->owner)->insert((namedb_txn_t *)txn, &key, &entry, 0); + int ret = db_api->insert((namedb_txn_t *)txn, &key, &entry, 0); free(entry.data); if (ret != 0) { return ret; @@ -203,7 +203,7 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type) { - if (!txn || !txn->owner || !tag || !name ) { + if (!txn || !txn->owner || !txn->owner->api || !tag || !name ) { return kr_error(EINVAL); } @@ -211,16 +211,16 @@ int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n size_t key_len = cache_key(keybuf, tag, name, type); namedb_val_t key = { keybuf, key_len }; txn->owner->stats.delete += 1; - return db_api(txn->owner)->del((namedb_txn_t *)txn, &key); + return txn->owner->api->del((namedb_txn_t *)txn, &key); } int kr_cache_clear(struct kr_cache_txn *txn) { - if (!txn || !txn->owner ) { + if (!txn || !txn->owner || !txn->owner->api) { return kr_error(EINVAL); } - return db_api(txn->owner)->clear((namedb_txn_t *)txn); + return txn->owner->api->clear((namedb_txn_t *)txn); } int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint32_t *timestamp) diff --git a/lib/cache.h b/lib/cache.h index 9981aba4fada1982941bd3a6f8fef3dc5b120056..ed955e244291008a615a2d9d40ecf6dd4aad4998 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -61,15 +61,6 @@ struct kr_cache_txn { struct kr_cache *owner; /**< Transaction owner */ }; -/** Used storage backend for cache (default LMDB) */ -//extern const namedb_api_t *(*kr_cache_storage)(void); - -/** Replace used cache storage backend. */ -//static inline void kr_cache_storage_set(const namedb_api_t *(*api)(void)) -//{ -// kr_cache_storage = api; -//} - /** * Open/create cache with provided storage options. * @param cache cache structure to be initialized diff --git a/tests/pydnstest/scenario.py b/tests/pydnstest/scenario.py index cfb04e629085d7f94e35d434a9b60bc9c4163ca0..2a9d05749eb547fe1025eb48783636370ae8291e 100644 --- a/tests/pydnstest/scenario.py +++ b/tests/pydnstest/scenario.py @@ -1,6 +1,7 @@ import dns.message import dns.rrset import dns.rcode +import dns.dnssec class Entry: """ @@ -135,6 +136,9 @@ class Entry: rdtype = args.pop(0) rr = dns.rrset.from_text(owner, ttl, rdclass, rdtype) if len(args) > 0: + if (rr.rdtype == dns.rdatatype.DS): + # convert textual algorithm identifier to number + args[1] = str(dns.dnssec.algorithm_from_text(args[1])) rd = dns.rdata.from_text(rr.rdclass, rr.rdtype, ' '.join(args), origin=dns.name.from_text(self.origin), relativize=False) rr.add(rd) return rr diff --git a/tests/test.h b/tests/test.h index d3cb3349962302608dff5fac373202d37b822a7d..b01d92fc3f3fceb41468fbb05d2884cc3d90c691 100644 --- a/tests/test.h +++ b/tests/test.h @@ -36,7 +36,7 @@ static inline void *mm_test_malloc(void *ctx, size_t n) { return test_malloc(n); } static inline void mm_test_free(void *p) -{ return test_free(p); } +{ if (p) test_free(p); } /** Memory context using CMocka allocator. */ static inline void test_mm_ctx_init(mm_ctx_t *mm) diff --git a/tests/test_cache.c b/tests/test_cache.c index 9312c74c2e20947bf37db52b4a1c1a0a3e09ec94..d3ea193deab8ec9efb2ee89a6488ac30a8e4e25a 100644 --- a/tests/test_cache.c +++ b/tests/test_cache.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <time.h> +#include <dlfcn.h> mm_ctx_t global_mm; struct kr_cache_txn global_txn; @@ -33,17 +34,63 @@ struct kr_cache_entry global_fake_ce; #define NAMEDB_DATA_SIZE (NAMEDB_INTS * sizeof(int)) uint8_t namedb_data[NAMEDB_DATA_SIZE]; namedb_val_t global_namedb_data = {namedb_data, NAMEDB_DATA_SIZE}; +bool is_malloc_mocked = false; #define CACHE_SIZE 10 * 4096 #define CACHE_TTL 10 #define CACHE_TIME 0 +void * (*original_malloc) (size_t __size); +int (*original_knot_rdataset_add)(knot_rdataset_t *rrs, const knot_rdata_t *rr, mm_ctx_t *mm) = NULL; + +void *malloc(size_t __size) +{ + Dl_info dli = {0}; + char insert_name[] = "kr_cache_insert"; + int err_mock = KNOT_EOK, insert_namelen = strlen(insert_name); + + if (original_malloc == NULL) + { + original_malloc = dlsym(RTLD_NEXT,"malloc"); + assert_non_null (malloc); + } + if (is_malloc_mocked) + { + dladdr (__builtin_return_address (0), &dli); + if (dli.dli_sname && (strncmp(insert_name,dli.dli_sname,insert_namelen) == 0)) + err_mock = mock(); + } + return (err_mock != KNOT_EOK) ? NULL : original_malloc (__size); +} + +int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, mm_ctx_t *mm) +{ + int err, err_mock; + err_mock = (int)mock(); + if (original_knot_rdataset_add == NULL) + { + original_knot_rdataset_add = dlsym(RTLD_NEXT,"knot_rdataset_add"); + assert_non_null (original_knot_rdataset_add); + } + err = original_knot_rdataset_add(rrs, rr, mm); + if (err_mock != KNOT_EOK) + err = err_mock; + return err; +} + /* Simulate init failure */ static int fake_test_init(namedb_t **db_ptr, mm_ctx_t *mm, void *arg) { + static char db[1024]; + *db_ptr = db; return mock(); } +static void fake_test_deinit(namedb_t *db) +{ + return; +} + /* Simulate commit failure */ static int fake_test_commit(namedb_txn_t *txn) { @@ -66,28 +113,35 @@ static int fake_test_find(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *va /* Stub for insert */ static int fake_test_ins(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsigned flags) { - int err = KNOT_EINVAL, res_cmp; struct kr_cache_entry *header = val->data; + int res_cmp, err = (int)mock(); if (val->len == sizeof (*header) + NAMEDB_DATA_SIZE) { header = val->data; res_cmp = memcmp(header->data,namedb_data,NAMEDB_DATA_SIZE); - if (header->timestamp == global_fake_ce.timestamp && - header->ttl == global_fake_ce.ttl && - header->ttl == global_fake_ce.ttl && - res_cmp == 0) - err = KNOT_EOK; + if (header->timestamp != global_fake_ce.timestamp || + header->ttl != global_fake_ce.ttl || + header->ttl != global_fake_ce.ttl || + res_cmp != 0) + { + err = KNOT_EINVAL; + } } return err; } +static int fake_test_txn_begin(namedb_t *db, namedb_txn_t *txn, unsigned flags) +{ + return KNOT_EOK; +} + /* Fake api */ static namedb_api_t *fake_namedb_lmdb_api(void) { static namedb_api_t fake_api = { "lmdb_fake_api", - fake_test_init, NULL, - NULL, fake_test_commit, fake_test_abort, + fake_test_init, fake_test_deinit, + fake_test_txn_begin, fake_test_commit, fake_test_abort, NULL, NULL, fake_test_find, fake_test_ins, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -100,6 +154,7 @@ static int test_open(void **state, namedb_api_t *api) { static struct kr_cache cache; struct namedb_lmdb_opts opts; + memset(&cache, 0, sizeof(cache)); memset(&opts, 0, sizeof(opts)); opts.path = global_env; opts.mapsize = CACHE_SIZE; @@ -111,6 +166,8 @@ static int test_open(void **state, namedb_api_t *api) static void test_open_fake_api(void **state) { bool res; + will_return(fake_test_init,KNOT_EINVAL); + assert_int_equal(test_open(state, fake_namedb_lmdb_api()),KNOT_EINVAL); will_return(fake_test_init,KNOT_EOK); assert_int_equal(test_open(state, fake_namedb_lmdb_api()),KNOT_EOK); res = (((struct kr_cache *)(*state))->api == fake_namedb_lmdb_api()); @@ -152,22 +209,61 @@ static struct kr_cache_txn *test_txn_rdonly(void **state) /* test invalid parameters and some api failures */ static void test_fake_invalid (void **state) { -// knot_dname_t dname[] = ""; -// assert_null(kr_cache_open(NULL, NULL, NULL)); -// assert_int_equal(kr_cache_peek(&global_txn, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, 0), -// &global_fake_ce); -// assert_int_not_equal(kr_cache_txn_commit(&global_txn), KNOT_EOK); - will_return(fake_test_init,KNOT_EINVAL); - assert_int_equal(test_open(state, fake_namedb_lmdb_api()),KNOT_EINVAL); + struct kr_cache_txn *txn = NULL; + const namedb_api_t *api_saved; + knot_dname_t dname[] = ""; + struct kr_cache_entry *ret; + + assert_int_not_equal(kr_cache_txn_commit(txn), KNOT_EOK); + txn = test_txn_write(state); + assert_int_not_equal(kr_cache_txn_commit(txn), KNOT_EOK); + ret = kr_cache_peek(txn, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, 0); + assert_int_equal(ret, &global_fake_ce); + api_saved = txn->owner->api; + txn->owner->api = NULL; + ret = kr_cache_peek(txn, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, 0); + txn->owner->api = api_saved; + assert_null(ret); } +static void test_fake_insert(void **state) +{ + int ret_cache_ins_ok, ret_cache_lowmem, ret_cache_ins_inval; + knot_dname_t dname[] = ""; + struct kr_cache_txn *txn = test_txn_write(state); + test_randstr((char *)&global_fake_ce,sizeof(global_fake_ce)); + test_randstr((char *)namedb_data,NAMEDB_DATA_SIZE); + + is_malloc_mocked = true; + will_return(malloc,KNOT_EINVAL); + ret_cache_lowmem = kr_cache_insert(txn, KR_CACHE_USER, dname, + KNOT_RRTYPE_TSIG, &global_fake_ce, global_namedb_data); + is_malloc_mocked = false; + will_return(fake_test_ins,KNOT_EOK); + ret_cache_ins_ok = kr_cache_insert(txn, KR_CACHE_USER, dname, + KNOT_RRTYPE_TSIG, &global_fake_ce, global_namedb_data); + will_return(fake_test_ins,KNOT_EINVAL); + ret_cache_ins_inval = kr_cache_insert(txn, KR_CACHE_USER, dname, + KNOT_RRTYPE_TSIG, &global_fake_ce, global_namedb_data); + assert_int_equal(ret_cache_lowmem, KNOT_ENOMEM); + assert_int_equal(ret_cache_ins_ok, KNOT_EOK); + assert_int_equal(ret_cache_ins_inval, KNOT_EINVAL); +} /* Test invalid parameters and some api failures. */ static void test_invalid(void **state) { knot_dname_t dname[] = ""; uint32_t timestamp = CACHE_TIME; + struct namedb_lmdb_opts opts; + + memset(&opts, 0, sizeof(opts)); + opts.path = global_env; + opts.mapsize = CACHE_SIZE; + knot_rrset_init_empty(&global_rr); + + assert_int_equal(kr_cache_open(NULL, NULL, &opts, &global_mm),KNOT_EINVAL); assert_int_not_equal(kr_cache_txn_begin(NULL, &global_txn, 0), 0); assert_int_not_equal(kr_cache_txn_begin(*state, NULL, 0), 0); assert_int_not_equal(kr_cache_txn_commit(NULL), 0); @@ -207,6 +303,38 @@ static void test_insert_rr(void **state) assert_int_equal(ret, KNOT_EOK); } +static void test_materialize(void **state) +{ + knot_rrset_t output_rr; + knot_dname_t * owner_saved = global_rr.owner; + bool res_cmp_ok_empty, res_cmp_fail_empty; + bool res_cmp_ok, res_cmp_fail; + + global_rr.owner = NULL; + knot_rrset_init(&output_rr, NULL, 0, 0); + kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); + res_cmp_ok_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_HEADER); + res_cmp_fail_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); + knot_rrset_clear(&output_rr,&global_mm); + global_rr.owner = owner_saved; + assert_true(res_cmp_ok_empty); + assert_false(res_cmp_fail_empty); + + knot_rrset_init(&output_rr, NULL, 0, 0); + will_return (knot_rdataset_add,KNOT_EOK); + kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); + res_cmp_ok = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); + knot_rrset_clear(&output_rr,&global_mm); + assert_true(res_cmp_ok); + + knot_rrset_init(&output_rr, NULL, 0, 0); + will_return (knot_rdataset_add,KNOT_EINVAL); + kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); + res_cmp_fail = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); + knot_rrset_clear(&output_rr,&global_mm); + assert_false(res_cmp_fail); +} + /* Test cache read */ static void test_query(void **state) { @@ -307,13 +435,17 @@ int main(void) const UnitTest tests_bad[] = { group_test_setup(test_open_fake_api), unit_test(test_fake_invalid), + unit_test(test_fake_insert), group_test_teardown(test_close) }; const UnitTest tests[] = { + /* Invalid input */ + unit_test(test_invalid), /* Cache persistence */ group_test_setup(test_open_conventional_api), unit_test(test_insert_rr), + unit_test(test_materialize), unit_test(test_query), /* Cache aging */ unit_test(test_query_aged), diff --git a/tests/test_integration.c b/tests/test_integration.c index 306dddc9554aed5a890f2dbefec53ffb5848e97b..4ea1517cc818d379c27484c5e905513a3038ee56 100644 --- a/tests/test_integration.c +++ b/tests/test_integration.c @@ -64,6 +64,7 @@ static PyObject* init(PyObject* self, PyObject* args) memset(&global_context, 0, sizeof(struct kr_context)); global_context.pool = &global_mm; global_context.modules = &global_modules; + /* Create cache */ global_tmpdir = test_tmpdir_create(); assert(global_tmpdir); @@ -72,7 +73,10 @@ static PyObject* init(PyObject* self, PyObject* args) opts.path = global_tmpdir; opts.mapsize = 100 * 4096; int ret = kr_cache_open(&global_context.cache, NULL, &opts, &global_mm); - assert(ret == 0); + if (ret != 0) { + return NULL; + } + /* Create RTT tracking */ global_context.nsrep = malloc(lru_size(kr_nsrep_lru_t, 1000)); assert(global_context.nsrep);