/*
 * Copyright (C) 1999-2001, 2004, 2005, 2007, 2009, 2011-2013, 2015, 2016  Internet Systems Consortium, Inc. ("ISC")
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/* $Id: t_db.c,v 1.41 2011/03/12 04:59:46 tbox Exp $ */

#include <config.h>

#include <ctype.h>
#include <stdlib.h>

#include <isc/entropy.h>
#include <isc/hash.h>
#include <isc/mem.h>
#include <isc/string.h>
#include <isc/util.h>

#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/result.h>

#include <tests/t_api.h>

static isc_result_t
t_create(const char *db_type, const char *origin, const char *class,
	 const char *model, isc_mem_t *mctx, dns_db_t **db)
{
	int			len;
	isc_result_t		dns_result;
	dns_dbtype_t		dbtype;
	isc_textregion_t	region;
	isc_buffer_t		origin_buffer;
	dns_fixedname_t		dns_origin;
	dns_rdataclass_t	rdataclass;


	dbtype = dns_dbtype_zone;
	if (strcasecmp(model, "cache") == 0)
		dbtype = dns_dbtype_cache;

	dns_fixedname_init(&dns_origin);
	len = strlen(origin);
	isc_buffer_constinit(&origin_buffer, origin, len);
	isc_buffer_add(&origin_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_origin),
				       &origin_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		return(dns_result);
	}

	DE_CONST(class, region.base);
	region.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &region);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		return(dns_result);
	}

	dns_result = dns_db_create(mctx, db_type,
				   dns_fixedname_name(&dns_origin),
				   dbtype, rdataclass, 0, NULL, db);
	if (dns_result != ISC_R_SUCCESS)
		t_info("dns_db_create failed %s\n",
		       dns_result_totext(dns_result));

	return(dns_result);

}

static int
t_dns_db_load(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*model;
	char			*class;
	char			*expected_load_result;
	char			*findname;
	char			*find_type;
	char			*expected_find_result;

	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		findname_buffer;
	dns_fixedname_t		dns_findname;
	dns_fixedname_t		dns_foundname;
	dns_rdataset_t		rdataset;
	dns_rdatatype_t		rdatatype;
	dns_dbversion_t		*versionp;
	isc_result_t		exp_load_result;
	isc_result_t		exp_find_result;

	db = NULL;
	mctx = NULL;
	ectx = NULL;
	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	model = T_ARG(3);
	class = T_ARG(4);
	expected_load_result = T_ARG(5);
	findname = T_ARG(6);
	find_type = T_ARG(7);
	expected_find_result = T_ARG(8);

	t_info("testing using file %s and name %s\n", filename, findname);

	exp_load_result = t_dns_result_fromtext(expected_load_result);
	exp_find_result = t_dns_result_fromtext(expected_find_result);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != exp_load_result) {
		t_info("dns_db_load returned %s, expected %s\n",
				dns_result_totext(dns_result),
				dns_result_totext(exp_load_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}
	if (dns_result != ISC_R_SUCCESS) {
		result = T_PASS;
		goto cleanup_db;
	}

	dns_fixedname_init(&dns_findname);
	len = strlen(findname);
	isc_buffer_init(&findname_buffer, findname, len);
	isc_buffer_add(&findname_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
				&findname_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = find_type;
	textregion.length = strlen(find_type);
	dns_result = dns_rdatatype_fromtext(&rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				find_type,
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	versionp = NULL;
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&rdataset);
	if (dns_db_iszone(db))
		dns_db_currentversion(db, &versionp);
	nodep = NULL;

	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_findname),
			versionp,
			rdatatype,
			DNS_DBFIND_GLUEOK,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&rdataset, NULL);

	if (dns_result != exp_find_result) {
		t_info("dns_db_find returned %s, expected %s\n",
				dns_result_totext(dns_result),
				dns_result_totext(exp_find_result));
		result = T_FAIL;
	} else {
		result = T_PASS;
	}

	if (dns_result != ISC_R_NOTFOUND) {
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&rdataset))
			dns_rdataset_disassociate(&rdataset);
	}

	if (dns_db_iszone(db))
		dns_db_closeversion(db, &versionp, ISC_FALSE);
 cleanup_db:
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);
	return(result);
}

static const char *a1 =
	"A call to dns_db_load(db, filename) loads the contents of "
	"the database in filename into db.";

static void
t1(void) {
	int	result;

	t_assert("dns_db_load", 1, T_REQUIRED, "%s", a1);
	result = t_eval("dns_db_load_data", t_dns_db_load, 9);
	t_result(result);
}


static const char *a2 =
	"When the database db has cache semantics, a call to "
	"dns_db_iscache(db) returns ISC_TRUE.";

static int
t_dns_db_zc_x(char *filename, char *db_type, char *origin, char *class,
	      dns_dbtype_t dbtype, isc_boolean_t(*cf)(dns_db_t *),
	      isc_boolean_t exp_result)
{
	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_rdataclass_t	rdataclass;
	isc_textregion_t	textregion;
	isc_buffer_t		origin_buffer;
	dns_fixedname_t		dns_origin;

	db = NULL;
	mctx = NULL;
	ectx = NULL;

	t_info("testing using file %s\n", filename);

	dns_fixedname_init(&dns_origin);
	len = strlen(origin);
	isc_buffer_init(&origin_buffer, origin, len);
	isc_buffer_add(&origin_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_origin),
				       &origin_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		return(T_UNRESOLVED);
	}

	textregion.base = class;
	textregion.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
		       isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_create(mctx, db_type,
				   dns_fixedname_name(&dns_origin),
				   dbtype, rdataclass, 0, NULL, &db);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_create failed %s\n",
		       dns_result_totext(dns_result));
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result == ISC_R_SUCCESS) {
		if ((*cf)(db) == exp_result)
			result = T_PASS;
		else
			result = T_FAIL;
	} else {
		t_info("dns_db_load failed %s\n",
		       dns_result_totext(dns_result));
		result = T_FAIL;
	}

	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);
	return(result);
}

