test_zone-update.c 10.4 KB
Newer Older
1
/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <assert.h>
#include <tap/basic.h>
19
#include <tap/files.h>
20

21
#include "test_conf.h"
22
#include "contrib/macros.h"
23
#include "contrib/getline.h"
24
#include "knot/updates/zone-update.h"
25
#include "knot/zone/node.h"
Jan Kadlec's avatar
Jan Kadlec committed
26
#include "zscanner/scanner.h"
27
#include "knot/server/server.h"
28

29 30
static const char *zone_str1 = "test. 600 IN SOA ns.test. m.test. 1 900 300 4800 900 \n";
static const char *zone_str2 = "test. IN TXT \"test\"\n";
31 32 33 34
static const char *add_str   = "test. IN TXT \"test2\"\n";
static const char *del_str   = "test. IN TXT \"test\"\n";
static const char *node_str1 = "node.test. IN TXT \"abc\"\n";
static const char *node_str2 = "node.test. IN TXT \"def\"\n";
35

36 37
knot_rrset_t rrset;

38 39 40
/*!< \brief Returns true if node contains given RR in its RRSets. */
static bool node_contains_rr(const zone_node_t *node,
                             const knot_rrset_t *rr)
41
{
42 43 44 45 46 47 48 49 50 51 52 53
	const knot_rdataset_t *zone_rrs = node_rdataset(node, rr->type);
	if (zone_rrs) {
		for (size_t i = 0; i < rr->rrs.rr_count; ++i) {
			if (!knot_rdataset_member(zone_rrs, knot_rdataset_at(&rr->rrs, i), false)) {
				return false;
			}
		}

		return true;
	} else {
		return false;
	}
54
}
55

56 57
static void process_rr(zs_scanner_t *scanner)
{
58
	knot_rrset_init(&rrset, scanner->r_owner, scanner->r_type, scanner->r_class);
59

60
	int ret = knot_rrset_add_rdata(&rrset, scanner->r_data,
61 62
	                               scanner->r_data_length,
	                               scanner->r_ttl, NULL);
63
	(void)ret;
64 65 66
	assert(ret == KNOT_EOK);
}

