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);