static int
test_dns_db_zc_x(const char *filename, dns_dbtype_t dbtype,
		 isc_boolean_t(*cf)(dns_db_t *), isc_boolean_t exp_result)
{

	FILE		*fp;
	char		*p;
	int		line;
	int		cnt;
	int		result;
	int		nfails;
	int		nprobs;
	char		*tokens[T_MAXTOKS];

	nfails = 0;
	nprobs = 0;

	fp = fopen(filename, "r");
	if (fp != NULL) {
		line = 0;
		while ((p = t_fgetbs(fp)) != NULL) {

			++line;

			/*
			 * Skip comment lines.
			 */
			if ((isspace((unsigned char)*p)) || (*p == '#')) {
				(void)free(p);
				continue;
			}

			cnt = t_bustline(p, tokens);
			if (cnt == 4) {
				result = t_dns_db_zc_x(tokens[0], /* file */
						       tokens[1], /* type */
						       tokens[2], /* origin */
						       tokens[3], /* class */
						       dbtype,     /* cache */
						       cf,     /* check func */
						       exp_result);/* expect */
				if (result != T_PASS) {
					if (result == T_FAIL)
						++nfails;
					else
						++nprobs;
				}
			} else {
				t_info("bad format in %s at line %d\n",
				       filename, line);
				++nprobs;
			}

			(void)free(p);
		}
		(void)fclose(fp);
	} else {
		t_info("Missing datafile %s\n", filename);
		++nprobs;
	}

	result = T_UNRESOLVED;

	if (nfails == 0 && nprobs == 0)
		result = T_PASS;
	else if (nfails)
		result = T_FAIL;

	return(result);
}

static void
t2(void) {
	int	result;

	t_assert("dns_db_iscache", 2, T_REQUIRED, "%s", a2);
	result = test_dns_db_zc_x("dns_db_iscache_1_data",
				  dns_dbtype_cache, dns_db_iscache, ISC_TRUE);
	t_result(result);
}


static const char *a3 =
	"When the database db has zone semantics, a call to "
	"dns_db_iscache(db) returns ISC_FALSE.";


static void
t3(void) {
	int	result;

	t_assert("dns_db_iscache", 3, T_REQUIRED, "%s", a3);
	result = test_dns_db_zc_x("dns_db_iscache_2_data",
				  dns_dbtype_zone, dns_db_iscache, ISC_FALSE);
	t_result(result);
}


static const char *a4 =
	"When the database db has zone semantics, a call to "
	"dns_db_iszone(db) returns ISC_TRUE.";


static void
t4(void) {
	int	result;

	t_assert("dns_db_iszone", 4, T_REQUIRED, "%s", a4);
	result = test_dns_db_zc_x("dns_db_iszone_1_data",
				  dns_dbtype_zone, dns_db_iszone, ISC_TRUE);
	t_result(result);
}


static const char *a5 =
	"When the database db has cache semantics, a call to "
	"dns_db_iszone(db) returns ISC_FALSE.";

static void
t5(void) {
	int	result;

	t_assert("dns_db_iszone", 5, T_REQUIRED, "%s", a5);
	result = test_dns_db_zc_x("dns_db_iszone_2_data",
				  dns_dbtype_cache, dns_db_iszone, ISC_FALSE);
	t_result(result);
}

static int
t_dns_db_origin(char **av) {

	char			*filename;
	char			*origin;

	int			result;
	int			len;
	int			order;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_db_t		*db;
	dns_fixedname_t		dns_origin;
	dns_fixedname_t		dns_dborigin;
	isc_buffer_t		origin_buffer;

	db = NULL;
	mctx = NULL;
	ectx = NULL;

	filename = T_ARG(0);
	origin = T_ARG(1);

	t_info("testing with database %s and origin %s\n",
			filename, origin);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
			isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create("rbt", origin, "in", "isc_true", mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("t_create failed %s\n",
			dns_result_totext(dns_result));
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}
	dns_fixedname_init(&dns_origin);
	dns_fixedname_init(&dns_dborigin);

	len = strlen(origin);
	isc_buffer_init(&origin_buffer, origin, len);
	isc_buffer_add(&origin_buffer, len);

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_origin),
				&origin_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}
	order = dns_name_compare(dns_fixedname_name(&dns_origin),
				 dns_db_origin(db));
	if (order == 0) {
		result = T_PASS;
	} else {
		t_info("dns_name_compare returned %d\n", order);
		result = T_FAIL;
	}

	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);
	return(result);

}

static const char *a6 =
	"A call to dns_db_origin(db) returns the origin of the database.";

static void
t6(void) {
	int	result;

	t_assert("dns_db_origin", 6, T_REQUIRED, "%s", a6);
	result = t_eval("dns_db_origin_data", t_dns_db_origin, 2);
	t_result(result);
}


static const char *a7 =
	"A call to dns_db_class(db) returns the class of the database.";


#define	CLASSBUFLEN	256

static int
t_dns_db_class(char **av) {

	char			*filename;
	char			*class;

	int			result;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_db_t		*db;
	dns_rdataclass_t	rdataclass;
	dns_rdataclass_t	db_rdataclass;
	isc_textregion_t	textregion;

	filename = T_ARG(0);
	class = T_ARG(1);
	db = NULL;
	mctx = NULL;
	ectx = NULL;

	t_info("testing with database %s and class %s\n",
			filename, class);

	textregion.base = class;
	textregion.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
				dns_result_totext(dns_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
			isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create("rbt", ".", class, "isc_true", mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("t_create failed %s\n",
			dns_result_totext(dns_result));
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	db_rdataclass = dns_db_class(db);
	if (db_rdataclass == rdataclass)
		result = T_PASS;
	else {
		char classbuf[DNS_RDATACLASS_FORMATSIZE];
		dns_rdataclass_format(db_rdataclass,
				      classbuf, sizeof(classbuf));
		t_info("dns_db_class returned %s, expected %s\n",
		       classbuf, class);
		result = T_FAIL;
	}

	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);
	return(result);

}
static void
t7(void) {
	int	result;

	t_assert("dns_db_class", 7, T_REQUIRED, "%s", a7);
	result = t_eval("dns_db_class_data", t_dns_db_class, 2);
	t_result(result);
}


static const char *a8 =
	"A call to dns_db_currentversion() opens the current "
	"version for reading.";

static int
t_dns_db_currentversion(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*model;
	char			*findname;
	char			*findtype;

	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		findname_buffer;
	dns_fixedname_t		dns_findname;
	dns_fixedname_t		dns_foundname;
	dns_rdataset_t		rdataset;
	dns_rdatatype_t		rdatatype;
	dns_dbversion_t		*cversionp;
	dns_dbversion_t		*nversionp;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	findname = T_ARG(5);
	findtype = T_ARG(6);
	db = NULL;
	mctx = NULL;
	ectx = NULL;

	t_info("testing using file %s and name %s\n", filename, findname);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_fixedname_init(&dns_findname);
	len = strlen(findname);
	isc_buffer_init(&findname_buffer, findname, len);
	isc_buffer_add(&findname_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
				&findname_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = findtype;
	textregion.length = strlen(findtype);
	dns_result = dns_rdatatype_fromtext(&rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				findtype,
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * find a name we know is there
	 */

	cversionp = NULL;
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&rdataset);
	dns_db_currentversion(db, &cversionp);
	nodep = NULL;

	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_findname),
			cversionp,
			rdatatype,
			0,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&rdataset, NULL);

	if (dns_result != ISC_R_SUCCESS) {
		t_info("unable to find %s using current version\n", findname);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * create a new version
	 * delete the found rdataset in the new version
	 * attempt to find the rdataset again and expect the find to fail
	 * close/commit the new version
	 * attempt to find the rdataset in the current version and
	 * expect the find to succeed
	 */

	nversionp = NULL;
	dns_result = dns_db_newversion(db, &nversionp);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_newversion failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_rdataset_disassociate(&rdataset);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Delete the found rdataset in the new version.
	 */
	dns_result = dns_db_deleterdataset(db, nodep, nversionp, rdatatype, 0);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_deleterdataset failed %s\n",
				dns_result_totext(dns_result));
		dns_rdataset_disassociate(&rdataset);
		dns_db_detachnode(db, &nodep);
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Don't need these now.
	 */
	dns_rdataset_disassociate(&rdataset);
	dns_db_detachnode(db, &nodep);
	nodep = NULL;

	/*
	 * Find the deleted rdataset and expect it to fail.
	 */
	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_findname),
			nversionp,
			rdatatype,
			0,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&rdataset, NULL);

	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {
		t_info("unexpectedly found %s using current version\n",
		       findname);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Close/commit the new version.
	 */
	dns_db_closeversion(db, &nversionp, ISC_TRUE);

	/*
	 * Find the deleted rdata in the current version.
	 */
	dns_result = dns_db_find(db, dns_fixedname_name(&dns_findname),
				 cversionp, rdatatype, DNS_DBFIND_GLUEOK,
				 0, &nodep, dns_fixedname_name(&dns_foundname),
				 &rdataset, NULL);

	/*
	 * And expect it to succeed.
	 */
	if (dns_result == ISC_R_SUCCESS) {
		result = T_PASS;
	} else {
		t_info("cound not find %s using current version\n", findname);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		result = T_FAIL;
	}

	dns_db_detachnode(db, &nodep);
	dns_rdataset_disassociate(&rdataset);

	dns_db_closeversion(db, &cversionp, ISC_FALSE);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	return(result);
}