67
void test_full(zone_t *zone, zs_scanner_t *sc)
68
{
69
	zone_update_t update;
70
	/* Init update */
71
	int ret = zone_update_init(&update, zone, UPDATE_FULL);
72
	is_int(KNOT_EOK, ret, "zone update: init full");
73

74 75 76 77
	if (zs_set_input_string(sc, zone_str1, strlen(zone_str1)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
78

79
	/* First addition */
80 81
	ret = zone_update_add(&update, &rrset);
	knot_rdataset_clear(&rrset.rrs, NULL);
82
	is_int(KNOT_EOK, ret, "full zone update: first addition");
83

84 85 86 87
	if (zs_set_input_string(sc, zone_str2, strlen(zone_str2)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
88

89
	/* Second addition */
90
	ret = zone_update_add(&update, &rrset);
91
	zone_node_t *node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
92 93 94
	bool rrset_present = node_contains_rr(node, &rrset);
	ok(ret == KNOT_EOK && rrset_present, "full zone update: second addition");

95
	/* Removal */
96
	ret = zone_update_remove(&update, &rrset);
97
	node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
98 99 100
	rrset_present = node_contains_rr(node, &rrset);
	ok(ret == KNOT_EOK && !rrset_present, "full zone update: removal");

101
	/* Last addition */
102
	ret = zone_update_add(&update, &rrset);
103
	node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
104 105 106 107 108
	rrset_present = node_contains_rr(node, &rrset);
	ok(ret == KNOT_EOK && rrset_present, "full zone update: last addition");

	knot_rdataset_clear(&rrset.rrs, NULL);

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
	/* Prepare node removal */
	if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
	ret = zone_update_add(&update, &rrset);
	assert(ret == KNOT_EOK);
	knot_rdataset_clear(&rrset.rrs, NULL);

	if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
	ret = zone_update_add(&update, &rrset);
	assert(ret == KNOT_EOK);
	knot_rdataset_clear(&rrset.rrs, NULL);
	knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
	node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
	assert(node && node_rdataset(node, KNOT_RRTYPE_TXT)->rr_count == 2);
	/* Node removal */
	ret = zone_update_remove_node(&update, rem_node_name);
	node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
	ok(ret == KNOT_EOK && !node, "full zone update: node removal");
	knot_dname_free(&rem_node_name, NULL);

	/* Test iteration */
135 136
	zone_update_iter_t it;
	ret = zone_update_iter(&it, &update);
137
	is_int(KNOT_EOK, ret, "full zone update: init iter");
138 139 140 141 142

	const zone_node_t *iter_node = zone_update_iter_val(&it);
	assert(iter_node);
	if (zs_set_input_string(sc, zone_str1, strlen(zone_str1)) != 0 ||
	    zs_parse_all(sc) != 0) {
143 144
		assert(0);
	}
145 146 147
	rrset_present = node_contains_rr(iter_node, &rrset);
	ok(rrset_present, "full zone update: first iter value check");
	knot_rdataset_clear(&rrset.rrs, NULL);
148

149 150
	if (zs_set_input_string(sc, zone_str2, strlen(zone_str2)) != 0 ||
	    zs_parse_all(sc) != 0) {
151 152
		assert(0);
	}
153 154
	rrset_present = node_contains_rr(iter_node, &rrset);
	ok(rrset_present, "full zone update: second iter value check");
155
	knot_rdataset_clear(&rrset.rrs, NULL);
156 157

	ret = zone_update_iter_next(&it);
158
	is_int(KNOT_EOK, ret, "full zone update: iter next");
159 160 161 162

	iter_node = zone_update_iter_val(&it);
	ok(iter_node == NULL, "full zone update: iter val past end");

163
	zone_update_iter_finish(&it);
164

165 166 167 168 169 170 171 172 173 174
	/* Re-add a node for later incremental functionality test */
	if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
	ret = zone_update_add(&update, &rrset);
	assert(ret == KNOT_EOK);
	knot_rdataset_clear(&rrset.rrs, NULL);

	/* Commit */
175 176 177 178
	ret = zone_update_commit(conf(), &update);
	node = zone_contents_find_node_for_rr(zone->contents, &rrset);
	rrset_present = node_contains_rr(node, &rrset);
	ok(ret == KNOT_EOK && rrset_present, "full zone update: commit");
179

180 181 182 183 184 185
	knot_rdataset_clear(&rrset.rrs, NULL);
}

void test_incremental(zone_t *zone, zs_scanner_t *sc)
{
	int ret = KNOT_EOK;
186

187
	/* Init update */
188
	zone_update_t update;
189 190
	zone_update_init(&update, zone, UPDATE_INCREMENTAL);
	ok(update.zone == zone && changeset_empty(&update.change) && update.mm.alloc,
191 192
	   "incremental zone update: init");

193 194
	if (zs_set_input_string(sc, add_str, strlen(add_str)) != 0 ||
	    zs_parse_all(sc) != 0) {
195 196
		assert(0);
	}
197

198
	/* Addition */
199 200
	ret = zone_update_add(&update, &rrset);
	knot_rdataset_clear(&rrset.rrs, NULL);
201
	is_int(KNOT_EOK, ret, "incremental zone update: addition");
202

203
	const zone_node_t *synth_node = zone_update_get_apex(&update);
204
	ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->rr_count == 2,
205
	   "incremental zone update: add change");
206

207 208
	if (zs_set_input_string(sc, del_str, strlen(del_str)) != 0 ||
	    zs_parse_all(sc) != 0) {
209 210
		assert(0);
	}
211
	/* Removal */
212
	ret = zone_update_remove(&update, &rrset);
213
	is_int(KNOT_EOK, ret, "incremental zone update: removal");
214
	knot_rdataset_clear(&rrset.rrs, NULL);
215

216
	synth_node = zone_update_get_apex(&update);
217
	ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->rr_count == 1,
218
	   "incremental zone update: del change");
219

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	/* Prepare node removal */
	if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
	ret = zone_update_add(&update, &rrset);
	assert(ret == KNOT_EOK);
	knot_rdataset_clear(&rrset.rrs, NULL);

	knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
	synth_node = zone_update_get_node(&update, rem_node_name);
	assert(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->rr_count == 2);
	/* Node Removal */
	ret = zone_update_remove_node(&update, rem_node_name);
	synth_node = zone_update_get_node(&update, rem_node_name);
235
	ok(ret == KNOT_EOK && !synth_node,
236 237 238 239
	   "incremental zone update: node removal");
	knot_dname_free(&rem_node_name, NULL);

	/* Test iteration */
240 241
	zone_update_iter_t it;
	ret = zone_update_iter(&it, &update);
242
	is_int(KNOT_EOK, ret, "incremental zone update: init iter");
243

244 245 246 247
	if (zs_set_input_string(sc, del_str, strlen(del_str)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
248 249 250 251 252 253 254 255 256 257 258 259 260 261
	const zone_node_t *iter_node = zone_update_iter_val(&it);
	assert(iter_node);

	bool rrset_present = node_contains_rr(iter_node, &rrset);
	ok(!rrset_present, "incremental zone update: first iter value check");

	knot_rdataset_clear(&rrset.rrs, NULL);

	if (zs_set_input_string(sc, add_str, strlen(add_str)) != 0 ||
	    zs_parse_all(sc) != 0) {
		assert(0);
	}
	rrset_present = node_contains_rr(iter_node, &rrset);
	ok(rrset_present, "incremental zone update: second iter value check");
262
	knot_rdataset_clear(&rrset.rrs, NULL);
263

264
	ret = zone_update_iter_next(&it);
265
	is_int(KNOT_EOK, ret, "incremental zone update: iter next");
266
	ret = zone_update_iter_next(&it);
267
	is_int(KNOT_EOK, ret, "incremental zone update: iter next");
268 269 270 271

	iter_node = zone_update_iter_val(&it);
	ok(iter_node == NULL, "incremental zone update: iter val past end");

272
	zone_update_iter_finish(&it);
273

274
	/* Commit */
275 276 277 278 279 280 281 282 283 284 285 286
	ret = zone_update_commit(conf(), &update);
	iter_node = zone_contents_find_node_for_rr(zone->contents, &rrset);
	rrset_present = node_contains_rr(iter_node, &rrset);
	ok(ret == KNOT_EOK && rrset_present, "incremental zone update: commit");

	knot_rdataset_clear(&rrset.rrs, NULL);
}

int main(int argc, char *argv[])
{
	plan_lazy();

287 288 289
	char *temp_dir = test_mkdtemp();
	ok(temp_dir != NULL, "make temporary directory");

Daniel Salzman's avatar
Daniel Salzman committed
290 291 292 293 294 295
	char conf_str[512];
	snprintf(conf_str, sizeof(conf_str),
	         "zone:\n"
	         " - domain: test.\n"
	         "template:\n"
	         " - id: default\n"
296
		 "   max-journal-db-size: 100M\n"
Daniel Salzman's avatar
Daniel Salzman committed
297 298
	         "   storage: %s\n",
	         temp_dir);
299

300 301
	/* Load test configuration. */
	int ret = test_conf(conf_str, NULL);
302
	is_int(KNOT_EOK, ret, "load configuration");
303

304 305
	server_t server;
	ret = server_init(&server, 1);
306
	is_int(KNOT_EOK, ret, "server init");
307

308
	/* Set up empty zone */
309 310 311
	knot_dname_t *apex = knot_dname_from_str_alloc("test");
	assert(apex);
	zone_t *zone = zone_new(apex);
312
	zone->journal_db = &server.journal_db;
313

314
	/* Setup zscanner */
315 316 317 318 319 320
	zs_scanner_t sc;
	if (zs_init(&sc, "test.", KNOT_CLASS_IN, 3600) != 0 ||
	    zs_set_processing(&sc, process_rr, NULL, NULL) != 0) {
		assert(0);
	}

321
	/* Test FULL update, commit it and use the result to test the INCREMENTAL update */
322 323
	test_full(zone, &sc);
	test_incremental(zone, &sc);
324

325
	zs_deinit(&sc);
326
	zone_free(&zone);
327
	server_deinit(&server);
328
	knot_dname_free(&apex, NULL);
329
	conf_free(conf());
330 331
	test_rm_rf(temp_dir);
	free(temp_dir);
332 333 334

	return 0;
}