static void
t8(void) {
	int	result;

	t_assert("dns_db_currentversion", 8, T_REQUIRED, "%s", a8);
	result = t_eval("dns_db_currentversion_data",
			t_dns_db_currentversion, 7);
	t_result(result);
}

static const char *a9 =
	"A call to dns_db_newversion() opens a new version for "
	"reading and writing.";

static int
t_dns_db_newversion(char **av) {

	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*model;
	char			*newname;
	char			*newtype;

	int			result;
	int			len;
	int			rval;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	dns_dbnode_t		*found_nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		newname_buffer;
	dns_fixedname_t		dns_newname;
	dns_fixedname_t		dns_foundname;
	dns_rdata_t		added_rdata = DNS_RDATA_INIT;
	const char *		added_rdata_data;
	dns_rdataset_t		added_rdataset;
	dns_rdata_t		found_rdata = DNS_RDATA_INIT;
	dns_rdataset_t		found_rdataset;
	dns_rdatatype_t		rdatatype;
	dns_rdataclass_t	rdataclass;
	dns_dbversion_t		*nversionp;
	dns_rdatalist_t		rdatalist;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	newname = T_ARG(5);
	newtype = T_ARG(6);
	db = NULL;
	mctx = NULL;
	ectx = NULL;

	/*
	 * Open a new version, add some data, commit it,
	 * close it, open a new version, and check that changes
	 * are present.
	 */

	t_info("testing using file %s and name %s\n", filename, newname);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Add a new name.
	 */

	dns_fixedname_init(&dns_newname);
	len = strlen(newname);
	isc_buffer_init(&newname_buffer, newname, len);
	isc_buffer_add(&newname_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_newname),
				&newname_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_newname),
				ISC_TRUE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Open a new version and associate some rdata with the new name.
	 */

	textregion.base = newtype;
	textregion.length = strlen(newtype);
	dns_result = dns_rdatatype_fromtext(&rdatatype, &textregion);

	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				newtype,
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = class;
	textregion.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_rdata_init(&added_rdata);
	added_rdata_data = "\x10\x00\x00\x01";
	DE_CONST(added_rdata_data, added_rdata.data);
	added_rdata.length = 4;
	added_rdata.rdclass = rdataclass;
	added_rdata.type = rdatatype;

	dns_rdatalist_init(&rdatalist);
	rdatalist.type = rdatatype;
	rdatalist.rdclass = rdataclass;
	ISC_LIST_APPEND(rdatalist.rdata, &added_rdata, link);

	dns_rdataset_init(&added_rdataset);
	dns_result = dns_rdatalist_tordataset(&rdatalist, &added_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatalist_tordataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nversionp = NULL;
	dns_result = dns_db_newversion(db, &nversionp);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_newversion failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_addrdataset(db, nodep, nversionp, 0,
				&added_rdataset, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_addrdataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Close and commit the version.
	 */
	dns_db_closeversion(db, &nversionp, ISC_TRUE);
	dns_db_detachnode(db, &nodep);
	if (dns_rdataset_isassociated(&added_rdataset))
		dns_rdataset_disassociate(&added_rdataset);
	nodep = NULL;

	/*
	 * Open a new version and find the data we added.
	 */
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&found_rdataset);
	nversionp = NULL;
	found_nodep = NULL;
	dns_db_newversion(db, &nversionp);

	/*
	 * Find the recently added name and rdata.
	 */
	dns_result = dns_db_find(db, dns_fixedname_name(&dns_newname),
				 nversionp, rdatatype, 0, 0, &found_nodep,
				 dns_fixedname_name(&dns_foundname),
				 &found_rdataset, NULL);

	if (dns_result != ISC_R_SUCCESS) {
		/* XXXWPK - NXRRSET ???  reference counts ??? */
		t_info("dns_db_find failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &found_nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	dns_result = dns_rdataset_first(&found_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataset_first failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Now make sure its what we expect.
	 */
	dns_rdata_init(&found_rdata);
	dns_rdataset_current(&found_rdataset, &found_rdata);
	rval = dns_rdata_compare(&added_rdata, &found_rdata);
	if (rval == 0) {
		result = T_PASS;
	} else {
		t_info("dns_rdata_compare returned %d\n", rval);
		result = T_FAIL;
	}

	/*
	 * Don't need these now.
	 */
	dns_db_closeversion(db, &nversionp, ISC_FALSE);
	if (dns_rdataset_isassociated(&found_rdataset))
		dns_rdataset_disassociate(&found_rdataset);
	dns_db_detachnode(db, &found_nodep);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	return(result);
}

static void
t9(void) {
	int	result;

	t_assert("dns_db_newversion", 9, T_REQUIRED, "%s", a9);
	result = t_eval("dns_db_newversion_data", t_dns_db_newversion, 7);
	t_result(result);
}

static const char *a10 =
	"When versionp points to a read-write version and commit is "
	"ISC_TRUE, a call to dns_db_closeversion(db, versionp, commit) "
	"causes all changes made in the version to take effect, "
	"and returns ISC_R_SUCCESS.";

static int
t_dns_db_closeversion_1(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*model;
	char			*new_name;
	char			*new_type;
	char			*existing_name;
	char			*existing_type;

	int			result;
	int			len;
	int			rval;
	int			nfails;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		name_buffer;
	dns_fixedname_t		dns_newname;
	dns_fixedname_t		dns_foundname;
	dns_fixedname_t		dns_existingname;
	dns_rdata_t		added_rdata = DNS_RDATA_INIT;
	const char *		added_rdata_data;
	dns_rdataset_t		added_rdataset;
	dns_rdata_t		found_rdata = DNS_RDATA_INIT;
	dns_rdataset_t		found_rdataset;
	dns_rdatatype_t		new_rdatatype;
	dns_rdatatype_t		existing_rdatatype;
	dns_rdataclass_t	rdataclass;
	dns_dbversion_t		*nversionp;
	dns_dbversion_t		*cversionp;
	dns_rdatalist_t		rdatalist;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	new_name = T_ARG(5);
	new_type = T_ARG(6);
	existing_name = T_ARG(7);
	existing_type = T_ARG(8);

	nfails = 0;
	db = NULL;
	mctx = NULL;
	ectx = NULL;

	/*
	 * Open a new version, add some data,
	 * remove some data, close with commit, open the current
	 * version and check that changes are present.
	 */

	t_info("testing using file %s and name %s\n", filename, new_name);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Remove all rdata for an existing name.
	 */

	dns_fixedname_init(&dns_existingname);
	len = strlen(existing_name);
	isc_buffer_init(&name_buffer, existing_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_existingname),
			&name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = existing_type;
	textregion.length = strlen(existing_type);
	dns_result = dns_rdatatype_fromtext(&existing_rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				existing_type,
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_existingname),
				ISC_FALSE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/* open a new version */
	nversionp = NULL;
	dns_result = dns_db_newversion(db, &nversionp);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_newversion failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_deleterdataset(db, nodep, nversionp,
					   existing_rdatatype, 0);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_deleterdataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * add a new name and associate some rdata with it
	 */

	dns_db_detachnode(db, &nodep);
	nodep = NULL;

	dns_fixedname_init(&dns_newname);
	len = strlen(new_name);
	isc_buffer_init(&name_buffer, new_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_newname),
				&name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_newname),
				ISC_TRUE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * associate some rdata with the new name
	 */

	textregion.base = new_type;
	textregion.length = strlen(new_type);
	dns_result = dns_rdatatype_fromtext(&new_rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				new_type,
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = class;
	textregion.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_rdata_init(&added_rdata);
	added_rdata_data = "\x10\x00\x00\x01";
	DE_CONST(added_rdata_data, added_rdata.data);
	added_rdata.length = 4;
	added_rdata.rdclass = rdataclass;
	added_rdata.type = new_rdatatype;

	dns_rdatalist_init(&rdatalist);
	rdatalist.type = new_rdatatype;
	rdatalist.rdclass = rdataclass;
	ISC_LIST_APPEND(rdatalist.rdata, &added_rdata, link);

	dns_rdataset_init(&added_rdataset);
	dns_result = dns_rdatalist_tordataset(&rdatalist, &added_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatalist_tordataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_addrdataset(db, nodep, nversionp, 0,
				&added_rdataset, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_addrdataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/* close and commit the version */
	dns_db_closeversion(db, &nversionp, ISC_TRUE);
	dns_db_detachnode(db, &nodep);
	nodep = NULL;

	/* open the current version and check changes */
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&found_rdataset);
	cversionp = NULL;
	dns_db_currentversion(db, &cversionp);

	/* find the recently added name and rdata */
	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_newname),
			cversionp,
			new_rdatatype,
			0,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&found_rdataset, NULL);

	if (dns_result != ISC_R_SUCCESS) {
		/* XXXWPK NXRRSET ??? reference counting ??? */
		t_info("dns_db_find failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	dns_result = dns_rdataset_first(&found_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataset_first failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Now make sure its what we expect.
	 */
	dns_rdata_init(&found_rdata);
	dns_rdataset_current(&found_rdataset, &found_rdata);
	rval = dns_rdata_compare(&added_rdata, &found_rdata);
	if (rval != 0) {
		t_info("dns_rdata_compare returned %d\n", rval);
		++nfails;
	}

	/*
	 * Now check the rdata deletion.
	 */

	if (dns_rdataset_isassociated(&found_rdataset))
		dns_rdataset_disassociate(&found_rdataset);
	dns_rdataset_init(&found_rdataset);
	dns_db_detachnode(db, &nodep);
	nodep = NULL;
	dns_fixedname_init(&dns_foundname);

	dns_result = dns_db_find(db, dns_fixedname_name(&dns_existingname),
				 cversionp, existing_rdatatype,
				 0, 0, &nodep,
				 dns_fixedname_name(&dns_foundname),
				 &found_rdataset, NULL);


	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {
		dns_rdataset_disassociate(&found_rdataset);
		dns_db_detachnode(db, &nodep);
		t_info("dns_db_find %s returned %s\n", existing_name,
		       dns_result_totext(dns_result));
		++nfails;
	}

	dns_db_closeversion(db, &cversionp, ISC_FALSE);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	if (nfails == 0)
		result = T_PASS;
	else
		result = T_FAIL;

	return(result);
}

static void
t10(void) {
	int	result;

	t_assert("dns_db_closeversion", 10, T_REQUIRED, "%s", a10);
	result = t_eval("dns_db_closeversion_1_data",
			t_dns_db_closeversion_1, 9);
	t_result(result);
}

static const char *a11 =
	"When versionp points to a read-write version and commit is "
	"ISC_FALSE, a call to dns_db_closeversion(db, versionp, commit) "
	"causes all changes made in the version to to be rolled back, "
	"and returns ISC_R_SUCCESS.";

static int
t_dns_db_closeversion_2(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*model;
	char			*new_name;
	char			*new_type;
	char			*existing_name;
	char			*existing_type;

	int			result;
	int			len;
	int			rval;
	int			nfails;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		name_buffer;
	dns_fixedname_t		dns_newname;
	dns_fixedname_t		dns_foundname;
	dns_fixedname_t		dns_existingname;
	dns_rdata_t		added_rdata = DNS_RDATA_INIT;
	const char *		added_rdata_data;
	dns_rdataset_t		added_rdataset;
	dns_rdata_t		found_rdata = DNS_RDATA_INIT;
	dns_rdataset_t		found_rdataset;
	dns_rdatatype_t		new_rdatatype;
	dns_rdatatype_t		existing_rdatatype;
	dns_rdataclass_t	rdataclass;
	dns_dbversion_t		*nversionp;
	dns_dbversion_t		*cversionp;
	dns_rdatalist_t		rdatalist;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	new_name = T_ARG(5);
	new_type = T_ARG(6);
	existing_name = T_ARG(7);
	existing_type = T_ARG(8);

	nfails = 0;
	db = NULL;
	mctx = NULL;
	ectx = NULL;

	/*
	 * Open a new version, add some data,
	 * remove some data, close with commit, open the current
	 * version and check that changes are present.
	 */

	t_info("testing using file %s and name %s\n", filename, new_name);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Remove all rdata for an existing name.
	 */

	dns_fixedname_init(&dns_existingname);
	len = strlen(existing_name);
	isc_buffer_init(&name_buffer, existing_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_existingname),
			&name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = existing_type;
	textregion.length = strlen(existing_type);
	dns_result = dns_rdatatype_fromtext(&existing_rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				existing_type,
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_existingname),
				ISC_FALSE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Open a new version.
	 */
	nversionp = NULL;
	dns_result = dns_db_newversion(db, &nversionp);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_newversion failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_deleterdataset(db, nodep, nversionp,
					   existing_rdatatype, 0);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_deleterdataset failed %s\n",
				dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * add a new name and associate some rdata with it
	 */

	dns_db_detachnode(db, &nodep);
	nodep = NULL;

	dns_fixedname_init(&dns_newname);
	len = strlen(new_name);
	isc_buffer_init(&name_buffer, new_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_newname),
				       &name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_newname),
				     ISC_TRUE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = new_type;
	textregion.length = strlen(new_type);
	dns_result = dns_rdatatype_fromtext(&new_rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
		       new_type, dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = class;
	textregion.length = strlen(class);
	dns_result = dns_rdataclass_fromtext(&rdataclass, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataclass_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_rdata_init(&added_rdata);
	added_rdata_data = "\x10\x00\x00\x01";
	DE_CONST(added_rdata_data, added_rdata.data);
	added_rdata.length = 4;
	added_rdata.rdclass = rdataclass;
	added_rdata.type = new_rdatatype;

	dns_rdatalist_init(&rdatalist);
	rdatalist.type = new_rdatatype;
	rdatalist.rdclass = rdataclass;
	ISC_LIST_APPEND(rdatalist.rdata, &added_rdata, link);

	dns_rdataset_init(&added_rdataset);
	dns_result = dns_rdatalist_tordataset(&rdatalist, &added_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatalist_tordataset failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_addrdataset(db, nodep, nversionp, 0,
				&added_rdataset, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_addrdataset failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Check that our changes took.
	 */
	dns_db_detachnode(db, &nodep);
	nodep = NULL;
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&found_rdataset);

	/*
	 * Find the recently added name and rdata.
	 */
	dns_result = dns_db_find(db, dns_fixedname_name(&dns_newname),
				 nversionp, new_rdatatype, 0, 0, &nodep,
				 dns_fixedname_name(&dns_foundname),
				 &found_rdataset, NULL);

	if ((dns_result == ISC_R_NOTFOUND) ||
	    (dns_result == DNS_R_NXDOMAIN) ||
	    (dns_result == DNS_R_NXRRSET)) {

		t_info("dns_db_find failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	dns_result = dns_rdataset_first(&found_rdataset);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdataset_first failed %s\n",
				dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_closeversion(db, &nversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Now make sure its what we expect.
	 */
	dns_rdata_init(&found_rdata);
	dns_rdataset_current(&found_rdataset, &found_rdata);
	rval = dns_rdata_compare(&added_rdata, &found_rdata);
	if (rval != 0) {
		t_info("dns_rdata_compare returned %d\n", rval);
		++nfails;
	}

	/*
	 * Now check the rdata deletion.
	 */
	if (dns_rdataset_isassociated(&found_rdataset))
		dns_rdataset_disassociate(&found_rdataset);
	dns_rdataset_init(&found_rdataset);
	dns_db_detachnode(db, &nodep);
	nodep = NULL;
	dns_fixedname_init(&dns_foundname);

	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_existingname),
			nversionp,
			existing_rdatatype,
			0,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&found_rdataset, NULL);


	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {
		t_info("dns_db_find %s returned %s\n", existing_name,
		       dns_result_totext(dns_result));
		if (dns_rdataset_isassociated(&found_rdataset))
			dns_rdataset_disassociate(&found_rdataset);
		dns_db_detachnode(db, &nodep);
		++nfails;
	}


	/*
	 * Close the version without a commit.
	 */
	dns_db_closeversion(db, &nversionp, ISC_FALSE);

	/*
	 * Open the current version and check changes.
	 */
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&found_rdataset);
	cversionp = NULL;
	dns_db_currentversion(db, &cversionp);

	/*
	 * Find the recently added name and rdata.
	 */
	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_newname),
			cversionp,
			new_rdatatype,
			0,
			0,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&found_rdataset, NULL);

	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {
		t_info("dns_db_find %s returned %s\n", new_name,
				dns_result_totext(dns_result));
		dns_rdataset_disassociate(&found_rdataset);
		dns_db_detachnode(db, &nodep);
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Now check the rdata deletion.
	 */
	nodep = NULL;
	dns_rdataset_init(&found_rdataset);
	dns_fixedname_init(&dns_foundname);

	dns_result = dns_db_find(db, dns_fixedname_name(&dns_existingname),
				 cversionp, existing_rdatatype, 0, 0,
				 &nodep, dns_fixedname_name(&dns_foundname),
				 &found_rdataset, NULL);


	if ((dns_result == ISC_R_NOTFOUND) ||
	    (dns_result == DNS_R_NXDOMAIN) ||
	    (dns_result == DNS_R_NXRRSET)) {

		t_info("dns_db_find %s returned %s\n", existing_name,
		       dns_result_totext(dns_result));
		dns_rdataset_disassociate(&found_rdataset);
		dns_db_detachnode(db, &nodep);
		++nfails;
	}

	dns_db_detachnode(db, &nodep);
	dns_rdataset_disassociate(&found_rdataset);
	dns_db_closeversion(db, &cversionp, ISC_FALSE);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	if (nfails == 0)
		result = T_PASS;
	else
		result = T_FAIL;

	return(result);
}

static void
t11(void) {
	int	result;

	t_assert("dns_db_closeversion", 11, T_REQUIRED, "%s", a11);
	result = t_eval("dns_db_closeversion_2_data",
			t_dns_db_closeversion_2, 9);
	t_result(result);
}

static const char *a12 =
	"A call to dns_db_expirenode() marks as stale all records at node  "
	"which expire at or before 'now'. If 'now' is zero, then the current  "
	"time will be used.";

static int
t_dns_db_expirenode(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*existing_name;
	char			*node_xtime;
	char			*find_xtime;
	char			*exp_find_result;

	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		exp_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_buffer_t		name_buffer;
	dns_fixedname_t		dns_foundname;
	dns_fixedname_t		dns_existingname;
	isc_stdtime_t		node_expire_time;
	isc_stdtime_t		find_expire_time;
	isc_stdtime_t		now;
	dns_rdataset_t		rdataset;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	existing_name = T_ARG(4);
	node_xtime = T_ARG(5);
	find_xtime = T_ARG(6);
	exp_find_result = T_ARG(7);
	mctx = NULL;
	ectx = NULL;

	/*
	 * Find a node, mark it as stale, do a dns_db_find on the name and
	 * expect it to fail.
	 */

	t_info("testing using file %s and name %s\n", filename, existing_name);

	node_expire_time = (isc_stdtime_t) strtol(node_xtime, NULL, 10);
	find_expire_time = (isc_stdtime_t) strtol(find_xtime, NULL, 10);
	exp_result = t_dns_result_fromtext(exp_find_result);

	isc_stdtime_get(&now);

	dns_fixedname_init(&dns_existingname);
	len = strlen(existing_name);
	isc_buffer_init(&name_buffer, existing_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_existingname),
				       &name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
		       dns_result_totext(dns_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
		       isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	db = NULL;
	dns_result = t_create(db_type, origin, class, "cache", mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
		       dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;

	/*
	 * Check that the node is there.
	 */
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_existingname),
				     ISC_FALSE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("unable to find %s\n", existing_name);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Expire it.
	 */
	if (node_expire_time != 0)
		node_expire_time += now;

	dns_result = dns_db_expirenode(db, nodep, node_expire_time);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_expirenode failed %s\n",
		       dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&rdataset);
	dns_db_detachnode(db, &nodep);
	nodep = NULL;

	if (find_expire_time != 0)
		find_expire_time += now;

	dns_result = dns_db_find(db,
				 dns_fixedname_name(&dns_existingname),
				 NULL,
				 dns_rdatatype_any,
				 0,
				 find_expire_time,
				 &nodep,
				 dns_fixedname_name(&dns_foundname),
				 &rdataset, NULL);

	if (dns_result == exp_result) {
		result = T_PASS;
	} else {
		t_info("dns_db_find %s returned %s\n", existing_name,
		       dns_result_totext(dns_result));
		result = T_FAIL;
	}

	if ((dns_result != ISC_R_NOTFOUND) &&
	    (dns_result != DNS_R_NXDOMAIN) &&
	    (dns_result != DNS_R_NXRRSET)) {

		/*
		 * Don't need to disassociate the rdataset because
		 * we're searching with dns_rdatatype_any.
		 */
		dns_db_detachnode(db, &nodep);
	}


	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	return(result);
}

static void
t12(void) {
	int	result;

	t_assert("dns_db_expirenode", 12, T_REQUIRED, "%s", a12);
	result = t_eval("dns_db_expirenode_data", t_dns_db_expirenode, 8);
	t_result(result);
}

static const char *a13 =
	"If the node name exists, then a call to "
	"dns_db_findnode(db, name, ISC_FALSE, nodep) initializes nodep "
	"to point to the node and returns ISC_R_SUCCESS, otherwise "
	"it returns ISC_R_NOTFOUND.";

static int
t_dns_db_findnode_1(char **av) {
	char		*filename;
	char		*db_type;
	char		*origin;
	char		*class;
	char		*model;
	char		*find_name;
	char		*find_type;
	char		*expected_result;

	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_buffer_t		name_buffer;
	dns_rdataset_t		rdataset;
	dns_rdatatype_t		rdatatype;
	isc_textregion_t	textregion;
	dns_fixedname_t		dns_name;
	dns_dbversion_t		*cversionp;
	isc_result_t		exp_result;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	find_name = T_ARG(5);
	find_type = T_ARG(6);
	expected_result = T_ARG(7);

	db = NULL;
	mctx = NULL;
	ectx = NULL;

	t_info("testing using file %s and name %s\n", filename, find_name);

	exp_result = t_dns_result_fromtext(expected_result);

	textregion.base = find_type;
	textregion.length = strlen(find_type);
	dns_result = dns_rdatatype_fromtext(&rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				find_type,
				dns_result_totext(dns_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;
	dns_fixedname_init(&dns_name);

	len = strlen(find_name);
	isc_buffer_init(&name_buffer, find_name, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_name),
				&name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			       dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_name),
				ISC_FALSE, &nodep);
	if (dns_result != exp_result) {
		t_info("dns_db_findnode failed %s\n",
				dns_result_totext(dns_result));
		if (dns_result == ISC_R_SUCCESS)
			dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * if we're expecting the find to succeed and it did,
	 * check that the node has been initialized
	 * by checking for the specified type of rdata
	 * and expecting the search to succeed
	 */

	if (dns_result == ISC_R_SUCCESS) {
		cversionp = NULL;
		dns_db_currentversion(db, &cversionp);
		dns_rdataset_init(&rdataset);

		dns_result = dns_db_findrdataset(db, nodep, cversionp,
						 rdatatype, 0,
						 0, &rdataset, NULL);
		if (dns_result == ISC_R_SUCCESS) {
			dns_rdataset_disassociate(&rdataset);
			result = T_PASS;
		} else {
			t_info("dns_db_findrdataset failed %s\n",
					dns_result_totext(dns_result));
			result = T_FAIL;
		}
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
		dns_db_detachnode(db, &nodep);
	} else {
		result = T_PASS;
	}

	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	return(result);
}

static void
t13(void) {
	int	result;

	t_assert("dns_db_findnode", 13, T_REQUIRED, "%s", a13);
	result = t_eval("dns_db_findnode_1_data", t_dns_db_findnode_1, 8);
	t_result(result);
}

static const char *a14 =
	"If the node name does not exist and create is ISC_TRUE, "
	"then a call to dns_db_findnode(db, name, create, nodep) "
	"creates the node, initializes nodep to point to the node, "
	"and returns ISC_R_SUCCESS.";

static int
t_dns_db_findnode_2(char **av) {
	char			*filename;
	char			*db_type;
	char			*origin;
	char			*class;
	char			*model;
	char			*newname;

	int			nfails;
	int			result;
	int			len;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	dns_dbnode_t		*newnodep;
	isc_buffer_t		name_buffer;
	dns_rdataset_t		rdataset;
	dns_fixedname_t		dns_name;
	dns_fixedname_t		dns_foundname;
	dns_dbversion_t		*cversionp;

	filename = T_ARG(0);
	db_type = T_ARG(1);
	origin = T_ARG(2);
	class = T_ARG(3);
	model = T_ARG(4);
	newname = T_ARG(5);

	db = NULL;
	mctx = NULL;
	ectx = NULL;
	nfails = 0;

	t_info("testing using file %s and name %s\n", filename, newname);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	dns_result = t_create(db_type, origin, class, model, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, filename);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	nodep = NULL;
	dns_fixedname_init(&dns_name);

	/*
	 * Make sure the name isn't there
	 */
	len = strlen(newname);
	isc_buffer_init(&name_buffer, newname, len);
	isc_buffer_add(&name_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_name),
				       &name_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_name),
				     ISC_FALSE, &nodep);
	if ((dns_result != ISC_R_NOTFOUND) &&
	    (dns_result != DNS_R_NXDOMAIN) &&
	    (dns_result != DNS_R_NXRRSET)) {
		t_info("dns_db_findnode %s\n",
		       dns_result_totext(dns_result));
		dns_db_detachnode(db, &nodep);
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	/*
	 * Add it.
	 */
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_name),
				ISC_TRUE, &nodep);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_findnode %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	/*
	 * Check it.
	 */
	newnodep = NULL;
	dns_rdataset_init(&rdataset);
	dns_fixedname_init(&dns_foundname);
	cversionp = NULL;
	dns_db_currentversion(db, &cversionp);

	/*
	 * First try dns_db_find DNS_R_NXDOMAIN.
	 */
	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_name),
			cversionp,
			dns_rdatatype_any,
			0,
			0,
			&newnodep,
			dns_fixedname_name(&dns_foundname),
			&rdataset, NULL);
	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {
		dns_db_detachnode(db, &newnodep);
	}

	if (dns_result != DNS_R_NXDOMAIN) {
		t_info("dns_db_find %s\n",
				dns_result_totext(dns_result));
		++nfails;
	}

	/*
	 * Then try dns_db_findnode ISC_R_SUCCESS.
	 */
	dns_result = dns_db_findnode(db, dns_fixedname_name(&dns_name),
				     ISC_FALSE, &newnodep);
	t_info("dns_db_findnode %s\n", dns_result_totext(dns_result));
	if (dns_result == ISC_R_SUCCESS) {
		dns_db_detachnode(db, &newnodep);
	} else {
		t_info("dns_db_findnode %s failed %s\n", newname,
				dns_result_totext(dns_result));
		++nfails;
	}


	dns_db_detachnode(db, &nodep);
	dns_db_closeversion(db, &cversionp, ISC_FALSE);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	if (nfails == 0)
		result = T_PASS;
	else
		result = T_FAIL;

	return(result);
}

static void
t14(void) {
	int	result;

	t_assert("dns_db_findnode", 14, T_REQUIRED, "%s", a14);
	result = t_eval("dns_db_findnode_2_data", t_dns_db_findnode_2, 6);
	t_result(result);
}

static int
t_dns_db_find_x(char **av) {
	char			*dbfile;
	char			*dbtype;
	char			*dborigin;
	char			*dbclass;
	char			*dbmodel;
	char			*findname;
	char			*findtype;
	char			*findopts;
	char			*findtime;
	char			*expected_result;

	int			result;
	int			len;
	int			opts;
	dns_db_t		*db;
	isc_result_t		dns_result;
	isc_result_t		isc_result;
	isc_stdtime_t		ftime;
	isc_stdtime_t		now;
	isc_result_t		exp_result;
	isc_mem_t		*mctx;
	isc_entropy_t		*ectx;
	dns_dbnode_t		*nodep;
	isc_textregion_t	textregion;
	isc_buffer_t		findname_buffer;
	dns_fixedname_t		dns_findname;
	dns_fixedname_t		dns_foundname;
	dns_rdataset_t		rdataset;
	dns_rdatatype_t		rdatatype;
	dns_dbversion_t		*cversionp;

	dbfile = T_ARG(0);
	dbtype = T_ARG(1);
	dborigin = T_ARG(2);
	dbclass = T_ARG(3);
	dbmodel = T_ARG(4);
	findname = T_ARG(5);
	findtype = T_ARG(6);
	findopts = T_ARG(7);
	findtime = T_ARG(8);
	expected_result = T_ARG(9);
	db = NULL;
	mctx = NULL;
	ectx = NULL;
	opts = 0;

	t_info("testing using %s, name %s, type %s\n", dbfile, findname,
	       findtype);

	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
				isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_entropy_create(mctx, &ectx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_entropy_create failed %s\n",
				isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_hash_create failed %s\n",
				isc_result_totext(isc_result));
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = t_create(dbtype, dborigin, dbclass, dbmodel, mctx, &db);
	if (dns_result != ISC_R_SUCCESS) {
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	dns_result = dns_db_load(db, dbfile);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_db_load returned %s\n",
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	exp_result = t_dns_result_fromtext(expected_result);

	dns_fixedname_init(&dns_findname);
	len = strlen(findname);
	isc_buffer_init(&findname_buffer, findname, len);
	isc_buffer_add(&findname_buffer, len);
	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
				&findname_buffer, NULL, 0, NULL);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_name_fromtext failed %s\n",
			dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	textregion.base = findtype;
	textregion.length = strlen(findtype);
	dns_result = dns_rdatatype_fromtext(&rdatatype, &textregion);
	if (dns_result != ISC_R_SUCCESS) {
		t_info("dns_rdatatype_fromtext %s failed %s\n",
				findtype,
				dns_result_totext(dns_result));
		dns_db_detach(&db);
		isc_hash_destroy();
		isc_entropy_detach(&ectx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	if (strstr(findopts, "DNS_DBFIND_GLUEOK"))
		opts |= DNS_DBFIND_GLUEOK;
	if (strstr(findopts, "DNS_DBFIND_VALIDATEGLUE"))
		opts |= DNS_DBFIND_VALIDATEGLUE;

	isc_stdtime_get(&now);

	ftime = strtol(findtime, NULL, 10);
	if (ftime != 0)
		ftime += now;

	cversionp = NULL;
	dns_fixedname_init(&dns_foundname);
	dns_rdataset_init(&rdataset);
	if (dns_db_iszone(db))
		dns_db_currentversion(db, &cversionp);
	nodep = NULL;

	dns_result = dns_db_find(db,
			dns_fixedname_name(&dns_findname),
			cversionp,
			rdatatype,
			opts,
			ftime,
			&nodep,
			dns_fixedname_name(&dns_foundname),
			&rdataset, NULL);

	if (dns_result != exp_result) {
		t_info("dns_db_find %s %s unexpectedly returned %s, "
		       "expected %s\n",
		       findname, findtype, dns_result_totext(dns_result),
		       dns_result_totext(exp_result));
		result = T_FAIL;
	} else {
		result = T_PASS;
	}

	if ((dns_result != ISC_R_NOTFOUND) && (dns_result != DNS_R_NXDOMAIN)) {

		if ((dns_result != DNS_R_NXRRSET) &&
		    (dns_result != DNS_R_ZONECUT))
			if (dns_rdataset_isassociated(&rdataset))
				dns_rdataset_disassociate(&rdataset);
		dns_db_detachnode(db, &nodep);
	}

	if (dns_db_iszone(db))
		dns_db_closeversion(db, &cversionp, ISC_FALSE);
	dns_db_detach(&db);
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
	isc_mem_destroy(&mctx);

	return(result);
}

static const char *a15 =
	"A call to dns_db_find(db, name, version, type, options, now, ...)  "
	"finds the best match for 'name' and 'type' in version 'version' "
	"of 'db'.";

static void
t15(void) {
	int	result;

	t_assert("dns_db_find", 15, T_REQUIRED, "%s", a15);
	result = t_eval("dns_db_find_1_data", t_dns_db_find_x, 10);
	t_result(result);
}


static const char *a16 =
	"When the desired node and type were found, but are glue, "
	"and the DNS_DBFIND_GLUEOK option is set, a call to "
	"dns_db_find(db, name, version, type, options, now, ...)  "
	"returns DNS_R_GLUE.";

static void
t16(void) {
	int	result;

	t_assert("dns_db_find", 16, T_REQUIRED, "%s", a16);
	result = t_eval("dns_db_find_2_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a17 =
	"A call to dns_db_find() returns DNS_R_DELEGATION when the data "
	"requested is beneath a zone cut.";

static void
t17(void) {
	int	result;

	t_assert("dns_db_find", 17, T_REQUIRED, "%s", a17);
	result = t_eval("dns_db_find_3_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a18 =
	"A call to dns_db_find() returns DNS_R_DELEGATION when type is "
	"dns_rdatatype_any and the desired node is a zone cut.";

static void
t18(void) {
	int	result;

	t_assert("dns_db_find", 18, T_REQUIRED, "%s", a18);
	result = t_eval("dns_db_find_4_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a19 =
	"A call to dns_db_find() returns DNS_R_DNAME when the data "
	"requested is beneath a DNAME.";

static void
t19(void) {
	int	result;

	t_assert("dns_db_find", 19, T_REQUIRED, "%s", a19);
	result = t_eval("dns_db_find_5_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a20 =
	"A call to dns_db_find() returns DNS_R_CNAME when the requested "
	"rdataset was not found but there is a CNAME at the desired name.";

static void
t20(void) {
	int	result;

	t_assert("dns_db_find", 20, T_REQUIRED, "%s", a20);
	result = t_eval("dns_db_find_6_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a21 =
	"A call to dns_db_find() returns DNS_R_NXDOMAIN when name "
	"does not exist.";

static void
t21(void) {
	int	result;

	t_assert("dns_db_find", 21, T_REQUIRED, "%s", a21);
	result = t_eval("dns_db_find_7_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a22 =
	"A call to dns_db_find() returns DNS_R_NXRRSET when "
	"the desired name exists, but the desired type does not.";

static void
t22(void) {
	int	result;

	t_assert("dns_db_find", 22, T_REQUIRED, "%s", a22);
	result = t_eval("dns_db_find_8_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a23 =
	"When db is a cache database, a call to dns_db_find() "
	"returns ISC_R_NOTFOUND when the desired name does not exist, "
	"and no delegation could be found.";

static void
t23(void) {
	int	result;

	t_assert("dns_db_find", 23, T_REQUIRED, "%s", a23);
	result = t_eval("dns_db_find_9_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a24 =
	"When db is a cache database, an rdataset will be found only "
	"if at least one rdataset at the found node expires after 'now'.";

static void
t24(void) {
	int	result;

	t_assert("dns_db_find", 24, T_REQUIRED, "%s", a24);
	result = t_eval("dns_db_find_10_data", t_dns_db_find_x, 10);
	t_result(result);
}

static const char *a25 =
	"A call to dns_db_load(db, filename) returns DNS_R_NOTZONETOP "
	"when the zone data contains a SOA not at the zone apex.";

static void
t25(void) {
	int	result;

	t_assert("dns_db_load", 25, T_REQUIRED, "%s", a25);
	result = t_eval("dns_db_load_soa_not_top", t_dns_db_load, 9);
	t_result(result);
}

testspec_t	T_testlist[] = {
	{	(PFV) t1,		"dns_db_load"		},
	{	(PFV) t2,		"dns_db_iscache"	},
	{	(PFV) t3,		"dns_db_iscache"	},
	{	(PFV) t4,		"dns_db_iszone"		},
	{	(PFV) t5,		"dns_db_iszone"		},
	{	(PFV) t6,		"dns_db_origin"		},
	{	(PFV) t7,		"dns_db_class"		},
	{	(PFV) t8,		"dns_db_currentversion"	},
	{	(PFV) t9,		"dns_db_newversion"	},
	{	(PFV) t10,		"dns_db_closeversion"	},
	{	(PFV) t11,		"dns_db_closeversion"	},
	{	(PFV) t12,		"dns_db_expirenode"	},
	{	(PFV) t13,		"dns_db_findnode"	},
	{	(PFV) t14,		"dns_db_findnode"	},
	{	(PFV) t15,		"dns_db_find"		},
	{	(PFV) t16,		"dns_db_find"		},
	{	(PFV) t17,		"dns_db_find"		},
	{	(PFV) t18,		"dns_db_find"		},
	{	(PFV) t19,		"dns_db_find"		},
	{	(PFV) t20,		"dns_db_find"		},
	{	(PFV) t21,		"dns_db_find"		},
	{	(PFV) t22,		"dns_db_find"		},
	{	(PFV) t23,		"dns_db_find"		},
	{	(PFV) t24,		"dns_db_find"		},
	{	(PFV) t25,		"dns_db_load"		},
	{	(PFV) 0,		NULL			}
};

#ifdef WIN32
int
main(int argc, char **argv) {
	t_settests(T_testlist);
	return (t_main(argc, argv));
}
#endif
