summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/README10
-rw-r--r--src/tests/common/acl_tests.c111
-rw-r--r--src/tests/common/acl_tests.h25
-rw-r--r--src/tests/common/da_tests.c330
-rw-r--r--src/tests/common/da_tests.h25
-rw-r--r--src/tests/common/events_tests.c192
-rw-r--r--src/tests/common/events_tests.h25
-rw-r--r--src/tests/common/fdset_tests.c177
-rw-r--r--src/tests/common/fdset_tests.h25
-rw-r--r--src/tests/common/skiplist_tests.c198
-rw-r--r--src/tests/common/skiplist_tests.h25
-rw-r--r--src/tests/common/slab_tests.c141
-rw-r--r--src/tests/common/slab_tests.h25
-rw-r--r--src/tests/files/sample_conf59
-rw-r--r--src/tests/knot/conf_tests.c141
-rw-r--r--src/tests/knot/conf_tests.h25
-rw-r--r--src/tests/knot/dthreads_tests.c392
-rw-r--r--src/tests/knot/dthreads_tests.h25
-rw-r--r--src/tests/knot/journal_tests.c184
-rw-r--r--src/tests/knot/journal_tests.h25
-rw-r--r--src/tests/knot/server_tests.c113
-rw-r--r--src/tests/knot/server_tests.h25
-rw-r--r--src/tests/libknot/files/parsed_databin0 -> 71188 bytes
-rw-r--r--src/tests/libknot/files/parsed_data_queriesbin0 -> 1325 bytes
-rw-r--r--src/tests/libknot/files/raw_databin0 -> 72100 bytes
-rw-r--r--src/tests/libknot/files/raw_data_queriesbin0 -> 1387 bytes
-rw-r--r--src/tests/libknot/libknot/cuckoo_tests.c382
-rw-r--r--src/tests/libknot/libknot/cuckoo_tests.h25
-rw-r--r--src/tests/libknot/libknot/dname_table_tests.c393
-rw-r--r--src/tests/libknot/libknot/dname_table_tests.h25
-rw-r--r--src/tests/libknot/libknot/dname_tests.c877
-rw-r--r--src/tests/libknot/libknot/dname_tests.h25
-rw-r--r--src/tests/libknot/libknot/edns_tests.c596
-rw-r--r--src/tests/libknot/libknot/edns_tests.h34
-rw-r--r--src/tests/libknot/libknot/node_tests.c344
-rw-r--r--src/tests/libknot/libknot/node_tests.h25
-rw-r--r--src/tests/libknot/libknot/nsec3_tests.c252
-rw-r--r--src/tests/libknot/libknot/nsec3_tests.h25
-rw-r--r--src/tests/libknot/libknot/packet_tests.c430
-rw-r--r--src/tests/libknot/libknot/packet_tests.h25
-rw-r--r--src/tests/libknot/libknot/query_tests.c160
-rw-r--r--src/tests/libknot/libknot/query_tests.h25
-rw-r--r--src/tests/libknot/libknot/rdata_tests.c954
-rw-r--r--src/tests/libknot/libknot/rdata_tests.h52
-rw-r--r--src/tests/libknot/libknot/response_tests.c450
-rw-r--r--src/tests/libknot/libknot/response_tests.h25
-rw-r--r--src/tests/libknot/libknot/rrset_tests.c888
-rw-r--r--src/tests/libknot/libknot/rrset_tests.h34
-rw-r--r--src/tests/libknot/libknot/zone_tests.c853
-rw-r--r--src/tests/libknot/libknot/zone_tests.h25
-rw-r--r--src/tests/libknot/libknot/zone_tree_tests.c758
-rw-r--r--src/tests/libknot/libknot/zone_tree_tests.h25
-rw-r--r--src/tests/libknot/libknot/zonedb_tests.c44
-rw-r--r--src/tests/libknot/libknot/zonedb_tests.h25
-rw-r--r--src/tests/libknot/realdata/files/parsed_databin0 -> 4851 bytes
-rw-r--r--src/tests/libknot/realdata/files/parsed_data_queriesbin0 -> 1325 bytes
-rw-r--r--src/tests/libknot/realdata/files/raw_databin0 -> 4935 bytes
-rw-r--r--src/tests/libknot/realdata/files/raw_data_queriesbin0 -> 1387 bytes
-rw-r--r--src/tests/libknot/realdata/libknot/dname_tests_realdata.c411
-rw-r--r--src/tests/libknot/realdata/libknot/dname_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/edns_tests_realdata.c563
-rw-r--r--src/tests/libknot/realdata/libknot/edns_tests_realdata.h35
-rw-r--r--src/tests/libknot/realdata/libknot/node_tests_realdata.c385
-rw-r--r--src/tests/libknot/realdata/libknot/node_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/packet_tests_realdata.c679
-rw-r--r--src/tests/libknot/realdata/libknot/packet_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/rdata_tests_realdata.c329
-rw-r--r--src/tests/libknot/realdata/libknot/rdata_tests_realdata.h53
-rw-r--r--src/tests/libknot/realdata/libknot/response_tests_realdata.c173
-rw-r--r--src/tests/libknot/realdata/libknot/response_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/rrset_tests_realdata.c289
-rw-r--r--src/tests/libknot/realdata/libknot/rrset_tests_realdata.h35
-rw-r--r--src/tests/libknot/realdata/libknot/zone_tests_realdata.c335
-rw-r--r--src/tests/libknot/realdata/libknot/zone_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c44
-rw-r--r--src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot_tests_loader_realdata.c1300
-rw-r--r--src/tests/libknot/realdata/libknot_tests_loader_realdata.h179
-rw-r--r--src/tests/libknot/realdata/unittests_libknot_realdata.c93
-rw-r--r--src/tests/libknot/unittests_libknot.c90
-rw-r--r--src/tests/unittests_main.c84
81 files changed, 15301 insertions, 0 deletions
diff --git a/src/tests/README b/src/tests/README
new file mode 100644
index 0000000..2f299ad
--- /dev/null
+++ b/src/tests/README
@@ -0,0 +1,10 @@
+Unit testing
+------------
+
+Make assembles "unittest" binary with all of the planned tests included.
+So far it is accepting the same parameters as the "cutedns",
+but an own parameter format is being developed.
+
+Example:
+bin/unittest samples/example.com.zone
+
diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c
new file mode 100644
index 0000000..b4232ac
--- /dev/null
+++ b/src/tests/common/acl_tests.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <sys/socket.h>
+
+#include "tests/common/acl_tests.h"
+#include "common/sockaddr.h"
+#include "common/acl.h"
+
+static int acl_tests_count(int argc, char *argv[]);
+static int acl_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api acl_tests_api = {
+ "ACL", //! Unit name
+ &acl_tests_count, //! Count scheduled tests
+ &acl_tests_run //! Run scheduled tests
+};
+
+static int acl_tests_count(int argc, char *argv[])
+{
+ return 13;
+}
+
+static int acl_tests_run(int argc, char *argv[])
+{
+ // 1. Create an ACL
+ acl_t *acl = acl_new(ACL_DENY, "simple ACL");
+ ok(acl != 0, "acl: new");
+
+ // 2. Create IPv4 address
+ sockaddr_t test_v4;
+ int ret = sockaddr_set(&test_v4, AF_INET, "127.0.0.1", 12345);
+ ok(ret > 0, "acl: new IPv4 address");
+
+ // 3. Create IPv6 address
+ sockaddr_t test_v6;
+ ret = sockaddr_set(&test_v6, AF_INET6, "::1", 54321);
+ ok(ret > 0, "acl: new IPv6 address");
+
+ // 4. Create simple IPv4 rule
+ ret = acl_create(acl, &test_v4, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv4 rule");
+
+ // 5. Create simple IPv6 rule
+ ret = acl_create(acl, &test_v6, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv6 rule");
+
+ // 6. Create simple IPv4 'any port' rule
+ sockaddr_t test_v4a;
+ sockaddr_set(&test_v4a, AF_INET, "20.20.20.20", 0);
+ ret = acl_create(acl, &test_v4a, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv4 'any port' rule");
+
+ // 7. Attempt to match unmatching address
+ sockaddr_t unmatch_v4;
+ sockaddr_set(&unmatch_v4, AF_INET, "10.10.10.10", 24424);
+ ret = acl_match(acl, &unmatch_v4);
+ ok(ret == ACL_DENY, "acl: matching non-existing address");
+
+ // 8. Attempt to match unmatching IPv6 address
+ sockaddr_t unmatch_v6;
+ sockaddr_set(&unmatch_v6, AF_INET6, "2001:db8::1428:57ab", 24424);
+ ret = acl_match(acl, &unmatch_v6);
+ ok(ret == ACL_DENY, "acl: matching non-existing IPv6 address");
+
+ // 9. Attempt to match matching address
+ ret = acl_match(acl, &test_v4);
+ ok(ret == ACL_ACCEPT, "acl: matching existing address");
+
+ // 10. Attempt to match matching address
+ ret = acl_match(acl, &test_v6);
+ ok(ret == ACL_ACCEPT, "acl: matching existing IPv6 address");
+
+ // 11. Attempt to match matching 'any port' address
+ sockaddr_t match_v4a;
+ sockaddr_set(&match_v4a, AF_INET, "20.20.20.20", 24424);
+ ret = acl_match(acl, &match_v4a);
+ ok(ret == ACL_ACCEPT, "acl: matching existing IPv4 'any port' address");
+
+ // 12. Attempt to match matching address without matching port
+ sockaddr_set(&unmatch_v4, AF_INET, "127.0.0.1", 54321);
+ ret = acl_match(acl, &unmatch_v4);
+ ok(ret == ACL_DENY, "acl: matching address without matching port");
+
+ // 13. Invalid parameters
+ lives_ok({
+ acl_delete(0);
+ acl_create(0, 0, ACL_ERROR);
+ acl_match(0, 0);
+ acl_truncate(0);
+ acl_name(0);
+ }, "acl: won't crash with NULL parameters");
+
+ // Return
+ return 0;
+}
diff --git a/src/tests/common/acl_tests.h b/src/tests/common/acl_tests.h
new file mode 100644
index 0000000..a928e2d
--- /dev/null
+++ b/src/tests/common/acl_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_ACL_TESTS_H_
+#define _KNOTD_ACL_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api acl_tests_api;
+
+#endif /* _KNOTD_ACL_TESTS_H_ */
diff --git a/src/tests/common/da_tests.c b/src/tests/common/da_tests.c
new file mode 100644
index 0000000..627e8aa
--- /dev/null
+++ b/src/tests/common/da_tests.c
@@ -0,0 +1,330 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/common/da_tests.h"
+#include "common/dynamic-array.h"
+#include <unistd.h>
+#include <urcu.h>
+
+static int da_tests_count(int argc, char *argv[]);
+static int da_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api da_tests_api = {
+ "Dynamic array",
+ &da_tests_count,
+ &da_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int DA_TEST_COUNT = 5;
+static const int RCU_THREADS = 3;
+static const int DA_FRAGMENT = 10;
+static const int DA_DEF_SIZE = 1000;
+static const int DA_OPERATIONS = 1000;
+enum Operations {
+ DA_RESERVE = 0,
+ DA_OCCUPY = 1,
+ DA_RELEASE = 2,
+ DA_OPCOUNT = 3
+};
+
+static int da_tests_count(int argc, char *argv[])
+{
+ return DA_TEST_COUNT;
+}
+
+static void do_something(int loops)
+{
+ int i;
+ int res = 1;
+
+ static const int LOOPS = 10000;
+
+ for (int j = 1; j <= LOOPS; ++j) {
+ for (i = 1; i <= loops; ++i) {
+ res *= i;
+ }
+ }
+}
+
+static void *test_rcu_routine(void *obj)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+
+ do_something(1000);
+
+ rcu_read_unlock();
+ rcu_unregister_thread();
+
+ return NULL;
+}
+
+static int test_rcu_threads()
+{
+ // Create threads
+ pthread_t *threads = malloc(RCU_THREADS * sizeof(pthread_t));
+ for (int i = 0; i < RCU_THREADS; ++i) {
+ if (pthread_create(&threads[i], NULL, test_rcu_routine, NULL)) {
+ diag("rcu: failed to create thread %d", i);
+ free(threads);
+ return 0;
+ }
+ }
+
+ // Join threads
+ void *pret = NULL;
+ for (int i = 0; i < RCU_THREADS; ++i) {
+ if (pthread_join(threads[i], &pret)) {
+ diag("rcu: failed to join thread %d", i);
+ free(threads);
+ return 0;
+ }
+ }
+
+ synchronize_rcu();
+ free(threads);
+
+ return 1;
+}
+
+static int test_da_init(da_array_t *arr)
+{
+ return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0;
+}
+
+static int test_da_random_op(da_array_t *arr)
+{
+ unsigned seed = (unsigned)time(0);
+ uint allocated = DA_DEF_SIZE;
+ uint size = 0;
+
+ for (int i = 0; i < DA_OPERATIONS; ++i) {
+ int r = rand_r(&seed) % DA_OPCOUNT;
+ int count = rand_r(&seed) % DA_FRAGMENT + 1;
+
+ switch (r) {
+
+ // Perform reserve operation
+ case DA_RESERVE:
+ if (da_reserve(arr, count) >= 0 &&
+ size <= allocated) {
+ if ((allocated - size) < count) {
+ allocated *= 2;
+ }
+ } else {
+ diag("dynamic-array: da_reserve(%p, %d) failed"
+ " (size %d, alloc'd %d)",
+ arr, count, size, allocated);
+ return 0;
+ }
+ break;
+
+ // Perform occupy operation
+ case DA_OCCUPY:
+ if (da_occupy(arr, count) == 0) {
+ uint *items = (uint *) da_get_items(arr);
+ for (int j = 0; j < da_get_count(arr); ++j) {
+ items[j] = rand_r(&seed);
+ }
+ if (size <= allocated &&
+ (allocated - size) >= count) {
+ size += count;
+ } else {
+ return 0;
+ }
+ } else {
+ diag("dynamic-array: da_occupy(%p, %d) failed"
+ " (size %d, alloc'd %d)",
+ arr, count, size, allocated);
+ return 0;
+ }
+ break;
+
+ // Perform release operation
+ case DA_RELEASE:
+ if (arr->count > 0) {
+ count = (rand_r(&seed) % DA_FRAGMENT) % arr->count;
+ da_release(arr, count);
+
+ if (size <= allocated && size >= count) {
+ size -= count;
+ } else {
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Check allocated / size
+ if (allocated != arr->allocated || size != arr->count) {
+ diag("dynamic-array: allocated memory %d (expected %d)"
+ " size %d (expected %d) mismatch",
+ arr->allocated, allocated, arr->count, size);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void *test_da_read(void *obj)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+
+ unsigned seed = (unsigned)time(0);
+ da_array_t *arr = (da_array_t *) obj;
+ int index = rand_r(&seed) % da_get_count(arr);
+
+ note(" dynamic-array: read thread");
+ note(" read thread: saving pointer to %d. item", index);
+ uint *item = &((uint *) da_get_items(arr))[index];
+ note(" read thread: before: pointer: %p item: %u", item, *item);
+
+ do_something(100000);
+
+ note(" read thread after: pointer: %p item: %u", item, *item);
+ rcu_read_unlock();
+ note(" read thread unlocked: pointer: %p item: %u", item, *item);
+
+ do_something(10000);
+
+ note(" read thread: now the item should be deallocated");
+ //note(" read thread: pointer: %p item: %u", item, *item);
+
+ rcu_unregister_thread();
+
+ return NULL;
+}
+
+static int test_da_resize_holding(da_array_t *arr)
+{
+ int ret = 1;
+ rcu_register_thread();
+ pthread_t reader;
+
+ // Create thread for reading
+ note("dynamic-array: creating read threads");
+ if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) {
+ diag("dynamic-array: failed to create reading thread",
+ __func__);
+ rcu_unregister_thread();
+ return 0;
+ }
+
+ // Wait some time, so the other thread gets the item for reading
+ do_something(5000);
+
+ // Force resize
+ note(" dynamic-array: array resized");
+ if (da_reserve(arr, arr->allocated - arr->count + 1) == -1) {
+ diag("dynamic-array: da_reserve(%p, %d) failed", arr,
+ arr->allocated - arr->count + 1);
+ ret = 0;
+ }
+
+ //Wait for the thread to finish
+ void *pret = NULL;
+ if (pthread_join(reader, &pret)) {
+ diag("dynamic-array: failed to join reading thread",
+ __func__);
+ ret = 0;
+ }
+
+ rcu_unregister_thread();
+ return ret;
+}
+
+static int test_da_resize(da_array_t *arr)
+{
+ unsigned seed = (unsigned)time(0);
+ int orig_count = da_get_count(arr);
+ note("dynamic-array: allocated: %d, items: %d", arr->allocated,
+ orig_count);
+ // store the items currently in the array
+ int *items = (int *)malloc(orig_count * sizeof(int));
+ for (int i = 0; i < orig_count; ++i) {
+ items[i] = ((int *)da_get_items(arr))[i];
+ }
+
+ // force resize
+ int res = 0;
+ while ((res = da_reserve(arr, 10)) == 0) {
+ int i = da_get_count(arr);
+ da_occupy(arr, 10);
+ for (; i < da_get_count(arr); ++i) {
+ ((int *)da_get_items(arr))[i] = rand_r(&seed);
+ }
+ }
+
+ if (res < 0) {
+ diag("dynamic-array: failed to reserve space");
+ return 0;
+ }
+
+ int errors = 0;
+ for (int i = 0; i < orig_count; ++i) {
+ if (items[i] != ((int *)da_get_items(arr))[i]) {
+ diag("dynamic-array: Wrong item on position %d."
+ "Should be: %d, "
+ "present value: %d", i, items[i],
+ ((int *)da_get_items(arr))[i]);
+ ++errors;
+ }
+ }
+
+ free(items);
+
+ return errors == 0;
+}
+
+static int da_tests_run(int argc, char *argv[])
+{
+ // Init
+ rcu_init();
+ da_array_t array;
+
+ // Test 1: test rcu
+ ok(test_rcu_threads(), "dynamic-array: rcu tests");
+
+ // Test 2: init
+ ok(test_da_init(&array), "dynamic-array: init");
+
+ // Test 3: reserve/occupy random operations
+ ok(test_da_random_op(&array),
+ "dynamic-array: randomized reserve/occupy/release");
+
+ // Test 4: resizing array while holding an item
+ ok(test_da_resize_holding(&array),
+ "dynamic-array: resize array while holding an item");
+
+ // Test 5: resize
+ ok(test_da_resize(&array), "dynamic-array: resize array");
+
+ // Cleanup
+ da_destroy(&array);
+ return 0;
+}
diff --git a/src/tests/common/da_tests.h b/src/tests/common/da_tests.h
new file mode 100644
index 0000000..d51b7be
--- /dev/null
+++ b/src/tests/common/da_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_DA_TESTS_H_
+#define _KNOTD_DA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api da_tests_api;
+
+#endif /* _KNOTD_DA_TESTS_H_ */
diff --git a/src/tests/common/events_tests.c b/src/tests/common/events_tests.c
new file mode 100644
index 0000000..d7702fe
--- /dev/null
+++ b/src/tests/common/events_tests.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdlib.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "tests/common/events_tests.h"
+#include "common/evqueue.h"
+#include "common/evsched.h"
+
+static int events_tests_count(int argc, char *argv[]);
+static int events_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api events_tests_api = {
+ "Event queue and scheduler", //! Unit name
+ &events_tests_count, //! Count scheduled tests
+ &events_tests_run //! Run scheduled tests
+};
+
+void* term_thr(void *arg)
+{
+ evsched_t *s = (evsched_t *)arg;
+
+ /* Sleep for 100ms. */
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000; // 100ms
+ select(0, 0, 0, 0, &tv);
+
+ /* Issue termination event. */
+ evsched_schedule_term(s, 0);
+ return 0;
+}
+
+static int events_tests_count(int argc, char *argv[])
+{
+ return 9 + 11;
+}
+
+static int events_tests_run(int argc, char *argv[])
+{
+ /*
+ * Event queue tests.
+ */
+
+ // 1. Construct an event queue
+ evqueue_t *q = evqueue_new();
+ ok(q != 0, "evqueue: new");
+
+ // 2. Send integer through event queue
+ int ret = 0;
+ uint8_t sent = 0xaf, rcvd = 0;
+ ret = evqueue_write(q, &sent, sizeof(uint8_t));
+ ok(ret == sizeof(uint8_t), "evqueue: send byte through");
+
+ // 3. Receive byte from event queue
+ ret = evqueue_read(q, &rcvd, sizeof(uint8_t));
+ ok(ret == sizeof(uint8_t), "evqueue: received byte");
+
+ // 4. Received match
+ ok(sent == rcvd, "evqueue: received byte match");
+
+ // 5. Sending event
+ event_t ev, rev;
+ memset(&ev, 0, sizeof(event_t));
+ memset(&rev, 0, sizeof(event_t));
+ ev.type = 0xfa11;
+ ev.data = (void*)0xceed;
+ ret = evqueue_add(q, &ev);
+ ok(ret == 0, "evqueue: sent event to queue");
+
+ // 6. Poll for new events
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100 * 1000 * 1000; // 100ms
+ ret = evqueue_poll(q, &ts, 0);
+ ok(ret > 0, "evqueue: polling queue for events");
+
+ // 7. Compare received event
+ ret = evqueue_get(q, &rev);
+ /* Compare useful data, as event owner was changed in evqueue_get(). */
+ if (ev.type == rev.type && ev.data == rev.data) {
+ ret = 0;
+ }
+ ok(ret == 0, "evqueue: received event matches sent");
+
+ // 8. Invalid parameters
+ lives_ok({
+ evqueue_free(0);
+ evqueue_poll(0,0,0);
+ evqueue_read(0, 0, 0);
+ evqueue_write(0, 0, 0);
+ evqueue_read(0, 0, 0);
+ evqueue_get(0, 0);
+ evqueue_add(0, 0);
+ }, "evqueue: won't crash with NULL parameters");
+
+ // 9. Free event queue
+ lives_ok({evqueue_free(&q);}, "evqueue: delete");
+
+ /*
+ * Event scheduler tests.
+ */
+
+ // 1. Construct event scheduler
+ event_t *e = 0;
+ evsched_t *s = evsched_new();
+ ok(s != 0, "evsched: new");
+
+ // 2. Schedule event to happen after N ms
+ int msecs = 50;
+ struct timeval st, rt;
+ gettimeofday(&st, 0);
+ e = evsched_schedule_cb(s, 0, (void*)0xcafe, msecs);
+ ok(e != 0, "evsched: scheduled empty event after %dms", msecs);
+
+ // 3. Wait for next event
+ e = evsched_next(s);
+ evsched_event_finished(s);
+ gettimeofday(&rt, 0);
+ ok(e != 0, "evsched: received valid event");
+
+ // 4. Check receive time
+ double passed = (rt.tv_sec - st.tv_sec) * 1000;
+ passed += (rt.tv_usec - st.tv_usec) / 1000;
+ double margin = msecs * 0.2;
+ double lb = msecs - margin, ub = msecs + margin;
+ int in_bounds = (passed >= lb) && (passed <= ub);
+ ok(in_bounds, "evsched: receive time %.1lfms is in <%.1lf,%.1lf>",
+ passed, lb, ub);
+
+ // 5. Check data
+ ok(e->data == (void*)0xcafe, "evsched: received data is valid");
+
+ // 6. Delete event
+ lives_ok({evsched_event_free(s, e);}, "evsched: deleted event");
+
+ // 7. Insert and immediately cancel an event
+ e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000);
+ ret = evsched_cancel(s, e);
+ ok(ret == 0, "evsched: inserted and cancelled an event");
+ if (e) {
+ evsched_event_free(s, e);
+ }
+
+ // 8. Start listener thread and block
+ pthread_t t;
+ pthread_create(&t, 0, term_thr, s);
+ e = evsched_next(s);
+ evsched_event_finished(s);
+ ok(e != 0, "evsched: received termination event");
+
+ // 9. Termination event is valid
+ ok(e->type == EVSCHED_TERM, "evsched: termination event is valid");
+ evsched_event_free(s, e);
+ pthread_join(t, 0);
+
+ // 10. Invalid parameters
+ lives_ok({
+ evsched_delete(0);
+ evsched_event_new(0, 0);
+ evsched_event_free(0, 0);
+ evsched_next(0);
+ evsched_schedule(0, 0, 0);
+ evsched_schedule_cb(0, 0, 0, 0);
+ evsched_schedule_term(0, 0);
+ evsched_cancel(0, 0);
+
+ }, "evsched: won't crash with NULL parameters");
+
+ // 11. Delete event scheduler
+ lives_ok({evsched_delete(&s);}, "evsched: delete");
+
+
+ return 0;
+}
diff --git a/src/tests/common/events_tests.h b/src/tests/common/events_tests.h
new file mode 100644
index 0000000..b54b6da
--- /dev/null
+++ b/src/tests/common/events_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD__EVENTS_TESTS_H_
+#define _KNOTD__EVENTS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api events_tests_api;
+
+#endif /* _KNOTD__EVENTS_TESTS_H_ */
diff --git a/src/tests/common/fdset_tests.c b/src/tests/common/fdset_tests.c
new file mode 100644
index 0000000..7dd95a1
--- /dev/null
+++ b/src/tests/common/fdset_tests.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdlib.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+#include "tests/common/fdset_tests.h"
+#include "common/fdset.h"
+
+#define WRITE_PATTERN ((char) 0xde)
+#define WRITE_PATTERN_LEN sizeof(char)
+
+
+/* Subtract the `struct timeval' values X and Y,
+ storing the result in RESULT.
+ Return 1 if the difference is negative, otherwise 0.
+ Copyright http://www.delorie.com/gnu/docs/glibc/libc_428.html
+*/
+static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval* y)
+{
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec) {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > 1000000) {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_usec is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+static size_t timeval_diff(struct timeval *from, struct timeval *to) {
+ struct timeval res;
+ timeval_subtract(&res, to, from);
+ return res.tv_sec*1000 + res.tv_usec/1000;
+}
+
+static int fdset_tests_count(int argc, char *argv[]);
+static int fdset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api fdset_tests_api = {
+ "Native fdset poll wrapper", //! Unit name
+ &fdset_tests_count, //! Count scheduled tests
+ &fdset_tests_run //! Run scheduled tests
+};
+
+void* thr_action(void *arg)
+{
+ int *fd = (int *)arg;
+
+ /* Sleep for 100ms. */
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000; // 100ms
+ select(0, 0, 0, 0, &tv);
+
+ /* Write pattern. */
+ char pattern = WRITE_PATTERN;
+ int ret = write(*fd, &pattern, WRITE_PATTERN_LEN);
+ ret = ret; /* Use variable. */
+
+ return 0;
+}
+
+static int fdset_tests_count(int argc, char *argv[])
+{
+ return 11;
+}
+
+static int fdset_tests_run(int argc, char *argv[])
+{
+ diag("fdset: implements '%s'", fdset_method());
+
+ /* 1. Create fdset. */
+ fdset_t *set = fdset_new();
+ ok(set != 0, "fdset: new");
+
+ /* 2. Create pipe. */
+ int fds[2], tmpfds[2];
+ int ret = pipe(fds);
+ ok(ret >= 0, "fdset: pipe() works");
+ ret = pipe(tmpfds);
+
+ /* 3. Add fd to set. */
+ ret = fdset_add(set, fds[0], OS_EV_READ);
+ ok(ret == 0, "fdset: add to set works");
+ fdset_add(set, tmpfds[0], OS_EV_READ);
+
+ /* Schedule write. */
+ struct timeval ts, te;
+ gettimeofday(&ts, 0);
+ pthread_t t;
+ pthread_create(&t, 0, thr_action, &fds[1]);
+
+ /* 4. Watch fdset. */
+ ret = fdset_wait(set);
+ gettimeofday(&te, 0);
+ size_t diff = timeval_diff(&ts, &te);
+
+ ok(ret > 0 && diff > 99 && diff < 10000,
+ "fdset: poll returned events in %zu ms", diff);
+
+ /* 5. Prepare event set. */
+ fdset_it_t it;
+ ret = fdset_begin(set, &it);
+ ok(ret == 0 && it.fd == fds[0], "fdset: begin is valid, ret=%d", ret);
+
+ /* 6. Receive data. */
+ char buf = 0x00;
+ ret = read(it.fd, &buf, WRITE_PATTERN_LEN);
+ ok(ret >= 0 && buf == WRITE_PATTERN, "fdset: contains valid data, fd=%d", it.fd);
+
+ /* 7. Iterate event set. */
+ ret = fdset_next(set, &it);
+ ok(ret < 0, "fdset: boundary check works");
+
+ /* 8. Remove from event set. */
+ ret = fdset_remove(set, fds[0]);
+ ok(ret == 0, "fdset: remove from fdset works");
+ close(fds[0]);
+ close(fds[1]);
+ ret = fdset_remove(set, tmpfds[0]);
+ close(tmpfds[1]);
+ close(tmpfds[1]);
+
+ /* 9. Poll empty fdset. */
+ ret = fdset_wait(set);
+ ok(ret <= 0, "fdset: polling empty fdset returns -1 (ret=%d)", ret);
+
+ /* 10. Crash test. */
+ lives_ok({
+ fdset_destroy(0);
+ fdset_add(0, -1, 0);
+ fdset_remove(0, -1);
+ fdset_wait(0);
+ fdset_begin(0, 0);
+ fdset_end(0, 0);
+ fdset_next(0, 0);
+ fdset_method();
+ }, "fdset: crash test successful");
+
+ /* 11. Destroy fdset. */
+ ret = fdset_destroy(set);
+ ok(ret == 0, "fdset: destroyed");
+
+ /* Cleanup. */
+ pthread_join(t, 0);
+
+ return 0;
+}
diff --git a/src/tests/common/fdset_tests.h b/src/tests/common/fdset_tests.h
new file mode 100644
index 0000000..d29e1a9
--- /dev/null
+++ b/src/tests/common/fdset_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_FDSET_TESTS_H_
+#define _KNOTD_FDSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api fdset_tests_api;
+
+#endif /* _KNOTD_FDSET_TESTS_H_ */
diff --git a/src/tests/common/skiplist_tests.c b/src/tests/common/skiplist_tests.c
new file mode 100644
index 0000000..4fe99ec
--- /dev/null
+++ b/src/tests/common/skiplist_tests.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <time.h>
+
+#include "tests/common/skiplist_tests.h"
+#include "common/skip-list.h"
+
+static int skiplist_tests_count(int argc, char *argv[]);
+static int skiplist_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api skiplist_tests_api = {
+ "Skip list",
+ &skiplist_tests_count,
+ &skiplist_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int SKIPLIST_TEST_COUNT = 5;
+
+static int skiplist_tests_count(int argc, char *argv[])
+{
+ return SKIPLIST_TEST_COUNT;
+}
+
+/* Comparing and merging limited to int keys used in test.
+ */
+int test_skip_compare_keys(void *key1, void *key2)
+{
+ return ((long)key1 < (long)key2) ?
+ -1 : (((long)key1 > (long)key2) ? 1 : 0);
+}
+
+int test_skip_merge_values(void **lvalue, void **rvalue)
+{
+ (*lvalue) = (void *)((long)(*lvalue) + (long)(*rvalue));
+ return 0;
+}
+
+int test_skiplist_create(skip_list_t **list)
+{
+ *list = skip_create_list(test_skip_compare_keys);
+ return *list != NULL;
+}
+
+int test_skiplist_fill(skip_list_t *list, long *uitems, int loops)
+{
+ int uitem_count = 0;
+ for (int i = 0; i < loops; ++i) {
+ long key = rand() % 100 + 1;
+ long value = rand() % 100 + 1;
+ int res = skip_insert(list, (void *)key, (void *)value,
+ test_skip_merge_values);
+ switch (res) {
+ case -2:
+ diag("skiplist: merging failed");
+ return 0;
+ break;
+ case -1:
+ diag("skiplist: insert failed");
+ return 0;
+ break;
+ case 0:
+ uitems[uitem_count++] = key;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return uitem_count;
+}
+
+int test_skiplist_lookup_seq(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+
+ // Sequential lookup
+ for (int i = 0; i < uitems_count; ++i) {
+ void *found = skip_find(list, (void *) uitems[i]);
+ if (found == NULL) {
+ diag("skiplist: sequential "
+ "lookup failed, key: %d", uitems[i]);
+ ++errors;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: %d found %d missed,"
+ " %.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+
+ return errors == 0;
+}
+
+int test_skiplist_lookup_rand(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+ srand((unsigned)time(NULL));
+
+ // Random lookup
+ for (int i = 0; i < uitems_count; ++i) {
+ long key = rand() % uitems_count + 1;
+ void *found = skip_find(list, (void *) key);
+ if (found == NULL) {
+ diag("skiplist: random lookup"
+ "failed, key: %d", uitems[i]);
+ ++errors;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: "
+ "%d found %d missed, %.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+ return errors == 0;
+}
+
+
+int test_skiplist_remove(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+
+ // delete items
+ for (int i = 0; i < uitems_count; ++i) {
+ int res = skip_remove(list, (void *) uitems[i], NULL, NULL);
+ switch (res) {
+ case 0:
+ break;
+ default:
+ ++errors;
+ break;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: %d found %d missed, "
+ "%.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+ return errors == 0;
+}
+
+static int skiplist_tests_run(int argc, char *argv[])
+{
+ const int loops = 100;
+ int uitems_count = 0;
+ long *uitems = malloc(loops * sizeof(long));
+ skip_list_t *list = 0;
+
+ // Test 1: create
+ ok(test_skiplist_create(&list), "skiplist: create");
+
+ // Test 2: fill
+ ok(uitems_count = test_skiplist_fill(list, uitems, loops),
+ "skiplist: fill");
+
+ // Test 3: sequential lookup
+ ok(test_skiplist_lookup_seq(list, uitems, uitems_count),
+ "skiplist: sequential lookup");
+
+ // Test 4: sequential lookup
+ ok(test_skiplist_lookup_seq(list, uitems, uitems_count),
+ "skiplist: random lookup lookup");
+
+ // Test 5: remove items
+ ok(test_skiplist_remove(list, uitems, uitems_count),
+ "skiplist: random lookup lookup");
+
+ // Cleanup
+ skip_destroy_list(&list, NULL, NULL);
+ free(uitems);
+ return 0;
+}
diff --git a/src/tests/common/skiplist_tests.h b/src/tests/common/skiplist_tests.h
new file mode 100644
index 0000000..ff91706
--- /dev/null
+++ b/src/tests/common/skiplist_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_SKIPLIST_TESTS_H_
+#define _KNOTD_SKIPLIST_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api skiplist_tests_api;
+
+#endif /* _KNOTD_SKIPLIST_TESTS_H_ */
diff --git a/src/tests/common/slab_tests.c b/src/tests/common/slab_tests.c
new file mode 100644
index 0000000..f362ca0
--- /dev/null
+++ b/src/tests/common/slab_tests.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include "tests/common/slab_tests.h"
+#include "common/slab/slab.h"
+#include "knot/common.h"
+
+/* Explicitly ask for symbols,
+ * as the constructor and destructor
+ * aren't created for test modules.
+ */
+extern void slab_init();
+extern void slab_deinit();
+
+static int slab_tests_count(int argc, char *argv[]);
+static int slab_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api slab_tests_api = {
+ "SLAB allocator", //! Unit name
+ &slab_tests_count, //! Count scheduled tests
+ &slab_tests_run //! Run scheduled tests
+};
+
+static int slab_tests_count(int argc, char *argv[])
+{
+ return 7;
+}
+
+static int slab_tests_run(int argc, char *argv[])
+{
+ // 1. Create slab cache
+ srand(time(0));
+ const unsigned pattern = 0xdeadbeef;
+ slab_cache_t cache;
+ int ret = slab_cache_init(&cache, sizeof(int));
+ ok(ret == 0, "slab: created empty cache");
+
+ // 2. Couple alloc/free
+ bool valid_free = true;
+ lives_ok({
+ for(int i = 0; i < 100; ++i) {
+ int* data = (int*)slab_cache_alloc(&cache);
+ *data = pattern;
+ slab_free(data);
+ if (*data == pattern)
+ valid_free = false;
+ }
+ }, "slab: couple alloc/free");
+
+ // 5. Verify freed block
+ ok(valid_free, "slab: freed memory is correctly invalidated");
+
+ // 4. Reap memory
+ slab_t* slab = cache.slabs_free;
+ int free_count = 0;
+ while (slab) {
+ slab_t* next = slab->next;
+ if (slab_isempty(slab)) {
+ ++free_count;
+ }
+ slab = next;
+ }
+
+ int reaped = slab_cache_reap(&cache);
+ cmp_ok(reaped, "==", free_count, "slab: cache reaping works");
+
+ // Stress cache
+ int alloc_count = 73521;
+ void** ptrs = alloca(alloc_count * sizeof(void*));
+ int ptrs_i = 0;
+ for(int i = 0; i < alloc_count; ++i) {
+ double roll = rand() / (double) RAND_MAX;
+ if ((ptrs_i == 0) || (roll < 0.6)) {
+ int id = ptrs_i++;
+ ptrs[id] = slab_cache_alloc(&cache);
+ if (ptrs[id] == 0) {
+ ptrs_i--;
+ } else {
+ int* data = (int*)ptrs[id];
+ *data = pattern;
+ }
+ } else {
+ slab_free(ptrs[--ptrs_i]);
+ }
+ }
+
+ // 5. Delete cache
+ slab_cache_destroy(&cache);
+ ok(cache.bufsize == 0, "slab: freed cache");
+
+ // 6. Greate GP allocator
+ slab_alloc_t alloc;
+ ret = slab_alloc_init(&alloc);
+ ok(ret == 0, "slab: created GP allocator");
+
+ // 7. Stress allocator
+ unsigned ncount = 0;
+ ptrs_i = 0;
+ for(int i = 0; i < alloc_count; ++i) {
+ double roll = rand() / (double) RAND_MAX;
+ size_t bsize = roll * 2048;
+ bsize = MAX(bsize, 8);
+ if ((ptrs_i == 0) || (roll < 0.6)) {
+ void* m = slab_alloc_alloc(&alloc, bsize);
+ if (m == 0) {
+ ++ncount;
+ } else {
+ ptrs[ptrs_i++] = m;
+ }
+ } else {
+ slab_free(ptrs[--ptrs_i]);
+ }
+ }
+
+ cmp_ok(ncount, "==", 0, "slab: GP allocator alloc/free working");
+
+ // 7. Destroy allocator
+ slab_alloc_destroy(&alloc);
+
+ return 0;
+}
diff --git a/src/tests/common/slab_tests.h b/src/tests/common/slab_tests.h
new file mode 100644
index 0000000..4d45fb8
--- /dev/null
+++ b/src/tests/common/slab_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_SLAB_TESTS_H_
+#define _KNOTD_SLAB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api slab_tests_api;
+
+#endif /* _KNOTD_SLAB_TESTS_H_ */
diff --git a/src/tests/files/sample_conf b/src/tests/files/sample_conf
new file mode 100644
index 0000000..6cd9e50
--- /dev/null
+++ b/src/tests/files/sample_conf
@@ -0,0 +1,59 @@
+# configuration file will follow bird (and juniper) type of configuration file
+# i.e. curly brackets will be used;
+
+# what to do with };
+# a) ignore ; if it follows }
+
+system {
+
+ identity "I have no mouth and must scream";
+ version "Infinitesimal";
+ storage "/var/run/knot/";
+}
+
+keys {
+ key0.example.net hmac-md5 "Wg=="; # key special for one remote
+ key1.example.net hmac-md5 "==gW"; # implicit key for whole zone
+}
+
+remotes {
+ remote0 { address 1.2.3.4; }
+}
+
+zones {
+ example.net {
+ file "/var/lib/knot/example.net";
+ xfr-out remote0;
+ }
+}
+
+interfaces {
+ interface0 {
+ address 10.10.1.1;
+ port 53531;
+ }
+
+ interface1 {
+ address ::0;
+ # port 53;
+ }
+}
+
+log {
+ syslog {
+ any notice, warning, error;
+ zone all;
+ }
+
+ file "/var/log/knot/server.err" {
+ server error;
+ }
+
+ stderr {
+ any warning, error;
+ }
+
+ stdout {
+ any info;
+ }
+}
diff --git a/src/tests/knot/conf_tests.c b/src/tests/knot/conf_tests.c
new file mode 100644
index 0000000..61520ea
--- /dev/null
+++ b/src/tests/knot/conf_tests.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdio.h>
+
+#include "tests/knot/conf_tests.h"
+#include "knot/conf/conf.h"
+
+/* Resources. */
+#include "tests/sample_conf.rc"
+
+static int conf_tests_count(int argc, char *argv[]);
+static int conf_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api conf_tests_api = {
+ "Configuration parser", //! Unit name
+ &conf_tests_count, //! Count scheduled tests
+ &conf_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int conf_tests_count(int argc, char *argv[])
+{
+ return 21;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int conf_tests_run(int argc, char *argv[])
+{
+
+ // Test 1: Allocate new config
+ const char *config_fn = "rc:/sample_conf";
+ conf_t *conf = conf_new(config_fn);
+ ok(conf != 0, "config_new()");
+
+ // Test 2: Parse config
+ int ret = conf_parse_str(conf, sample_conf_rc);
+ ok(ret == 0, "parsing configuration file %s", config_fn);
+ skip(ret != 0, conf_tests_count(argc, argv) - 2);
+ {
+
+ // Test 3: Test server version (0-level depth)
+ is(conf->version, "Infinitesimal", "server version loaded ok");
+
+ // Test 4: Test interfaces (1-level depth)
+ ok(!EMPTY_LIST(conf->ifaces), "configured interfaces exist");
+
+ // Test 5,6,7,8: Interfaces content (2-level depth)
+ struct node *n = HEAD(conf->ifaces);
+ conf_iface_t *iface = (conf_iface_t*)n;
+ is(iface->address, "10.10.1.1", "interface0 address check");
+ cmp_ok(iface->port, "==", 53531, "interface0 port check");
+ n = n->next;
+ iface = (conf_iface_t*)n;
+ is(iface->address, "::0", "interface1 address check");
+ cmp_ok(iface->port, "==", 53, "interface1 default port check");
+
+ // Test 9,10: Check server key
+ if(conf->key_count <= 0) {
+ ok(0, "TSIG key algorithm check - NO KEY FOUND");
+ ok(0, "TSIG key secret check - NO KEY FOUND");
+ } else {
+ knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
+ cmp_ok(k->algorithm, "==", KNOT_TSIG_ALG_HMAC_MD5,
+ "TSIG key algorithm check");
+ is(k->secret, "Wg==", "TSIG key secret check");
+ }
+
+ // Test 11,12,13,14,15,16,17,18: Check logging facilities
+ cmp_ok(conf->logs_count, "==", 4, "log facilites count check");
+ n = HEAD(conf->logs);
+ ok(!EMPTY_LIST(conf->logs), "log facilities not empty");
+
+ conf_log_t *log = (conf_log_t*)n;
+ node *nm = HEAD(log->map);
+ conf_log_map_t *m = (conf_log_map_t*)nm;
+ cmp_ok(log->type, "==", LOGT_SYSLOG, "log0 is syslog");
+
+ skip(EMPTY_LIST(log->map), 5);
+ {
+ cmp_ok(m->source, "==", LOG_ANY, "syslog first rule is ANY");
+ int mask = LOG_MASK(LOG_NOTICE)|LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR);
+ cmp_ok(m->prios, "==", mask, "syslog mask is equal");
+ nm = nm->next;
+ m = (conf_log_map_t*)nm;
+ ok(m != 0, "syslog has more than 1 rule");
+ skip(!m, 2);
+ {
+ cmp_ok(m->source, "==", LOG_ZONE, "syslog next rule is for zone");
+ cmp_ok(m->prios, "==", 0xff, "rule for zone is: any level");
+ }
+ endskip;
+ } endskip;
+
+ // Test 19,20: File facility checks
+ n = n->next;
+ log = (conf_log_t*)n;
+ ok(n != 0, "log has next facility");
+ skip(!n, 1);
+ {
+ is(log->file, "/var/log/knot/server.err", "log file matches");
+ } endskip;
+
+ // Test 21: Load key dname
+ const char *sample_str = "key0.example.net";
+ knot_dname_t *sample = knot_dname_new_from_str(sample_str,
+ strlen(sample_str), 0);
+ if (conf->key_count > 0) {
+ knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
+ ok(knot_dname_compare(sample, k->name) == 0,
+ "TSIG key dname check");
+ } else {
+ ok(0, "TSIG key dname check - NO KEY FOUND");
+ }
+ knot_dname_free(&sample);
+
+ } endskip;
+
+ // Deallocating config
+ conf_free(conf);
+
+ return 0;
+}
diff --git a/src/tests/knot/conf_tests.h b/src/tests/knot/conf_tests.h
new file mode 100644
index 0000000..dfd2fd7
--- /dev/null
+++ b/src/tests/knot/conf_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_CONF_TESTS_H_
+#define _KNOTD_CONF_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api conf_tests_api;
+
+#endif /* _KNOTD_CONF_TESTS_H_ */
diff --git a/src/tests/knot/dthreads_tests.c b/src/tests/knot/dthreads_tests.c
new file mode 100644
index 0000000..d95fbed
--- /dev/null
+++ b/src/tests/knot/dthreads_tests.c
@@ -0,0 +1,392 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <pthread.h>
+#include <sched.h>
+#include <sys/select.h>
+#include <signal.h>
+
+#include "tests/knot/dthreads_tests.h"
+#include "knot/server/dthreads.h"
+
+static int dt_tests_count(int argc, char *argv[]);
+static int dt_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api dthreads_tests_api = {
+ "DThreads",
+ &dt_tests_count,
+ &dt_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+static const int DT_TEST_COUNT = 23;
+
+/* Unit runnable data. */
+static pthread_mutex_t _runnable_mx;
+static volatile int _runnable_i = 0;
+static const int _runnable_cycles = 10000;
+
+/*! \brief Unit runnable. */
+int runnable(struct dthread_t *thread)
+{
+ for (int i = 0; i < _runnable_cycles; ++i) {
+
+ // Increase counter
+ pthread_mutex_lock(&_runnable_mx);
+ ++_runnable_i;
+ pthread_mutex_unlock(&_runnable_mx);
+
+ // Cancellation point
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ // Yield
+ sched_yield();
+ }
+
+ return 0;
+}
+
+/*! \brief Unit blocking runnable. */
+int runnable_simio(struct dthread_t *thread)
+{
+ // Infinite blocking, must be interrupted
+ select(0, 0, 0, 0, 0);
+ return 0;
+}
+
+/*! \brief Create unit. */
+static inline dt_unit_t *dt_test_create(int size)
+{
+ return dt_create(size);
+}
+
+/*! \brief Assign a task. */
+static inline int dt_test_single(dt_unit_t *unit)
+{
+ return dt_repurpose(unit->threads[0], &runnable, NULL) == 0;
+}
+
+/*! \brief Assign task to all unit threads. */
+static inline int dt_test_coherent(dt_unit_t *unit)
+{
+ int ret = 0;
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, NULL);
+ }
+
+ return ret == 0;
+}
+
+/*! \brief Repurpose single thread. */
+static inline int dt_test_repurpose(dt_unit_t *unit, int id)
+{
+ return dt_repurpose(unit->threads[id], &runnable_simio, NULL) == 0;
+}
+
+/*! \brief Cancel single thread. */
+static inline int dt_test_cancel(dt_unit_t *unit, int id)
+{
+ return dt_cancel(unit->threads[id]) == 0;
+}
+
+/*! \brief Reanimate dead threads. */
+static inline int dt_test_reanimate(dt_unit_t *unit)
+{
+ // Compact all threads
+ int ret = 0;
+ ret += dt_compact(unit);
+
+ // Remove purpose from all
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], 0, 0);
+ }
+
+ // Set single thread to purpose
+ ret += dt_repurpose(unit->threads[0], &runnable, 0);
+
+ // Restart
+ _runnable_i = 0;
+ ret += dt_start(unit);
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected = 1 * _runnable_cycles;
+ if (_runnable_i != expected) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Resize unit. */
+static inline int dt_test_resize(dt_unit_t *unit, int size)
+{
+ // Resize
+ int ret = 0;
+ ret = dt_resize(unit, size);
+ if (ret < 0) {
+ return 0;
+ }
+
+ // Check outcome
+ if (unit->size != size) {
+ return 0;
+ }
+
+ // Repurpose all
+ _runnable_i = 0;
+ for (int i = 0; i < size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, 0);
+ ret += dt_start_id(unit->threads[i]);
+ }
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected = size * _runnable_cycles;
+ note("resize test: %d threads, %d ticks, %d expected",
+ size, _runnable_i, expected);
+ if (_runnable_i != expected) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Resize unit while threads are active. */
+static inline int dt_test_liveresize(dt_unit_t *unit)
+{
+ // Size
+ int size = unit->size;
+ int size_hi = size + 2;
+ int size_lo = size - 1;
+
+ // Expand
+ int ret = 0;
+ ret = dt_resize(unit, size_hi);
+ if (ret < 0) {
+ return 0;
+ }
+
+ // Repurpose all
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, 0);
+ }
+
+ // Restart
+ _runnable_i = 0;
+ ret += dt_start(unit);
+
+ // Shrink
+ ret += dt_resize(unit, size_lo);
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected_hi = size_hi * _runnable_cycles;
+ int expected_lo = size_lo * _runnable_cycles;
+ note("resize test: %d->%d->%d threads, %d ticks, <%d,%d> expected",
+ size, size_hi, size_lo, _runnable_i, expected_lo, expected_hi);
+
+ if (_runnable_i > expected_hi || _runnable_i < expected_lo) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Start unit. */
+static inline int dt_test_start(dt_unit_t *unit)
+{
+ return dt_start(unit) == 0;
+}
+
+/*! \brief Stop unit. */
+static inline int dt_test_stop(dt_unit_t *unit)
+{
+ return dt_stop(unit);
+}
+
+/*! \brief Join unit. */
+static inline int dt_test_join(dt_unit_t *unit)
+{
+ return dt_join(unit) == 0;
+}
+
+/*! API: return number of tests. */
+static int dt_tests_count(int argc, char *argv[])
+{
+ return DT_TEST_COUNT;
+}
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+static int dt_tests_run(int argc, char *argv[])
+{
+ // Register service and signal handler
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ /* Initialize */
+ srand(time(NULL));
+ struct timeval tv;
+ pthread_mutex_init(&_runnable_mx, NULL);
+
+ /* Test 1: Create unit */
+ dt_unit_t *unit = dt_test_create(dt_optimal_size());
+ ok(unit != 0, "dthreads: create unit (optimal size %d)", unit->size);
+ skip(unit == 0, DT_TEST_COUNT - 1);
+
+ /* Test 2: Assign a single task. */
+ ok(dt_test_single(unit), "dthreads: assign single task");
+
+ /* Test 3: Start tasks. */
+ _runnable_i = 0;
+ ok(dt_test_start(unit), "dthreads: start single task");
+
+ /* Test 4: Wait for tasks. */
+ ok(dt_test_join(unit), "dthreads: join threads");
+
+ /* Test 5: Compare counter. */
+ int expected = _runnable_cycles * 1;
+ cmp_ok(_runnable_i, "==", expected, "dthreads: result ok");
+
+ /* Test 6: Repurpose threads. */
+ _runnable_i = 0;
+ ok(dt_test_coherent(unit), "dthreads: repurpose to coherent");
+
+ /* Test 7: Restart threads. */
+ ok(dt_test_start(unit), "dthreads: start coherent unit");
+
+ /* Test 8: Repurpose single thread. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 4000 + rand() % 1000; // 4-5ms
+ note("waiting for %dus to let thread do some work ...",
+ tv.tv_usec);
+ select(0, 0, 0, 0, &tv);
+ ok(dt_test_repurpose(unit, 0), "dthreads: repurpose on-the-fly");
+
+ /* Test 9: Cancel blocking thread. */
+ tv.tv_sec = 0;
+ tv.tv_usec = (250 + rand() % 500) * 1000; // 250-750ms
+ note("waiting for %dms to let thread pretend blocking I/O ...",
+ tv.tv_usec / 1000);
+ select(0, 0, 0, 0, &tv);
+ ok(dt_test_cancel(unit, 0), "dthreads: cancel blocking thread");
+
+ /* Test 10: Wait for tasks. */
+ ok(dt_test_join(unit), "dthreads: join threads");
+
+ /* Test 11: Compare counter. */
+ int expected_lo = _runnable_cycles * (unit->size - 1);
+ cmp_ok(_runnable_i, ">=", expected_lo,
+ "dthreads: result %d is => %d", _runnable_i, expected_lo);
+
+ /* Test 12: Compare counter #2. */
+ int expected_hi = _runnable_cycles * unit->size;
+ cmp_ok(_runnable_i, "<=", expected_hi,
+ "dthreads: result %d is <= %d", _runnable_i, expected_hi);
+
+ /* Test 13: Reanimate dead threads. */
+ ok(dt_test_reanimate(unit), "dthreads: reanimate dead threads");
+
+ /* Test 14: Expand unit by 100%. */
+ int size = unit->size * 2;
+ ok(dt_test_resize(unit, size),
+ "dthreads: expanding unit to size * 2 (%d threads)", size);
+
+ /* Test 15: Shrink unit to half. */
+ size = unit->size / 2;
+ ok(dt_test_resize(unit, size),
+ "dthreads: shrinking unit to size / 2 (%d threads)", size);
+
+ /* Test 16: Resize while threads are active. */
+ ok(dt_test_liveresize(unit), "dthreads: resizing unit while active");
+
+ /* Test 17: Deinitialize */
+ dt_delete(&unit);
+ ok(unit == 0, "dthreads: delete unit");
+ endskip;
+
+ /* Test 18: Wrong values. */
+ unit = dt_create(-1);
+ ok(unit == 0, "dthreads: create with negative count");
+ unit = dt_create_coherent(dt_optimal_size(), 0, 0);
+
+ /* Test 19: NULL runnable. */
+ cmp_ok(dt_start(unit), "==", 0, "dthreads: start with NULL runnable");
+
+ /* Test 20: resize to negative value. */
+ cmp_ok(dt_resize(unit, -19),
+ "<", 0, "dthreads: resize to negative size");
+
+ /* Test 21: resize to zero value. */
+ cmp_ok(dt_resize(unit, 0), "<", 0, "dthreads: resize to NULL size");
+ dt_join(unit);
+ dt_delete(&unit);
+
+ /* Test 22: NULL operations crashing. */
+ int op_count = 14;
+ int expected_min = op_count * -1;
+ // All functions must return -1 at least
+ int ret = 0;
+ lives_ok( {
+ ret += dt_activate(0); // -1
+ ret += dt_cancel(0); // -1
+ ret += dt_compact(0); // -1
+ dt_delete(0); //
+ ret += dt_is_cancelled(0); // 0
+ ret += dt_join(0); // -1
+ ret += dt_repurpose(0, 0, 0); // -1
+ ret += dt_resize(0, 0); // -1
+ ret += dt_setprio(0, 0); // -1
+ ret += dt_signalize(0, SIGALRM); // -1
+ ret += dt_start(0); // -1
+ ret += dt_start_id(0); // -1
+ ret += dt_stop(0); // -1
+ ret += dt_stop_id(0); // -1
+ ret += dt_unit_lock(0); // -1
+ ret += dt_unit_unlock(0); // -1
+ }, "dthreads: not crashed while executing functions on NULL context");
+
+ /* Test 23: expected results. */
+ cmp_ok(ret, "<=", expected_min,
+ "dthreads: correct values when passed NULL context "
+ "(%d, min: %d)", ret, expected_min);
+
+ pthread_mutex_destroy(&_runnable_mx);
+ return 0;
+}
diff --git a/src/tests/knot/dthreads_tests.h b/src/tests/knot/dthreads_tests.h
new file mode 100644
index 0000000..e41bdc5
--- /dev/null
+++ b/src/tests/knot/dthreads_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_DTHREADS_TESTS_H_
+#define _KNOTD_DTHREADS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dthreads_tests_api;
+
+#endif /* _KNOTD_DTHREADS_TESTS_H_ */
diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c
new file mode 100644
index 0000000..21c92fe
--- /dev/null
+++ b/src/tests/knot/journal_tests.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <string.h>
+
+#include "tests/knot/journal_tests.h"
+#include "knot/server/journal.h"
+#include "knot/other/error.h"
+
+static int journal_tests_count(int argc, char *argv[]);
+static int journal_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api journal_tests_api = {
+ "Journal",
+ &journal_tests_count,
+ &journal_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+static const int JOURNAL_TEST_COUNT = 11;
+
+/*! \brief Generate random string with given length. */
+static int randstr(char* dst, size_t len)
+{
+ for (int i = 0; i < len - 1; ++i) {
+ dst[i] = '0' + (int) (('Z'-'0') * (rand() / (RAND_MAX + 1.0)));
+ }
+ dst[len - 1] = '\0';
+
+ return 0;
+}
+
+/*! \brief Walk journal of chars into buffer. */
+static int _wbi = 0;
+static char _walkbuf[7];
+static int walkchars_cmp(uint64_t k1, uint64_t k2) {
+ return k1 - k2;
+}
+
+static int walkchars(journal_t *j, journal_node_t *n) {
+ journal_read(j, n->id, walkchars_cmp, _walkbuf + _wbi);
+ ++_wbi;
+ return 0;
+}
+
+/*! API: return number of tests. */
+static int journal_tests_count(int argc, char *argv[])
+{
+ return JOURNAL_TEST_COUNT;
+}
+
+/*! API: run tests. */
+static int journal_tests_run(int argc, char *argv[])
+{
+ /* Test 1: Create tmpfile. */
+ int fsize = 8092;
+ int jsize = 6;
+ char jfn_buf[] = "/tmp/journal.XXXXXX";
+ int tmp_fd = mkstemp(jfn_buf);
+ ok(tmp_fd >= 0, "journal: create temporary file");
+ skip(tmp_fd < 0, JOURNAL_TEST_COUNT - 1);
+
+ /* Test 2: Create journal. */
+ const char *jfilename = jfn_buf;
+ int ret = journal_create(jfilename, jsize);
+ ok(ret == KNOTD_EOK, "journal: create journal '%s'", jfilename);
+
+ /* Test 3: Open journal. */
+ journal_t *j = journal_open(jfilename, fsize, 0);
+ ok(j != 0, "journal: open");
+
+ /* Test 4: Write entry to log. */
+ const char *sample = "deadbeef";
+ ret = journal_write(j, 0x0a, sample, strlen(sample));
+ ok(ret == KNOTD_EOK, "journal: write");
+
+ /* Test 5: Read entry from log. */
+ char tmpbuf[64] = {'\0'};
+ ret = journal_read(j, 0x0a, 0, tmpbuf);
+ ok(ret == KNOTD_EOK, "journal: read entry");
+
+ /* Test 6: Compare read data. */
+ ret = strncmp(sample, tmpbuf, strlen(sample));
+ ok(ret == 0, "journal: read data integrity check");
+
+ /* Append several characters. */
+ journal_write(j, 0, "X", 1); /* Dummy */
+ char word[7] = { 'w', 'o', 'r', 'd', '0', '\0', '\0' };
+ for (int i = 0; i < strlen(word); ++i) {
+ journal_write(j, i, word+i, 1);
+ }
+
+ /* Test 7: Compare journal_walk() result. */
+ _wbi = 0;
+ journal_walk(j, walkchars);
+ _walkbuf[_wbi] = '\0';
+ ret = strcmp(word, _walkbuf);
+ ok(ret == 0, "journal: read data integrity check 2 '%s'", _walkbuf);
+ _wbi = 0;
+
+ /* Test 8: Change single letter and compare. */
+ word[5] = 'X';
+ journal_write(j, 5, word+5, 1); /* append 'X', shifts out 'w' */
+ journal_walk(j, walkchars);
+ _walkbuf[_wbi] = '\0';
+ ret = strcmp(word + 1, _walkbuf);
+ ok(ret == 0, "journal: read data integrity check 3 '%s'", _walkbuf);
+ _wbi = 0;
+
+ /* Close journal. */
+ journal_close(j);
+
+ /* Recreate journal. */
+ remove(jfilename);
+ fsize = 8092;
+ jsize = 512;
+ ret = journal_create(jfilename, jsize);
+ j = journal_open(jfilename, fsize, 0);
+
+ /* Test 9: Write random data. */
+ int chk_key = 0;
+ char chk_buf[64] = {'\0'};
+ ret = 0;
+ const int itcount = 1;//jsize * 5 + 5;
+ for (int i = 0; i < itcount; ++i) {
+ int key = rand() % 65535;
+ randstr(tmpbuf, sizeof(tmpbuf));
+ if (journal_write(j, key, tmpbuf, sizeof(tmpbuf)) != KNOTD_EOK) {
+ ret = -1;
+ break;
+ }
+
+ /* Store some key on the end. */
+ if (i == itcount - 2) {
+ chk_key = key;
+ memcpy(chk_buf, tmpbuf, sizeof(chk_buf));
+ }
+ }
+ ok(ret == 0, "journal: sustained looped writes");
+
+ /* Test 10: Check data integrity. */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ journal_read(j, chk_key, 0, tmpbuf);
+ ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
+ ok(ret == 0, "journal: read data integrity check");
+
+ /* Test 11: Reopen log and re-read value. */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ journal_close(j);
+ j = journal_open(jfilename, fsize, 0);
+ journal_read(j, chk_key, 0, tmpbuf);
+ ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
+ ok(ret == 0, "journal: read data integrity check after close/open");
+
+ /* Close journal. */
+ journal_close(j);
+
+ /* Close temporary file fd. */
+ close(tmp_fd);
+
+ /* Delete journal. */
+ remove(jfilename);
+
+ endskip;
+
+ return 0;
+}
diff --git a/src/tests/knot/journal_tests.h b/src/tests/knot/journal_tests.h
new file mode 100644
index 0000000..beec8ca
--- /dev/null
+++ b/src/tests/knot/journal_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_JOURNAL_TESTS_H_
+#define _KNOTD_JOURNAL_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api journal_tests_api;
+
+#endif /* _KNOTD_JOURNAL_TESTS_H_ */
diff --git a/src/tests/knot/server_tests.c b/src/tests/knot/server_tests.c
new file mode 100644
index 0000000..5ae04d8
--- /dev/null
+++ b/src/tests/knot/server_tests.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/knot/server_tests.h"
+#include "knot/server/server.h"
+
+static int server_tests_count(int argc, char *argv[]);
+static int server_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api server_tests_api = {
+ "Server",
+ &server_tests_count,
+ &server_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int SERVER_TEST_COUNT = 4;
+
+/*! Test: create server. */
+server_t *test_server_create()
+{
+ return server_create();
+}
+
+/*! Test: start server. */
+int test_server_start(server_t *s)
+{
+ return server_start(s) == 0;
+}
+
+/*! Test: finish server. */
+int test_server_finish(server_t *s)
+{
+ return server_wait(s) == 0;
+}
+
+/*! Test: stop server. */
+int test_server_destroy(server_t *s)
+{
+ server_destroy(&s);
+ return s == 0;
+}
+
+/*! API: return number of tests. */
+static int server_tests_count(int argc, char *argv[])
+{
+ return SERVER_TEST_COUNT + 1;
+}
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+static int server_tests_run(int argc, char *argv[])
+{
+ server_t *server = 0;
+ int ret = 0;
+
+ // Register service and signal handler
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ //! Test server for correct initialization
+ server = test_server_create();
+ ok(server != 0, "server: initialized");
+
+ //! Test server startup
+ ret = 0;
+ lives_ok( {
+ ret = test_server_start(server);
+ }, "server: not crashing on runtime");
+
+ //! Test server exit code
+ ok(ret, "server: started ok");
+ if (ret) {
+ server_stop(server);
+ } else {
+ diag("server crashed, skipping deinit and destroy tests");
+ }
+
+ //! Test server waiting for finish
+ skip(!ret, 2);
+ ok(test_server_finish(server), "server: waiting for finish");
+
+ //! Test server for correct deinitialization
+ ok(test_server_destroy(server), "server: deinit");
+ endskip;
+
+ return 0;
+}
diff --git a/src/tests/knot/server_tests.h b/src/tests/knot/server_tests.h
new file mode 100644
index 0000000..43ad0c1
--- /dev/null
+++ b/src/tests/knot/server_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_SERVER_TESTS_H_
+#define _KNOTD_SERVER_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api server_tests_api;
+
+#endif /* _KNOTD_SERVER_TESTS_H_ */
diff --git a/src/tests/libknot/files/parsed_data b/src/tests/libknot/files/parsed_data
new file mode 100644
index 0000000..4027c92
--- /dev/null
+++ b/src/tests/libknot/files/parsed_data
Binary files differ
diff --git a/src/tests/libknot/files/parsed_data_queries b/src/tests/libknot/files/parsed_data_queries
new file mode 100644
index 0000000..5857c87
--- /dev/null
+++ b/src/tests/libknot/files/parsed_data_queries
Binary files differ
diff --git a/src/tests/libknot/files/raw_data b/src/tests/libknot/files/raw_data
new file mode 100644
index 0000000..f94236b
--- /dev/null
+++ b/src/tests/libknot/files/raw_data
Binary files differ
diff --git a/src/tests/libknot/files/raw_data_queries b/src/tests/libknot/files/raw_data_queries
new file mode 100644
index 0000000..9062d5a
--- /dev/null
+++ b/src/tests/libknot/files/raw_data_queries
Binary files differ
diff --git a/src/tests/libknot/libknot/cuckoo_tests.c b/src/tests/libknot/libknot/cuckoo_tests.c
new file mode 100644
index 0000000..c1306a3
--- /dev/null
+++ b/src/tests/libknot/libknot/cuckoo_tests.c
@@ -0,0 +1,382 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <time.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/cuckoo_tests.h"
+
+#include "libknot/hash/cuckoo-hash-table.h"
+
+//#define CK_TEST_DEBUG
+//#define CK_TEST_LOOKUP
+//#define CK_TEST_OUTPUT
+//#define CK_TEST_REMOVE
+//#define CK_TEST_COMPARE
+
+#ifdef CK_TEST_DEBUG
+#define CK_TEST_LOOKUP
+#define CK_TEST_OUTPUT
+#define CK_TEST_REMOVE
+#define CK_TEST_COMPARE
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+static int cuckoo_tests_count(int argc, char *argv[]);
+static int cuckoo_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api cuckoo_tests_api = {
+ "Cuckoo hashing", //! Unit name
+ &cuckoo_tests_count, //! Count scheduled tests
+ &cuckoo_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Unit implementation
+ */
+static const int CUCKOO_TESTS_COUNT = 13;
+static const int CUCKOO_MAX_ITEMS = 1000;
+static const int CUCKOO_TEST_MAX_KEY_SIZE = 10;
+
+typedef struct test_cuckoo_items {
+ char **keys;
+ size_t *key_sizes;
+ size_t *values;
+ size_t *deleted;
+ int count;
+ int total_count;
+} test_cuckoo_items;
+
+/*----------------------------------------------------------------------------*/
+
+static inline char rand_char()
+{
+ return (char)((rand() % 26) + 97);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline void rand_str(char *str, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ str[i] = rand_char();
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int cuckoo_tests_count(int argc, char *argv[])
+{
+ return CUCKOO_TESTS_COUNT;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_create(ck_hash_table_t **table, uint items)
+{
+ *table = ck_create_table(items);
+ return (*table != NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_insert(ck_hash_table_t *table,
+ const test_cuckoo_items *items)
+{
+ assert(table != NULL);
+ int errors = 0;
+ for (int i = 0; i < items->count; ++i) {
+ assert(items->values[i] != 0);
+ if (ck_insert_item(table, items->keys[i], items->key_sizes[i],
+ (void *)items->values[i]) != 0) {
+ ++errors;
+ }
+ }
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_lookup(ck_hash_table_t *table,
+ const test_cuckoo_items *items)
+{
+ int errors = 0;
+ for (int i = 0; i < items->count; ++i) {
+ const ck_hash_table_item_t *found = ck_find_item(
+ table, items->keys[i], items->key_sizes[i]);
+ if (!found) {
+ if (items->deleted[i] == 0) {
+ diag("Not found item with key %.*s\n",
+ items->key_sizes[i], items->keys[i]);
+ ++errors;
+ }
+ } else {
+ if (items->deleted[i] != 0
+ || found->key != items->keys[i]
+ || (size_t)(found->value) != items->values[i]) {
+ diag("Found item with key %.*s (size %u) "
+ "(should be %.*s (size %u)) and value %zu "
+ "(should be %d).\n",
+ found->key_length, found->key,
+ found->key_length, items->key_sizes[i],
+ items->keys[i], items->key_sizes[i],
+ (size_t)found->value, items->values[i]);
+ ++errors;
+ }
+ }
+ }
+
+ if (errors > 0) {
+ diag("Not found %d of %d items.\n", errors, items->count);
+ } else {
+ note("Found %d items.\n", items->count);
+ }
+
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_delete(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ int errors = 0;
+ // delete approx. 1/10 items from the table
+ int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1;
+
+ for (int i = 0; i < count; ++i) {
+ int item = rand() % items->count;
+ if (items->deleted[item] == 0
+ && ck_delete_item(table, items->keys[item],
+ items->key_sizes[item], NULL, 0) != 0) {
+ ++errors;
+ } else {
+ items->deleted[item] = 1;
+ }
+ }
+
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_modify(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ int errors = 0;
+ // modify approx. 1/10 items from the table
+ int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1;
+
+ for (int i = 0; i < count; ++i) {
+ int item = rand() % items->count;
+ int old_value = items->values[item];
+ items->values[item] = rand() + 1;
+ if (ck_update_item(table, items->keys[item],
+ items->key_sizes[item],
+ (void *)items->values[item], NULL) != 0
+ && items->deleted[item] == 1) {
+ ++errors;
+ items->values[item] = old_value;
+ }
+ }
+
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_rehash(ck_hash_table_t *table)
+{
+ return (ck_rehash(table) == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_resize(ck_hash_table_t *table)
+{
+ // test the resize explicitly
+ return (ck_resize_table(table) == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_full(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ // invoke the resize by inserting so much items that thay cannot
+ // fit into the table
+ int new_count = table->items;
+
+ while (new_count < hashsize(table->table_size_exp) * table->table_count) {
+ new_count += table->items;
+ }
+
+ note("Old item count: %d, new count: %d, capacity of the table: %d\n",
+ table->items, new_count,
+ hashsize(table->table_size_exp) * table->table_count);
+
+ assert(new_count <= items->total_count);
+
+ int errors = 0;
+
+ for (int i = items->count; i < new_count; ++i) {
+ assert(items->values[i] != 0);
+ if (ck_insert_item(table, items->keys[i], items->key_sizes[i],
+ (void *)items->values[i]) != 0) {
+ ++errors;
+ }
+ }
+
+ items->count = new_count;
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void create_random_items(test_cuckoo_items *items, int item_count)
+{
+ assert(items != NULL);
+
+ items->count = item_count;
+ items->total_count = item_count * 10;
+ items->values = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->key_sizes = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->deleted = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->keys = (char **)malloc(items->total_count * sizeof(char *));
+
+ for (int i = 0; i < items->total_count; ++i) {
+ int value = rand() + 1;
+ int key_size = rand() % CUCKOO_TEST_MAX_KEY_SIZE + 1;
+ char *key = malloc(key_size * sizeof(char));
+ assert(key != NULL);
+ rand_str(key, key_size);
+
+ // check if the key is not already in the table
+ int found = 0;
+ for (int j = 0; j < i; ++j) {
+ if (items->key_sizes[j] == key_size
+ && strncmp(items->keys[j], key, key_size) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ assert(value != 0);
+ items->values[i] = value;
+ items->key_sizes[i] = key_size;
+ items->keys[i] = key;
+ items->deleted[i] = 0;
+ } else {
+ free(key);
+ --i;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void delete_items(test_cuckoo_items *items)
+{
+ free(items->deleted);
+ free(items->key_sizes);
+ free(items->values);
+ for (int i = 0; i < items->total_count; ++i) {
+ free(items->keys[i]);
+ }
+ free(items->keys);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int cuckoo_tests_run(int argc, char *argv[])
+{
+ srand(time(NULL));
+ int res;
+
+ const int item_count = rand() % CUCKOO_MAX_ITEMS + 1;
+ test_cuckoo_items *items = (test_cuckoo_items *)
+ malloc(sizeof(test_cuckoo_items));
+
+ ck_hash_table_t *table = NULL;
+
+ // Test 1: create
+ ok(res = test_cuckoo_create(&table, item_count),
+ "cuckoo hashing: create");
+
+ create_random_items(items, item_count);
+
+ skip(!res, 10);
+ // Test 2: insert
+ ok(test_cuckoo_insert(table, items), "cuckoo hashing: insert");
+
+ // Test 3: lookup
+ ok(test_cuckoo_lookup(table, items), "cuckoo hashing: lookup");
+
+ // Test 4: delete
+ ok(test_cuckoo_delete(table, items), "cuckoo hashing: delete");
+
+ // Test 5: lookup 2
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after delete");
+
+ // Test 6: modify
+ ok(test_cuckoo_modify(table, items), "cuckoo hashing: modify");
+
+ // Test 7: lookup 3
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after modify");
+
+ // Test 8: rehash
+ ok(test_cuckoo_rehash(table), "cuckoo hashing: rehash");
+
+ // Test 9: lookup 4
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after rehash");
+
+ // Test 10: resize
+ ok(test_cuckoo_resize(table), "cuckoo hashing: resize");
+
+ // Test 11: lookup 5
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after resize");
+
+ // Test 12: owerflow the table
+ ok(test_cuckoo_full(table, items), "cuckoo hashing: overflow");
+
+ // Test 13: lookup 5
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after overflow");
+
+ endskip;
+
+ /**
+ * \note These last 2 tests found some major bug in the cuckoo hash
+ * table, so running them results in abort upon assertion.
+ * Disabled for now.
+ */
+
+ // Cleanup
+ ck_destroy_table(&table, NULL, 0);
+ delete_items(items);
+ free(items);
+
+ return 0;
+}
diff --git a/src/tests/libknot/libknot/cuckoo_tests.h b/src/tests/libknot/libknot/cuckoo_tests.h
new file mode 100644
index 0000000..b6b0db8
--- /dev/null
+++ b/src/tests/libknot/libknot/cuckoo_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_CUCKOO_TESTS_H_
+#define _KNOTD_CUCKOO_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api cuckoo_tests_api;
+
+#endif /* _KNOTD_CUCKOO_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/dname_table_tests.c b/src/tests/libknot/libknot/dname_table_tests.c
new file mode 100644
index 0000000..0d00a44
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_table_tests.c
@@ -0,0 +1,393 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "dname_table_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/dname-table.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int knot_dname_table_tests_count(int argc, char *argv[]);
+static int knot_dname_table_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_table_tests_api = {
+ "Dname table", //! Unit name
+ &knot_dname_table_tests_count, //! Count scheduled tests
+ &knot_dname_table_tests_run //! Run scheduled tests
+};
+
+/* Helper functions. */
+static knot_dname_t *dname_from_test_dname_str(const test_dname_t *test_dname)
+{
+ assert(test_dname != NULL);
+ knot_dname_t *ret = knot_dname_new_from_str (test_dname->str,
+ strlen(test_dname->str),
+ NULL);
+ CHECK_ALLOC(ret, NULL);
+
+ return ret;
+}
+
+static int dname_compare_sort_wrapper(const void *ptr1, const void *ptr2)
+{
+ const knot_dname_t *dname1 =
+ dname_from_test_dname_str((const test_dname_t *)ptr1);
+ const knot_dname_t *dname2 =
+ dname_from_test_dname_str((const test_dname_t *)ptr2);
+ assert(dname1 && dname2);
+ return knot_dname_compare(dname1, dname2);
+}
+
+/* Unit implementation. */
+enum {DNAME_TABLE_DNAME_COUNT = 3};
+
+/* Strings are enough, we're not testing dname here ... */
+static test_dname_t DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT] = {
+ /* list ptr, string, wire, length, labels, label_count */
+ {NULL, NULL, ".", NULL, 1, NULL, 0},
+ {NULL, NULL, "a.ns.nic.cz.", NULL, 13, NULL, 0},
+ {NULL, NULL, "b.ns.nic.cz.", NULL, 13, NULL, 0}
+};
+
+static int test_dname_table_new()
+{
+ knot_dname_table_t *table = knot_dname_table_new();
+ if (table == NULL) {
+ return 0;
+ }
+
+ knot_dname_table_free(&table);
+ return 1;
+}
+
+struct test_dname_table_arg {
+ /* Times two - safety measure. */
+ knot_dname_t *array[DNAME_TABLE_DNAME_COUNT * 2];
+ uint count;
+};
+
+static void save_dname_to_array(knot_dname_t *node, void *data)
+{
+ assert(data);
+ struct test_dname_table_arg *arg = (struct test_dname_table_arg *)data;
+ arg->array[arg->count] = node;
+ arg->count++;
+}
+
+static int test_dname_table_adding()
+{
+ int errors = 0;
+ knot_dname_table_t *table = knot_dname_table_new();
+ CHECK_ALLOC(table, 0);
+
+ /* Add NULL */
+ if (knot_dname_table_add_dname(table, NULL) != KNOT_EBADARG) {
+ diag("Adding NULL dname did not result in an error!");
+ errors++;
+ }
+
+ /* Add to NULL table*/
+ if (knot_dname_table_add_dname(NULL, NULL) != KNOT_EBADARG) {
+ diag("Adding to NULL table did not result in an error!");
+ errors++;
+ }
+
+ /* Add NULL */
+ if (knot_dname_table_add_dname_check(table, NULL) != KNOT_EBADARG) {
+ diag("Adding NULL dname did not result in an error!");
+ errors++;
+ }
+
+ /* Add to NULL table*/
+ if (knot_dname_table_add_dname_check(NULL, NULL) != KNOT_EBADARG) {
+ diag("Adding to NULL table did not result in an error!");
+ errors++;
+ }
+
+
+ /* Add valid dnames. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+ if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) {
+ diag("Could not add dname! (%s)",
+ DNAME_TABLE_DNAMES[i].str);
+ errors++;
+ }
+ }
+
+ /*
+ * Using inorder traversal of the table,
+ * create array containing dnames.
+ */
+
+ struct test_dname_table_arg arg;
+ arg.count = 0;
+
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != DNAME_TABLE_DNAME_COUNT) {
+ diag("Table contains too many dnames!");
+ /* No sense in continuing. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ /*
+ * Check that inordered array is really sorted
+ * and contains valid dnames.
+ */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) {
+ assert(arg.array[i]);
+ const char *str = knot_dname_to_str(arg.array[i]);
+ if (str == NULL) {
+ diag("Wrong dname in table!");
+ errors++;
+ continue;
+ }
+
+ if (arg.array[i]->size !=
+ DNAME_TABLE_DNAMES[i].size) {
+ diag("Wrong dname size in table!");
+ diag("Is: %u should be %u.",
+ arg.array[i]->size,
+ DNAME_TABLE_DNAMES[i].size);
+ errors++;
+ continue;
+ }
+
+ if (strncmp(str, DNAME_TABLE_DNAMES[i].str,
+ DNAME_TABLE_DNAMES[i].size) != 0) {
+ diag("Wrong dname wire in table!");
+ errors++;
+ }
+ }
+
+ /* Now add one dname once again. It has to be the first item! */
+
+ if (knot_dname_table_add_dname(table,
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0])) !=
+ KNOT_EOK) {
+ diag("Could not add dname to table once it's already there!");
+ /* Next test would not make sense. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ /*
+ * After walking the table, there should now be
+ * DNAME_TABLE_DNAME_COUNT + 1 items, with 2 identical
+ * items at the beginning.
+ */
+
+ memset(arg.array, 0,
+ sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2);
+ arg.count = 0;
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != DNAME_TABLE_DNAME_COUNT + 1) {
+ diag("Identical dname was not added!");
+ /* Again, next test would not make any sense. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ if (knot_dname_compare(arg.array[0], arg.array[1]) != 0) {
+ diag("First two dnames in table are not identical!");
+ errors++;
+ }
+
+ /* Delete table, wipe out array. */
+ knot_dname_table_deep_free(&table);
+ memset(arg.array, 0,
+ sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2);
+ arg.count = 0;
+
+ table = knot_dname_table_new();
+ assert(table);
+
+ /*
+ * Add dname with same content twice using knot_dname_table_add2 -
+ * table should now only contain one item.
+ */
+
+ knot_dname_t *tmp_dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]);
+ assert(tmp_dname);
+
+ if (knot_dname_table_add_dname_check(table, &tmp_dname) != KNOT_EOK) {
+ diag("Could not add dname using dname_table_add_dname2!");
+ knot_dname_table_deep_free(&table);
+ knot_dname_free(&tmp_dname);
+ return 0;
+ }
+
+ tmp_dname = dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]);
+ assert(tmp_dname);
+
+ knot_dname_t *dname_before_add = tmp_dname;
+
+ if (knot_dname_table_add_dname_check(table, &tmp_dname) != 1) {
+ diag("Could not add dname again using dname_table_add_dname2!");
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ if (tmp_dname == dname_before_add) {
+ diag("Dname was not freed after insertion!");
+ errors++;
+ }
+
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != 1) {
+ diag("Add_dname2 has added dname when it shouldn't!");
+ errors++;
+ }
+
+ if (knot_dname_compare(tmp_dname, arg.array[0]) != 0) {
+ diag("Add_dname2 has added wrong dname!");
+ errors++;
+ }
+
+ knot_dname_table_deep_free(&table);
+ return (errors == 0);
+}
+
+static int test_dname_table_find()
+{
+ int errors = 0;
+ knot_dname_table_t *table = knot_dname_table_new();
+ assert(table);
+
+ if (knot_dname_table_find_dname(table, NULL) != NULL) {
+ diag("Dname table did not return NULL when searching NULL!");
+ errors++;
+ }
+
+ if (knot_dname_table_find_dname(NULL, NULL) != NULL) {
+ diag("Passing NULL instead of dname table did not "
+ "return NULL!");
+ errors++;
+ }
+
+ /* Add all dnames but the last one. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+ if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) {
+ diag("Could not add dname! (%s)",
+ DNAME_TABLE_DNAMES[i].str);
+ errors++;
+ }
+ }
+
+ /* Search for added dnames. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+
+ knot_dname_t *found_dname =
+ knot_dname_table_find_dname(table, dname);
+
+ if (found_dname == NULL) {
+ diag("Dname table did not return "
+ "dname when it should!");
+ errors++;
+ continue;
+ }
+
+ if (knot_dname_compare(found_dname, dname) != 0) {
+ diag("Returned dname did not match!");
+ errors++;
+ continue;
+ }
+ }
+
+ /* Search for last dname, it should return NULL. */
+ knot_dname_t *dname =
+ dname_from_test_dname_str(
+ &DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT]);
+ assert(dname);
+
+ if (knot_dname_table_find_dname(table, dname) != NULL) {
+ diag("Dname table returned dname when it "
+ "should not be there!");
+ errors++;
+ }
+
+ knot_dname_free(&dname);
+ knot_dname_table_deep_free(&table);
+
+ return (errors == 0);
+}
+
+static const int KNOT_DNAME_TABLE_TEST_COUNT = 3;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_table_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TABLE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_table_tests_run(int argc, char *argv[])
+{
+ int final_res = 1;
+ int res = 0;
+
+ /* Sort array containing test dnames. */
+ qsort(DNAME_TABLE_DNAMES, DNAME_TABLE_DNAME_COUNT,
+ sizeof(test_dname_t), dname_compare_sort_wrapper);
+
+ ok((res = test_dname_table_new()), "dname table: new");
+ final_res *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_dname_table_adding()), "dname table: adding");
+ final_res *= res;
+
+ ok((res = test_dname_table_find()), "dname table: searching");
+ final_res *= res;
+
+ endskip;
+
+ return final_res;
+}
diff --git a/src/tests/libknot/libknot/dname_table_tests.h b/src/tests/libknot/libknot/dname_table_tests.h
new file mode 100644
index 0000000..f3088e9
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_table_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_DNAME_TABLE_TESTS_H_
+#define _KNOTD_DNAME_TABLE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_table_tests_api;
+
+#endif /* _KNOTD_DNAME_TABLE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/dname_tests.c b/src/tests/libknot/libknot/dname_tests.c
new file mode 100644
index 0000000..9730756
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_tests.c
@@ -0,0 +1,877 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <string.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/dname_tests.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+
+static int knot_dname_tests_count(int argc, char *argv[]);
+static int knot_dname_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_tests_api = {
+ "DNS library - dname", //! Unit name
+ &knot_dname_tests_count, //! Count scheduled tests
+ &knot_dname_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+// C will not accept const int in other const definition
+enum { TEST_DOMAINS_OK = 8 };
+
+enum { TEST_DOMAINS_BAD = 4 };
+
+enum { TEST_DOMAINS_NON_FQDN = 6 };
+
+static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF;
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+static const struct test_domain // sizes are strlen()s here
+ test_domains_non_fqdn[TEST_DOMAINS_NON_FQDN] = {
+ { "www", "\3www", 4, "\x0", 1 },
+ { "example", "\7example", 8, "\x0", 1 },
+ { "com", "\3com", 4, "\x0", 1 },
+ { "www.example.com", "\3www\7example\3com", 16, "\x0\x4\xC",
+ 3 },
+ { "some", "\4some", 5, "\x0", 1 },
+ { "example.com", "\7example\3com", 12, "\x0\x8", 2 }
+ };
+
+static const struct test_domain
+ test_domains_bad[TEST_DOMAINS_BAD] = {
+ { NULL, "\2ex\3com", 0, "", 0 },
+ { "ex.com.", NULL, 0, "", 0 },
+ { "ex.com.\5", "\3ex\3com\0\5", 10, "", 0 },
+ { "example.com", "\3example\3com", 12, "\x0\x8", 2 }
+};
+
+static int test_dname_create()
+{
+ knot_dname_t *dname = knot_dname_new();
+ if (dname == NULL
+ || knot_dname_name(dname) != NULL
+ || knot_dname_size(dname) != 0
+ || knot_dname_node(dname, 0) != NULL) {
+ diag("New domain name not initialized properly!");
+ return 0;
+ }
+ knot_dname_free(&dname);
+ if (dname != NULL) {
+ diag("Pointer to the structure not set to"
+ "NULL when deallocating!");
+ return 0;
+ }
+ return 1;
+}
+
+static int test_dname_delete()
+{
+ // how to test this??
+ return 0;
+}
+
+static int check_domain_name(const knot_dname_t *dname,
+ const struct test_domain *test_domains, int i,
+ int check_node)
+{
+ int errors = 0;
+
+ if (dname == NULL) {
+ diag("Domain name #%d not created!", i);
+ return 1;
+ }
+
+ // check size
+ if (knot_dname_size(dname) != test_domains[i].size) {
+ diag("Bad size of the created domain name: %u (should be %u).",
+ knot_dname_size(dname), test_domains[i].size);
+ ++errors;
+ }
+ // check wire format
+ uint size = knot_dname_size(dname);
+ if (strncmp((char *)knot_dname_name(dname),
+ test_domains[i].wire, size) != 0) {
+ diag("The wire format of the created domain name is wrong:"
+ " '%.*s' (should be '%.*s').",
+ size, knot_dname_name(dname),
+ size, test_domains[i].wire);
+ ++errors;
+ }
+ // check labels
+ if (test_domains[i].label_count != dname->label_count) {
+ diag("Label count of the created domain name is wrong:"
+ " %d (should be %d)\n", dname->label_count,
+ test_domains[i].label_count);
+ ++errors;
+ }
+ if (strncmp((char *)dname->labels, test_domains[i].labels,
+ test_domains[i].label_count) != 0) {
+ diag("Label offsets of the created domain name are wrong.\n");
+ ++errors;
+ }
+
+ if (check_node) {
+ if (knot_dname_node(dname, 0) != NODE_ADDRESS) {
+ diag("Node pointer in the created domain name is wrong:"
+ "%p (should be %p)",
+ knot_dname_node(dname, 0), NODE_ADDRESS);
+ ++errors;
+ }
+ }
+
+ return errors;
+}
+
+static int test_dname_create_from_str()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ dname = knot_dname_new_from_str(test_domains_ok[i].str,
+ strlen(test_domains_ok[i].str), NODE_ADDRESS);
+ errors += check_domain_name(dname, test_domains_ok, i, 1);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_str_non_fqdn()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ //note("testing domain: %s", test_domains_non_fqdn[i].str);
+ dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str,
+ strlen(test_domains_non_fqdn[i].str), NULL);
+ errors += check_domain_name(dname, test_domains_non_fqdn, i, 0);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_cat()
+{
+ int errors = 0;
+
+ /*
+ * This uses three particular dnames from test_domains structure
+ * where the third dname is a concatenation of the first two dnames.
+ */
+
+ knot_dname_t *d1, *d2, *d3;
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[0].str,
+ strlen(test_domains_non_fqdn[0].str), NULL);
+ d2 = knot_dname_new_from_str(test_domains_non_fqdn[1].str,
+ strlen(test_domains_non_fqdn[1].str), NULL);
+ d3 = knot_dname_new_from_str(test_domains_non_fqdn[2].str,
+ strlen(test_domains_non_fqdn[2].str), NULL);
+
+ knot_dname_cat(d1, d2);
+ knot_dname_cat(d1, d3);
+
+ errors += check_domain_name(d1, test_domains_non_fqdn, 3, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&d2);
+ knot_dname_free(&d3);
+
+ /*
+ * Same thing as above, only different case.
+ */
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[4].str,
+ strlen(test_domains_non_fqdn[4].str),
+ NODE_ADDRESS);
+
+ d2 = knot_dname_new_from_str(test_domains_ok[4].str,
+ strlen(test_domains_ok[4].str),
+ NODE_ADDRESS);
+
+ knot_dname_cat(d1, d2);
+
+ errors += check_domain_name(d1, test_domains_ok, 1, 1);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&d2);
+
+ return (errors == 0);
+}
+
+static int test_dname_left_chop()
+{
+ int errors = 0;
+
+ /* Uses same principle as test_dname_cat(), only reversed */
+
+ /* TODO this would maybe deserver separate structure */
+
+ knot_dname_t *d1;
+
+ d1 = knot_dname_new_from_str(test_domains_ok[1].str,
+ strlen(test_domains_ok[1].str),
+ NODE_ADDRESS);
+
+ knot_dname_t *chopped;
+
+ chopped = knot_dname_left_chop(d1);
+
+ errors += check_domain_name(chopped, test_domains_ok, 4, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&chopped);
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[3].str,
+ strlen(test_domains_non_fqdn[3].str),
+ NODE_ADDRESS);
+
+ chopped = knot_dname_left_chop(d1);
+
+ errors += check_domain_name(chopped, test_domains_non_fqdn, 5, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&chopped);
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_wire()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ assert(strlen(test_domains_ok[i].wire) + 1 ==
+ test_domains_ok[i].size);
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ errors += check_domain_name(dname, test_domains_ok, i, 1);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_to_str()
+{
+ int errors = 0;
+
+ /*
+ * Converts dname wireformat to string represenation, which is compared
+ * with entries in test_domains structure.
+ */
+
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ char *name_str = knot_dname_to_str(dname);
+ if (strcmp(name_str, test_domains_ok[i].str) != 0) {
+ diag("Presentation format of domain name wrong:"
+ " %s (should be %s)",
+ name_str, test_domains_ok[i].str);
+ ++errors;
+ }
+ free(name_str);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+/* called by lives_ok */
+static int test_faulty_data()
+{
+ knot_dname_t *dname = NULL;
+
+ /*
+ * This takes dnames from test_domains_bad array, which contains
+ * malformed dnames. TODO add something like: 2www3foo - it's gonna fail
+ */
+
+ for (int i = 0; i < TEST_DOMAINS_BAD; i++) {
+
+ if (test_domains_bad[i].str != NULL) {
+ dname = knot_dname_new_from_str(
+ test_domains_bad[i].str,
+ strlen(test_domains_bad[i].str),
+ NODE_ADDRESS);
+ } else {
+ dname = knot_dname_new_from_str(
+ test_domains_bad[i].str, 0, NODE_ADDRESS);
+ }
+
+ knot_dname_free(&dname);
+
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_bad[i].wire,
+ test_domains_bad[i].size, NODE_ADDRESS);
+
+ knot_dname_free(&dname);
+ }
+
+ return 1; //did it get here? success
+}
+
+static int test_dname_compare()
+{
+ knot_dname_t *dnames[TEST_DOMAINS_OK];
+
+ /* This uses particular dnames from TEST_DOMAINS_OK array */
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ dnames[i] = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ }
+
+ int errors = 0;
+ /* abc < some */
+ if (knot_dname_compare(dnames[0], dnames[1]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* abc.test.domain.com. < foo.bar.net. */
+ if (knot_dname_compare(dnames[0], dnames[6]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* foo.bar.net. < . */
+ if (knot_dname_compare(dnames[5], dnames[0]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* bar.net. < foo.bar.net. */
+ if (knot_dname_compare(dnames[7], dnames[6]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* some == some */
+ if (knot_dname_compare(dnames[1], dnames[3]) != 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /*xyz > some */
+ if (knot_dname_compare(dnames[2], dnames[1]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /*foo.bar.net. > xyz.test.domain.com. */
+ if (knot_dname_compare(dnames[6], dnames[3]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+// /* xyz.test.domain.com. > . */
+// if (knot_dname_compare(dnames[3], dnames[5]) <= 0) {
+// diag("Dname comparison error");
+// errors++;
+// }
+
+ /* bar.net. < foo.bar.net. */
+ if (knot_dname_compare(dnames[6], dnames[7]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ knot_dname_free(&dnames[i]);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_fqdn()
+{
+ int errors = 0;
+
+ knot_dname_t *dname;
+
+ /* All dnames in TEST_DOMAINS_OK are fqdn */
+
+ for (int i = 0; i < TEST_DOMAINS_OK && !errors; ++i) {
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ errors += !knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ /* None of the following dnames should be fqdn */
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN && !errors; ++i) {
+ dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str,
+ strlen(test_domains_non_fqdn[i].str), NULL);
+ errors += knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_subdomain()
+{
+ int errors = 0;
+
+ knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+ knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ dnames_fqdn[i] = knot_dname_new_from_wire(
+ (const uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NULL);
+ assert(dnames_fqdn[i] != NULL);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ dnames_non_fqdn[i] = knot_dname_new_from_str(
+ test_domains_non_fqdn[i].str,
+ test_domains_non_fqdn[i].size, NULL);
+ assert(dnames_non_fqdn[i] != NULL);
+ }
+
+ // fqdn names 0 - 3 should be subdomains of name 4
+ knot_dname_t *parent = dnames_fqdn[4];
+ for (int i = 0; i < 3; ++i) {
+ if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) {
+ diag("(fqdn 1-%d) "
+ "Name %s was not considered subdomain of %s", i,
+ knot_dname_name(dnames_fqdn[i]),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ }
+
+ // fqdn names 0 - 4 should be subdomains of name 5 (root)
+ parent = dnames_fqdn[5];
+ for (int i = 0; i < 4; ++i) {
+ if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) {
+ diag("(fqdn 2-%d) "
+ "Name %s was not considered subdomain of %s", i,
+ knot_dname_name(dnames_fqdn[i]),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ }
+
+ // non-fqdn names 3 and 5 should be subdomains of non-fqdn name 2
+ parent = dnames_non_fqdn[2];
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) {
+ diag("(non-fqdn 1) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[3]),
+ knot_dname_name(dnames_non_fqdn[3]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[5], parent)) {
+ diag("(non-fqdn 2) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[5]),
+ knot_dname_name(dnames_non_fqdn[5]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+
+ // non-fqdn name 3 should be subdomain of non-fqdn name 5
+ parent = dnames_non_fqdn[5];
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) {
+ diag("(non-fqdn 3) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[3]),
+ knot_dname_name(dnames_non_fqdn[3]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+
+ // identical names should not be considered subdomains
+ if (knot_dname_is_subdomain(dnames_fqdn[0], dnames_fqdn[0])) {
+ diag("(identical names) "
+ "Name %s was considered subdomain of itself",
+ knot_dname_name(dnames_fqdn[0]));
+ ++errors;
+ }
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_fqdn[3])) {
+ diag("(identical names) "
+ "Name %s was considered subdomain of %s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_name(dnames_fqdn[3]));
+ ++errors;
+ }
+
+ // fqdn name should not be considered subdomain of non-fqdn name
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) {
+ diag("(fqdn subdomain of non-fqdn) "
+ "Name %s was considered subdomain of %.*s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_size(dnames_non_fqdn[2]),
+ knot_dname_name(dnames_non_fqdn[2]));
+ ++errors;
+ }
+
+ // non-fqdn name should not be considered subdomain of fqdn name
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) {
+ diag("(non-fqdn subdomain of fqdn) "
+ "Name %s was considered subdomain of %.*s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_size(dnames_non_fqdn[2]),
+ knot_dname_name(dnames_non_fqdn[2]));
+ ++errors;
+ }
+
+ // parent name should not be considered subdomain of its subdomain
+ if (knot_dname_is_subdomain(dnames_fqdn[4], dnames_fqdn[0])) {
+ diag("(ancestor subdomain of name) "
+ "Name %s was considered subdomain of %s",
+ knot_dname_name(dnames_fqdn[4]),
+ knot_dname_name(dnames_fqdn[0]));
+ ++errors;
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ knot_dname_free(&dnames_fqdn[i]);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ knot_dname_free(&dnames_non_fqdn[i]);
+ }
+
+ return (errors == 0);
+}
+
+static int check_wires(const uint8_t *wire1, uint size1,
+ uint8_t *wire2, uint size2)
+{
+ if (size1 != size2) {
+ return 0;
+ }
+
+ int i;
+
+ for (i = 0; (i < size1); i++) {
+ if (wire1[i] != wire2[i]) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*!< \note not to be run separately */
+static int test_dname_name(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ const uint8_t *tmp_name;
+
+ tmp_name = knot_dname_name(dnames_fqdn[i]);
+ if (!check_wires(tmp_name, dnames_fqdn[i]->size,
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size)) {
+ diag("Got bad name value from structure: "
+ "%s, should be: %s. Sizes: %d and: %d",
+ tmp_name, test_domains_ok[i].wire,
+ dnames_fqdn[i]->size,
+ test_domains_ok[i].size);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ const uint8_t *tmp_name;
+ tmp_name = knot_dname_name(dnames_non_fqdn[i]);
+ if (!check_wires(tmp_name, dnames_non_fqdn[i]->size - 1,
+ (uint8_t *)test_domains_non_fqdn[i].wire,
+ test_domains_non_fqdn[i].size)) {
+ diag("Got bad name value from structure: "
+ "%s, should be: %s. Sizes: %d and %d\n",
+ tmp_name, test_domains_non_fqdn[i].wire,
+ dnames_non_fqdn[i]->size,
+ test_domains_non_fqdn[i].size);
+// hex_print(dnames_non_fqdn[i]->name,
+// dnames_non_fqdn[i]->size);
+// hex_print(test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size);
+// diag("%s and %s\n",
+// knot_dname_to_str(dnames_non_fqdn[i]),
+// test_domains_non_fqdn[i]);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+/* \note not to be run separately */
+static int test_dname_size(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ uint8_t tmp_size;
+ if ((tmp_size = knot_dname_size(dnames_fqdn[i])) !=
+ test_domains_ok[i].size) {
+ diag("Got bad size value from structure: "
+ "%u, should be: %u",
+ tmp_size, test_domains_ok[i].size);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ uint8_t tmp_size;
+ if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) !=
+ test_domains_non_fqdn[i].size) {
+ diag("Got bad size value from structure: "
+ "%u, should be: %u",
+ tmp_size, test_domains_non_fqdn[i].size);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+/* \note not to be run separately */
+static int test_dname_node(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ const knot_node_t *tmp_node;
+ if ((tmp_node = knot_dname_node(dnames_fqdn[i], 0)) !=
+ NODE_ADDRESS) {
+ diag("Got bad node value from structure: "
+ "%p, should be: %p",
+ tmp_node, NODE_ADDRESS);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ const knot_node_t *tmp_node;
+ if ((tmp_node = knot_dname_node(dnames_non_fqdn[i], 0)) !=
+ NODE_ADDRESS) {
+ diag("Got bad node value from structure: "
+ "%s, should be: %s",
+ tmp_node, NODE_ADDRESS);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+static int test_dname_getters(uint type)
+{
+ int errors = 0;
+
+ knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+ knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ dnames_fqdn[i] = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ assert(dnames_fqdn[i] != NULL);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ printf("Creating dname: %s size: %d\n", test_domains_non_fqdn[i].wire, test_domains_non_fqdn[i].size);
+ dnames_non_fqdn[i] = knot_dname_new_from_str(
+ test_domains_non_fqdn[i].str,
+ test_domains_non_fqdn[i].size, NODE_ADDRESS);
+ assert(dnames_non_fqdn[i] != NULL);
+ }
+
+ switch (type) {
+ case 0: {
+ errors += test_dname_name(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+
+ case 1: {
+ errors += test_dname_size(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+
+ case 2: {
+ errors += test_dname_node(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+ } /* switch */
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ knot_dname_free(&dnames_fqdn[i]);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ knot_dname_free(&dnames_non_fqdn[i]);
+ }
+
+ return (errors == 0);
+}
+
+static const int KNOT_DNAME_TEST_COUNT = 15;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_str = 0,
+ res_wire = 0,
+ res_str_non_fqdn = 0,
+ res_final = 1;
+
+ res = test_dname_create();
+ ok(res, "dname: create empty");
+ res_final *= res;
+
+ skip(!res, 12);
+
+ todo();
+
+ ok((res = test_dname_delete()), "dname: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok((res_str = test_dname_create_from_str()), "dname: create from str");
+ ok((res_wire = test_dname_create_from_wire()),
+ "dname: create from wire");
+ ok((res_str_non_fqdn = test_dname_create_from_str_non_fqdn()),
+ "dname: create from str non fqdn");
+ res_final *= res_str;
+ res_final *= res_wire;
+ res_final *= res_str_non_fqdn;
+
+ todo();
+ res = test_dname_getters(0);
+ ok(res, "dname: name");
+ endtodo;
+
+ todo();
+ res = test_dname_getters(1);
+ ok(res, "dname: size");
+ endtodo;
+
+ res = test_dname_getters(2);
+ ok(res, "dname: node");
+
+ skip(!res_str || !res_wire || !res_str_non_fqdn, 2);
+
+ ok((res = test_dname_to_str()), "dname: convert to str");
+ res_final *= res;
+
+ lives_ok(test_faulty_data(); , "dname: faulty data test");
+
+ endskip; /* !res_str || !res_wire */
+
+ ok((res = test_dname_compare()), "dname: compare");
+ res_final *= res;
+
+ ok((res = test_dname_cat()), "dname: cat");
+ res_final *= res;
+
+ ok((res = test_dname_is_fqdn()), "dname: fqdn");
+ res_final *= res;
+
+ ok((res = test_dname_left_chop()), "dname: left chop");
+ res_final *= res;
+
+ ok((res = test_dname_is_subdomain()), "dname: is subdomain");
+ res_final *= res;
+
+ endskip; /* create failed */
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/dname_tests.h b/src/tests/libknot/libknot/dname_tests.h
new file mode 100644
index 0000000..a7d75aa
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_DNAME_TESTS_H_
+#define _KNOTD_DNAME_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_tests_api;
+
+#endif /* _KNOTD_DNAME_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/edns_tests.c b/src/tests/libknot/libknot/edns_tests.c
new file mode 100644
index 0000000..ac5d130
--- /dev/null
+++ b/src/tests/libknot/libknot/edns_tests.c
@@ -0,0 +1,596 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/libknot/edns_tests.h"
+#include "libknot/common.h"
+#include "libknot/edns.h"
+
+static int knot_edns_tests_count(int argc, char *argv[]);
+static int knot_edns_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api edns_tests_api = {
+ "DNS library - EDNS", //! Unit name
+ &knot_edns_tests_count, //! Count scheduled tests
+ &knot_edns_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+enum { TEST_EDNS = 1, OPTION_COUNT = 3 };
+
+struct test_edns_options {
+ uint16_t code;
+ uint16_t length;
+ uint8_t *data;
+};
+
+struct test_edns {
+ struct test_edns_options *options;
+ uint16_t payload;
+ uint8_t ext_rcode;
+ uint8_t version;
+ uint16_t flags;
+ short option_count;
+ short options_max;
+ short size;
+};
+
+typedef struct test_edns test_edns_t;
+
+struct test_edns_options test_options_data[OPTION_COUNT] = {
+ {5, 7, (uint8_t *)"123456"},
+ {4, 3, (uint8_t *)"12"},
+ {1, 5, (uint8_t *)"13333"}
+};
+
+test_edns_t test_edns_data[TEST_EDNS] = {
+{ NULL, 4096, 2, 0, 0, 0, 10, 11}
+};
+
+enum edns_mask {
+ KNOT_EDNS_DO_MASK = (uint16_t)0x8000
+};
+
+/* Creates actual knot_opt_rr_t variable from test_edns_t variable */
+static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns)
+{
+ knot_opt_rr_t *ret = knot_edns_new();
+
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ ret->flags = test_edns->flags;
+ ret->ext_rcode = test_edns->ext_rcode;
+ ret->payload = test_edns->payload;
+ ret->version = test_edns->version;
+
+ for (int i = 0; i < test_edns->option_count; i++) {
+ if (knot_edns_add_option(ret, test_edns->options[i].code,
+ test_edns->options[i].length,
+ test_edns->options[i].data) != 0) {
+ knot_edns_free(&ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+/* simple wire compare - 0 if same, 1 otherwise */
+static int edns_compare_wires(uint8_t *wire1,
+ uint8_t *wire2,
+ uint16_t length)
+{
+ for (uint i = 0; i < length; i++) {
+ if (wire1[i] != wire2[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int check_edns(const knot_opt_rr_t *edns,
+ const test_edns_t *test_edns)
+{
+ if (edns->option_count != test_edns->option_count) {
+ diag("Option count is wrong");
+ return -1;
+ }
+
+ for (int i = 0; i < edns->option_count; i++) {
+ /* check options */
+ if (edns->options[i].code != test_edns->options[i].code) {
+ diag("Code in options is wrong");
+ return -1;
+ }
+
+ if (edns->options[i].length != test_edns->options[i].length) {
+ diag("Length in options is wrong");
+ return -1;
+ }
+
+ if (edns_compare_wires(edns->options[i].data,
+ test_edns->options[i].data,
+ edns->options[i].length) != 0) {
+ diag("Data in options are wrong");
+ return -1;
+ }
+ }
+
+ if (edns->version != test_edns->version) {
+ diag("Version is wrong");
+ return -1;
+ }
+
+ if (edns->flags != test_edns->flags) {
+ diag("Flags are wrong");
+ return -1;
+ }
+
+ if (edns->size != test_edns->size) {
+ diag("Size is wrong");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_edns_get_payload(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_payload(edns) !=
+ test_edns->payload) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_ext_rcode(edns) !=
+ test_edns->ext_rcode) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_flags(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_flags(edns) !=
+ test_edns->flags) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_version(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_version(edns) !=
+ test_edns->version) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_do(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_do(edns) !=
+ (test_edns->flags & KNOT_EDNS_DO_MASK)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns)
+{
+ if (knot_edns_size(edns) !=
+ test_edns->size) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_payload(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_payload(edns, test_edns->payload);
+
+ if (edns->payload !=
+ test_edns->payload) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_ext_rcode(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_ext_rcode(edns, test_edns->ext_rcode);
+ if (edns->ext_rcode !=
+ test_edns->ext_rcode) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_version(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_version(edns,
+ test_edns->version);
+
+ if (edns->version !=
+ test_edns->version) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_do(knot_opt_rr_t *edns)
+{
+ knot_edns_set_do(edns);
+
+ if (!knot_edns_do(edns)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_getters(uint type)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ switch(type) {
+ case 0:
+ if (test_edns_get_payload(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong payload!");
+ errors++;
+ }
+ break;
+ case 1:
+ if (test_edns_get_ext_rcode(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong extended RCODE!");
+ errors++;
+ }
+ break;
+ case 2:
+ if (test_edns_get_flags(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong flags!");
+
+ errors++;
+ }
+ break;
+ case 3:
+ if (test_edns_get_version(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong version!");
+ errors++;
+ }
+ break;
+ case 4:
+ if (test_edns_do(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong DO bit!");
+ errors++;
+ }
+ break;
+ case 5:
+ if (test_edns_size(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong size!");
+ errors++;
+ }
+ break;
+ default:
+ diag("Unknown option");
+ errors++;
+ } /* switch */
+
+ knot_edns_free(&edns);
+ }
+
+ return (errors == 0);
+}
+
+static int test_edns_setters(uint type)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ switch(type) {
+ case 0:
+ if (test_edns_set_payload(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong payload!");
+ errors++;
+ }
+ break;
+ case 1:
+ if (test_edns_set_ext_rcode(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong ext_rcode");
+ errors++;
+ }
+ break;
+ case 2:
+ if (test_edns_set_version(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong version!");
+ errors++;
+ }
+ break;
+ case 3:
+ if (test_edns_set_do(edns) != 1) {
+ diag("Set wrong DO bit!");
+ errors++;
+ }
+ break;
+ default:
+ diag("Unknown option");
+ errors++;
+ } /* switch */
+
+ knot_edns_free(&edns);
+ }
+
+ return (errors == 0);
+}
+
+static int test_edns_wire()
+{
+ /*
+ * Tests to_wire and from_wire in one test.
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ /* Creates instance from test_edns_t. */
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ uint8_t *wire = NULL;
+ wire = malloc(sizeof(uint8_t) * edns->size);
+ CHECK_ALLOC_LOG(wire, 0);
+
+ /* Converts EDNS to wire. */
+ short wire_size = knot_edns_to_wire(edns, wire, 100);
+
+ if (wire_size == -1) {
+ diag("Could not create EDNS wire");
+ return 0;
+ }
+
+ knot_opt_rr_t *edns_from_wire = knot_edns_new();
+ if (edns == NULL) {
+ return 0;
+ }
+
+ /* TODO use some constant */
+ /* Creates new EDNS from wire */
+ if (knot_edns_new_from_wire(edns_from_wire,
+ wire,
+ 100) <= 0) {
+ diag("Could not create from wire");
+ return 0;
+ }
+
+ /* Checks whether EDNS created from wire is the same */
+ if (check_edns(edns_from_wire,
+ &(test_edns_data[i])) != 0) {
+ diag("EDNS created from wire is different from the "
+ "original one");
+ }
+
+ free(wire);
+ knot_edns_free(&edns_from_wire);
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static int test_edns_add_option()
+{
+ /*
+ * Create empty EDNS and add options one by one, testing their presence.
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns = knot_edns_new();
+ assert(edns->option_count == 0);
+
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ for (int j = 0; j < test_edns_data[i].option_count; j++) {
+ if (knot_edns_add_option(edns,
+ test_edns_data[i].options[j].code,
+ test_edns_data[i].options[j].length,
+ test_edns_data[i].options[j].
+ data) != 0) {
+ diag("Could not add option");
+ return 0;
+ }
+
+ if (edns->options[j].code !=
+ test_edns_data[i].options[j].code) {
+ diag("Option code wrongly added!");
+ return 0;
+ }
+
+ if (edns->options[j].length !=
+ test_edns_data[i].options[j].length) {
+ diag("Option length wrongly added!");
+ return 0;
+ }
+
+ if (edns_compare_wires(edns->options[j].data,
+ test_edns_data[i].
+ options[j].data,
+ edns->options[j].length) != 0) {
+ diag("Option wire wrongly added!");
+ return 0;
+ }
+ }
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static int test_edns_has_option()
+{
+ /*
+ * Create empty EDNS and add options one by one, testing their presence
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns = knot_edns_new();
+ assert(edns->option_count == 0);
+
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ for (int j = 0; j < test_edns_data[i].option_count; j++) {
+ if (knot_edns_add_option(edns,
+ test_edns_data[i].options[j].code,
+ test_edns_data[i].options[j].length,
+ test_edns_data[i].options[j].
+ data) != 0) {
+ diag("Could not add option");
+ return 0;
+ }
+
+ if (knot_edns_has_option(edns,
+ test_edns_data[i].options[j].code) != 1) {
+ diag("Option not found!");
+ return 0;
+ }
+ }
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static const int KNOT_EDNS_TESTS_COUNT = 12;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_edns_tests_count(int argc, char *argv[])
+{
+ return KNOT_EDNS_TESTS_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_edns_tests_run(int argc, char *argv[])
+{
+ int res = 0;
+ int res_final = 1;
+
+ res = test_edns_getters(0);
+ ok(res, "ends: get payload");
+ res_final *= res;
+
+ res = test_edns_getters(1);
+ ok(res, "ends: get extenden RCODE");
+ res_final *= res;
+
+ res = test_edns_getters(2);
+ ok(res, "ends: get flags");
+ res_final *= res;
+
+ res = test_edns_getters(3);
+ ok(res, "ends: get version");
+ res_final *= res;
+
+ res = test_edns_getters(4);
+ ok(res, "ends: do");
+ res_final *= res;
+
+ res = test_edns_getters(5);
+ ok(res, "ends: size");
+ res_final *= res;
+
+ res = test_edns_setters(0);
+ ok(res, "ends: set payload");
+ res_final *= res;
+
+ res = test_edns_setters(1);
+ ok(res, "ends: set extended RCODE");
+ res_final *= res;
+
+ res = test_edns_setters(2);
+ ok(res, "ends: set version");
+ res_final *= res;
+
+ res = test_edns_setters(3);
+ ok(res, "ends: set DO");
+ res_final *= res;
+
+ res = test_edns_add_option();
+ ok(res, "ends: add option");
+ res_final *= res;
+
+ res = test_edns_has_option();
+ ok(res, "ends: has option");
+ res_final *= res;
+
+ res = test_edns_wire();
+ ok(res, "ends: to_wire and from_wire");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/edns_tests.h b/src/tests/libknot/libknot/edns_tests.h
new file mode 100644
index 0000000..4553234
--- /dev/null
+++ b/src/tests/libknot/libknot/edns_tests.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/*!
+ * \file edns_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for ENDS API
+ *
+ * Contains tests for:
+ * - ENDS API
+ */
+#ifndef _KNOTD__EDNS_TESTS_H_
+#define _KNOTD__EDNS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api edns_tests_api;
+
+#endif /* _KNOTD__EDNS_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/node_tests.c b/src/tests/libknot/libknot/node_tests.c
new file mode 100644
index 0000000..f04a202
--- /dev/null
+++ b/src/tests/libknot/libknot/node_tests.c
@@ -0,0 +1,344 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/libknot/node_tests.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/descriptor.h"
+
+static int knot_node_tests_count(int argc, char *argv[]);
+static int knot_node_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api node_tests_api = {
+ "DNS library - node", //! Unit name
+ &knot_node_tests_count, //! Count scheduled tests
+ &knot_node_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+// C will not accept const int in other const definition
+enum { TEST_NODES = 2, RRSETS = 5};
+
+struct test_node {
+ knot_dname_t owner;
+ knot_node_t *parent;
+ uint size;
+};
+
+static knot_dname_t test_dnames[TEST_NODES] = {
+ {{}, (uint8_t *)"\3www\7example\3com", 17},
+ {{}, (uint8_t *)"\3www\7example\3com", 17}
+};
+
+static struct test_node test_nodes[TEST_NODES] = {
+ {{{}, (uint8_t *)"\3com", 4}, (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3www\7example\3com", 17}, (knot_node_t *)NULL}
+};
+
+static knot_rrset_t rrsets[RRSETS] = {
+ {&test_dnames[0], 1, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 2, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 7, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 3, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 9, 1, 3600, NULL, NULL}
+};
+
+static int test_node_create()
+{
+ /* Tests creation of node by comparing with test_node struct */
+ knot_node_t *tmp;
+ int errors = 0;
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ if (tmp == NULL ||
+ tmp->owner != &test_nodes[i].owner ||
+ tmp->parent != test_nodes[i].parent ||
+ tmp->rrset_tree == NULL) {
+ errors++;
+ diag("Failed to create node structure");
+ }
+ knot_node_free(&tmp, 0, 0);
+ }
+ return (errors == 0);
+}
+
+static int test_node_add_rrset()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ /* create node from test_node structure */
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ rrset = &rrsets[i];
+ if (knot_node_add_rrset(tmp, rrset, 0) < 0) {
+ errors++;
+ diag("Failed to insert rrset into node");
+ }
+
+ /* check if rrset is really there */
+
+ const knot_rrset_t *rrset_from_node = NULL;
+ if ((rrset_from_node =
+ knot_node_rrset(tmp, rrset->type)) == NULL) {
+ errors++;
+ diag("Inserted rrset could not be found");
+ continue;
+ }
+
+ /* compare rrset from node with original rrset */
+
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ int cmp = 0;
+
+ if ((rrset_from_node->rdata == NULL) &&
+ (rrset->rdata == NULL)) {
+ cmp = 0;
+ } else if ((rrset_from_node->rdata != NULL) &&
+ (rrset->rdata != NULL)) {
+ cmp = knot_rdata_compare(rrset_from_node->rdata,
+ rrset->rdata,
+ desc->wireformat);
+ } else { /* one is not NULL and other is -> error */
+ cmp = 1;
+ }
+
+ if (!((rrset_from_node->type == rrset->type) &&
+ (rrset_from_node->rclass == rrset->rclass) &&
+ (rrset_from_node->ttl == rrset->ttl) &&
+ (rrset_from_node->rrsigs == rrset->rrsigs) &&
+ (cmp == 0))) {
+ errors++;
+ diag("Values in found rrset are wrong");
+ }
+
+ knot_node_free(&tmp, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_get_rrset()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ knot_node_t *nodes[TEST_NODES];
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ nodes[i] = tmp;
+ for (int j = 0; j < RRSETS; j++) {
+ knot_node_add_rrset(tmp, &rrsets[j], 0);
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ for (int j = 0; j < RRSETS; j++) {
+ rrset = &rrsets[j];
+ if (knot_node_rrset(nodes[i], rrset->type)
+ != rrset) {
+ errors++;
+ diag("Failed to get proper rrset from node");
+ }
+ }
+ knot_node_free(&nodes[i], 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_get_parent()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ knot_node_t *nodes[TEST_NODES];
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ nodes[i] = tmp;
+ rrset = &rrsets[i];
+ knot_node_add_rrset(tmp, rrset, 0);
+ }
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ rrset = &rrsets[i];
+ if (knot_node_parent(nodes[i], 0) != test_nodes[i].parent) {
+ errors++;
+ diag("Failed to get proper parent from node");
+ }
+ knot_node_free(&nodes[i], 0, 0);
+ }
+ return (errors == 0);
+}
+
+static int test_node_sorting()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ tmp = knot_node_new(&test_nodes[0].owner, test_nodes[0].parent, 0);
+
+ /* Will add rrsets to node. */
+
+ for (int i = 0; i < RRSETS && !errors; i++) {
+ rrset = &rrsets[i];
+ knot_node_add_rrset(tmp, rrset, 0);
+ }
+
+// const skip_node_t *node = skip_first(tmp->rrsets);
+
+// int last = *((uint16_t *)node->key);
+
+// /* TODO there is now an API function knot_node_rrsets ... */
+
+// /* Iterates through skip list and checks, whether it is sorted. */
+
+// while ((node = skip_next(node)) != NULL) {
+// if (last > *((uint16_t *)node->key)) {
+// errors++;
+// diag("RRset sorting error");
+// }
+// last = *((uint16_t *)node->key);
+// }
+
+ knot_node_free(&tmp, 0, 0);
+ return (errors == 0);
+}
+
+static int test_node_delete()
+{
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_free(&tmp_node, 0, 0);
+
+ errors += (tmp_node != NULL);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_set_parent()
+{
+ knot_node_t *tmp_parent = knot_node_new(NULL, NULL, 0);
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_set_parent(tmp_node, tmp_parent);
+
+ if (tmp_node->parent != tmp_node->parent) {
+ diag("Parent node is wrongly set.");
+ errors++;
+ }
+ knot_node_free(&tmp_node, 0, 0);
+ }
+ knot_node_free(&tmp_parent, 0, 0);
+ return (errors == 0);
+}
+
+static int test_node_free_rrsets()
+{
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_free_rrsets(tmp_node, 0);
+
+// errors += (tmp_node->rrsets != NULL);
+
+ knot_node_free(&tmp_node, 0, 0);
+ }
+ return (errors == 0);
+}
+
+static const int KNOT_NODE_TEST_COUNT = 8;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_node_tests_count(int argc, char *argv[])
+{
+ return KNOT_NODE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_node_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+ res = test_node_create();
+ ok(res, "node: create");
+ res_final *= res;
+
+ skip(!res, 6)
+
+ ok((res = test_node_add_rrset()), "node: add");
+ res_final *= res;
+
+ ok((res = test_node_get_rrset()), "node: get");
+ res_final *= res;
+
+ ok((res = test_node_get_parent()), "node: get parent");
+ res_final *= res;
+
+ ok((res = test_node_set_parent()), "node: set parent");
+ res_final *= res;
+
+ ok((res = test_node_sorting()), "node: sort");
+ res_final *= res;
+
+ ok((res = test_node_free_rrsets()), "node: free rrsets");
+ res_final *= res;
+
+ endskip;
+
+ ok((res = test_node_delete()), "node: delete");
+ //res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/node_tests.h b/src/tests/libknot/libknot/node_tests.h
new file mode 100644
index 0000000..a90179f
--- /dev/null
+++ b/src/tests/libknot/libknot/node_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_NODE_TESTS_H_
+#define _KNOTD_NODE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api node_tests_api;
+
+#endif /* _KNOTD_NODE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/nsec3_tests.c b/src/tests/libknot/libknot/nsec3_tests.c
new file mode 100644
index 0000000..7b95549
--- /dev/null
+++ b/src/tests/libknot/libknot/nsec3_tests.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "libknot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/nsec3.h"
+#include "libknot/util/utils.h"
+#include "common/base32hex.h"
+#include "nsec3_tests.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int knot_nsec3_tests_count(int argc, char *argv[]);
+static int knot_nsec3_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api nsec3_tests_api = {
+ "NSEC3", //! Unit name
+ &knot_nsec3_tests_count, //! Count scheduled tests
+ &knot_nsec3_tests_run //! Run scheduled tests
+};
+
+extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count);
+
+static int test_nsec3_params_from_wire()
+{
+ /* Create sample NSEC3PARAM rdata */
+ knot_rdata_item_t items[4];
+ knot_rdata_t *rdata = knot_rdata_new();
+ rdata->items = items;
+ rdata->count = 4;
+ knot_rdata_item_set_raw_data(rdata, 0, (uint16_t *)"\x1\x0\x1");
+ knot_rdata_item_set_raw_data(rdata, 1, (uint16_t *)"\x1\x0\x0");
+ knot_rdata_item_set_raw_data(rdata, 2, (uint16_t *)"\x2\x0\x0\x64");
+ knot_rdata_item_set_raw_data(rdata, 3,
+ (uint16_t *)"\xF\x0\xE\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF");
+
+ knot_rrset_t *rrset =
+ knot_rrset_new(knot_dname_new_from_str("cz.",
+ strlen("cz."), NULL),
+ KNOT_RRTYPE_NSEC3PARAM,
+ KNOT_CLASS_IN,
+ 3600);
+ assert(rrset);
+ int ret = knot_rrset_add_rdata(rrset, rdata);
+ assert(ret == KNOT_EOK);
+
+ knot_nsec3_params_t nsec3_test_params;
+
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ /* Create special variable for this block. */
+ if (knot_nsec3_params_from_wire(NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_nsec3_params_from_wire(&nsec3_test_params, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_nsec3_params_from_wire(NULL, rrset) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ }, "nsec3 params from wire NULL tests");
+ errors += lived != 1;
+
+ if (knot_nsec3_params_from_wire(&nsec3_test_params,
+ rrset) != KNOT_EOK) {
+ diag("Could not convert nsec3 params to wire!");
+ return 0;
+ }
+
+ if (nsec3_test_params.algorithm != 1) {
+ diag("Algorithm error");
+ errors++;
+ }
+
+ if (nsec3_test_params.flags != 0) {
+ diag("Flags error %d", nsec3_test_params.flags);
+ errors++;
+ }
+
+ if (nsec3_test_params.iterations != 100) {
+ diag("Iterations error %d", nsec3_test_params.iterations);
+ errors++;
+ }
+ printf("salt length: %d\n", nsec3_test_params.salt_length);
+
+ if (nsec3_test_params.salt_length != 14) {
+ diag("Salt length error %d", nsec3_test_params.salt_length);
+ return 0;
+ }
+
+ if (compare_wires_simple((uint8_t *)nsec3_test_params.salt,
+ (uint8_t *)"\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF",
+ 14) != 0) {
+ diag("Salt wire error");
+ errors++;
+ }
+
+ knot_rrset_free(&rrset);
+ return (errors == 0);
+}
+
+static int test_nsec3_sha1()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_nsec3_params_t nsec3_test_params;
+
+ lives_ok({
+ if (knot_nsec3_sha1(NULL, NULL, 1, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ NULL, 1, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ uint8_t data[20];
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ data, 20, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ uint8_t *digest = NULL;
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ data, 20, &digest, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+// size_t size = 0;
+// lived = 1;
+// lived = 0;
+// if (knot_nsec3_sha1(&nsec3_test_params,
+// data, 20, &digest, &size) !=
+// KNOT_EBADARG) {
+// errors++;
+// }
+ lived = 1;
+ }, "NSEC3: nsec3 sha1 NULL tests");
+ if (errors) {
+ diag("Does not return KNOT_EBADARG after "
+ "execution with wrong arguments!");
+ }
+
+ errors += lived != 1;
+
+ uint8_t *digest = NULL;
+ size_t digest_size = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ (uint8_t *)"\2ns\3nic\2cz",
+ strlen("\2ns\3nic\2cz"), &digest,
+ &digest_size) != KNOT_EOK) {
+ diag("Could not hash name!");
+ return 0;
+ }
+
+#ifdef TEST_WITH_LDNS
+ ldns_rdf *name = ldns_dname_new_frm_str("ns.nic.cz.");
+ assert(name);
+ ldns_rdf *hashed_name = ldns_nsec3_hash_name(name,
+ nsec3_test_params.algorithm,
+ nsec3_test_params.iterations,
+ nsec3_test_params.salt_length,
+ nsec3_test_params.salt);
+ assert(hashed_name);
+// knot_dname_t *dname_from_ldns =
+// knot_dname_new_from_wire(ldns_rdf_data(hashed_name),
+// ldns_rdf_size(hashed_name),
+// NULL);
+
+ char *name_b32 = NULL;
+ size_t size_b32 = base32hex_encode_alloc((char *)digest, digest_size,
+ &name_b32);
+
+// hex_print(name_b32, size_b32);
+// hex_print(ldns_rdf_data(hashed_name), ldns_rdf_size(hashed_name));
+ if (ldns_rdf_size(hashed_name) != size_b32) {
+ diag("Wrong hashed name length! Should be: %d is: %d",
+ ldns_rdf_size(hashed_name), size_b32);
+ return 0;
+ }
+
+ if (compare_wires_simple(ldns_rdf_data(hashed_name),
+ (uint8_t *)name_b32, size_b32) != 0) {
+ diag("Wrong hashed name wire!");
+ errors++;
+ }
+#endif
+
+#ifndef TEST_WITH_LDNS
+ diag("Warning: without ldns this test is only partial!");
+#endif
+ return (errors == 0);
+}
+
+static const int KNOT_NSEC3_TESTS_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_nsec3_tests_count(int argc, char *argv[])
+{
+ return KNOT_NSEC3_TESTS_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_nsec3_tests_run(int argc, char *argv[])
+{
+ ok(test_nsec3_params_from_wire(), "nsec3: params from wire");
+ ok(test_nsec3_sha1(), "nsec3: sha1");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/nsec3_tests.h b/src/tests/libknot/libknot/nsec3_tests.h
new file mode 100644
index 0000000..10e7ed9
--- /dev/null
+++ b/src/tests/libknot/libknot/nsec3_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_NSEC3_TESTS_H_
+#define _KNOTD_NSEC3_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api nsec3_tests_api;
+
+#endif /* _KNOTD_NSEC3_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/packet_tests.c b/src/tests/libknot/libknot/packet_tests.c
new file mode 100644
index 0000000..185504f
--- /dev/null
+++ b/src/tests/libknot/libknot/packet_tests.c
@@ -0,0 +1,430 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "packet_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/util/wire.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int packet_tests_count(int argc, char *argv[]);
+static int packet_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api packet_tests_api = {
+ "packet", //! Unit name
+ &packet_tests_count, //! Count scheduled tests
+ &packet_tests_run //! Run scheduled tests
+};
+
+static int test_packet_new()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_node constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_query constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ packet = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_resp constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ /*!< \todo Should it create packet using any size? */
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_from_wire()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+
+ int tmp = 0;
+ lives_ok({
+ if (knot_packet_parse_from_wire(NULL, NULL, 0, 0) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse NULL packet with NULL wire "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if (knot_packet_parse_from_wire(packet, NULL, 0, 0) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse with NULL wire "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if (knot_packet_parse_from_wire(packet, (uint8_t *)0xbeef,
+ 0, 0) !=
+ KNOT_EFEWDATA) {
+ diag("Trying to parse 0 lengt"
+ "did not return KNOT_EOK!");
+ errors++;
+ }
+ tmp = 1;
+ }, "packet: parse from wire NULL tests.");
+ errors += tmp != 1;
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_next_rr_answer()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ int tmp = 0;
+ lives_ok({
+ int ret = 0;
+ if (knot_packet_parse_next_rr_answer(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse next RR answer with "
+ "NULL packet with and NULL RRSet "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if ((ret = knot_packet_parse_next_rr_answer(packet,
+ NULL)) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse next RR with NULL RRSet pointer "
+ "did not return KNOT_EBADARG! Got %d.",
+ ret);
+ errors++;
+ }
+ tmp = 1;
+// knot_rrset_t *rrset = (knot_rrset_t *)0xaaaa;
+// tmp = 0;
+// if (knot_packet_parse_next_rr_answer(packet,
+// &rrset) !=
+// KNOT_EBADARG) {
+// diag("Trying to parse next RR answer with rrset pointer"
+// " not pointing to NULL did not "
+// "return KNOT_EBADARG!");
+// errors++;
+// }
+// tmp = 1;
+ }, "packet: parse next rr answer NULL tests.");
+ errors += tmp != 1;
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_rest()
+{
+ int res = 0;
+ lives_ok({res = knot_packet_parse_rest(NULL);},
+ "packet: parse rest NULL test");
+
+ if (res != KNOT_EBADARG) {
+ diag("parse rest NULL did not return KNOT_EBADARG.\n");
+ return 1;
+ }
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ assert(packet);
+
+ todo();
+ lives_ok({res = knot_packet_parse_rest(packet);},
+ "packet: parser rest empty packet");
+ endtodo;
+
+ knot_packet_free(&packet);
+
+ return 1;
+}
+
+
+static int test_packet_set_max_size()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ assert(packet);
+
+ int lived = 0;
+
+ lives_ok({
+ lived = 0;
+ if (knot_packet_set_max_size(NULL, 1) != KNOT_EBADARG) {
+ diag("Calling packet_set_max() with NULL packet "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: set max size NULL test");
+
+ errors += lived != 1;
+
+ if (knot_packet_set_max_size(packet, 0) != KNOT_EBADARG) {
+ diag("Calling packet_set_max() with size eqeal to 0 did not "
+ "return KNOT_EBADARG");
+ errors++;
+ }
+
+ if (knot_packet_set_max_size(packet, 10) != KNOT_EOK) {
+ diag("Calling packet_set_max() with valid arguments did not "
+ "return KNOT_EOK");
+ errors++;
+ }
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_add_tmp_rrset()
+{
+ int errors = 0;
+ int lived = 0;
+
+ /* knot_packet_add_tmp_rrset only works with pointers. */
+ knot_rrset_t *rrset = (knot_rrset_t *)0xabcdef;
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_add_tmp_rrset(NULL, rrset) !=
+ KNOT_EBADARG) {
+ diag("Trying to add to NULL packet did not return "
+ "KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_packet_add_tmp_rrset(packet, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to add NULL rrset did not return "
+ "KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_packet_add_tmp_rrset(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to add NULL rrset to NULL packet "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: add tmp rrset NULL test");
+ errors += lived != 1;
+
+ if (knot_packet_add_tmp_rrset(packet, rrset) != KNOT_EOK) {
+ diag("Could not add valid RRSet to packet!");
+ errors++;
+ }
+
+ /* Not freeing because RRSet is fake. */
+// knot_packet_free(&packet);
+
+ free(packet->wireformat);
+ free(packet);
+
+ return (errors == 0);
+}
+
+//static int test_packet_contains()
+//{
+// int errors = 0;
+// int lives = 0;
+
+// knot_packet_t *packet =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// assert(packet);
+
+// lives_ok({
+// if (knot_packet_contains(packet, NULL,
+// KNOT_RRSET_COMPARE_PTR) !=
+// KNOT_EBADARG{
+// diag();
+// }
+// }, "packet: contains NULL tests);
+
+// knot_packet_contains()
+
+//}
+
+static int test_packet_header_to_wire()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ size_t size;
+
+ lives_ok({
+ knot_packet_header_to_wire(NULL, NULL, NULL);
+ lived = 1;
+ lived = 0;
+ knot_packet_header_to_wire(&packet->header, NULL, &size);
+ lived = 1;
+ }, "packet: header to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_question_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_question_to_wire(NULL) != KNOT_EBADARG) {
+ diag("Calling packet_question_to_wire with "
+ "NULL pointer did not result to KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: question to wire NULL tests");
+ errors += lived != 1;
+
+ packet->size = KNOT_WIRE_HEADER_SIZE + 1;
+ if (knot_packet_question_to_wire(packet) != KNOT_ERROR) {
+ diag("Calling packet_question_to_wire with oversized packet "
+ "did not return KNOT_ERROR!");
+ errors++;
+ }
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_edns_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ knot_packet_edns_to_wire(NULL);
+ lived = 1;
+ }, "packet: question to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_to_wire(NULL, NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "NULL pointers did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ size_t size;
+ lived = 0;
+ if (knot_packet_to_wire(packet, NULL, &size) !=
+ KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "NULL wire did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ uint8_t *wire = (uint8_t *)0xabcdef;
+ lived = 0;
+ if (knot_packet_to_wire(packet, &wire, &size) !=
+ KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "wire not pointing to NULL did not return"
+ " KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static const uint KNOT_PACKET_TEST_COUNT = 21;
+
+static int packet_tests_count(int argc, char *argv[])
+{
+ return KNOT_PACKET_TEST_COUNT;
+}
+
+static int packet_tests_run(int argc, char *argv[])
+{
+ int res = 0;
+ ok(res = test_packet_new(), "packet: new");
+ skip(!res, 20);
+ ok(test_packet_parse_rest(), "packet: parse rest");
+ ok(test_packet_parse_from_wire(), "packet: parse from wire");
+ ok(test_packet_parse_next_rr_answer(), "packet: parse next rr answer");
+ ok(test_packet_set_max_size(), "packet: set max size");
+ ok(test_packet_add_tmp_rrset(), "packet: add tmp rrset");
+ ok(test_packet_header_to_wire(), "packet: header to wire");
+ ok(test_packet_question_to_wire(), "packet: header to wire");
+ ok(test_packet_edns_to_wire(), "packet: header to wire");
+ ok(test_packet_to_wire(), "packet: to wire");
+// ok(res = test_packet_contains(), "Packet: contains");
+ endskip;
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/packet_tests.h b/src/tests/libknot/libknot/packet_tests.h
new file mode 100644
index 0000000..5a8ce03
--- /dev/null
+++ b/src/tests/libknot/libknot/packet_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_PACKET_TESTS_H_
+#define _KNOTD_PACKET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api packet_tests_api;
+
+#endif /* _KNOTD_PACKET_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/query_tests.c b/src/tests/libknot/libknot/query_tests.c
new file mode 100644
index 0000000..1e4e081
--- /dev/null
+++ b/src/tests/libknot/libknot/query_tests.c
@@ -0,0 +1,160 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "packet_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/util/wire.h"
+#include "libknot/packet/query.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int query_tests_count(int argc, char *argv[]);
+static int query_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api query_tests_api = {
+ "query", //! Unit name
+ &query_tests_count, //! Count scheduled tests
+ &query_tests_run //! Run scheduled tests
+};
+
+static const uint KNOT_QUERY_TEST_COUNT = 1;
+
+static int query_tests_count(int argc, char *argv[])
+{
+ return KNOT_QUERY_TEST_COUNT;
+}
+
+static int test_query_init()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(query);
+ lives_ok({
+ if (knot_query_init(NULL) != KNOT_EBADARG) {
+ diag("Calling query_init with NULL query did "
+ "not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "query: init NULL tests");
+ errors += lived != 1;
+
+ assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK);
+ if (knot_query_init(query) != KNOT_EOK) {
+ diag("Calling query_init with valid query did not return "
+ "KNOT_EOK!");
+ errors++;
+ }
+
+ if (!knot_packet_is_query(query)) {
+ diag("QR flag was not set!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_query_set_question()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(query);
+ assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK);
+ knot_query_init(query);
+
+ knot_rrset_t *rrset =
+ knot_rrset_new(knot_dname_new_from_str("a.ns.cz.",
+ strlen("a.ns.cz."),
+ NULL),
+ KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ assert(rrset);
+
+ knot_question_t *question = malloc(sizeof(knot_question_t));
+ assert(question);
+ question->qname = rrset->owner;
+ question->qtype = rrset->type;
+ question->qclass = rrset->rclass;
+
+ lives_ok({
+ if (knot_query_set_question(NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_query_set_question(query, NULL) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_query_set_question(NULL, question) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ }, "query: set question NULL tests");
+ errors += lived != 1;
+
+ if (knot_query_set_question(query, question) != KNOT_EOK) {
+ diag("Calling query_set_question with valid arguments ");
+ errors++;
+ }
+
+ if (query->question.qname != rrset->owner) {
+ diag("Qname was not set right!");
+ errors++;
+ }
+
+ if (query->question.qtype != rrset->type) {
+ diag("Qtype was not set right!");
+ errors++;
+ }
+
+ if (query->question.qclass != rrset->rclass) {
+ diag("Qclass was not set right!");
+ errors++;
+ }
+
+ if (query->header.qdcount != 1) {
+ diag("Qdcount was not set right!");
+ errors++;
+ }
+
+ knot_packet_free(&query);
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+
+ return (errors == 0);
+}
+
+static int query_tests_run(int argc, char *argv[])
+{
+ ok(test_query_init(), "query: init");
+ ok(test_query_set_question(), "query: set question");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/query_tests.h b/src/tests/libknot/libknot/query_tests.h
new file mode 100644
index 0000000..037ecab
--- /dev/null
+++ b/src/tests/libknot/libknot/query_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_QUERY_TESTS_H_
+#define _KNOTD_QUERY_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api query_tests_api;
+
+#endif /* _KNOTD_QUERY_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/rdata_tests.c b/src/tests/libknot/libknot/rdata_tests.c
new file mode 100644
index 0000000..561686a
--- /dev/null
+++ b/src/tests/libknot/libknot/rdata_tests.c
@@ -0,0 +1,954 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdlib.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/rdata_tests.h"
+#include "libknot/common.h"
+#include "libknot/rdata.h"
+#include "libknot/dname.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "libknot/util/error.h"
+
+enum { TEST_DOMAINS_OK = 8 };
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+
+static int knot_rdata_tests_count(int argc, char *argv[]);
+static int knot_rdata_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rdata_tests_api = {
+ "DNS library - rdata", //! Unit name
+ &knot_rdata_tests_count, //! Count scheduled tests
+ &knot_rdata_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+static uint16_t *RDATA_ITEM_PTR = (uint16_t *)0xDEADBEEF;
+
+enum { RDATA_ITEMS_COUNT = 7, TEST_RDATA_COUNT = 4 , RDATA_DNAMES_COUNT = 2 };
+
+static knot_dname_t RDATA_DNAMES[RDATA_DNAMES_COUNT] = {
+ {{}, (uint8_t *)"\6abcdef\7example\3com", 20,
+ (uint8_t *)"\x0\x7\xF", 3},
+ {{}, (uint8_t *)"\6abcdef\3foo\3com", 16,
+ (uint8_t *)"\x0\x7\xB", 3}
+};
+
+static knot_rdata_item_t TEST_RDATA_ITEMS[RDATA_ITEMS_COUNT] = {
+ {.dname = (knot_dname_t *)0xF00},
+ {.raw_data = (uint16_t *)"some data"},
+ {.raw_data = (uint16_t *)"other data"},
+ {.raw_data = (uint16_t *)"123456"},
+ {.raw_data = (uint16_t *)"654321"},
+ {.dname = &RDATA_DNAMES[0]},
+ {.dname = &RDATA_DNAMES[1]}
+};
+
+/* \note indices 0 to 3 should not be changed - used in (and only in)
+ * test_rdata_compare() - better than creating new struct just for this
+ */
+static knot_rdata_t test_rdata[TEST_RDATA_COUNT] = {
+ {&TEST_RDATA_ITEMS[3], 1, &test_rdata[1]},
+ {&TEST_RDATA_ITEMS[4], 1, &test_rdata[2]},
+ {&TEST_RDATA_ITEMS[5], 1, &test_rdata[3]},
+ {&TEST_RDATA_ITEMS[6], 1, &test_rdata[4]},
+};
+
+static knot_rdata_t TEST_RDATA = {
+ &TEST_RDATA_ITEMS[0],
+ 3,
+ &TEST_RDATA
+};
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_new().
+ *
+ * Creates new RDATA structure with no items and tests if there really are no
+ * items in it.
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_create()
+{
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (rdata == NULL) {
+ diag("RDATA structure not created!");
+ return 0;
+ }
+
+ if (knot_rdata_item(rdata, 0) != NULL) {
+ diag("Get item returned something else than NULL!");
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ knot_rdata_free(&rdata);
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_free().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_delete()
+{
+ // how to test this??
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void generate_rdata(uint8_t *data, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ data[i] = rand() % 256;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int fill_rdata(uint8_t *data, int max_size, uint16_t rrtype,
+ knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ uint8_t *pos = data;
+ int used = 0;
+ int wire_size = 0;
+
+ //note("Filling RRType %u", rrtype);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ uint item_count = desc->length;
+ knot_rdata_item_t *items =
+ (knot_rdata_item_t *)malloc(item_count
+ * sizeof(knot_rdata_item_t));
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ knot_dname_t *dname = NULL;
+ int binary = 0;
+ int stored_size = 0;
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[0].wire,
+ test_domains_ok[0].size, NULL);
+ assert(dname != NULL);
+ /* note("Created domain name: %s",
+ knot_dname_name(dname)); */
+ //note("Domain name ptr: %p", dname);
+ domain = 1;
+ size = knot_dname_size(dname);
+ //note("Size of created domain name: %u", size);
+ assert(size < KNOT_MAX_RDATA_ITEM_SIZE);
+ // store size of the domain name
+ *(pos++) = size;
+ // copy the domain name
+ memcpy(pos, knot_dname_name(dname), size);
+ pos += size;
+ break;
+ default:
+ binary = 1;
+ size = rand() % KNOT_MAX_RDATA_ITEM_SIZE;
+ }
+
+ if (binary) {
+ // Rewrite the actual 2 bytes in the data array
+ // with length.
+ // (this is a bit ugly, but does the work ;-)
+ knot_wire_write_u16(pos, size);
+ //*pos = size;
+ }
+
+ //note("Filling %u bytes", size);
+ used += size;
+ assert(used < max_size);
+
+ if (domain) {
+ items[i].dname = dname;
+ wire_size += knot_dname_size(dname);
+/* note("Saved domain name ptr on index %d: %p",
+ i, items[i].dname); */
+ } else {
+ free(dname);
+// note("Saved raw data ptr on index %d: %p",i, pos);
+ items[i].raw_data = (uint16_t *)pos;
+ pos += size;
+ wire_size += size;
+ if (binary && !stored_size) {
+ wire_size -= 2;
+ }
+ }
+ }
+
+ int res = knot_rdata_set_items(rdata, items, item_count);
+ if (res != 0) {
+ diag("knot_rdata_set_items() returned %d.", res);
+ free(items);
+ return -1;
+ } else {
+ free(items);
+ return wire_size;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if all RDATA items in the given RDATA structure are correct.
+ *
+ * \return Number of errors encountered. Error is either if some RDATA item
+ * is not set (i.e. NULL) or if it has other than the expected value.
+ */
+static int check_rdata(const uint8_t *data, int max_size, uint16_t rrtype,
+ const knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ int errors = 0;
+
+ const uint8_t *pos = data;
+ int used = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+ uint item_count = desc->length;
+ //note("check_rdata(), RRType: %u", rrtype);
+ //note(" item count: %u", item_count);
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ int binary = 0;
+
+ //note(" item: %d", i);
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ //note(" domain name");
+ domain = 1;
+ size = knot_dname_size(knot_rdata_item(
+ rdata, i)->dname);
+ break;
+ default:
+ size =
+ knot_wire_read_u16((uint8_t *)
+ (knot_rdata_item(
+ rdata, i)->raw_data));
+ }
+
+ assert(size > 0);
+ //note("Size: %u", size);
+ used += size;
+ assert(used < max_size);
+
+ //note(" item size: %u", size);
+
+ if (domain) {
+ /*note("Domain name ptr: %p",
+ knot_rdata_get_item(rdata, i)->dname);*/
+ // check dname size
+ if (*pos != size) {
+ diag("Domain name stored in %d-th"
+ "RDATA has wrong size: %d"
+ " (should be %d)", size, *pos);
+ ++errors;
+ } else if (strncmp((char *)knot_dname_name(
+ knot_rdata_item(rdata, i)->dname),
+ (char *)(pos + 1), *pos) != 0) {
+ diag("Domain name stored in %d-th"
+ "RDATA item is wrong: %s ("
+ "should be %.*s)", i,
+ knot_dname_name(knot_rdata_item(
+ rdata, i)->dname),
+ *pos, (char *)(pos + 1));
+ ++errors;
+ }
+
+ pos += *pos + 1;
+
+ continue;
+ }
+
+ if (binary &&
+ size !=
+ knot_wire_read_u16(
+ (uint8_t *)(knot_rdata_item(rdata, i)->raw_data))) {
+ diag("Size of stored binary data is wrong:"
+ " %u (should be %u)",
+ knot_rdata_item(rdata, i)->raw_data[0] + 1,
+ size);
+ ++errors;
+ }
+
+ if (strncmp((char *)
+ (&knot_rdata_item(rdata, i)->raw_data[0]),
+ (char *)pos, size) != 0) {
+/* knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype); */
+
+ diag("Data stored in %d-th RDATA item are wrong.", i);
+ ++errors;
+ }
+
+ pos += size;
+ }
+
+ return errors;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//static int convert_to_wire(const uint8_t *data, int max_size, uint16_t rrtype,
+// uint8_t *data_wire)
+//{
+// //note("Converting type %u", rrtype);
+
+// int wire_size = 0;
+// const uint8_t *pos = data;
+// uint8_t *pos_wire = data_wire;
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(rrtype);
+// uint item_count = desc->length;
+
+// for (int i = 0; i < item_count; ++i) {
+// const uint8_t *from = NULL;
+// uint to_copy = 0;
+
+// switch (desc->wireformat[i]) {
+// case KNOT_RDATA_WF_COMPRESSED_DNAME:
+// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+// case KNOT_RDATA_WF_LITERAL_DNAME:
+// // copy the domain name without its length
+// from = pos + 1;
+// to_copy = *pos;
+// pos += *pos + 1;
+///* note("Domain name in wire format (size %u): %s",
+// to_copy, (char *)from); */
+// break;
+// case KNOT_RDATA_WF_BYTE:
+// //note(" 1byte int");
+// from = pos;
+// to_copy = 1;
+// pos += 1;
+// break;
+// case KNOT_RDATA_WF_SHORT:
+// //note(" 2byte int");
+// from = pos;
+// to_copy = 2;
+// pos += 2;
+// break;
+// case KNOT_RDATA_WF_LONG:
+// //note(" 4byte int");
+// from = pos;
+// to_copy = 4;
+// pos += 4;
+// break;
+// case KNOT_RDATA_WF_A:
+// //note(" A");
+// from = pos;
+// to_copy = 4;
+// pos += 4;
+// break;
+// case KNOT_RDATA_WF_AAAA:
+// //note(" AAAA");
+// from = pos;
+// to_copy = 16;
+// pos += 16;
+// break;
+// case KNOT_RDATA_WF_BINARY:
+// case KNOT_RDATA_WF_APL: // saved as binary
+// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary
+// //note(" binary");
+// from = pos + 1;
+// to_copy = *pos;
+// pos += *pos + 1;
+// break;
+// case KNOT_RDATA_WF_TEXT:
+// case KNOT_RDATA_WF_BINARYWITHLENGTH:
+// //note(" text or binary with length (%u)", *pos);
+// to_copy = *pos + 1;
+// from = pos;
+// pos += *pos + 1;
+// break;
+// default:
+// assert(0);
+// }
+
+// //note("Copying %u bytes from %p", to_copy, from);
+
+// assert(from != NULL);
+// assert(to_copy != 0);
+
+// memcpy(pos_wire, from, to_copy);
+// pos_wire += to_copy;
+// wire_size += to_copy;
+
+// assert(wire_size < max_size);
+// }
+
+// return wire_size;
+//}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_set_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_set_item()
+{
+ knot_rdata_t *rdata = knot_rdata_new();
+ knot_rdata_item_t item;
+ item.raw_data = RDATA_ITEM_PTR;
+
+ int ret = knot_rdata_set_item(rdata, 0, item);
+ if (ret == 0) {
+ diag("knot_rdata_set_item() called on empty RDATA"
+ "returned %d instead of error (-1).", ret);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+// assert(data);
+ uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+ // set items through set_items() and then call set_item()
+ uint16_t rrtype = rand() % KNOT_RRTYPE_LAST + 1;
+ if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, rrtype, rdata) < 0) {
+ knot_rdata_free(&rdata);
+ diag("Error filling RDATA");
+ return 0;
+ }
+
+ uint8_t pos = rand() % knot_rrtype_descriptor_by_type(rrtype)->length;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ // if the rdata on this position is domain name, free it to avoid leaks
+ if (desc->wireformat[pos] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || desc->wireformat[pos] == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || desc->wireformat[pos] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ knot_dname_free(&(rdata->items[pos].dname));
+ }
+
+ ret = knot_rdata_set_item(rdata, pos, item);
+ if (ret != 0) {
+ diag("knot_rdata_set_item() called on filled"
+ " RDATA returned %d instead of 0.", ret);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ if (knot_rdata_item(rdata, pos)->raw_data != RDATA_ITEM_PTR) {
+ diag("RDATA item on position %d is wrong: %p (should be %p).",
+ pos, knot_rdata_item(rdata, pos)->raw_data,
+ RDATA_ITEM_PTR);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ for (int x = 0; x < desc->length; x++) {
+ if (x != pos && (
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_LITERAL_DNAME)) {
+ knot_dname_free(&(rdata->items[x].dname));
+ }
+ }
+
+// knot_rdata_free(&rdata);
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_set_items().
+ *
+ * Iterates over the test_rdatas array and for each testing RDATA it creates
+ * the RDATA structure, sets its items (\see set_rdata_all()) and checks if the
+ * items are set properly (\see check_rdata()).
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_set_items()
+{
+ knot_rdata_t *rdata = NULL;
+ knot_rdata_item_t *item = (knot_rdata_item_t *)0xDEADBEEF;
+ int errors = 0;
+
+ // check error return values
+ if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items() "
+ "when rdata == NULL is wrong");
+ return 0;
+ } else {
+ rdata = knot_rdata_new();
+ assert(rdata != NULL);
+
+ if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items()"
+ " when items == NULL is wrong");
+// knot_rdata_free(&rdata);
+ return 0;
+ } else if (knot_rdata_set_items(rdata, item, 0) !=
+ KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items()"
+ " when count == 0"
+ "is wrong");
+// knot_rdata_free(&rdata);
+ return 0;
+ }
+// knot_rdata_free(&rdata);
+ }
+
+ // generate some random data
+// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+ uint8_t data [KNOT_MAX_RDATA_WIRE_SIZE];
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+ for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+ rdata = knot_rdata_new();
+
+ if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata)
+ < 0) {
+ ++errors;
+ }
+ errors += check_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i,
+ rdata);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(i);
+
+ for (int x = 0; x < desc->length; x++) {
+ if (desc->wireformat[x] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_LITERAL_DNAME) {
+// printf("freeing %p\n", rdata->items[x].dname);
+ knot_dname_free(&(rdata->items[x].dname));
+ }
+ }
+
+// knot_rdata_free(&rdata);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_get_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_get_item()
+{
+ const knot_rdata_t *rdata = &TEST_RDATA;
+
+ if (knot_rdata_item(rdata, TEST_RDATA.count) != NULL) {
+ diag("knot_rdata_get_item() called with"
+ "invalid position did not return NULL");
+ return 0;
+ }
+
+ int errors = 0;
+ if ((knot_rdata_item(rdata, 0)->dname)
+ != TEST_RDATA.items[0].dname) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 0), TEST_RDATA.items[0]);
+ ++errors;
+ }
+ if ((knot_rdata_item(rdata, 1)->raw_data)
+ != TEST_RDATA.items[1].raw_data) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 1), TEST_RDATA.items[1]);
+ ++errors;
+ }
+ if ((knot_rdata_item(rdata, 2)->raw_data)
+ != TEST_RDATA.items[2].raw_data) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 2), TEST_RDATA.items[2]);
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_rdata_compare()
+{
+ int errors = 0;
+
+ uint8_t format_rawdata = KNOT_RDATA_WF_BINARY;
+
+ uint8_t format_dname = KNOT_RDATA_WF_LITERAL_DNAME;
+
+ /* 123456 \w 654321 -> result -1 */
+ if (knot_rdata_compare(&test_rdata[0],
+ &test_rdata[1],
+ &format_rawdata) != -1) {
+ diag("RDATA raw data comparison failed 0");
+ errors++;
+ }
+
+ /* 123456 \w 123456 -> result 0 */
+ if (knot_rdata_compare(&test_rdata[0],
+ &test_rdata[0],
+ &format_rawdata) != 0) {
+ diag("RDATA raw data comparison failed 1 ");
+ errors++;
+ }
+
+ /* 123456 \w 654321 -> result 1 */
+ if (knot_rdata_compare(&test_rdata[1],
+ &test_rdata[0],
+ &format_rawdata) != 1) {
+ diag("RDATA raw data comparison failed 2");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.foo.com. -> result -1 */
+ int ret = 0;
+ if ((ret = knot_rdata_compare(&test_rdata[2],
+ &test_rdata[3],
+ &format_dname)) >= 0) {
+ diag("RDATA dname comparison failed 3");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.example.com. -> result 0 */
+ if (knot_rdata_compare(&test_rdata[2],
+ &test_rdata[2],
+ &format_dname) != 0) {
+ diag("RDATA dname comparison failed 4");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.foo.com -> result 1 */
+ if (knot_rdata_compare(&test_rdata[3],
+ &test_rdata[2],
+ &format_dname) != 1) {
+ diag("RDATA dname comparison failed 5");
+ errors++;
+ }
+
+
+
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+//static int test_rdata_wire_size()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// int counted_size = knot_rdata_wire_size(rdata,
+// knot_rrtype_descriptor_by_type(i)->wireformat);
+// if (size != counted_size) {
+// diag("Wrong wire size computed (type %d):"
+// " %d (should be %d)",
+// i, counted_size, size);
+// ++errors;
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+/*----------------------------------------------------------------------------*/
+
+//static int test_rdata_to_wire()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// uint8_t data_wire[KNOT_MAX_RDATA_WIRE_SIZE];
+// uint8_t rdata_wire[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// int size_expected =
+// convert_to_wire(data, KNOT_MAX_RDATA_WIRE_SIZE, i,
+// data_wire);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// if (size != size_expected) {
+// diag("Wire format size (%u) not"
+// " as expected (%u)",
+// size, size_expected);
+// ++errors;
+// } else {
+// if (knot_rdata_to_wire(rdata,
+// knot_rrtype_descriptor_by_type(i)->
+// wireformat, rdata_wire,
+// KNOT_MAX_RDATA_WIRE_SIZE) != 0) {
+// diag("Error while converting RDATA"
+// " to wire format.");
+// ++errors;
+// } else {
+// if (strncmp((char *)data_wire,
+// (char *)rdata_wire, size)
+// != 0) {
+// diag("RDATA converted to wire"
+// "format does not match"
+// " the expected value");
+// ++errors;
+// }
+// }
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+static int test_rdata_free()
+{
+ return 0;
+// knot_rdata_t *tmp_rdata;
+
+// tmp_rdata = knot_rdata_new();
+
+// knot_rdata_free(&tmp_rdata);
+
+// return (tmp_rdata == NULL);
+}
+/* Can't test this with current implementation
+ * would be trying to free pointers on stack */
+static int test_rdata_deep_free()
+{
+ return 0;
+
+/* int errors = 0;
+
+ knot_rdata_t *tmp_rdata;
+
+ uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+
+ for (int i = 0; i <= KNOT_RRTYPE_LAST; i++) {
+ tmp_rdata = knot_rdata_new();
+
+ fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, tmp_rdata);
+
+ knot_rdata_deep_free(&tmp_rdata, i, 0);
+ errors += (tmp_rdata != NULL);
+ }
+
+ return (errors == 0); */
+}
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RDATA_TEST_COUNT = 8;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_count(int argc, char *argv[])
+{
+ return KNOT_RDATA_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+ res = test_rdata_create();
+ ok(res, "rdata: create empty");
+ res_final *= res;
+
+ skip(!res, 6);
+
+ todo();
+
+ ok(res = test_rdata_delete(), "rdata: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok(res = test_rdata_get_item(), "rdata: get item");
+ res_final *= res;
+
+ skip(!res, 4)
+
+ ok(res = test_rdata_set_items(), "rdata: set items all at once");
+ res_final *= res;
+
+ skip(!res, 3);
+
+ ok(res = test_rdata_set_item(), "rdata: set items one-by-one");
+ res_final *= res;
+
+ ok(res = test_rdata_compare(), "rdata: compare");
+ res_final *= res;
+
+// ok(res = test_rdata_wire_size(), "rdata: wire size");
+// res_final *= res;
+
+// skip(!res, 1);
+
+// ok(res = test_rdata_to_wire(), "rdata: to wire");
+// res_final *= res;
+
+// endskip; /* test_rdata_wire_size() failed */
+
+ endskip; /* test_rdata_set_items() failed */
+
+ endskip; /* test_rdata_get_item() failed */
+
+ endskip; /* test_rdata_create() failed */
+
+ todo();
+
+ ok(res = test_rdata_deep_free(), "rdata: deep free");
+ res_final *= res;
+
+ ok(res = test_rdata_free(), "rdata: free");
+ res_final *= res;
+
+ endtodo;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/rdata_tests.h b/src/tests/libknot/libknot/rdata_tests.h
new file mode 100644
index 0000000..1f43c91
--- /dev/null
+++ b/src/tests/libknot/libknot/rdata_tests.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/*!
+ * \file rdata_tests.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains unit tests for RDATA (knot_rdata_t) and RDATA item
+ * (knot_rdata_item_t) structures.
+ *
+ * Contains tests for:
+ * - creating empty RDATA structure with or without reserved space.
+ * - setting RDATA items one-by-one
+ * - setting RDATA items all at once
+ *
+ * As for now, the tests use several (TEST_RDATAS) RDATA structures, each
+ * with different number of RDATA items (given by test_rdatas). These are all
+ * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR,
+ * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer
+ * is set properly.
+ *
+ * \todo It may be better to test also some RDATAs with predefined contents,
+ * such as some numbers, some domain name, etc. For this purpose, we'd
+ * need RDATA descriptors (telling the types of each RDATA item within an
+ * RDATA).
+ *
+ * \todo It will be fine to test all possible output values of all functions,
+ * e.g. test whether knot_rdata_get_item() returns NULL when passed an
+ * illegal position, etc.
+ */
+#ifndef _KNOTD_RDATA_TESTS_H_
+#define _KNOTD_RDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rdata_tests_api;
+
+#endif /* _KNOTD_RDATA_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/response_tests.c b/src/tests/libknot/libknot/response_tests.c
new file mode 100644
index 0000000..93cf2df
--- /dev/null
+++ b/src/tests/libknot/libknot/response_tests.c
@@ -0,0 +1,450 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <inttypes.h>
+
+//#define RESP_TEST_DEBUG
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "tests/libknot/libknot/response_tests.h"
+#include "common/lists.h"
+#include "libknot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/response.h"
+#include "libknot/rdata.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/util/wire.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/edns.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int knot_response_tests_count(int argc, char *argv[]);
+static int knot_response_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api response_tests_api = {
+ "DNS library - response", //! Unit name
+ &knot_response_tests_count, //! Count scheduled tests
+ &knot_response_tests_run //! Run scheduled tests
+};
+
+static int test_response_init()
+{
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ if (knot_response_init(NULL) != KNOT_EBADARG) {
+ diag("Calling response_init with NULL packet did "
+ "not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "response: init NULL tests");
+ errors += lived != 1;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(response);
+ response->max_size = KNOT_WIRE_HEADER_SIZE - 1;
+ if (knot_response_init(response) != KNOT_ESPACE) {
+ diag("Calling response_init too small packet did "
+ "not return KNOT_ESPACE!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_response_init_query()
+{
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ if (knot_response_init_from_query(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL packet and "
+ "NULL query did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response,
+ KNOT_PACKET_PREALLOC_RESPONSE);
+ knot_response_init(response);
+ lived = 0;
+ if (knot_response_init_from_query(response, NULL) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL query "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (knot_response_init_from_query(NULL, query) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL response "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ }, "response: init from query NULL tests");
+ errors += lived != 1;
+
+ /* Cannot test the rest of return values, since there is now constant
+ * controlling value that could return KNOT_EDNAMEPTR */
+
+ return (errors == 0);
+}
+
+int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+
+//static int test_response_clear()
+//{
+// int errors = 0;
+// int lived = 0;
+// lives_ok({
+// knot_response_clear(NULL, 1);
+// lived = 1;
+// }, "response: clear NULL tests");
+// errors += lived != 1;
+
+// /*
+// * Create new response, convert to wire, then add something, clear
+// * the response, convert to wire again and compare wires.
+// */
+
+// knot_packet_t *response =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// knot_packet_set_max_size(response, KNOT_WIRE_HEADER_SIZE * 100);
+// assert(knot_response_init(response) == KNOT_EOK);
+
+// uint8_t *original_wire = NULL;
+// size_t original_size = 0;
+// assert(knot_packet_to_wire(response, &original_wire,
+// &original_size) ==
+// KNOT_EOK);
+// /* Do something in question section. */
+//// test_dname_t test_dname;
+//// test_dname.str = "ns8.nic.cz.";
+//// knot_dname_t *dname = dname_from_test_dname_str(&test_dname);
+//// assert(dname);
+
+// response->question.qtype = KNOT_RRTYPE_HINFO;
+// response->question.qclass = KNOT_CLASS_CH;
+
+// uint8_t *question_changed_wire = NULL;
+// size_t question_changed_size = 0;
+// assert(knot_packet_to_wire(response,
+// &question_changed_wire,
+// &question_changed_size) ==
+// KNOT_EOK);
+
+// knot_response_set_aa(response);
+// knot_response_set_tc(response);
+// knot_response_set_rcode(response, knot_quick_rand());
+
+// knot_response_clear(response, 0);
+// uint8_t *new_wire = NULL;
+// size_t new_size = 0;
+// assert(knot_packet_to_wire(response, &new_wire, &new_size) ==
+// KNOT_EOK);
+// if (question_changed_size != new_size) {
+// diag("Wrong wire size after calling response_clear! "
+// "got %d should be %d", new_size, question_changed_size);
+// errors++;
+// } else {
+// if (compare_wires_simple(question_changed_wire,
+// new_wire, new_size)) {
+// diag("Wrong wire after calling response_clear! ");
+// errors++;
+// }
+// }
+// free(new_wire);
+
+// new_wire = NULL;
+// new_size = 0;
+
+// /*!< \todo figure out this segfault! */
+
+//// knot_response_clear(response, 1);
+//// assert(knot_packet_to_wire(response, &new_wire, &new_size) ==
+//// KNOT_EOK);
+
+//// if (original_size != new_size) {
+//// diag("Wrong wire size after calling response_clear!");
+//// errors++;
+//// } else {
+//// if (compare_wires_simple(original_wire,
+//// new_wire, new_size)) {
+//// diag("Wrong wire after calling response_clear!");
+//// errors++;
+//// }
+//// }
+
+//// free(new_wire);
+//// free(original_wire);
+//// free(question_changed_wire);
+//// knot_packet_free(&response);
+
+// return (errors == 0);
+//}
+
+static int test_response_add_opt()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_opt_rr_t opt;
+ opt.payload = 512;
+ opt.ext_rcode = 0;
+ opt.version = EDNS_VERSION_0;
+ opt.flags = 0;
+ opt.options = NULL;
+ opt.option_count = 0;
+ opt.options_max = 0;
+ opt.size = 25; // does it matter?
+
+ lives_ok({
+ if (knot_response_add_opt(NULL, NULL, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL arguments "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ lived = 0;
+ if (knot_response_add_opt(response,
+ NULL, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL OPT RR "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_response_add_opt(NULL,
+ &opt, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL response "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_free(&response);
+ }, "response: add opt NULL tests");
+ errors += lived != 1;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response, KNOT_PACKET_PREALLOC_RESPONSE * 100);
+ assert(knot_response_init(response) == KNOT_EOK);;
+
+ if (knot_response_add_opt(response, &opt, 0) != KNOT_EOK) {
+ diag("Adding valid OPT RR to response "
+ "did not return KNOT_EOK");
+ errors++;
+ }
+
+ opt.payload = response->max_size + 1;
+ if (knot_response_add_opt(response, &opt, 1) != KNOT_EPAYLOAD) {
+ diag("If OPT RR payload is bigger than response max size "
+ "response_add_opt does not return KNOT_EPAYLOAD!");
+ errors++;
+ }
+
+ opt.payload = 0;
+ if (knot_response_add_opt(response, &opt, 1) != KNOT_EBADARG) {
+ diag("Calling response_add_opt with OPT RR payload set to 0 "
+ "did not return KNOT_EBADARG");
+ }
+
+ knot_packet_free(&response);
+ return (errors == 0);
+}
+
+static int test_response_add_generic(int (*func)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int))
+{
+ int errors = 0;
+ int lived = 0;
+
+ lives_ok({
+ if (func(NULL, NULL, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL "
+ "arguments did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ lived = 0;
+ if (func(response, NULL, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL rrset "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_dname_t *owner =
+ knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz."),
+ NULL);
+ assert(owner);
+ knot_rrset_t *rrset =
+ knot_rrset_new(owner, KNOT_RRTYPE_A,
+ KNOT_CLASS_IN, 3600);
+ assert(rrset);
+ lived = 0;
+ if (func(NULL, rrset, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL response "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ knot_packet_free(&response);
+ }, "response: rrset adding NULL tests");
+ errors += lived != 1;
+
+ /*!< \todo Test case when KNOT_ESPACE should be returned. */
+ /*!< \todo Compression and so on - should it be tested here? */
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+
+ knot_dname_t *owner =
+ knot_dname_new_from_str("ns12.nic.cz.",
+ strlen("ns12.nic.cz."),
+ NULL);
+ assert(owner);
+ knot_rrset_t *rrset =
+ knot_rrset_new(owner, KNOT_RRTYPE_NS,
+ KNOT_CLASS_IN, 3600);
+ assert(rrset);
+ if (func(response, rrset, 0, 0, 0) != KNOT_EOK) {
+ diag("Adding valid RRSet to response did not result to "
+ "KNOT_EOK");
+ errors++;
+ }
+
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ knot_packet_free(&response);
+
+ return (errors == 0);
+}
+
+static void test_response_add_rrset()
+{
+ ok(test_response_add_generic(knot_response_add_rrset_answer),
+ "response: add answer rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_authority),
+ "response: add answer authority");
+ ok(test_response_add_generic(knot_response_add_rrset_additional),
+ "response: add answer additional");
+}
+
+static int test_response_add_nsid()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+
+ uint8_t *nsid = (uint8_t *)"knotDNS";
+ uint16_t nsid_size = strlen((char *)nsid);
+ lives_ok({
+ if (knot_response_add_nsid(NULL,
+ NULL, 1) != KNOT_EBADARG) {
+ diag("Calling response add nsid with NULL arguments "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_response_add_nsid(NULL, nsid,
+ nsid_size) != KNOT_EBADARG) {
+ diag("Calling response add nsid with NULL response "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+// lived = 0;
+// if (knot_response_add_nsid(response, nsid,
+// 0) != KNOT_EBADARG) {
+// diag("Calling response add nsid with zero size "
+// "did not return KNOT_EBADARG");
+// errors++;
+// }
+// lived = 1;
+ }, "response: add nsid NULL tests");
+ errors += lived != 1;
+
+ if (knot_response_add_nsid(response, nsid,
+ nsid_size) != KNOT_EOK) {
+ diag("Adding valid nsid to response did not return KNOT_EOK");
+ errors++;
+ }
+
+ knot_packet_free(&response);
+ return (errors == 0);
+}
+
+static const int KNOT_response_TEST_COUNT = 14;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_response_tests_count(int argc, char *argv[])
+{
+ return KNOT_response_TEST_COUNT;
+}
+
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_response_tests_run(int argc, char *argv[])
+{
+ ok(test_response_init(), "response: init");
+ ok(test_response_init_query(), "response: init from query");
+// ok(test_response_clear(), "response: clear");
+ ok(test_response_add_opt(), "response: add opt");
+ test_response_add_rrset();
+ ok(test_response_add_nsid(), "response: add nsid");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/response_tests.h b/src/tests/libknot/libknot/response_tests.h
new file mode 100644
index 0000000..c9a117b
--- /dev/null
+++ b/src/tests/libknot/libknot/response_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_response_TESTS_H_
+#define _KNOTD_response_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api response_tests_api;
+
+#endif /* _KNOTD_response_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/rrset_tests.c b/src/tests/libknot/libknot/rrset_tests.c
new file mode 100644
index 0000000..fa75195
--- /dev/null
+++ b/src/tests/libknot/libknot/rrset_tests.c
@@ -0,0 +1,888 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/libknot/rrset_tests.h"
+#include "libknot/common.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/util/utils.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/debug.h"
+
+static int knot_rrset_tests_count(int argc, char *argv[]);
+static int knot_rrset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rrset_tests_api = {
+ "DNS library - rrset", //! Unit name
+ &knot_rrset_tests_count, //! Count scheduled tests
+ &knot_rrset_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF;
+
+enum { TEST_RRSETS = 6 , TEST_RRSIGS = 6};
+
+//void *RRSIG_ADDRESS = (void *)0xDEADBEEF;
+//void *RRSIG_FIRST = RRSIG_ADDRESS + 10;
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+struct test_rrset {
+ char *owner;
+ uint16_t type;
+ uint16_t rclass;
+ uint32_t ttl;
+ knot_rdata_t *rdata;
+ const knot_rrset_t *rrsigs;
+};
+
+/* this has to changed */
+static const char *signature_strings[TEST_RRSIGS] =
+{"signature 1", "signature 2", "signature 3",
+ "signature 4", "signature 5", "signature 6"};
+
+enum {
+ RR_DNAMES_COUNT = 3,
+ RR_ITEMS_COUNT = 3,
+ RR_RDATA_COUNT = 4,
+};
+
+enum { TEST_DOMAINS_OK = 8 };
+
+static knot_dname_t RR_DNAMES[RR_DNAMES_COUNT] =
+ { {{}, (uint8_t *)"\7example\3com", 13, NULL}, //0's at the end are added
+ {{}, (uint8_t *)"\3ns1\7example\3com", 17, NULL},
+ {{}, (uint8_t *)"\3ns2\7example\3com", 17, NULL} };
+
+/* 192.168.1.1 */
+static uint8_t address[4] = {0xc0, 0xa8, 0x01, 0x01};
+
+static knot_rdata_item_t RR_ITEMS[RR_ITEMS_COUNT] =
+ { {.dname = &RR_DNAMES[1]},
+ {.dname = &RR_DNAMES[2]},
+ {.raw_data = (uint16_t *)address} };
+
+/*! \warning Do not change the order. */
+/* TODO this does not work as expected */
+static knot_rdata_t RR_RDATA[RR_RDATA_COUNT] =
+ { {&RR_ITEMS[0], 1, &RR_RDATA[0]}, /* first ns */
+ {&RR_ITEMS[1], 1, &RR_RDATA[1]}, /* second ns */
+ {&RR_ITEMS[0], 1, &RR_RDATA[3]}, /* both in cyclic list */
+ {&RR_ITEMS[1], 1, &RR_RDATA[2]} };
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+static struct test_rrset test_rrsets[TEST_RRSETS] = {
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example2.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example3.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL }
+};
+
+static const struct test_rrset test_rrsigs[TEST_RRSIGS] = {
+ { "example.com.", 46, 1, 3600, NULL },
+ { "example2.com.", 46, 1, 3600, NULL },
+ { "example3.com.", 46, 1, 3600, NULL },
+ { "example4.com.", 46, 1, 3600, NULL },
+ { "example5.com.", 46, 1, 3600, NULL },
+ { "example6.com.", 46, 1, 3600, NULL }
+};
+
+static void generate_rdata(uint8_t *data, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ data[i] = rand() % 256;
+ }
+}
+
+static int fill_rdata_r(uint8_t *data, int max_size, uint16_t rrtype,
+ knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ uint8_t *pos = data;
+ int used = 0;
+ int wire_size = 0;
+
+// note("Filling RRType %u", rrtype);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ uint item_count = desc->length;
+ knot_rdata_item_t *items =
+ (knot_rdata_item_t *)malloc(item_count
+ * sizeof(knot_rdata_item_t));
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ knot_dname_t *dname = NULL;
+ int binary = 0;
+ int stored_size = 0;
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[0].wire,
+ test_domains_ok[0].size, NULL);
+ assert(dname != NULL);
+// note("Created domain name: %s",
+// knot_dname_name(dname));
+// note("Domain name ptr: %p", dname);
+ domain = 1;
+ size = knot_dname_size(dname);
+// note("Size of created domain name: %u", size);
+ assert(size < KNOT_MAX_RDATA_ITEM_SIZE);
+ // store size of the domain name
+ *(pos++) = size;
+ // copy the domain name
+ memcpy(pos, knot_dname_name(dname), size);
+ pos += size;
+ break;
+ default:
+ binary = 1;
+ size = rand() % KNOT_MAX_RDATA_ITEM_SIZE;
+ }
+
+ if (binary) {
+ // Rewrite the actual 2 bytes in the data array
+ // with length.
+ // (this is a bit ugly, but does the work ;-)
+ knot_wire_write_u16(pos, size);
+ //*pos = size;
+ }
+
+ //note("Filling %u bytes", size);
+ used += size;
+ assert(used < max_size);
+
+ if (domain) {
+ items[i].dname = dname;
+ wire_size += knot_dname_size(dname);
+/* note("Saved domain name ptr on index %d: %p",
+ i, items[i].dname); */
+ } else {
+ free(dname);
+// note("Saved raw data ptr on index %d: %p",i, pos);
+ items[i].raw_data = (uint16_t *)pos;
+ pos += size;
+ wire_size += size;
+ if (binary && !stored_size) {
+ wire_size -= 2;
+ }
+ }
+ }
+
+ int res = knot_rdata_set_items(rdata, items, item_count);
+ if (res != 0) {
+ diag("knot_rdata_set_items() returned %d.", res);
+ free(items);
+ return -1;
+ } else {
+ free(items);
+ return wire_size;
+ }
+}
+
+/* fills test_rrsets with random rdata when empty */
+static void create_rdata()
+{
+ knot_rdata_t *r;
+
+ uint8_t *data =
+ malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+
+ assert(data);
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (test_rrsets[i].rdata == NULL) {
+ r = knot_rdata_new();
+
+ /* from rdata tests */
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+ if (fill_rdata_r(data, KNOT_MAX_RDATA_WIRE_SIZE,
+ test_rrsets[i].type, r) <= 0) {
+ diag("Error creating rdata!");
+
+ }
+
+ test_rrsets[i].rdata = r;
+ }
+ }
+
+ free(data);
+}
+
+static int check_rrset(const knot_rrset_t *rrset, int i,
+ int check_rdata, int check_items,
+ int check_rrsigs)
+{
+ /* following implementation should be self-explanatory */
+ int errors = 0;
+
+ if (rrset == NULL) {
+ diag("RRSet not created!");
+ return 1;
+ }
+
+ char *owner = knot_dname_to_str(rrset->owner);
+ if (strcmp(owner, test_rrsets[i].owner) != 0) {
+ diag("OWNER domain name wrong: '%s' (should be '%s')",
+ owner, test_rrsets[i].owner);
+ ++errors;
+ }
+ free(owner);
+
+ if (rrset->type != test_rrsets[i].type) {
+ diag("TYPE wrong: %u (should be: %u)", rrset->type,
+ test_rrsets[i].type);
+ ++errors;
+ }
+
+ if (rrset->rclass != test_rrsets[i].rclass) {
+ diag("CLASS wrong: %u (should be: %u)", rrset->rclass,
+ test_rrsets[i].rclass);
+ ++errors;
+ }
+
+ if (rrset->ttl != test_rrsets[i].ttl) {
+ diag("TTL wrong: %u (should be: %u)", rrset->ttl,
+ test_rrsets[i].ttl);
+ ++errors;
+ }
+
+ if (check_rdata) {
+ /* TODO use rdata_compare */
+ knot_rdata_t *rdata = rrset->rdata;
+
+ if (rdata == NULL) {
+ diag("There are no RDATAs in the RRSet");
+ ++errors;
+ }
+
+ if (rdata != NULL) {
+ while (rdata->next != NULL &&
+ rdata->next != rrset->rdata) {
+ rdata = rdata->next;
+ }
+ if (rdata->next == NULL) {
+ diag("The list of RDATAs is not cyclic!");
+ ++errors;
+ } else {
+ assert(rdata->next == rrset->rdata);
+ }
+ }
+ }
+
+ if (check_items) {
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+ if (knot_rdata_compare(rrset->rdata,
+ test_rrsets[i].rdata,
+ desc->wireformat) != 0) {
+ diag("Rdata items do not match.");
+ errors++;
+ }
+ }
+
+ /* TODO this deserves a major improvement!!! */
+
+ /*
+ * Will work only with null terminated strings,
+ * consider changing to more versatile implementation
+ */
+
+ /* How about, once it's tested, using rdata_compare */
+
+ if (check_rrsigs) {
+
+ const knot_rrset_t *rrsigs;
+
+ rrsigs = knot_rrset_rrsigs(rrset);
+ if (strcmp((const char *)rrsigs->rdata->items[0].raw_data,
+ signature_strings[i])) {
+ diag("Signatures are not equal"
+ "to those set when creating."
+ "Comparing %s with %s",
+ rrsigs->rdata->items[0].raw_data,
+ signature_strings[i]);
+ errors++;
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_create()
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_RRSETS; ++i) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+ knot_rrset_t *rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ errors += check_rrset(rrset, i, 0, 0, 0);
+
+ knot_rrset_free(&rrset);
+ knot_dname_free(&owner);
+ }
+
+ //diag("Total errors: %d", errors);
+
+ return (errors == 0);
+}
+
+/* Not implemented - no way how to test unfreed memory from here (yet) */
+static int test_rrset_delete()
+{
+ return 0;
+}
+
+static int test_rrset_add_rdata()
+{
+ /* rdata add */
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ knot_rrset_t *rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrset, test_rrsets[i].rdata);
+
+ errors += check_rrset(rrset, i, 1, 0, 0);
+
+ knot_rrset_free(&rrset);
+ knot_dname_free(&owner);
+ }
+
+ /* test whether adding works properly = keeps order of added elements */
+
+ /*
+ * Beware, this is dependent on the internal structure of rrset and
+ * may change.
+ */
+
+ knot_rrset_t *rrset = knot_rrset_new(NULL, 0, 0, 0);
+
+ knot_rdata_t *r;
+
+ knot_rdata_item_t *item;
+
+ static const char *test_strings[10] =
+ { "-2", "9", "2", "10", "1", "5", "8", "4", "6", "7" };
+
+ /* add items */
+
+ for (int i = 0; i < 10; i++) {
+ r = knot_rdata_new();
+ item = malloc(sizeof(knot_rdata_item_t));
+ item->raw_data = (uint16_t *)test_strings[i];
+ //following statement creates a copy
+ knot_rdata_set_items(r, item, 1);
+ knot_rrset_add_rdata(rrset, r);
+ free(item);
+ }
+
+ knot_rdata_t *tmp = rrset->rdata;
+
+ /* check if order has been kept */
+
+ int i = 0;
+ while (tmp->next != rrset->rdata && !errors) {
+ if (strcmp(test_strings[i], (char *)tmp->items[0].raw_data)) {
+ diag("Adding RDATA error!, is %s should be %s",
+ tmp->items[0].raw_data, test_strings[i]);
+ errors++;
+ }
+ i++;
+ tmp = tmp->next;
+
+ }
+
+ tmp = rrset->rdata;
+
+ knot_rdata_t *next;
+
+ while (tmp->next != rrset->rdata) {
+ next = tmp->next;
+ knot_rdata_free(&tmp);
+ tmp = next;
+ }
+
+ knot_rdata_free(&tmp);
+
+ knot_rrset_free(&rrset);
+
+ return (errors == 0);
+}
+
+static int test_rrset_rrsigs()
+{
+ int errors = 0;
+
+ knot_rdata_item_t *item;
+
+ knot_rdata_t *tmp;
+
+ knot_dname_t *owner;
+
+ knot_rrset_t *rrset;
+
+ /* Gets rrsigs and checks, if signatures are the same */
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ owner = knot_dname_new_from_str(test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner), NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ rrset = knot_rrset_new(owner, test_rrsets[i].type,
+ test_rrsets[i].rclass, test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrset, test_rrsets[i].rdata);
+
+ //owners are the same
+
+ assert(TEST_RRSETS == TEST_RRSIGS);
+
+ knot_rrset_t *rrsig = knot_rrset_new(owner,
+ test_rrsigs[i].type,
+ test_rrsigs[i].rclass,
+ test_rrsigs[i].ttl);
+
+ tmp = knot_rdata_new();
+ item = malloc(sizeof(knot_rdata_item_t));
+ /* signature is just a string,
+ * should be sufficient for testing */
+ item->raw_data = (uint16_t *)signature_strings[i];
+ knot_rdata_set_items(tmp, item, 1);
+ knot_rrset_add_rdata(rrsig, tmp);
+
+ if (knot_rrset_set_rrsigs(rrset, rrsig)
+ != 0) {
+ diag("Could not set rrsig");
+ errors++;
+ }
+ errors += check_rrset(rrset, i, 0, 0, 1);
+ knot_rrset_free(&rrset);
+ free(item);
+ knot_rdata_free(&tmp);
+ knot_rrset_free(&rrsig);
+ }
+ return (errors == 0);
+}
+
+static int test_rrset_merge()
+{
+ knot_rrset_t *merger1;
+ knot_rrset_t *merger2;
+ knot_dname_t *owner1;
+ knot_dname_t *owner2;
+
+ int r;
+
+ owner1 = knot_dname_new_from_str(test_rrsets[3].owner,
+ strlen(test_rrsets[3].owner), NULL);
+ merger1 = knot_rrset_new(owner1, test_rrsets[3].type,
+ test_rrsets[3].rclass,
+ test_rrsets[3].ttl);
+
+ knot_rrset_add_rdata(merger1, test_rrsets[3].rdata);
+
+ owner2 = knot_dname_new_from_str(test_rrsets[4].owner,
+ strlen(test_rrsets[4].owner), NULL);
+ merger2 = knot_rrset_new(owner2, test_rrsets[4].type,
+ test_rrsets[4].rclass,
+ test_rrsets[4].ttl);
+
+ knot_rrset_add_rdata(merger2, test_rrsets[4].rdata);
+
+// knot_rrset_dump(merger1, 1);
+
+ int ret = 0;
+ if ((ret = knot_rrset_merge((void **)&merger1,
+ (void **)&merger2)) != 0) {
+ diag("Could not merge rrsets. (reason %d)", ret);
+ return 0;
+ }
+
+// knot_rrset_dump(merger1, 1);
+
+ r = check_rrset(merger1, 5, 1, 1, 0);
+
+ knot_rrset_free(&merger1);
+ knot_rrset_free(&merger2);
+
+ if (r) {
+ diag("Merged rdata are wrongly set.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_rrset_owner(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ char *dname_str =
+ knot_dname_to_str(knot_rrset_owner(rrsets[i]));
+ if (strcmp(dname_str, test_rrsets[i].owner)) {
+ diag("Got wrong value for owner from rrset.");
+ errors++;
+ }
+ free(dname_str);
+ }
+ return errors;
+}
+
+static int test_rrset_type(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_type(rrsets[i]) != test_rrsets[i].type) {
+ errors++;
+ diag("Got wrong value for type from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_class(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_class(rrsets[i]) != test_rrsets[i].rclass) {
+ errors++;
+ diag("Got wrong value for class from rrset.");
+ }
+ }
+
+ return errors;
+}
+
+static int test_rrset_ttl(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_ttl(rrsets[i]) != test_rrsets[i].ttl) {
+ errors++;
+ diag("Got wrong value for ttl from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_ret_rdata(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+
+ desc = knot_rrtype_descriptor_by_type(rrsets[i]->type);
+ assert(desc);
+
+// knot_rdata_dump(test_rrsets[i].rdata, 1);
+ // knot_rdata_dump(rrsets[i]->rdata, 1);
+
+ if (knot_rdata_compare(knot_rrset_rdata(rrsets[i]),
+ test_rrsets[i].rdata,
+ desc->wireformat)) {
+ errors++;
+ diag("Got wrong value for rdata from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_get_rdata(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ desc = knot_rrtype_descriptor_by_type(rrsets[i]->type);
+ assert(desc);
+ if (knot_rdata_compare(knot_rrset_get_rdata(rrsets[i]),
+ test_rrsets[i].rdata,
+ desc->wireformat)) {
+ errors++;
+ diag("Got wrong value for rdata from rrset. (Get)");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_ret_rrsigs(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ /* TODO should I test the insides of structure as well? */
+ if (knot_rrset_rrsigs(rrsets[i]) != test_rrsets[i].rrsigs) {
+ errors++;
+ diag("Got wrong value for rrsigs from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_getters(uint type)
+{
+ int errors = 0;
+
+ knot_rrset_t *rrsets[TEST_RRSETS];
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+ rrsets[i] = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrsets[i], test_rrsets[i].rdata);
+ }
+
+ switch (type) {
+ case 0: {
+ errors += test_rrset_owner(rrsets);
+ break;
+ }
+ case 1: {
+ errors += test_rrset_type(rrsets);
+ break;
+ }
+ case 2: {
+ errors += test_rrset_class(rrsets);
+ break;
+ }
+ case 3: {
+ errors += test_rrset_ttl(rrsets);
+ break;
+ }
+ case 4: {
+ errors += test_rrset_ret_rdata(rrsets);
+ break;
+ }
+ case 5: {
+ errors += test_rrset_get_rdata(rrsets);
+ break;
+ }
+ case 6: {
+ errors += test_rrset_ret_rrsigs(rrsets);
+ break;
+ }
+ } /* switch */
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_free(&rrsets[i]->owner);
+ knot_rrset_free(&rrsets[i]);
+ }
+
+
+ return (errors == 0);
+}
+
+static int test_rrset_deep_free()
+{
+ /*!< \warning Cannot be run when some rdata are on stack! */
+ int errors = 0;
+
+ knot_rrset_t *tmp_rrset;
+ knot_dname_t *owner;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ tmp_rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(tmp_rrset, test_rrsets[i].rdata);
+
+ knot_rrset_deep_free(&tmp_rrset, 1, 1, 0);
+
+ errors += (tmp_rrset != NULL);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RRSET_TEST_COUNT = 13;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_count(int argc, char *argv[])
+{
+ return KNOT_RRSET_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+/* for (int i = 0; i < 4; i++) {
+ knot_rdata_dump(&RR_RDATA[i], 2, 1);
+ printf("%p %p\n", &RR_RDATA[i], (&RR_RDATA)[i]->next);
+ } */
+
+ create_rdata();
+
+ res = test_rrset_create();
+ ok(res, "rrset: create");
+ res_final *= res;
+
+ skip(!res, 11);
+
+ todo();
+
+ ok(res = test_rrset_delete(), "rrset: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok(res = test_rrset_getters(0), "rrset: owner");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(1), "rrset: type");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(2), "rrset: class");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(3), "rrset: ttl");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(4), "rrset: rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(5), "rrset: get rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(6), "rrset: rrsigs");
+ res_final *= res;
+
+ ok(res = test_rrset_add_rdata(), "rrset: add_rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_rrsigs(), "rrset: rrsigs manipulation");
+ res_final *= res;
+
+ ok(res = test_rrset_merge(), "rrset: rdata merging");
+ res_final *= res;
+
+ ok(res = test_rrset_deep_free(), "rrset: deep free");
+ res_final *= res;
+
+ endskip; /* !res_create */
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/rrset_tests.h b/src/tests/libknot/libknot/rrset_tests.h
new file mode 100644
index 0000000..b0787d6
--- /dev/null
+++ b/src/tests/libknot/libknot/rrset_tests.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/*!
+ * \file rrset_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for RRSet (knot_rrset_t) and its API.
+ *
+ * Contains tests for:
+ * -
+ */
+#ifndef _KNOTD_RRSET_TESTS_H_
+#define _KNOTD_RRSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rrset_tests_api;
+
+#endif /* _KNOTD_RRSET_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zone_tests.c b/src/tests/libknot/libknot/zone_tests.c
new file mode 100644
index 0000000..2fdd61a
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tests.c
@@ -0,0 +1,853 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/libknot/zone_tests.h"
+#include "libknot/common.h"
+#include "libknot/zone/dname-table.h"
+#include "libknot/zone/zone.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/node.h"
+
+static int knot_zone_tests_count(int argc, char *argv[]);
+static int knot_zone_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tests_api = {
+ "DNS library - zone", //! Unit name
+ &knot_zone_tests_count, //! Count scheduled tests
+ &knot_zone_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+enum { TEST_NODES_GOOD = 7, TEST_NODES_BAD = 1, TRAVERSAL_TYPES = 3};
+
+struct zone_test_node {
+ knot_dname_t owner;
+ knot_node_t *parent;
+};
+
+static struct zone_test_node test_apex =
+{{{}, (uint8_t *)"\3com\0", 5, (uint8_t *)"\x0", 1}, (knot_node_t *)NULL};
+
+static struct zone_test_node test_nodes_bad[TEST_NODES_BAD] = {
+ {{{},(uint8_t *)"\5other\6domain\0", 14, (uint8_t *)"\x0\x6", 2},
+ (knot_node_t *)NULL}
+};
+
+static struct zone_test_node test_nodes_good[TEST_NODES_GOOD] = {
+ {{{}, (uint8_t *)"\7example\3com\0", 13, (uint8_t *)"\x0\x8", 2},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3www\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\7another\6domain\3com\0", 20, (uint8_t *)"\x0\x8\xF", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\5mail1\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\5mail2\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3smb\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\4smtp\7example\3com\0", 18, (uint8_t *)"\x0\x5\xD", 3},
+ (knot_node_t *)NULL},
+};
+
+static int test_zone_check_node(const knot_node_t *node,
+ const struct zone_test_node *test_node,
+ int test_parent)
+{
+ return (node->owner == &test_node->owner) &&
+ ((test_parent) ? node->parent == test_node->parent : 1);
+}
+
+static int test_zone_create(knot_zone_contents_t **zone)
+{
+// knot_dname_t *dname = knot_dname_new_from_wire(
+// test_apex.owner.name, test_apex.owner.size, NULL);
+// assert(dname);
+
+ knot_node_t *node = knot_node_new(&test_apex.owner,
+ test_apex.parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create zone apex.");
+ return 0;
+ }
+
+ *zone = knot_zone_contents_new(node, 0, 0, NULL);
+
+ if ((*zone) == NULL) {
+ diag("zone: Failed to create zone.");
+ knot_node_free(&node, 1, 0);
+ return 0;
+ }
+
+ if ((*zone)->apex != node) {
+ diag("zone: Zone apex not set right.");
+ knot_node_free(&node, 1, 0);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3)
+{
+ /*
+ * NSEC3 nodes are de facto identical to normal nodes, so there is no
+ * need for separate tests. The only difference is where are they stored
+ * in the zone structure.
+ */
+
+ int errors = 0;
+ int res = 0;
+
+ //note("Good nodes");
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ knot_node_t *node = knot_node_new(&test_nodes_good[i].owner,
+ test_nodes_good[i].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, node, 0, 0, 0))) != 0) {
+ diag("zone: Failed to insert node into zone (returned"
+ " %d).", res);
+ knot_node_free(&node, 0, 0);
+ ++errors;
+ }
+ /* TODO check values in the node as well */
+ }
+
+ //note("Bad nodes");
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner,
+ test_nodes_bad[i].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, node, 0, 0, 0))) !=
+ KNOT_EBADZONE) {
+ diag("zone: Inserting wrong node did not result in"
+ "proper return value (%d instead of %d).", res,
+ KNOT_EBADZONE);
+ ++errors;
+ }
+ knot_node_free(&node, 0, 0);
+ }
+
+ //note("NULL zone");
+
+ note("Inserting into NULL zone...\n");
+
+ knot_node_t *node = knot_node_new(&test_nodes_good[0].owner,
+ test_nodes_good[0].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(NULL, node, 0, 0, 0)
+ : knot_zone_contents_add_node(NULL, node, 0, 0, 0))) != KNOT_EBADARG) {
+ diag("zone: Inserting node to NULL zone did not result in"
+ "proper return value (%d instead of %d)", res,
+ KNOT_EBADARG);
+ ++errors;
+ }
+
+ knot_node_free(&node, 0, 0);
+
+ //note("NULL node");
+ note("Inserting NULL node...\n");
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, NULL, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, NULL, 0, 0, 0))) != KNOT_EBADARG) {
+ diag("zone: Inserting NULL node to zone did not result in"
+ "proper return value (%d instead of %d)", res,
+ KNOT_EBADARG);
+ ++errors;
+ }
+
+ if (!nsec3) {
+ //note("Inserting Apex again...\n");
+
+ node = knot_node_new(&test_apex.owner, test_apex.parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ //note("Apex again");
+
+ if ((res = knot_zone_contents_add_node(zone, node, 0, 0, 0)) !=
+ KNOT_EBADZONE) {
+ diag("zone: Inserting zone apex again did not result in"
+ "proper return value (%d instead of -2)",
+ KNOT_EBADZONE);
+ ++errors;
+ }
+
+ knot_node_free(&node, 0, 0);
+ }
+
+ // check if all nodes are inserted
+ //int nodes = 0;
+ if (!nsec3
+ && !test_zone_check_node(knot_zone_contents_apex(zone), &test_apex, !nsec3)) {
+ diag("zone: Apex of zone not right.");
+// diag("Apex owner: %s (%p), apex parent: %p\n",
+// knot_dname_to_str(knot_zone_apex(zone)->owner),
+// knot_zone_apex(zone)->owner,
+// knot_zone_apex(zone)->parent);
+// diag("Should be: owner: %s (%p), parent: %p\n",
+// knot_dname_to_str(&test_apex.owner),
+// &test_apex.owner,
+// test_apex.parent);
+ ++errors;
+ }
+ //++nodes;
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ const knot_node_t *n = ((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_good[i].owner) :
+ knot_zone_contents_find_node(zone, &test_nodes_good[i].owner));
+ if (n == NULL) {
+ diag("zone: Missing node with owner %s",
+ test_nodes_good[i].owner.name);
+ ++errors;
+ continue;
+ }
+
+ if (!test_zone_check_node(n, &test_nodes_good[i], !nsec3)) {
+ diag("zone: Node does not match: owner: %s (should be "
+ "%s), parent: %p (should be %p)",
+ n->owner->name, test_nodes_good[i].owner.name,
+ n->parent, test_nodes_good[i].parent);
+ ++errors;
+ }
+ //++nodes;
+ }
+
+ //note("zone: %d nodes in the zone (including apex)", nodes);
+
+ return (errors == 0);
+}
+
+static int test_zone_get_node(knot_zone_contents_t *zone, int nsec3)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(
+ zone, &test_nodes_good[i].owner)
+ : knot_zone_contents_get_node(zone, &test_nodes_good[i].owner))
+ == NULL) {
+ diag("zone: Node (%s) not found in zone.",
+ (char *)test_nodes_good[i].owner.name);
+ ++errors;
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(
+ zone, &test_nodes_bad[i].owner)
+ : knot_zone_contents_get_node(zone, &test_nodes_bad[i].owner))
+ != NULL) {
+ diag("zone: Node (%s) found in zone even if it should"
+ "not be there.",
+ (char *)test_nodes_bad[i].owner.name);
+ ++errors;
+ }
+ }
+
+ if (((nsec3)
+ ? knot_zone_contents_get_nsec3_node(NULL, &test_nodes_good[0].owner)
+ : knot_zone_contents_get_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+ diag("zone: Getting node from NULL zone did not result in"
+ "proper return value (NULL)");
+ ++errors;
+ }
+
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(zone, NULL)
+ : knot_zone_contents_get_node(zone, NULL)) != NULL) {
+ diag("zone: Getting node with NULL owner from zone did not "
+ "result in proper return value (NULL)");
+ ++errors;
+ }
+
+ if (!nsec3 && knot_zone_contents_get_node(zone, &test_apex.owner) == NULL) {
+ diag("zone: Getting zone apex from the zone failed");
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+static int test_zone_find_node(knot_zone_contents_t *zone, int nsec3)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_good[i].owner)
+ : knot_zone_contents_find_node(zone, &test_nodes_good[i].owner))
+ == NULL) {
+ diag("zone: Node (%s) not found in zone.",
+ (char *)test_nodes_good[i].owner.name);
+ ++errors;
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_bad[i].owner)
+ : knot_zone_contents_find_node(zone, &test_nodes_bad[i].owner))
+ != NULL) {
+ diag("zone: Node (%s) found in zone even if it should"
+ "not be there.",
+ (char *)test_nodes_bad[i].owner.name);
+ ++errors;
+ }
+ }
+
+ if (((nsec3)
+ ? knot_zone_contents_find_nsec3_node(NULL, &test_nodes_good[0].owner)
+ : knot_zone_contents_find_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+ diag("zone: Finding node from NULL zone did not result in"
+ "proper return value (NULL)");
+ ++errors;
+ }
+
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(zone, NULL)
+ : knot_zone_contents_find_node(zone, NULL)) != NULL) {
+ diag("zone: Finding node with NULL owner from zone did not "
+ "result in proper return value (NULL)");
+ ++errors;
+ }
+
+ if (!nsec3 && knot_zone_contents_find_node(zone, &test_apex.owner) == NULL) {
+ diag("zone: Finding zone apex from the zone failed");
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+//static void test_zone_destroy_node_from_tree(knot_node_t *node,
+// void *data)
+//{
+// UNUSED(data);
+// knot_node_free(&node, 0);
+//}
+
+/* explained below */
+static size_t node_index = 0;
+
+/*! \brief
+ * This function will overwrite parent field in node structure -
+ * we don't (and can't, with current structures) use it in these tests anyway.
+ * Since zone structure itself has no count field, only option known to me
+ * is (sadly) to use a global variable.
+ */
+static void tmp_apply_function(knot_node_t *node, void *data)
+{
+ node->parent = (knot_node_t *)node_index;
+ node_index++;
+}
+
+/* \note Since I am unaware of a way how to get a return value from traversal
+ * functions, I will use (hopefully for the last time here) global variable
+ */
+
+static int compare_ok = 1;
+
+static void tmp_compare_function(knot_node_t *node, void *data)
+{
+ /* node_index will start set to zero */
+ if (node->parent != (knot_node_t *)node_index) {
+ compare_ok = 0;
+ return;
+ } else if (!compare_ok) {
+ diag("Traversal function has partially set values right");
+ }
+ node->parent = NULL;
+ node_index++;
+}
+
+static int test_zone_tree_apply(knot_zone_contents_t *zone,
+ int type, int nsec3)
+{
+
+ assert(node_index == 0);
+ assert(compare_ok == 1);
+
+ int (*traversal_func)(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node,
+ void *data),
+ void *data);
+
+ switch (type) {
+ case 0: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_postorder;
+ diag("Testing postorder traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_postorder;
+ diag("Testing postorder traversal - NSEC3");
+ }
+ break;
+ }
+ case 1: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_inorder;
+ diag("Testing inorder traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_inorder;
+ diag("Testing inorder traversal - NSEC3");
+ }
+ break;
+ }
+ case 2: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_inorder_reverse;
+ diag("Testing inorder reverse traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_inorder_reverse;
+ diag("Testing inorder reverse "
+ "traversal - NSEC3");
+ }
+ break;
+ }
+ default: {
+ diag("Unknown traversal function type");
+ return 0;
+ }
+ }
+
+ /*
+ * This will iterate through tree and set node->parent field values
+ * from 0 to number of nodes.
+ */
+
+ traversal_func(zone, &tmp_apply_function, NULL);
+
+ node_index = 0;
+
+ /*
+ * This will check whether the values were set accordingly.
+ */
+
+ traversal_func(zone, &tmp_compare_function, NULL);
+
+ int ret = compare_ok;
+
+ compare_ok = 1;
+ node_index = 0;
+
+ return (ret);
+}
+
+/* Tests all kinds of zone traversals, explainded above */
+static int test_zone_traversals(knot_zone_contents_t *zone)
+{
+ for (int i = 0; i < TRAVERSAL_TYPES; i++) {
+ for (int j = 0; j < 2; j++) {
+ if (!test_zone_tree_apply(zone, i, j)) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+struct zone_test_param {
+ /* Times 2 so that we don't have to mess with mallocs. */
+ knot_node_t *knot_node_array[TEST_NODES_GOOD * 5];
+ knot_dname_t *table_node_array[TEST_NODES_GOOD * 5];
+ size_t count;
+};
+
+static void tree_node_to_array(knot_node_t *node, void *data)
+{
+ struct zone_test_param *param = (struct zone_test_param *)data;
+ param->knot_node_array[param->count++] = node;
+}
+
+static void tree_dname_node_to_array(knot_dname_t *node,
+ void *data)
+{
+ struct zone_test_param *param = (struct zone_test_param *)data;
+ param->table_node_array[param->count++] = node;
+}
+
+extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count);
+static int test_zone_shallow_copy()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_dname_t *apex_dname =
+ knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"), NULL);
+ assert(apex_dname);
+ knot_node_t *apex_node =
+ knot_node_new(apex_dname, NULL, 0);
+ assert(apex_node);
+ lives_ok({
+ if (knot_zone_contents_shallow_copy(NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL "
+ "arguments did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ knot_zone_contents_t *zone = knot_zone_contents_new(apex_node,
+ 0, 1, 0);
+ if (knot_zone_contents_shallow_copy(zone, NULL) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL destination "
+ "zone argument did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_contents_shallow_copy(NULL, &zone) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL source "
+ "zone argument did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_contents_shallow_copy(zone, &zone) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with identical source "
+ "and destination zone did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_zone_contents_free(&zone);
+ }, "zone: shallow copy NULL tests");
+ errors += lived != 1;
+
+ knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[0].owner);
+ if (d == NULL) {
+ return 0;
+ }
+ knot_node_t *n = knot_node_new(d, NULL, 0);
+
+ /* example.com. */
+// knot_zone_t *from_zone =
+// knot_zone_new(knot_node_new(&test_nodes_good[0].owner,
+// test_nodes_good[0].parent, 0), 10, 1);
+ knot_zone_t *from_zone = knot_zone_new(n, 10, 1);
+ knot_zone_contents_t *from = knot_zone_get_contents(from_zone);
+
+ /* Add nodes to zone. */
+ for (int i = 1; i < TEST_NODES_GOOD; ++i) {
+ knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[i].owner);
+ if (d == NULL) {
+ return 0;
+ }
+ knot_node_t *node = knot_node_new(d, test_nodes_good[i].parent,
+ 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if (knot_zone_contents_add_node(from, node, 1, 1, 1) != KNOT_EOK) {
+ diag("zone: Could not add node. %s",
+ knot_dname_to_str(node->owner));
+// return 0;
+ }
+ }
+
+ /* Make a copy of zone */
+ knot_zone_contents_t *to = NULL;
+ int ret = 0;
+ if ((ret = knot_zone_contents_shallow_copy(from, &to) != KNOT_EOK)) {
+ diag("Could not copy zone! %s", knot_strerror(ret));
+ return 0;
+ }
+
+ assert(to);
+
+ /* Compare non-tree parts of the zone. */
+// if (from->data != to->data) {
+// diag("Zone data field wrong after shallow copy!");
+// errors++;
+// }
+
+// if (from->dtor != to->dtor) {
+// diag("Zone data destructor field wrong after shallow copy!");
+// errors++;
+// }
+
+ if (from->node_count != to->node_count) {
+ diag("Zone node count data field wrong after shallow copy!");
+ errors++;
+ }
+
+// if (from->version != to->version) {
+// diag("Zone version data field wrong after shallow copy!");
+// errors++;
+// }
+
+ if (from->apex != to->apex) {
+ diag("Zone apex differ after shallow copy!");
+ }
+
+ if (compare_wires_simple((uint8_t *)(&from->nsec3_params),
+ (uint8_t *)(&to->nsec3_params),
+ sizeof(from->nsec3_params)) != 0) {
+ diag("Nsec3_params data field wrong after shallow copy!");
+ errors++;
+ }
+
+ if (from->nodes == to->nodes) {
+ diag("Copied zones have identical trees!");
+ errors++;
+ }
+
+ if (from->nsec3_nodes == to->nsec3_nodes) {
+ diag("Copied zones have identical trees!");
+ errors++;
+ }
+
+ /* Compare nodes, convert tree to array then compare those arrays. */
+ struct zone_test_param param1;
+ memset(&param1, 0, sizeof(struct zone_test_param));
+
+ knot_zone_contents_tree_apply_inorder(from, tree_node_to_array,
+ (void *)&param1);
+
+ struct zone_test_param param2;
+ memset(&param2, 0, sizeof(struct zone_test_param));
+
+ knot_zone_contents_tree_apply_inorder(to, tree_node_to_array,
+ (void *)&param2);
+
+ if (param1.count != param2.count) {
+ diag("wrong tree");
+ return 0;
+ }
+
+ for (int i = 0; i < param1.count; i++) {
+ if (param1.knot_node_array[i] !=
+ param2.knot_node_array[i]) {
+ diag("wrong tree");
+ return 0;
+ }
+ }
+
+ param1.count = 0;
+ knot_dname_table_tree_inorder_apply(from->dname_table,
+ tree_dname_node_to_array,
+ (void *)&param1);
+
+ param2.count = 0;
+ knot_dname_table_tree_inorder_apply(to->dname_table,
+ tree_dname_node_to_array,
+ (void *)&param2);
+
+ if (param1.count != param2.count) {
+ diag("wrong table count");
+ return 0;
+ }
+
+ for (int i = 0; i < param1.count; i++) {
+ if (param1.table_node_array[i] != param2.table_node_array[i]) {
+ diag("wrong table nodes");
+ errors++;
+ }
+ }
+
+#ifdef USE_HASH_TABLE
+ if (from->table) {
+ if (from->table == to->table) {
+ diag("hash tables after shallow copy are identical!");
+ return 0;
+ }
+ uint i;
+ if (hashsize(from->table->table_size_exp) !=
+ hashsize(to->table->table_size_exp)) {
+ diag("hash tables after shallow copy error!");
+ return 0;
+ }
+
+ if (from->table->table_count != to->table->table_count) {
+ diag("hash tables after shallow copy error!");
+ return 0;
+ }
+
+ for (uint t = 0; t < from->table->table_count; ++t) {
+ for (i = 0; i <
+ hashsize(from->table->table_size_exp); i++) {
+ if (from->table->tables[t][i] == NULL) {
+ if (to->table->tables[t][i] != NULL) {
+ diag("hash table item error");
+ }
+ continue;
+ }
+ if ((from->table->tables[t])[i]->key_length !=
+ (to->table->tables[t])[i]->key_length) {
+ diag("hash table key lengths error!");
+ return 0;
+ }
+ if ((from->table->tables[t])[i]->key !=
+ (to->table->tables[t])[i]->key) {
+ diag("hash table key error!");
+ return 0;
+ }
+ if ((from->table->tables[t])[i]->value !=
+ (to->table->tables[t])[i]->value) {
+ diag("hash table value error!");
+ return 0;
+ }
+ }
+ }
+
+ ck_stash_item_t *item1 = from->table->stash;
+ ck_stash_item_t *item2 = to->table->stash;
+ while (item1 != NULL && item2 != NULL) {
+ if (item1->item->key_length !=
+ item2->item->key_length) {
+ diag("hash stash key length error!");
+ return 0;
+ }
+ if (item1->item->key != item2->item->key) {
+ diag("hash stash key error!");
+ return 0;
+ }
+ if (item1->item->value != item2->item->value) {
+ diag("hash stash value error!");
+ return 0;
+ }
+
+ item1 = item1->next;
+ item2 = item2->next;
+ }
+ } else {
+ if (to->table) {
+ diag("Hash table is not set to NULL "
+ "after shallow copy!");
+ errors++;
+ }
+ }
+#endif
+
+// knot_zone_deep_free(&from_zone, 0);
+// knot_zone_contents_free(&to);
+ return (errors == 0);
+
+}
+
+//static int test_zone_free(knot_zone_t **zone)
+//{
+// knot_zone_tree_apply_postorder(*zone,
+// test_zone_destroy_node_from_tree,
+// NULL);
+// knot_zone_nsec3_apply_postorder(*zone,
+// test_zone_destroy_node_from_tree,
+// NULL);
+// knot_zone_free(zone);
+// return (*zone == NULL);
+//}
+
+static const int KNOT_ZONE_TEST_COUNT = 10;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_zone_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_zone_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 0;
+
+ knot_zone_contents_t *zone = NULL;
+
+ ok((res = test_zone_create(&zone)), "zone: create");
+ res_final *= res;
+
+ skip(!res, 6);
+
+ ok((res = test_zone_add_node(zone, 0)), "zone: add node");
+ res_final *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_zone_get_node(zone, 0)), "zone: get node");
+ res_final *= res;
+
+ skip(!res, 1);
+
+ ok((res = test_zone_find_node(zone, 0)), "zone: find node");
+ res_final *= res;
+
+ endskip; // get node failed
+
+ endskip; // add node failed
+
+ ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node");
+ res_final *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_zone_get_node(zone, 1)), "zone: get nsec3 node");
+ res_final *= res;
+
+ skip(!res, 1);
+
+ ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node");
+ res_final *= res;
+
+ endskip; // get nsec3 node failed
+
+ endskip; // add nsec3 node failed
+
+ ok(res = test_zone_traversals(zone), "zone: traversals");
+ res_final *= res;
+
+ ok((res = test_zone_shallow_copy()), "zone: shallow copy");
+ res_final *= res;
+
+// ok((res = test_zone_free(&zone)), "zone: free");
+// res_final *= res;
+
+ endskip; // create failed
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/zone_tests.h b/src/tests/libknot/libknot/zone_tests.h
new file mode 100644
index 0000000..5539709
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_ZONE_TESTS_H_
+#define _KNOTD_ZONE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tests_api;
+
+#endif /* _KNOTD_ZONE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zone_tree_tests.c b/src/tests/libknot/libknot/zone_tree_tests.c
new file mode 100644
index 0000000..c26746e
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tree_tests.c
@@ -0,0 +1,758 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <string.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/zone_tree_tests.h"
+#include "libknot/zone/zone-tree.h"
+#include "libknot/util/error.h"
+
+static int knot_zone_tree_tests_count(int argc, char *argv[]);
+static int knot_zone_tree_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tree_tests_api = {
+ "DNS library - zone tree", //! Unit name
+ &knot_zone_tree_tests_count, //! Count scheduled tests
+ &knot_zone_tree_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+static int test_tree_init()
+{
+ int errors = 0;
+ int lived = 0;
+
+ lives_ok({
+ if (knot_zone_tree_init(NULL) != KNOT_EBADARG) {
+ diag("Calling knot_zone_tree_init with NULL "
+ "tree did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: init NULL tests");
+ errors += lived != 1;
+
+ return (errors == 0);
+}
+
+static int test_tree_insert()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz."),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_insert(NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_insert(tree, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_insert(NULL, node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: insert NULL tests");
+ if (errors) {
+ diag("Zone tree insert did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+ errors += lived != 1;
+
+ if (knot_zone_tree_insert(tree, node) != KNOT_EOK) {
+ diag("Calling zone tree insert with valid arguments "
+ "did not return KNOT_EOK");
+ errors++;
+ }
+
+ /* Sorting will be tested in traversal functions. */
+ return (errors == 0);
+}
+
+static int test_tree_finding()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ const knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz."),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_find(NULL, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, node->owner,
+ NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *found_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find(NULL, node->owner,
+ &found_node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, NULL,
+ &found_node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: find NULL tests");
+ if (errors) {
+ diag("Zone tree find did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ errors += lived != 1;
+
+ /* Insert node */
+ assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK);
+
+ knot_node_t *found_node = NULL;
+ if (knot_zone_tree_find(tree, node->owner,
+ (const knot_node_t **)&found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get(tree, node->owner, &found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get did not return right node");
+ errors++;
+ }
+
+ /* Try to search for node not in tree. */
+ knot_dname_t *alien_dname =
+ knot_dname_new_from_str("this.name.is.not.in.the.tree.",
+ strlen("this.name.is.not.in.the.tree."),
+ NULL);
+
+ if (knot_zone_tree_find(tree, alien_dname,
+ (const knot_node_t **)&found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != NULL) {
+ diag("Zone tree find returned node that was not in the tree!");
+ errors++;
+ }
+
+ if (knot_zone_tree_get(tree, alien_dname, &found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != NULL) {
+ diag("Zone tree get returned node that was not in the tree!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_finding_less_or_equal()
+{
+ diag("Issue nr.: 1145");
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ const knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_find_less_or_equal(NULL,
+ NULL,
+ NULL,
+ NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree, NULL,
+ NULL, NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree,
+ node->owner,
+ NULL,
+ NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *found_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(NULL, node->owner,
+ &found_node, NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *previous_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree, NULL,
+ &found_node,
+ &previous_node, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: tree find less or equal NULL tests");
+ if (errors) {
+ diag("Zone tree find did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ if (!lived) {
+ errors++;
+ }
+
+ const knot_node_t *previous_node = NULL;
+
+ /* Insert node - exact match. */
+ assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK);
+
+
+ const knot_node_t *found_node = NULL;
+ if (knot_zone_tree_find_less_or_equal(tree,
+ node->owner,
+ &found_node,
+ &previous_node, 0) <= 0) {
+ diag("Calling zone tree find less with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree, node->owner,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree get less with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get less did not return right node");
+ errors++;
+ }
+
+ knot_dname_t *less_dname =
+ knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz."),
+ NULL);
+
+ assert(knot_dname_compare(less_dname, node->owner) < 0);
+
+ if (knot_zone_tree_find_less_or_equal(tree,
+ less_dname,
+ &found_node,
+ &previous_node, 0) <= 0) {
+ diag("Calling zone tree find less or equal "
+ "with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find less or equal did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree, less_dname,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree less or equal with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get less or equal did not return right node");
+ errors++;
+ }
+
+ /* Try to search for node not in tree. */
+ knot_dname_t *alien_dname =
+ knot_dname_new_from_str("this.name.is.not.in.the.tree.",
+ strlen("this.name.is.not.in.the.tree."),
+ NULL);
+
+ if (knot_zone_tree_find_less_or_equal(tree, alien_dname,
+ &found_node,
+ &previous_node, 0) !=
+ 0) {
+ diag("Calling zone tree find less with valid arguments did "
+ "not return 0");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree,
+ alien_dname,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) !=
+ 0) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return 0");
+ errors++;
+ }
+
+ /* Set node previous label. */
+ knot_node_t *tmp_node =
+ knot_node_new(knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz"),
+ NULL), NULL, 0);
+ assert(tmp_node);
+ knot_node_set_parent((knot_node_t *)node, tmp_node);
+
+ if (knot_zone_tree_find_less_or_equal(tree, node->owner,
+ &found_node,
+ &previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node || previous_node != tmp_node) {
+ diag("Zone tree find did not return valid nodes!");
+ errors++;
+ }
+
+
+ if (knot_zone_tree_get_less_or_equal(tree, node->owner,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node || previous_node != tmp_node) {
+ diag("Zone get find did not return valid nodes!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_remove()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ /* Add node. */
+ int ret = knot_zone_tree_insert(tree, node);
+ assert(ret == 0);
+ assert(ret == 0);
+
+ lives_ok({
+ if (knot_zone_tree_remove(NULL, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, node->owner, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(NULL, node->owner, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ knot_zone_tree_node_t *deleted_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_remove(NULL, node->owner, &deleted_node) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, NULL, &deleted_node) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: remove NULL tests");
+ if (errors) {
+ diag("Zone tree remove did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ errors += lived != 1;
+
+ knot_zone_tree_node_t *removed_node = NULL;
+
+ /* Remove previously inserted node. */
+ if (knot_zone_tree_remove(tree, node->owner, &removed_node) !=
+ KNOT_EOK) {
+ diag("Could not remove previously inserted node!");
+ errors++;
+ }
+
+ if (removed_node == NULL || removed_node->node != node) {
+ diag("Wrong node was removed!");
+ errors++;
+ }
+
+ /*
+ * Try remove the node again - it should not be there and
+ * removed_node should be NULL.
+ */
+
+ if (knot_zone_tree_remove(tree, node->owner, &removed_node) !=
+ KNOT_EOK) {
+ diag("Could not remove previously inserted node!");
+ errors++;
+ }
+
+ if (removed_node != NULL) {
+ diag("Zone tree remove returned previously removed node!");
+ errors++;
+ }
+
+ return (errors == 0);
+
+}
+
+struct test_zone_tree_args {
+ knot_node_t *array[10 * 1024];
+ size_t count;
+};
+
+static void add_to_array(knot_zone_tree_node_t *node, void *data)
+{
+ struct test_zone_tree_args *args =
+ (struct test_zone_tree_args *)data;
+ args->array[args->count++] = node->node;
+}
+
+static int test_traversal(knot_node_t **nodes,
+ size_t node_count,
+ uint code)
+{
+ int errors = 0;
+ int lived = 0;
+
+ int (*trav_func)(knot_zone_tree_t *,
+ void (*)(knot_zone_tree_node_t *, void *),
+ void *);
+
+ trav_func = (code) ? knot_zone_tree_reverse_apply_inorder :
+ knot_zone_tree_forward_apply_inorder;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+
+ lives_ok({
+ if (trav_func(NULL, NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (trav_func(tree, NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (trav_func(NULL, add_to_array, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: traversal NULL tests");
+
+ if (errors) {
+ diag("Traversal function did not return KNOT_EBADARG "
+ "when given NULL parameters");
+ }
+
+ errors += lived != 1;
+
+ /* Add nodes to tree. */
+ for (int i = 0; i < node_count; i++) {
+ assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK);
+ }
+
+ struct test_zone_tree_args args;
+ args.count = 0;
+
+ trav_func(tree, add_to_array, &args);
+
+ if (args.count != node_count) {
+ diag("Traversal function traversed more nodes than it "
+ "should have!");
+ return ++errors;
+ }
+
+ for (int i = 0; i < node_count; i++) {
+ int match = nodes[i] == args.array[i];
+ if (!match) {
+ diag("Traversal function returned nodes in wrong "
+ "order!");
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+static int test_tree_traversals()
+{
+ /*!< \todo I can test inorder and reverse inorder, but I don't know
+ * how to test others. It is somehow tested in zone tests. */
+ int errors = 0;
+
+ /* Create few nodes. (5 should be enough) */
+ knot_node_t *nodes[5];
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = i + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ }
+
+ if (test_traversal(nodes, 5, 0)) {
+ diag("Inorder traversal failed");
+ errors++;
+ }
+
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = (5 - i) + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ }
+
+ if (test_traversal(nodes, 5, 1)) {
+ diag("Reverse inorder traversal failed");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_shallow_copy()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+
+ lives_ok({
+ if (knot_zone_tree_shallow_copy(NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_shallow_copy(tree, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_shallow_copy(NULL, tree) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: shallow copy NULL tests");
+ if (errors) {
+ diag("Zone tree shallow copy did not return KNOT_EBADARG when "
+ "given NULL arguments");
+ }
+ errors += lived != 1;
+
+ /* Create few nodes. (5 should be enough) */
+ knot_node_t *nodes[5];
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = i + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ /* Insert node to tree. */
+ assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK);
+ }
+
+ /* Create shallow copy. */
+ knot_zone_tree_t *new_tree = malloc(sizeof(knot_zone_tree_t));
+ assert(new_tree);
+ knot_zone_tree_init(new_tree);
+
+ if (knot_zone_tree_shallow_copy(tree, new_tree) != KNOT_EOK) {
+ diag("Zone tree shallow copy did not return KNOT_EOK "
+ "when executed with valid parameters");
+ return 0;
+ }
+
+ /* Traverse the tree twice and check that arrays are the same. */
+ struct test_zone_tree_args args1;
+ args1.count = 0;
+
+ knot_zone_tree_forward_apply_inorder(tree, add_to_array,
+ &args1);
+
+
+ struct test_zone_tree_args args2;
+ args2.count = 0;
+ knot_zone_tree_forward_apply_inorder(new_tree, add_to_array,
+ &args2);
+
+ if (args1.count != args2.count) {
+ diag("Zone tree created by shallow copy has wrong count"
+ "of nodes");
+ return 0;
+ }
+
+ for (int i = 0; i < args1.count; i++) {
+ if (args1.array[i] != args2.array[i]) {
+ diag("Zone tree created by shallow copy has wrong "
+ "nodes");
+ errors++;
+ }
+ }
+
+ return (errors == 0);
+
+}
+
+
+static const int KNOT_ZONE_TREE_TEST_COUNT = 14;
+
+static int knot_zone_tree_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TREE_TEST_COUNT;
+}
+
+static int knot_zone_tree_tests_run(int argc, char *argv[])
+{
+ ok(test_tree_init(), "zone tree: init");
+ ok(test_tree_insert(), "zone tree: insertion");
+ ok(test_tree_finding(), "zone tree: finding");
+ todo();
+ ok(test_tree_finding_less_or_equal(), "zone tree: find less or equal");
+ endtodo;
+ ok(test_tree_remove(), "zone tree: removal");
+ ok(test_tree_traversals(), "zone tree: traversals");
+ ok(test_tree_shallow_copy(), "zone tree: shallow copy");
+
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/zone_tree_tests.h b/src/tests/libknot/libknot/zone_tree_tests.h
new file mode 100644
index 0000000..4cea88c
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tree_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTDZONE_TREE_TESTS_H_
+#define _KNOTDZONE_TREE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tree_tests_api;
+
+#endif /* _KNOTDZONE_TREE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zonedb_tests.c b/src/tests/libknot/libknot/zonedb_tests.c
new file mode 100644
index 0000000..7b45587
--- /dev/null
+++ b/src/tests/libknot/libknot/zonedb_tests.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/libknot/zonedb_tests.h"
+
+
+static int zonedb_tests_count(int argc, char *argv[]);
+static int zonedb_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zonedb_tests_api = {
+ "Zone database", //! Unit name
+ &zonedb_tests_count, //! Count scheduled tests
+ &zonedb_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int zonedb_tests_count(int argc, char *argv[])
+{
+ return 0;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int zonedb_tests_run(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/src/tests/libknot/libknot/zonedb_tests.h b/src/tests/libknot/libknot/zonedb_tests.h
new file mode 100644
index 0000000..0c4f8ef
--- /dev/null
+++ b/src/tests/libknot/libknot/zonedb_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_ZONEDB_TESTS_H_
+#define _KNOTD_ZONEDB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zonedb_tests_api;
+
+#endif /* _KNOTD_ZONEDB_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/files/parsed_data b/src/tests/libknot/realdata/files/parsed_data
new file mode 100644
index 0000000..fe22b90
--- /dev/null
+++ b/src/tests/libknot/realdata/files/parsed_data
Binary files differ
diff --git a/src/tests/libknot/realdata/files/parsed_data_queries b/src/tests/libknot/realdata/files/parsed_data_queries
new file mode 100644
index 0000000..5857c87
--- /dev/null
+++ b/src/tests/libknot/realdata/files/parsed_data_queries
Binary files differ
diff --git a/src/tests/libknot/realdata/files/raw_data b/src/tests/libknot/realdata/files/raw_data
new file mode 100644
index 0000000..502005e
--- /dev/null
+++ b/src/tests/libknot/realdata/files/raw_data
Binary files differ
diff --git a/src/tests/libknot/realdata/files/raw_data_queries b/src/tests/libknot/realdata/files/raw_data_queries
new file mode 100644
index 0000000..9062d5a
--- /dev/null
+++ b/src/tests/libknot/realdata/files/raw_data_queries
Binary files differ
diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.c b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c
new file mode 100644
index 0000000..d0216c7
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c
@@ -0,0 +1,411 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "tests/libknot/realdata/libknot/dname_tests_realdata.h"
+#include "libknot/dname.h"
+#include "libknot/common.h"
+
+#include "common/print.h"
+#include "common/lists.h"
+
+static int knot_dname_tests_count(int argc, char *argv[]);
+static int knot_dname_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_tests_api = {
+ "DNS library - dname", //! Unit name
+ &knot_dname_tests_count, //! Count scheduled tests
+ &knot_dname_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+int check_domain_name(const knot_dname_t *dname,
+ const test_dname_t *test_dname)
+{
+ int errors = 0;
+
+ if (dname == NULL) {
+ diag("Domain name not created!");
+ return 1;
+ }
+
+// diag("test_dname: %p, dname: %p", test_dname, dname);
+ // check size
+ if (knot_dname_size(dname) != test_dname->size) {
+ diag("Bad size of the created domain name: %u (should be %u).",
+ knot_dname_size(dname), test_dname->size);
+ ++errors;
+ } else {
+ // check wire format
+ uint size = knot_dname_size(dname);
+ if (strncmp((char *)knot_dname_name(dname),
+ (char *)test_dname->wire, size) != 0) {
+ diag("The wire format of the created "
+ "domain name is wrong:"
+ " '%.*s' (should be '%.*s').",
+ size, knot_dname_name(dname),
+ size, test_dname->wire);
+ ++errors;
+ }
+ }
+ // check labels
+ if (test_dname->label_count != dname->label_count) {
+ diag("Label count of the created domain name is wrong:"
+ " %d (should be %d)\n", dname->label_count,
+ test_dname->label_count);
+ ++errors;
+ }
+ if (strncmp((char *)dname->labels, (char *)test_dname->labels,
+ test_dname->label_count) != 0) {
+ diag("Label offsets of the created domain name are wrong.\n");
+ hex_print((char *)dname->labels, test_dname->label_count);
+ hex_print((char *)test_dname->labels, test_dname->label_count);
+ ++errors;
+ }
+
+ return errors;
+}
+
+static int test_dname_create_from_str(const list *dname_list)
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_str(test_dname->str,
+ strlen(test_dname->str), NULL);
+ errors += check_domain_name(dname, test_dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_wire(const list *dname_list)
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size, NULL);
+ errors += check_domain_name(dname, test_dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_to_str(const list *dname_list)
+{
+ int errors = 0;
+
+ /*
+ * Converts dname wireformat to string represenation, which is compared
+ * with entries in test_domains structure.
+ */
+
+ knot_dname_t *dname = NULL;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(
+ test_dname->wire,
+ test_dname->size,
+ NULL);
+ if (dname == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ char *name_str = knot_dname_to_str(dname);
+ if (strcmp(name_str, test_dname->str) != 0) {
+ diag("Presentation format of domain name wrong:"
+ " %s (should be %s)",
+ name_str, test_dname->str);
+ ++errors;
+ }
+ free(name_str);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_fqdn(const list *dname_list)
+{
+ int errors = 0;
+
+ knot_dname_t *dname;
+
+ /* All dnames from real data are fqdn */
+
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size, NULL);
+ errors += !knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+//static int check_wires(const uint8_t *wire1, uint size1,
+// uint8_t *wire2, uint size2)
+//{
+// if (size1 != size2) {
+// return 0;
+// }
+
+// int i;
+
+// for (i = 0; (i < size1); i++) {
+// if (wire1[i] != wire2[i]) {
+// return 0;
+// }
+// }
+
+// return 1;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_name(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// const uint8_t *tmp_name;
+// tmp_name = knot_dname_name(dnames_fqdn[i]);
+// if (!check_wires(tmp_name, dnames_fqdn[i]->size,
+// (uint8_t *)test_domains_ok[i].wire,
+// test_domains_ok[i].size)) {
+// diag("Got bad name value from structure: "
+// "%s, should be: %s",
+// tmp_name, test_domains_ok[i].wire);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// const uint8_t *tmp_name;
+// tmp_name = knot_dname_name(dnames_non_fqdn[i]);
+// if (!check_wires(tmp_name, dnames_non_fqdn[i]->size,
+// (uint8_t *)test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size)) {
+// diag("Got bad name value from structure: "
+// "%s, should be: %s",
+// tmp_name, test_domains_non_fqdn[i].wire);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_size(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// uint8_t tmp_size;
+// if ((tmp_size = knot_dname_size(dnames_fqdn[i])) !=
+// test_domains_ok[i].size) {
+// diag("Got bad size value from structure: "
+// "%u, should be: %u",
+// tmp_size, test_domains_ok[i].size);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// uint8_t tmp_size;
+// if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) !=
+// test_domains_non_fqdn[i].size) {
+// diag("Got bad size value from structure: "
+// "%u, should be: %u",
+// tmp_size, test_domains_non_fqdn[i].size);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_node(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// const knot_node_t *tmp_node;
+// if ((tmp_node = knot_dname_node(dnames_fqdn[i])) !=
+// NODE_ADDRESS) {
+// diag("Got bad node value from structure: "
+// "%p, should be: %p",
+// tmp_node, NODE_ADDRESS);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// const knot_node_t *tmp_node;
+// if ((tmp_node = knot_dname_node(dnames_non_fqdn[i])) !=
+// NODE_ADDRESS) {
+// diag("Got bad node value from structure: "
+// "%s, should be: %s",
+// tmp_node, NODE_ADDRESS);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+//static int test_dname_getters(uint type)
+//{
+// int errors = 0;
+
+// knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+// knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// dnames_fqdn[i] = knot_dname_new_from_wire(
+// (uint8_t *)test_domains_ok[i].wire,
+// test_domains_ok[i].size, NODE_ADDRESS);
+// assert(dnames_fqdn[i] != NULL);
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// dnames_non_fqdn[i] = knot_dname_new_from_wire(
+// (uint8_t *)test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size, NODE_ADDRESS);
+// assert(dnames_non_fqdn[i] != NULL);
+// }
+
+// switch (type) {
+// case 0: {
+// errors += test_dname_name(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+
+// case 1: {
+// errors += test_dname_size(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+
+// case 2: {
+// errors += test_dname_node(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+// } /* switch */
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// knot_dname_free(&dnames_fqdn[i]);
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// knot_dname_free(&dnames_non_fqdn[i]);
+// }
+
+// return (errors == 0);
+//}
+
+static const int KNOT_DNAME_TEST_COUNT = 4;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+ int res = 0,
+ res_str = 0,
+ res_wire = 0,
+ res_str_non_fqdn = 0,
+ res_final = 1;
+
+ ok((res_str = test_dname_create_from_str(&data->dname_list)),
+ "dname: create from string");
+ ok((res_wire = test_dname_create_from_wire(&data->dname_list)),
+ "dname: create from wire");
+
+ res_final *= res_str;
+ res_final *= res_wire;
+ res_final *= res_str_non_fqdn;
+
+// res = test_dname_getters(0);
+// ok(res, "dname: name");
+
+// res = test_dname_getters(1);
+// ok(res, "dname: size");
+
+// res = test_dname_getters(2);
+// ok(res, "dname: node");
+
+// skip(!res_str || !res_wire || !res_str_non_fqdn, 2);
+
+ ok((res = test_dname_to_str(&data->dname_list)),
+ "dname: convert to str");
+ res_final *= res;
+
+// endskip; /* !res_str || !res_wire */
+
+ ok((res = test_dname_is_fqdn(&data->dname_list)), "dname: fqdn");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.h b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h
new file mode 100644
index 0000000..a7d75aa
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_DNAME_TESTS_H_
+#define _KNOTD_DNAME_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_tests_api;
+
+#endif /* _KNOTD_DNAME_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.c b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c
new file mode 100644
index 0000000..257d480
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c
@@ -0,0 +1,563 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/realdata/libknot/edns_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/edns.h"
+
+static int knot_edns_tests_count(int argc, char *argv[]);
+static int knot_edns_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api edns_tests_api = {
+ "DNS library - EDNS", //! Unit name
+ &knot_edns_tests_count, //! Count scheduled tests
+ &knot_edns_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+///* Creates actual knot_opt_rr_t variable from test_edns_t variable */
+//static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns)
+//{
+// knot_opt_rr_t *ret = knot_edns_new();
+
+// CHECK_ALLOC_LOG(ret, NULL);
+
+// ret->flags = test_edns->flags;
+// ret->ext_rcode = test_edns->ext_rcode;
+// ret->payload = test_edns->payload;
+// ret->version = test_edns->version;
+
+// for (int i = 0; i < test_edns->option_count; i++) {
+// if (knot_edns_add_option(ret, test_edns->options[i].code,
+// test_edns->options[i].length,
+// test_edns->options[i].data) != 0) {
+// knot_edns_free(&ret);
+// return NULL;
+// }
+// }
+
+// return ret;
+//}
+
+///* simple wire compare - 0 if same, 1 otherwise */
+//static int edns_compare_wires(uint8_t *wire1,
+// uint8_t *wire2,
+// uint16_t length)
+//{
+// for (uint i = 0; i < length; i++) {
+// if (wire1[i] != wire2[i]) {
+// return 1;
+// }
+// }
+
+// return 0;
+//}
+
+//static int check_edns(const knot_opt_rr_t *edns,
+// const test_edns_t *test_edns)
+//{
+// if (edns->option_count != test_edns->option_count) {
+// diag("Option count is wrong");
+// return -1;
+// }
+
+// for (int i = 0; i < edns->option_count; i++) {
+// /* check options */
+// if (edns->options[i].code != test_edns->options[i].code) {
+// diag("Code in options is wrong");
+// return -1;
+// }
+
+// if (edns->options[i].length != test_edns->options[i].length) {
+// diag("Length in options is wrong");
+// return -1;
+// }
+
+// if (edns_compare_wires(edns->options[i].data,
+// test_edns->options[i].data,
+// edns->options[i].length) != 0) {
+// diag("Data in options are wrong");
+// return -1;
+// }
+// }
+
+// if (edns->version != test_edns->version) {
+// diag("Version is wrong");
+// return -1;
+// }
+
+// if (edns->flags != test_edns->flags) {
+// diag("Flags are wrong");
+// return -1;
+// }
+
+// if (edns->size != test_edns->size) {
+// diag("Size is wrong");
+// return -1;
+// }
+
+// return 0;
+//}
+
+//static int test_edns_get_payload(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_payload(edns) !=
+// test_edns->payload) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_ext_rcode(edns) !=
+// test_edns->ext_rcode) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_flags(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_flags(edns) !=
+// test_edns->flags) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_version(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_version(edns) !=
+// test_edns->version) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_do(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_do(edns) !=
+// (test_edns->flags & KNOT_EDNS_DO_MASK)) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns)
+//{
+// diag("%d %d\n", edns->size, test_edns->size);
+// if (knot_edns_size(edns) !=
+// test_edns->size) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_payload(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_payload(edns, test_edns->payload);
+
+// if (edns->payload !=
+// test_edns->payload) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_ext_rcode(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_ext_rcode(edns, test_edns->ext_rcode);
+// if (edns->ext_rcode !=
+// test_edns->ext_rcode) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_version(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_version(edns,
+// test_edns->version);
+
+// if (edns->version !=
+// test_edns->version) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_do(knot_opt_rr_t *edns)
+//{
+// knot_edns_set_do(edns);
+
+// if (!knot_edns_do(edns)) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_getters(uint type)
+//{
+// int errors = 0;
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// switch(type) {
+// case 0:
+// if (test_edns_get_payload(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong payload!");
+// errors++;
+// }
+// break;
+// case 1:
+// if (test_edns_get_ext_rcode(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong extended RCODE!");
+// errors++;
+// }
+// break;
+// case 2:
+// if (test_edns_get_flags(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong flags!");
+
+// errors++;
+// }
+// break;
+// case 3:
+// if (test_edns_get_version(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong version!");
+// errors++;
+// }
+// break;
+// case 4:
+// if (test_edns_do(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong DO bit!");
+// errors++;
+// }
+// break;
+// case 5:
+// if (test_edns_size(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong size!");
+// errors++;
+// }
+// break;
+// default:
+// diag("Unknown option");
+// errors++;
+// } /* switch */
+
+// knot_edns_free(&edns);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_edns_setters(uint type)
+//{
+// int errors = 0;
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// switch(type) {
+// case 0:
+// if (test_edns_set_payload(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong payload!");
+// errors++;
+// }
+// break;
+// case 1:
+// if (test_edns_set_ext_rcode(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong ext_rcode");
+// errors++;
+// }
+// break;
+// case 2:
+// if (test_edns_set_version(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong version!");
+// errors++;
+// }
+// break;
+// case 3:
+// if (test_edns_set_do(edns) != 1) {
+// diag("Set wrong DO bit!");
+// errors++;
+// }
+// break;
+// default:
+// diag("Unknown option");
+// errors++;
+// } /* switch */
+
+// knot_edns_free(&edns);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_edns_wire()
+//{
+// /*
+// * Tests to_wire and from_wire in one test.
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// /* Creates instance from test_edns_t. */
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// uint8_t *wire = NULL;
+// wire = malloc(sizeof(uint8_t) * edns->size);
+// CHECK_ALLOC_LOG(wire, 0);
+
+// /* Converts EDNS to wire. */
+// short wire_size = knot_edns_to_wire(edns, wire, 100);
+
+// if (wire_size == -1) {
+// diag("Could not create EDNS wire");
+// return 0;
+// }
+
+// knot_opt_rr_t *edns_from_wire = knot_edns_new();
+// if (edns == NULL) {
+// return 0;
+// }
+
+// /* TODO use some constant */
+// /* Creates new EDNS from wire */
+// if (knot_edns_new_from_wire(edns_from_wire,
+// wire,
+// 100) <= 0) {
+// diag("Could not create from wire");
+// return 0;
+// }
+
+// /* Checks whether EDNS created from wire is the same */
+// if (check_edns(edns_from_wire,
+// &(test_edns_data[i])) != 0) {
+// diag("EDNS created from wire is different from the "
+// "original one");
+// }
+
+// free(wire);
+// knot_edns_free(&edns_from_wire);
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+//static int test_edns_add_option()
+//{
+// /*
+// * Create empty EDNS and add options one by one, testing their presence.
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns = knot_edns_new();
+// assert(edns->option_count == 0);
+
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return 0;
+// }
+
+// for (int j = 0; j < test_edns_data[i].option_count; j++) {
+// if (knot_edns_add_option(edns,
+// test_edns_data[i].options[j].code,
+// test_edns_data[i].options[j].length,
+// test_edns_data[i].options[j].
+// data) != 0) {
+// diag("Could not add option");
+// return 0;
+// }
+
+// if (edns->options[j].code !=
+// test_edns_data[i].options[j].code) {
+// diag("Option code wrongly added!");
+// return 0;
+// }
+
+// if (edns->options[j].length !=
+// test_edns_data[i].options[j].length) {
+// diag("Option length wrongly added!");
+// return 0;
+// }
+
+// if (edns_compare_wires(edns->options[j].data,
+// test_edns_data[i].
+// options[j].data,
+// edns->options[j].length) != 0) {
+// diag("Option wire wrongly added!");
+// return 0;
+// }
+// }
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+//static int test_edns_has_option()
+//{
+// /*
+// * Create empty EDNS and add options one by one, testing their presence
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns = knot_edns_new();
+// assert(edns->option_count == 0);
+
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return 0;
+// }
+
+// for (int j = 0; j < test_edns_data[i].option_count; j++) {
+// if (knot_edns_add_option(edns,
+// test_edns_data[i].options[j].code,
+// test_edns_data[i].options[j].length,
+// test_edns_data[i].options[j].
+// data) != 0) {
+// diag("Could not add option");
+// return 0;
+// }
+
+// if (knot_edns_has_option(edns,
+// test_edns_data[i].options[j].code) != 1) {
+// diag("Option not found!");
+// return 0;
+// }
+// }
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+static const int KNOT_EDNS_TESTS_COUNT = 0;
+
+///*! This helper routine should report number of
+// * scheduled tests for given parameters.
+// */
+static int knot_edns_tests_count(int argc, char *argv[])
+{
+ return KNOT_EDNS_TESTS_COUNT;
+}
+
+///*! Run all scheduled tests for given parameters.
+// */
+static int knot_edns_tests_run(int argc, char *argv[])
+{
+// int res = 0;
+ int res_final = 1;
+
+// res = test_edns_getters(0);
+// ok(res, "EDNS: get payload");
+// res_final *= res;
+
+// res = test_edns_getters(1);
+// ok(res, "EDNS: get extenden RCODE");
+// res_final *= res;
+
+// res = test_edns_getters(2);
+// ok(res, "EDNS: get flags");
+// res_final *= res;
+
+// res = test_edns_getters(3);
+// ok(res, "EDNS: get version");
+// res_final *= res;
+
+// res = test_edns_getters(4);
+// ok(res, "EDNS: do");
+// res_final *= res;
+
+// res = test_edns_getters(5);
+// ok(res, "EDNS: size");
+// res_final *= res;
+
+// res = test_edns_setters(0);
+// ok(res, "EDNS: set payload");
+// res_final *= res;
+
+// res = test_edns_setters(1);
+// ok(res, "EDNS: set extended RCODE");
+// res_final *= res;
+
+// res = test_edns_setters(2);
+// ok(res, "EDNS: set version");
+// res_final *= res;
+
+// res = test_edns_setters(3);
+// ok(res, "EDNS: set DO");
+// res_final *= res;
+
+// res = test_edns_add_option();
+// ok(res, "EDNS: add option");
+// res_final *= res;
+
+// res = test_edns_has_option();
+// ok(res, "EDNS: has option");
+// res_final *= res;
+
+// res = test_edns_wire();
+// ok(res, "EDNS: to_wire and from_wire");
+// res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.h b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h
new file mode 100644
index 0000000..cfa64b0
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h
@@ -0,0 +1,35 @@
+/*!
+ * \file edns_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for ENDS API
+ *
+ * Contains tests for:
+ * - ENDS API
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD__EDNS_TESTS_H_
+#define _KNOTD__EDNS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api edns_tests_api;
+
+#endif /* _KNOTD__EDNS_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.c b/src/tests/libknot/realdata/libknot/node_tests_realdata.c
new file mode 100644
index 0000000..3218c8e
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.c
@@ -0,0 +1,385 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/realdata/libknot/node_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/descriptor.h"
+
+static int knot_node_tests_count(int argc, char *argv[]);
+static int knot_node_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api node_tests_api = {
+ "DNS library - node", //! Unit name
+ &knot_node_tests_count, //! Count scheduled tests
+ &knot_node_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+/* TODO It would be wise not to name variables totally same as structures ... */
+knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname)
+{
+ assert(test_dname != NULL);
+ knot_dname_t *ret = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size,
+ NULL);
+ CHECK_ALLOC(ret, NULL);
+
+ return ret;
+}
+
+static knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset)
+{
+ assert(test_rrset != NULL);
+ knot_dname_t *owner = dname_from_test_dname(test_rrset->owner);
+ CHECK_ALLOC(owner, NULL);
+
+ knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&owner);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static int test_node_create(const list *node_list)
+{
+ /* Tests creation of node by comparing with test_node struct */
+ knot_node_t *tmp;
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, *node_list) {
+ const test_node_t *tmp_node = (test_node_t *)n;
+ assert(tmp_node);
+
+ knot_dname_t *owner =
+ dname_from_test_dname(tmp_node->owner);
+ if (owner == NULL) {
+ return 0;
+ }
+ tmp = knot_node_new(owner,
+ (knot_node_t *)tmp_node->parent, 0);
+ if (tmp == NULL ||
+ (strncmp((char *)tmp->owner->name,
+ (char *)tmp_node->owner->wire,
+ tmp->owner->size) != 0) ||
+ tmp->parent != (knot_node_t *)tmp_node->parent ||
+ tmp->rrset_tree == NULL) {
+ errors++;
+ diag("Failed to create node structure");
+ }
+ knot_node_free(&tmp, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_add_rrset(list *rrset_list)
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, *rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ rrset = rrset_from_test_rrset(test_rrset);
+ if (rrset == NULL) {
+ diag("Could not create rrset from test data");
+ return 0;
+ }
+
+ /* create node from test_node structure. Always the first one.*/
+ knot_dname_t *owner =
+ dname_from_test_dname(test_rrset->owner);
+ if (owner == NULL) {
+ diag("Could not create owner from test data");
+ return 0;
+ }
+
+ tmp = knot_node_new(owner, NULL, 0);
+
+ if (knot_node_add_rrset(tmp, rrset, 0) != 0) {
+ errors++;
+ diag("Failed to insert rrset into node");
+ }
+
+ /* check if rrset is really there */
+
+ const knot_rrset_t *rrset_from_node = NULL;
+ if ((rrset_from_node =
+ knot_node_rrset(tmp, rrset->type)) == NULL) {
+ errors++;
+ diag("Inserted rrset could not be found");
+ continue;
+ }
+
+ /* compare rrset from node with original rrset */
+
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ int cmp = 0;
+
+ if ((rrset_from_node->rdata == NULL) &&
+ (rrset->rdata == NULL)) {
+ cmp = 0;
+ } else if ((rrset_from_node->rdata != NULL) &&
+ (rrset->rdata != NULL)) {
+ cmp = knot_rdata_compare(rrset_from_node->rdata,
+ rrset->rdata,
+ desc->wireformat);
+ } else { /* one is not NULL and other is -> error */
+ cmp = 1;
+ }
+
+ if (!((rrset_from_node->type == rrset->type) &&
+ (rrset_from_node->rclass == rrset->rclass) &&
+ (rrset_from_node->ttl == rrset->ttl) &&
+ (rrset_from_node->rrsigs == rrset->rrsigs) &&
+ (cmp == 0))) {
+ errors++;
+ diag("Values in found rrset are wrong");
+ }
+
+ knot_node_free(&tmp, 1, 0);
+ }
+
+ return (errors == 0);
+}
+
+//static int test_node_get_rrset()
+//{
+// knot_node_t *tmp;
+// knot_rrset_t *rrset;
+// int errors = 0;
+
+// knot_node_t *nodes[TEST_NODES];
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// tmp = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+// nodes[i] = tmp;
+// for (int j = 0; j < RRSETS; j++) {
+// knot_node_add_rrset(tmp, &rrsets[j]);
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// for (int j = 0; j < RRSETS; j++) {
+// rrset = &rrsets[j];
+// if (knot_node_rrset(nodes[i], rrset->type)
+// != rrset) {
+// errors++;
+// diag("Failed to get proper rrset from node");
+// }
+// }
+// knot_node_free(&nodes[i], 0);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_node_get_parent()
+//{
+// knot_node_t *tmp;
+// knot_rrset_t *rrset;
+// int errors = 0;
+
+// knot_node_t *nodes[TEST_NODES];
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// tmp = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+// nodes[i] = tmp;
+// rrset = &rrsets[i];
+// knot_node_add_rrset(tmp, rrset);
+// }
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// rrset = &rrsets[i];
+// if (knot_node_parent(nodes[i]) != test_nodes[i].parent) {
+// errors++;
+// diag("Failed to get proper parent from node");
+// }
+// knot_node_free(&nodes[i], 0);
+// }
+// return (errors == 0);
+//}
+
+//static int test_node_sorting()
+//{
+// knot_node_t *tmp = NULL;
+// knot_rrset_t *rrset = NULL;
+// int errors = 0;
+
+// knot_dname_t *owner = dname_from_test_dname(test_nodes[0].owner);
+
+// tmp = knot_node_new(owner,
+// (knot_node_t *)test_nodes[0].parent);
+
+// /* Will add rrsets to node. */
+// knot_node_add_rrset(tmp, rrset);
+// }
+
+// const skip_node_t *node = skip_first(tmp->rrsets);
+
+// int last = *((uint16_t *)node->key);
+
+// /* TODO there is now an API function knot_node_rrsets ... */
+
+// /* Iterates through skip list and checks, whether it is sorted. */
+
+// while ((node = skip_next(node)) != NULL) {
+// if (last > *((uint16_t *)node->key)) {
+// errors++;
+// diag("RRset sorting error");
+// }
+// last = *((uint16_t *)node->key);
+// }
+
+// knot_node_free(&tmp, 1);
+// return (errors == 0);
+//}
+
+//static int test_node_delete()
+//{
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// knot_dname_t *owner =
+// dname_from_test_dname(test_nodes[i].owner);
+// tmp_node = knot_node_new(owner,
+// (knot_node_t *)test_nodes[i].parent);
+
+// knot_node_free(&tmp_node, 1);
+
+// errors += (tmp_node != NULL);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_node_set_parent()
+//{
+// knot_node_t *tmp_parent = (knot_node_t *)0xABCDEF;
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// tmp_node = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+
+// knot_node_set_parent(tmp_node, tmp_parent);
+
+// if (tmp_node->parent != tmp_node->parent) {
+// diag("Parent node is wrongly set.");
+// errors++;
+// }
+// knot_node_free(&tmp_node, 0);
+// }
+// return (errors == 0);
+//}
+
+//static int test_node_free_rrsets()
+//{
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// knot_dname_t *owner =
+// dname_from_test_dname(test_nodes[i].owner);
+// if (owner == NULL) {
+// return 0;
+// }
+
+// tmp_node = knot_node_new(owner,
+// (knot_node_t *)test_nodes[i].parent);
+
+// knot_node_free_rrsets(tmp_node, 0);
+
+// errors += (tmp_node->rrsets != NULL);
+
+// knot_node_free(&tmp_node, 1);
+// }
+// return (errors == 0);
+//}
+
+static const int KNOT_NODE_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_node_tests_count(int argc, char *argv[])
+{
+ return KNOT_NODE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_node_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+ int res = 0,
+ res_final = 1;
+
+ res = test_node_create(&data->node_list);
+ ok(res, "node: create");
+ res_final *= res;
+
+
+ ok((res = test_node_add_rrset(&data->rrset_list)), "node: add");
+ res_final *= res;
+
+// ok((res = test_node_get_rrset()), "node: get");
+// res_final *= res;
+
+// ok((res = test_node_get_parent()), "node: get parent");
+// res_final *= res;
+
+// ok((res = test_node_set_parent()), "node: set parent");
+// res_final *= res;
+
+// ok((res = test_node_sorting()), "node: sort");
+// res_final *= res;
+
+// ok((res = test_node_free_rrsets()), "node: free rrsets");
+// res_final *= res;
+
+// endskip;
+
+// ok((res = test_node_delete()), "node: delete");
+// //res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.h b/src/tests/libknot/realdata/libknot/node_tests_realdata.h
new file mode 100644
index 0000000..a90179f
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_NODE_TESTS_H_
+#define _KNOTD_NODE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api node_tests_api;
+
+#endif /* _KNOTD_NODE_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.c b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c
new file mode 100644
index 0000000..08c0882
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c
@@ -0,0 +1,679 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include <config.h>
+#include "knot/common.h"
+#include "packet_tests_realdata.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/packet/response.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int packet_tests_count(int argc, char *argv[]);
+static int packet_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api packet_tests_api = {
+ "DNS library - packet", //! Unit name
+ &packet_tests_count, //! Count scheduled tests
+ &packet_tests_run //! Run scheduled tests
+};
+
+#ifdef TEST_WITH_LDNS
+/* Compares one rdata knot with rdata from ldns.
+ * Comparison is done through comparing wireformats.
+ * Returns 0 if rdata are the same, 1 otherwise
+ */
+int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr,
+ uint16_t type)
+{
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ for (int i = 0; i < rdata->count; i++) {
+ /* check for ldns "descriptors" as well */
+
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+ if (rdata->items[i].dname->size !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ diag("%s", rdata->items[i].dname->name);
+ diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i)));
+ diag("%d", ldns_rdf_size(ldns_rr_rdf(rr, i)));
+ diag("%d", rdata->items[i].dname->size);
+ diag("Dname sizes in rdata differ");
+ return 1;
+ }
+ if (compare_wires_simple(rdata->items[i].dname->name,
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].dname->size) != 0) {
+ diag("%s", rdata->items[i].dname->name);
+ diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i)));
+ diag("Dname wires in rdata differ");
+ return 1;
+ }
+ } else {
+ /* Compare sizes first, then actual data */
+ if (rdata->items[i].raw_data[0] !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ /* \note ldns stores the size including the
+ * length, knot does not */
+ diag("Raw data sizes in rdata differ");
+ diag("knot: %d ldns: %d",
+ rdata->items[i].raw_data[0],
+ ldns_rdf_size(ldns_rr_rdf(rr, i)));
+// hex_print((char *)
+// (rdata->items[i].raw_data + 1),
+// rdata->items[i].raw_data[0]);
+// hex_print((char *)ldns_rdf_data(ldns_rr_rdf(rr,
+// i)),
+// ldns_rdf_size(ldns_rr_rdf(rr, i)));
+ if (abs(rdata->items[i].raw_data[0] -
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) {
+ return 1;
+ }
+ }
+ if (compare_wires_simple((uint8_t *)
+ (rdata->items[i].raw_data + 1),
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].raw_data[0]) != 0) {
+// hex_print((char *)
+// (rdata->items[i].raw_data + 1),
+// rdata->items[i].raw_data[0]);
+// hex_print((char *)
+// ldns_rdf_data(ldns_rr_rdf(rr, i)),
+// rdata->items[i].raw_data[0]);
+ diag("Raw data wires in rdata differ in item "
+ "%d", i);
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset,
+ ldns_rr_list *rr_set, char check_rdata)
+{
+ /* We should have only one rrset from ldns, although it is
+ * represented as rr_list ... */
+
+ int errors = 0;
+
+ ldns_rr *rr = ldns_rr_list_rr(rr_set, 0);
+ assert(rr);
+ assert(rrset);
+
+ /* compare headers */
+
+ if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) {
+ char *tmp_dname = knot_dname_to_str(rrset->owner);
+ diag("RRSet owner names differ in length");
+ diag("ldns: %d, knot: %d", ldns_rdf_size(ldns_rr_owner(rr)),
+ rrset->owner->size);
+ diag("%s", tmp_dname);
+ diag("%s", ldns_rdf_data(ldns_rr_owner(rr)));
+ free(tmp_dname);
+ errors++;
+ }
+
+ if (compare_wires_simple(rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)),
+ rrset->owner->size) != 0) {
+ diag("RRSet owner wireformats differ");
+ diag("%s \\w %s\n", rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)));
+ errors++;
+ }
+
+ if (rrset->type != ldns_rr_get_type(rr)) {
+ diag("RRset types differ");
+ diag("knot type: %d Ldns type: %d", rrset->type,
+ ldns_rr_get_type(rr));
+ errors++;
+ }
+
+ if (rrset->rclass != ldns_rr_get_class(rr)) {
+ diag("RRset classes differ");
+ errors++;
+ }
+
+ if (rrset->ttl != ldns_rr_ttl(rr)) {
+ diag("RRset TTLs differ");
+ diag("knot: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr));
+ errors++;
+ }
+
+ /* compare rdatas */
+
+ if (rrset->rdata == NULL) {
+ diag("RRSet has no RDATA!");
+ return errors;
+ }
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+
+ int i = 0;
+
+ while ((rr = ldns_rr_list_pop_rr(rr_set))) {
+ assert(rr);
+
+ if (compare_rr_rdata(tmp_rdata, rr, rrset->type) != 0) {
+ diag("Rdata differ");
+ return 1;
+ }
+
+ tmp_rdata = tmp_rdata->next;
+ i++;
+ }
+
+//// if (check_rdata) {
+//// if (compare_rr_rdata(rrset->rdata, rr, rrset->type) != 0) {
+//// diag("Rdata differ");
+//// errors++;
+//// }
+//// }
+
+ return errors;
+}
+
+int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets,
+ ldns_rr_list *rrlist, int count)
+{
+ int errors = 0;
+
+ /* There are no rrsets currenty. Everything is just rr */
+
+ ldns_rr_list *rr_set = NULL;
+
+ ldns_rr_list_sort(rrlist);
+
+ if (count < 0) {
+ return 0;
+ }
+
+ for (int i = 0; i < count ; i++) {
+ /* normally ldns_pop_rrset or such should be here */
+
+ rr_set = ldns_rr_list_pop_rrset(rrlist);
+ /* Get one rr from list. */
+ ldns_rr *rr = ldns_rr_list_rr(rr_set, 0);
+ assert(rr);
+
+ if (rr_set == NULL) {
+ diag("Ldns and knot structures have different "
+ "counts of rrsets.");
+ diag("knot: %d ldns: %d",
+ count, (count - 1) - i);
+ return -1;
+ }
+
+// diag("RRset from ldns is %d long", ldns_rr_list_rr_count(rr_set));
+
+// diag("Got type from ldns: %d (%d)\n", ldns_rr_get_type(rr), i);
+
+ int j = 0;
+ for (j = 0; j < count; j++) {
+// diag("Got type from knot: %d\n", rrsets[j]->type);
+ if (rrsets[j]->type == ldns_rr_get_type(rr) &&
+ rrsets[j]->owner->size ==
+ ldns_rdf_size(ldns_rr_owner(rr)) &&
+ (compare_wires_simple(ldns_rdf_data(ldns_rr_owner(rr)), rrsets[j]->owner->name,
+ rrsets[j]->owner->size) == 0)) {
+ errors += compare_rrset_w_ldns_rr(rrsets[j],
+ rr_set, 1);
+ break;
+ }
+ }
+ if (j == count) {
+ diag("There was no RRSet of the same type!");
+// errors++;
+ }
+ }
+
+ return errors;
+}
+
+int check_packet_w_ldns_packet(knot_packet_t *packet,
+ ldns_pkt *ldns_packet,
+ int check_header,
+ int check_question,
+ int check_body,
+ int check_edns)
+{
+ int errors = 0;
+ if (check_header) {
+// if (packet->header.id != ldns_pkt_id(ldns_packet)) {
+// diag("response ID does not match - %d %d",
+// packet->header.id,
+// ldns_pkt_id(ldns_packet));
+// errors++;
+// }
+
+ /* qdcount is always 1 in knot's case */
+
+ /* TODO check flags1 and flags2 - no API for that,
+ * write my own */
+
+ if (packet->header.ancount !=
+ ldns_pkt_ancount(ldns_packet)) {
+ diag("Answer RRSet count wrongly converted");
+ errors++;
+ }
+
+ if (packet->header.nscount !=
+ ldns_pkt_nscount(ldns_packet)) {
+ diag("Authority RRSet count wrongly converted.\n"
+ "got %d should be %d",
+ packet->header.nscount,
+ ldns_pkt_nscount(ldns_packet));
+ errors++;
+ }
+
+ /* - 1 because ldns does not include OPT_RR to additional "
+ "section */
+ int minus = (!ldns_pkt_edns_version(ldns_packet)) ? 1 : 0;
+// int minus = 0;
+
+ if ((packet->header.arcount - minus) !=
+ ldns_pkt_arcount(ldns_packet)) {
+ diag("Additional RRSet count wrongly converted.\n"
+ "got %d should be %d",
+ packet->header.arcount,
+ ldns_pkt_arcount(ldns_packet));
+ errors++;
+ }
+
+ /*!< \todo Check OPT RR! */
+
+ if (errors) {
+ return errors;
+ }
+ }
+ /* Header checked */
+
+ /* Question section */
+
+ int ret = 0;
+ if (check_question) {
+ knot_rrset_t *question_rrset =
+ knot_rrset_new(packet->
+ question.qname,
+ packet->
+ question.qtype,
+ packet->
+ question.qclass,
+ 3600);
+
+ if ((ret = compare_rrset_w_ldns_rr(question_rrset,
+ ldns_pkt_question(ldns_packet), 0)) != 0) {
+ diag("Question rrsets wrongly converted");
+ errors++;
+ }
+ knot_rrset_free(&question_rrset);
+ }
+
+ if (check_body) {
+
+ /* other RRSets */
+
+ if ((ret =
+ compare_rrsets_w_ldns_rrlist(packet->answer,
+ ldns_pkt_answer(ldns_packet),
+ knot_packet_answer_rrset_count(packet))) != 0) {
+ diag("Answer rrsets wrongly converted");
+ errors++;
+ }
+
+
+
+ if ((ret = compare_rrsets_w_ldns_rrlist(packet->authority,
+ ldns_pkt_authority(ldns_packet),
+ knot_packet_authority_rrset_count(packet))) != 0) {
+ diag("Authority rrsets wrongly converted - %d", ret);
+ errors++;
+ }
+
+ /* We don't want to test OPT RR, which is the last rrset
+ * in the additional section */
+
+ if ((ret = compare_rrsets_w_ldns_rrlist(packet->additional,
+ ldns_pkt_additional(ldns_packet),
+ knot_packet_additional_rrset_count(packet) - 1)) != 0) {
+ diag("Additional rrsets wrongly converted");
+ errors++;
+ }
+
+ }
+
+ if (check_edns) {
+
+ /* OPT RR */
+
+ if (ldns_pkt_edns(ldns_packet)) {
+ /* if (packet->edns_packet == NULL) {
+ diag("ldns has edns section, knot has not");
+ return 1;
+ } */
+
+ knot_opt_rr_t *opt = &(packet->opt_rr);
+
+ if (ldns_pkt_edns_udp_size(ldns_packet) !=
+ knot_edns_get_payload(opt)) {
+ diag("Payloads in EDNS are different");
+ errors++;
+ }
+
+ if (ldns_pkt_edns_version(ldns_packet) !=
+ knot_edns_get_version(opt)) {
+ diag("Versions in EDNS are different");
+ errors++;
+ }
+
+ if (ldns_pkt_edns_extended_rcode(ldns_packet) !=
+ knot_edns_get_ext_rcode(opt)) {
+ diag("Extended rcodes in EDNS are different");
+ errors++;
+ }
+
+ /* TODO parse flags do bit, z value ... */
+ }
+ }
+
+ return errors;
+}
+#endif
+
+extern knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset);
+extern knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname);
+
+/* Converts knot_rrset_t to knot_opt_rr */
+static knot_opt_rr_t *opt_rrset_to_opt_rr(knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ knot_opt_rr_t *opt_rr = knot_edns_new();
+ assert(opt_rr);
+
+ knot_edns_set_payload(opt_rr, rrset->rclass);
+
+ knot_edns_set_ext_rcode(opt_rr, rrset->ttl);
+
+ /* TODO rdata? mostly empty, I guess, but should be done */
+
+ return opt_rr;
+}
+
+knot_packet_t *packet_from_test_response(test_response_t *test_packet)
+{
+ knot_rrset_t *parsed_opt = NULL;
+
+ for (int j = 0; j < test_packet->arcount; j++) {
+ if (test_packet->additional[j]->type ==
+ KNOT_RRTYPE_OPT) {
+ parsed_opt =
+ rrset_from_test_rrset(
+ test_packet->additional[j]);
+ assert(parsed_opt);
+ break;
+ }
+ }
+
+ knot_opt_rr_t *opt_rr = NULL;
+ if (parsed_opt != NULL) {
+ opt_rr =
+ opt_rrset_to_opt_rr(parsed_opt);
+ assert(opt_rr);
+ } else {
+ opt_rr = NULL;
+ }
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ knot_packet_set_max_size(packet, 1024 * 10);
+
+ if (opt_rr != NULL) {
+ packet->opt_rr = *opt_rr;
+ }
+
+ packet->header.id = test_packet->id;
+ packet->header.qdcount = test_packet->qdcount;
+
+ packet->question.qname = dname_from_test_dname(test_packet->qname);
+ packet->size += test_packet->qname->size;
+ packet->question.qtype = test_packet->qtype;
+ packet->question.qclass = test_packet->qclass;
+
+ packet->size += 4;
+
+ packet->answer =
+ malloc(sizeof(knot_rrset_t *) * test_packet->ancount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->ancount; j++) {
+ if (&(test_packet->answer[j])) {
+ packet->answer[packet->an_rrsets++] =
+ rrset_from_test_rrset(test_packet->answer[j]);
+ }
+ }
+
+ packet->authority =
+ malloc(sizeof(knot_rrset_t *) * test_packet->nscount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->nscount; j++) {
+ if (&(test_packet->authority[j])) {
+ packet->authority[packet->ns_rrsets++] =
+ rrset_from_test_rrset(test_packet->authority[j]);
+ }
+ }
+
+ packet->authority =
+ malloc(sizeof(knot_rrset_t *) * test_packet->arcount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->arcount; j++) {
+ if (&(test_packet->additional[j])) {
+ if (test_packet->additional[j]->type ==
+ KNOT_RRTYPE_OPT) {
+ continue;
+ }
+ packet->additional[packet->ar_rrsets++] =
+ rrset_from_test_rrset(test_packet->additional[j]);
+ }
+ }
+
+ return packet;
+}
+
+static int test_packet_parse_from_wire(list raw_response_list)
+{
+#ifdef TEST_WITH_LDNS
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n ,raw_response_list) {
+ test_raw_packet_t *raw_packet = (test_raw_packet_t *)n;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ int ret = 0;
+ if ((ret =
+ knot_packet_parse_from_wire(packet, raw_packet->data,
+ raw_packet->size, 0)) !=
+ KNOT_EOK) {
+ diag("Warning: could not parse wire! "
+ "(might be caused by malformed dump) - "
+ "knot error: %s", knot_strerror(ret));
+// hex_print(raw_packet->data,
+// raw_packet->size);
+ continue;
+ }
+
+ ldns_pkt *ldns_packet = NULL;
+
+ if (ldns_wire2pkt(&ldns_packet, raw_packet->data,
+ raw_packet->size) != LDNS_STATUS_OK) {
+ diag("Could not parse wire using ldns");
+ diag("%s",
+ ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet,
+ raw_packet->data,
+ raw_packet->size)));
+ return 0;
+ }
+
+ if (check_packet_w_ldns_packet(packet, ldns_packet, 1,
+ 1, 1, 1) != 0) {
+ diag("Wrongly created packet");
+ errors++;
+ }
+
+ ldns_pkt_free(ldns_packet);
+ knot_packet_free(&packet);
+ }
+
+ return (errors == 0);
+#endif
+#ifndef TEST_WITH_LDNS
+ diag("Enable ldns to test this feature");
+ return 0;
+#endif
+}
+
+static int test_packet_to_wire(list raw_response_list)
+{
+#ifdef TEST_WITH_LDNS
+ int errors = 0;
+ /*!< \todo test queries too! */
+// /* We'll need data from both lists. */
+// test_packet_t **test_packets = NULL;
+// uint test_packet_count = 0;
+// node *n = NULL;
+// WALK_LIST(n, response_list) {
+// test_packet_count++;
+// }
+
+// test_packets =
+// malloc(sizeof(test_packet_t *) * test_packet_count);
+// assert(test_packets);
+// int i = 0;
+// WALK_LIST(n, response_list) {
+// test_packets[i++] = (test_response_t *)n;
+// }
+
+// test_raw_packet_t **test_packets = NULL;
+// uint test_packet_count = 0;
+// n = NULL;
+// WALK_LIST(n, raw_response_list) {
+// test_packet_count++;
+// }
+
+// test_packets =
+// malloc(sizeof(test_raw_packet_t *) * test_packet_count);
+// assert(test_packets);
+// i = 0;
+// WALK_LIST(n, raw_response_list) {
+// test_packets[i++] = (test_raw_packet_t *)n;
+// }
+
+// assert(test_response_count == test_packet_count);
+ node *n = NULL;
+ WALK_LIST(n, raw_response_list) {
+ /* Create packet from raw response. */
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ test_raw_packet_t *raw_packet = (test_raw_packet_t *)n;
+ if (knot_packet_parse_from_wire(packet, raw_packet->data,
+ raw_packet->size, 0) !=
+ KNOT_EOK) {
+ diag("Warning: could not parse wire! "
+ "(might be caused be malformed dump)");
+ continue;
+ }
+ knot_packet_set_max_size(packet, 1024 * 10);
+ /* Use this packet to create wire */
+ uint8_t *wire = NULL;
+ size_t size = 0;
+ if (knot_packet_to_wire(packet, &wire ,&size) != KNOT_EOK) {
+ diag("Could not convert packet to wire");
+ }
+ /* Create ldns packet from created wire */
+ ldns_pkt *ldns_packet = NULL;
+
+ if (ldns_wire2pkt(&ldns_packet, wire,
+ size) != LDNS_STATUS_OK) {
+ diag("Could not parse wire using ldns");
+ /*!< \todo get rid of this */
+ diag("%s",
+ ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet,
+ wire,
+ size)));
+ return 0;
+ }
+
+ if (check_packet_w_ldns_packet(packet, ldns_packet, 1, 1, 1,
+ 1) != 0) {
+ diag("Packet wrongly converted to wire!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+ ldns_pkt_free(ldns_packet);
+ }
+
+ return (errors == 0);
+#endif
+#ifndef TEST_WITH_LDNS
+ diag("Enable ldns to test this feature!");
+ return 0;
+#endif
+}
+
+static const uint KNOT_PACKET_TEST_COUNT = 2;
+
+static int packet_tests_count(int argc, char *argv[])
+{
+ return KNOT_PACKET_TEST_COUNT;
+}
+
+static int packet_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+ int res = 0;
+ todo();
+ ok(res = test_packet_parse_from_wire(data->raw_packet_list),
+ "packet: from wire");
+ diag("Resolve issue with arcount.");
+ endtodo;
+// skip(!res, 1);
+ ok(test_packet_to_wire(data->raw_packet_list), "packet: to wire");
+// endskip;
+
+ return 1;
+}
+
diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.h b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h
new file mode 100644
index 0000000..c0e0479
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_PACKET_REALDATA_TESTS_H_
+#define _KNOTD_PACKET_REALDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api packet_tests_api;
+
+#endif /* _KNOTD_PACKET_REALDATA_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c
new file mode 100644
index 0000000..f4ba64c
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c
@@ -0,0 +1,329 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdlib.h>
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/rdata.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "libknot/util/error.h"
+
+static int knot_rdata_tests_count(int argc, char *argv[]);
+static int knot_rdata_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rdata_tests_api = {
+ "DNS library - rdata", //! Unit name
+ &knot_rdata_tests_count, //! Count scheduled tests
+ &knot_rdata_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+extern int check_domain_name(const knot_dname_t *dname,
+ const test_dname_t *test_dname);
+
+extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count);
+
+/*!
+ * \brief Checks if all RDATA items in the given RDATA structure are correct.
+ *
+ * \return Number of errors encountered. Error is either if some RDATA item
+ * is not set (i.e. NULL) or if it has other than the expected value.
+ */
+static int check_rdata(const knot_rdata_t *rdata,
+ const test_rdata_t *test_rdata)
+{
+ assert(rdata != NULL);
+ assert(test_rdata != NULL);
+
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(test_rdata->type);
+ //note("check_rdata(), RRType: %u", rrtype);
+
+ for (int i = 0; i < desc->length; ++i) {
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ if (check_domain_name(rdata->items[i].dname,
+ test_rdata->items[i].dname) != 0) {
+ errors++;
+ diag("Rdata contains wrong dname item");
+ }
+ break;
+ default:
+ if (test_rdata->items[i].raw_data[0] !=
+ rdata->items[i].raw_data[0]) {
+ diag("Raw rdata in items have different "
+ "sizes!");
+ return 0;
+ }
+
+ errors +=
+ compare_wires_simple(
+ (uint8_t *)test_rdata->items[i].raw_data,
+ (uint8_t *)rdata->items[i].raw_data,
+ (uint)rdata->items[i].raw_data[0]);
+ }
+ }
+ return errors;
+}
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+
+///*!
+// * \brief Tests knot_rdata_set_item().
+// *
+// * \retval > 0 on success.
+// * \retval 0 otherwise.
+// */
+//static int test_rdata_set_item(list rdata_list)
+//{
+// node *n = NULL;
+// WALK_LIST(n, rdata_list) {
+// knot_rdata_t *rdata = knot_rdata_new();
+// assert(rdata);
+// test_rdata_t *test_rdata = (test_rdata_t *)n;
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(test_rdata->type);
+// for (int i = 0; i < test_rdata->count; i++) {
+// knot_rdata_item_t item;
+// if (test_rdata->items[i].type == TEST_ITEM_DNAME) {
+// item.dname =
+// dname_from_test_dname(
+// test_rdata->items[i].dname);
+// } else {
+// item.raw_data = test_rdata->items[i].raw_data;
+// }
+// if (knot_rdata_set_item(rdata, i, item) != 0) {
+// diag("Could not set item, rdata count: %d",
+// rdata->count);
+// return 0;
+// }
+// }
+
+// /* Check that all items are OK */
+// if (check_rdata(rdata, test_rdata) != 0) {
+// return 0;
+// }
+// }
+// return 1;
+//}
+
+static knot_rdata_item_t *items_from_test_items(test_item_t *test_items,
+ size_t count)
+{
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * count);
+ assert(items);
+ for (int i = 0; i < count; i++) {
+ if (test_items[i].type == TEST_ITEM_DNAME) {
+ items[i].dname =
+ dname_from_test_dname(test_items[i].dname);
+ } else {
+ items[i].raw_data = test_items[i].raw_data;
+ }
+ }
+
+ return items;
+}
+
+static int test_rdata_set_items(list rdata_list)
+{
+ int errors = 0;
+
+ // check error return values
+ knot_rdata_t *rdata = knot_rdata_new();
+ assert(rdata);
+
+ node *n = NULL;
+ WALK_LIST(n, rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ knot_rdata_t *rdata = knot_rdata_new();
+
+ /* create dnslib items from tests items. */
+ knot_rdata_item_t *items =
+ items_from_test_items(test_rdata->items,
+ test_rdata->count);
+
+ assert(items);
+ assert(test_rdata->count > 0);
+ assert(rdata->items == NULL);
+
+ if (knot_rdata_set_items(rdata, items,
+ test_rdata->count) != 0) {
+ diag("Could not set items!");
+ errors++;
+ }
+
+ if (check_rdata(rdata, test_rdata) != 0) {
+ diag("Wrong rdata after knot_rdata_set_items!");
+ errors++;
+ }
+
+ knot_rdata_free(&rdata);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_get_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_get_item(list rdata_list)
+{
+ node *n = NULL;
+ WALK_LIST(n, rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ knot_rdata_t *rdata = knot_rdata_new();
+ assert(rdata);
+ knot_rdata_item_t *items =
+ items_from_test_items(test_rdata->items,
+ test_rdata->count);
+ assert(knot_rdata_set_items(rdata, items,
+ test_rdata->count) == 0);
+ knot_rdata_item_t *new_items =
+ malloc(sizeof(knot_rdata_item_t) * test_rdata->count);
+ for (int i = 0; i < test_rdata->count; i++) {
+ knot_rdata_item_t *item =
+ knot_rdata_get_item(rdata, i);
+ if (item == NULL) {
+ diag("Could not get item");
+ return 0;
+ }
+ new_items[i] = *item;
+ }
+
+ knot_rdata_free(&rdata);
+ free(items);
+
+ knot_rdata_t *new_rdata = knot_rdata_new();
+ assert(new_rdata);
+ assert(knot_rdata_set_items(new_rdata,
+ new_items,
+ test_rdata->count) == 0);
+
+ if (check_rdata(new_rdata, test_rdata) != 0) {
+ diag("Wrong rdata created using rdata_get_item");
+ return 0;
+ }
+
+ knot_rdata_free(&new_rdata);
+ free(new_items);
+ }
+
+ return 1;
+}
+
+//static int test_rdata_wire_size()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// int counted_size = knot_rdata_wire_size(rdata,
+// knot_rrtype_descriptor_by_type(i)->wireformat);
+// if (size != counted_size) {
+// diag("Wrong wire size computed (type %d):"
+// " %d (should be %d)",
+// i, counted_size, size);
+// ++errors;
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RDATA_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_count(int argc, char *argv[])
+{
+ return KNOT_RDATA_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+ int res = 0,
+ res_final = 1;
+
+ ok(res = test_rdata_set_items(data->rdata_list),
+ "rdata: set items all at once");
+ res_final *= res;
+
+ ok(res = test_rdata_get_item(data->rdata_list),
+ "rdata: get item");
+ res_final *= res;
+
+// ok(res = test_rdata_set_item(data->rdata_list),
+// "rdata: set items one-by-one");
+// res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h
new file mode 100644
index 0000000..570b2b1
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h
@@ -0,0 +1,53 @@
+/*!
+ * \file rdata_tests.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains unit tests for RDATA (knot_rdata_t) and RDATA item
+ * (knot_rdata_item_t) structures.
+ *
+ * Contains tests for:
+ * - creating empty RDATA structure with or without reserved space.
+ * - setting RDATA items one-by-one
+ * - setting RDATA items all at once
+ *
+ * As for now, the tests use several (TEST_RDATAS) RDATA structures, each
+ * with different number of RDATA items (given by test_rdatas). These are all
+ * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR,
+ * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer
+ * is set properly.
+ *
+ * \todo It may be better to test also some RDATAs with predefined contents,
+ * such as some numbers, some domain name, etc. For this purpose, we'd
+ * need RDATA descriptors (telling the types of each RDATA item within an
+ * RDATA).
+ *
+ * \todo It will be fine to test all possible output values of all functions,
+ * e.g. test whether knot_rdata_get_item() returns NULL when passed an
+ * illegal position, etc.
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_RDATA_TESTS_H_
+#define _KNOTD_RDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rdata_tests_api;
+
+#endif /* _KNOTD_RDATA_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.c b/src/tests/libknot/realdata/libknot/response_tests_realdata.c
new file mode 100644
index 0000000..5bbda36
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "packet_tests_realdata.h"
+#include "knot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/packet/response.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#ifdef TEST_WITH_LDNS
+#include "ldns/packet.h"
+#endif
+
+static int response_tests_count(int argc, char *argv[]);
+static int response_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api response_tests_api = {
+ "DNS library - response", //! Unit name
+ &response_tests_count, //! Count scheduled tests
+ &response_tests_run //! Run scheduled tests
+};
+
+#ifdef TEST_WITH_LDNS
+extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count);
+extern int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr, uint16_t type);
+extern int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset,
+ ldns_rr *rr, char check_rdata);
+extern int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets,
+ ldns_rr_list *rrlist, int count);
+
+extern int check_packet_w_ldns_packet(knot_packet_t *packet,
+ ldns_pkt *ldns_packet,
+ int check_header,
+ int check_question,
+ int check_body,
+ int check_edns);
+#endif
+
+extern knot_packet_t *packet_from_test_response(test_response_t *response);
+
+static int test_response_init_from_query(list query_list)
+{
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, query_list) {
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_t *query =
+ packet_from_test_response((test_response_t *)n);
+ assert(query);
+ knot_packet_set_max_size(response, 1024 * 10);
+ if (knot_response_init_from_query(response,
+ query) != KNOT_EOK) {
+ diag("Could not init response from query!");
+ errors++;
+ }
+ knot_packet_free(&response);
+ knot_packet_free(&query);
+ }
+ return (errors == 0);
+}
+
+//static int test_response_add_opt(list opt_list)
+//{
+// int errors = 0;
+// node *n = NULL;
+// WALK_LIST(n, query_list) {
+// knot_packet_t *response =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// assert(response);
+// knot_opt_rr_t *opt =
+// opt_from_test_opt((test_opt_t *)n);
+// assert(query);
+// if (knot_response_add_opt(response,
+// opt, 1)!= KNOT_EOK) {
+// diag("Could not add OPT RR to response!");
+// errors++;
+// }
+// knot_packet_free(&response);
+// knot_opt_rr_free(&opt);
+// }
+// return (errors == 0);
+//}
+
+extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset);
+
+static int test_response_add_generic(int (*func)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int),
+ list rrset_list)
+{
+ /*!< \todo Now adding only one RRSet at the time, try more, use nodes */
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response,
+ KNOT_PACKET_PREALLOC_RESPONSE * 100);
+ assert(knot_response_init(response) == KNOT_EOK);
+
+ knot_rrset_t *rrset =
+ rrset_from_test_rrset((test_rrset_t *)n);
+ assert(rrset);
+
+ int ret = 0;
+ if ((ret = func(response, rrset, 0, 1, 0)) != KNOT_EOK) {
+ diag("Could not add RRSet to response! Returned: %d",
+ ret);
+ diag("(owner: %s type %s)",
+ ((test_rrset_t *)n)->owner->str,
+ knot_rrtype_to_string((
+ (test_rrset_t *)n)->type));
+ errors++;
+ }
+ knot_packet_free(&response);
+ knot_rrset_deep_free(&rrset, 1, 1, 1);
+ }
+
+ return (errors == 0);
+}
+
+static void test_response_add_rrset(list rrset_list)
+{
+ ok(test_response_add_generic(knot_response_add_rrset_answer,
+ rrset_list),
+ "response: add answer rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_authority,
+ rrset_list),
+ "response: add authority rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_additional,
+ rrset_list),
+ "response: add additional rrset");
+}
+
+static const uint KNOT_response_TEST_COUNT = 4;
+
+static int response_tests_count(int argc, char *argv[])
+{
+ return KNOT_response_TEST_COUNT;
+}
+
+static int response_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+// int res = 0;
+ ok(test_response_init_from_query(data->query_list),
+ "response: init from query");
+ test_response_add_rrset(data->rrset_list);
+ return 1;
+}
diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.h b/src/tests/libknot/realdata/libknot/response_tests_realdata.h
new file mode 100644
index 0000000..731604b
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_PACKET_response_TESTS_H_
+#define _KNOTD_PACKET_response_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api response_tests_api;
+
+#endif /* _KNOTD_PACKET_response_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c
new file mode 100644
index 0000000..cb59f4c
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/realdata/libknot/rrset_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/util/utils.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/debug.h"
+
+static int knot_rrset_tests_count(int argc, char *argv[]);
+static int knot_rrset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rrset_tests_api = {
+ "DNS library - rrset", //! Unit name
+ &knot_rrset_tests_count, //! Count scheduled tests
+ &knot_rrset_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+/* count1 == count2 */
+int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+
+knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset)
+{
+// diag("owner: %s\n", test_rrset->owner->str);
+ knot_dname_t *owner =
+ knot_dname_new_from_wire(test_rrset->owner->wire,
+ test_rrset->owner->size, NULL);
+
+// diag("Created owner: %s (%p) from %p\n", knot_dname_to_str(owner),
+// owner, test_rrset->owner);
+
+ if (!owner) {
+ return NULL;
+ }
+
+ knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+
+ /* Add rdata to rrset. */
+ knot_rdata_t *rdata = knot_rdata_new();
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(test_rrset->type);
+
+ node *n = NULL;
+ WALK_LIST(n, test_rrset->rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ if (test_rdata->count != desc->length) {
+ diag("Malformed RRSet data!");
+ knot_rdata_free(&rdata);
+ return ret;
+ }
+ assert(test_rdata->type == test_rrset->type);
+ /* Add items to the actual rdata. */
+ rdata->items = malloc(sizeof(knot_rdata_item_t) * desc->length);
+ if (rdata->items == NULL) {
+ return NULL;
+ }
+// diag("Rdata type: %s\n", knot_rrtype_to_string(test_rrset->type));
+ for (int i = 0; i < desc->length; i++) {
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+// diag("%p\n", test_rdata->items[i].raw_data);
+ assert(test_rdata->items[i].type == TEST_ITEM_DNAME);
+ rdata->items[i].dname =
+ knot_dname_new_from_wire(test_rdata->items[i].dname->wire,
+ test_rdata->items[i].dname->size,
+ NULL);
+ } else {
+// diag("%p\n", test_rdata->items[i].dname);
+ assert(test_rdata->items[i].type == TEST_ITEM_RAW_DATA);
+ assert(test_rdata->items[i].raw_data != NULL);
+ rdata->items[i].raw_data = test_rdata->items[i].raw_data;
+ }
+ }
+ }
+
+ rdata->next = rdata;
+
+ ret->rdata = rdata;
+
+ return ret;
+}
+
+extern int check_domain_name(knot_dname_t *dname, test_dname_t *test_dname);
+
+int check_rrset(const knot_rrset_t *rrset,
+ const test_rrset_t *test_rrset,
+ int check_rdata, int check_items,
+ int check_rrsigs)
+{
+ /* following implementation should be self-explanatory */
+ int errors = 0;
+
+ if (rrset == NULL) {
+ diag("RRSet not created!");
+ return 1;
+ }
+
+ errors += check_domain_name(rrset->owner, test_rrset->owner);
+
+ if (rrset->type != test_rrset->type) {
+ diag("TYPE wrong: %u (should be: %u)", rrset->type,
+ test_rrset->type);
+ ++errors;
+ }
+
+ if (rrset->rclass != test_rrset->rclass) {
+ diag("CLASS wrong: %u (should be: %u)", rrset->rclass,
+ test_rrset->rclass);
+ ++errors;
+ }
+
+ if (rrset->ttl != test_rrset->ttl) {
+ diag("TTL wrong: %u (should be: %u)", rrset->ttl,
+ test_rrset->ttl);
+ ++errors;
+ }
+
+ if (check_rdata) {
+ /* TODO use rdata_compare */
+ knot_rdata_t *rdata = rrset->rdata;
+
+ if (rdata == NULL) {
+ diag("There are no RDATAs in the RRSet");
+ ++errors;
+ }
+
+ if (rdata != NULL) {
+ while (rdata->next != NULL &&
+ rdata->next != rrset->rdata) {
+ rdata = rdata->next;
+ }
+ if (rdata->next == NULL) {
+ diag("The list of RDATAs is not cyclic!");
+ ++errors;
+ } else {
+ assert(rdata->next == rrset->rdata);
+ }
+ }
+ }
+
+ /* Iterate rrset rdata list and compare items. */
+ if (check_items && rrset->rdata != NULL) {
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+ node *n = NULL;
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+ WALK_LIST(n, test_rrset->rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ for (int i = 0; i < desc->length; i++) {
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ errors += check_domain_name(tmp_rdata->items[i].dname,
+ test_rdata->items[i].dname);
+ } else {
+ assert(tmp_rdata != NULL);
+ errors += compare_wires_simple((uint8_t *)tmp_rdata->items[i].raw_data,
+ (uint8_t *)test_rdata->items[i].raw_data,
+ test_rdata->items[i].raw_data[0]);
+ }
+ }
+ }
+ } else if (check_items && rrset->rdata == NULL) {
+ diag("Could not test items, since rdata is empty!");
+ }
+
+ if (check_rrsigs) {
+ /* there are currently no rrsigs */
+ }
+ return errors;
+}
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+
+static int test_rrset_create(const list rrset_list)
+{
+ int errors = 0;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *rrset =
+ knot_rrset_new(dname_from_test_dname
+ (test_rrset->owner),
+ test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ assert(rrset);
+ errors += check_rrset(rrset, test_rrset, 0, 0, 0);
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_rrset_add_rdata(list rrset_list)
+{
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *tmp_rrset = rrset_from_test_rrset(test_rrset);
+ /* TODO use all the rdata */
+ assert(tmp_rrset->rdata->next = tmp_rrset->rdata);
+ knot_rrset_t *rrset =
+ knot_rrset_new(dname_from_test_dname
+ (test_rrset->owner),
+ test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ assert(rrset);
+ knot_rrset_add_rdata(rrset, tmp_rrset->rdata);
+ errors += check_rrset(rrset, test_rrset, 1, 1, 1);
+ knot_rrset_free(&tmp_rrset);
+ knot_rrset_deep_free(&rrset, 1, 1, 0);
+
+ }
+ return (errors == 0);
+}
+
+static const int KNOT_RRSET_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_count(int argc, char *argv[])
+{
+ return KNOT_RRSET_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+
+ int res = 0,
+ res_final = 1;
+
+ res = test_rrset_create(data->rrset_list);
+ ok(res, "rrset: create");
+ res_final *= res;
+
+ ok(res = test_rrset_add_rdata(data->rrset_list), "rrset: add_rdata");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h
new file mode 100644
index 0000000..cc3b705
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h
@@ -0,0 +1,35 @@
+/*!
+ * \file rrset_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for RRSet (knot_rrset_t) and its API.
+ *
+ * Contains tests for:
+ * -
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_RRSET_TESTS_H_
+#define _KNOTD_RRSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rrset_tests_api;
+
+#endif /* _KNOTD_RRSET_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.c b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c
new file mode 100644
index 0000000..445997f
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c
@@ -0,0 +1,335 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/realdata/libknot/zone_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/zone/zone.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/node.h"
+
+static int knot_zone_tests_count(int argc, char *argv[]);
+static int knot_zone_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tests_api = {
+ "DNS library - zone", //! Unit name
+ &knot_zone_tests_count, //! Count scheduled tests
+ &knot_zone_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset);
+
+static knot_node_t *node_from_test_node(const test_node_t *test_node)
+{
+ knot_dname_t *owner = dname_from_test_dname(test_node->owner);
+ /* TODO parent? */
+ knot_node_t *new_node = knot_node_new(owner, NULL, 0);
+ node *n = NULL;
+ WALK_LIST(n, test_node->rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *rrset = rrset_from_test_rrset(test_rrset);
+ assert(rrset);
+ assert(knot_node_add_rrset(new_node, rrset, 0) == 0);
+ }
+
+ return new_node;
+}
+
+static int test_zone_create(list node_list)
+{
+// knot_dname_t *dname = knot_dname_new_from_wire(
+// test_apex.owner.name, test_apex.owner.size, NULL);
+// assert(dname);
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, node_list) {
+ test_node_t *test_node = (test_node_t *)n;
+ knot_node_t *node = node_from_test_node(test_node);
+ assert(node);
+
+ knot_zone_t *zone = knot_zone_new(node, 0, 0);
+ if (zone == NULL) {
+ diag("Could not create zone with owner: %s\n",
+ test_node->owner->str);
+ errors++;
+ }
+ knot_node_free_rrsets(node, 1);
+ knot_node_free(&node, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+//static int test_zone_add_node(knot_zone_t *zone, int nsec3)
+//{
+// /*
+// * NSEC3 nodes are de facto identical to normal nodes, so there is no
+// * need for separate tests. The only difference is where are they stored
+// * in the zone structure.
+// */
+
+// int errors = 0;
+// int res = 0;
+
+// //note("Good nodes");
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// knot_node_t *node = knot_node_new(&test_nodes_good[i].owner,
+// test_nodes_good[i].parent);
+// if (node == NULL) {
+// diag("zone: Could not create node.");
+// return 0;
+// }
+
+// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node)
+// : knot_zone_add_node(zone, node))) != 0) {
+// diag("zone: Failed to insert node into zone (returned"
+// " %d).", res);
+// knot_node_free(&node, 0);
+// ++errors;
+// }
+// /* TODO check values in the node as well */
+// }
+
+// //note("Bad nodes");
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner,
+// test_nodes_bad[i].parent);
+// if (node == NULL) {
+// diag("zone: Could not create node.");
+// return 0;
+// }
+
+// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node)
+// : knot_zone_add_node(zone, node))) !=
+// KNOT_EBADZONE) {
+// diag("zone: Inserting wrong node did not result in"
+// "proper return value (%d instead of %d).", res,
+// KNOT_EBADZONE);
+// ++errors;
+// }
+// knot_node_free(&node, 0);
+// }
+
+// // check if all nodes are inserted
+// //int nodes = 0;
+// if (!nsec3
+// && !test_zone_check_node(knot_zone_apex(zone), &test_apex)) {
+// diag("zone: Apex of zone not right.");
+//// diag("Apex owner: %s (%p), apex parent: %p\n",
+//// knot_dname_to_str(knot_zone_apex(zone)->owner),
+//// knot_zone_apex(zone)->owner,
+//// knot_zone_apex(zone)->parent);
+//// diag("Should be: owner: %s (%p), parent: %p\n",
+//// knot_dname_to_str(&test_apex.owner),
+//// &test_apex.owner,
+//// test_apex.parent);
+// ++errors;
+// }
+// //++nodes;
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// const knot_node_t *n = ((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_good[i].owner) :
+// knot_zone_find_node(zone, &test_nodes_good[i].owner));
+// if (n == NULL) {
+// diag("zone: Missing node with owner %s",
+// test_nodes_good[i].owner.name);
+// ++errors;
+// continue;
+// }
+
+// if (!test_zone_check_node(n, &test_nodes_good[i])) {
+// diag("zone: Node does not match: owner: %s (should be "
+// "%s), parent: %p (should be %p)",
+// node->owner->name, test_nodes_good[i].owner.name,
+// node->parent, test_nodes_good[i].parent);
+// ++errors;
+// }
+// //++nodes;
+// }
+
+// //note("zone: %d nodes in the zone (including apex)", nodes);
+
+// return (errors == 0);
+//}
+
+//static int test_zone_get_node(knot_zone_t *zone, int nsec3)
+//{
+// int errors = 0;
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// if (((nsec3) ? knot_zone_get_nsec3_node(
+// zone, &test_nodes_good[i].owner)
+// : knot_zone_get_node(zone, &test_nodes_good[i].owner))
+// == NULL) {
+// diag("zone: Node (%s) not found in zone.",
+// (char *)test_nodes_good[i].owner.name);
+// ++errors;
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// if (((nsec3) ? knot_zone_get_nsec3_node(
+// zone, &test_nodes_bad[i].owner)
+// : knot_zone_get_node(zone, &test_nodes_bad[i].owner))
+// != NULL) {
+// diag("zone: Node (%s) found in zone even if it should"
+// "not be there.",
+// (char *)test_nodes_bad[i].owner.name);
+// ++errors;
+// }
+// }
+
+// if (((nsec3)
+// ? knot_zone_get_nsec3_node(NULL, &test_nodes_good[0].owner)
+// : knot_zone_get_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+// diag("zone: Getting node from NULL zone did not result in"
+// "proper return value (NULL)");
+// ++errors;
+// }
+
+// if (((nsec3) ? knot_zone_get_nsec3_node(zone, NULL)
+// : knot_zone_get_node(zone, NULL)) != NULL) {
+// diag("zone: Getting node with NULL owner from zone did not "
+// "result in proper return value (NULL)");
+// ++errors;
+// }
+
+// if (!nsec3 && knot_zone_get_node(zone, &test_apex.owner) == NULL) {
+// diag("zone: Getting zone apex from the zone failed");
+// ++errors;
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_zone_find_node(knot_zone_t *zone, int nsec3)
+//{
+// int errors = 0;
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// if (((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_good[i].owner)
+// : knot_zone_find_node(zone, &test_nodes_good[i].owner))
+// == NULL) {
+// diag("zone: Node (%s) not found in zone.",
+// (char *)test_nodes_good[i].owner.name);
+// ++errors;
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// if (((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_bad[i].owner)
+// : knot_zone_find_node(zone, &test_nodes_bad[i].owner))
+// != NULL) {
+// diag("zone: Node (%s) found in zone even if it should"
+// "not be there.",
+// (char *)test_nodes_bad[i].owner.name);
+// ++errors;
+// }
+// }
+
+// if (((nsec3)
+// ? knot_zone_find_nsec3_node(NULL, &test_nodes_good[0].owner)
+// : knot_zone_find_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+// diag("zone: Finding node from NULL zone did not result in"
+// "proper return value (NULL)");
+// ++errors;
+// }
+
+// if (((nsec3) ? knot_zone_find_nsec3_node(zone, NULL)
+// : knot_zone_find_node(zone, NULL)) != NULL) {
+// diag("zone: Finding node with NULL owner from zone did not "
+// "result in proper return value (NULL)");
+// ++errors;
+// }
+
+// if (!nsec3 && knot_zone_find_node(zone, &test_apex.owner) == NULL) {
+// diag("zone: Finding zone apex from the zone failed");
+// ++errors;
+// }
+
+// return (errors == 0);
+//}
+
+static const int KNOT_ZONE_TEST_COUNT = 1;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_zone_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_zone_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 0;
+
+ test_data_t *data = data_for_knot_tests;
+
+ ok((res = test_zone_create(data->node_list)), "zone: create");
+ res_final *= res;
+
+// skip(!res, 6);
+
+// ok((res = test_zone_add_node(zone, 0)), "zone: add node");
+// res_final *= res;
+
+// skip(!res, 2);
+
+// skip(!res, 1);
+
+// ok((res = test_zone_find_node(zone, 0)), "zone: find node");
+// res_final *= res;
+
+// endskip; // get node failed
+
+// endskip; // add node failed
+
+// ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node");
+// res_final *= res;
+
+// skip(!res, 2);
+
+// skip(!res, 1);
+
+// ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node");
+// res_final *= res;
+
+// endskip; // get nsec3 node failed
+
+// endskip; // add nsec3 node failed
+
+// endskip; // create failed
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.h b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h
new file mode 100644
index 0000000..5539709
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_ZONE_TESTS_H_
+#define _KNOTD_ZONE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tests_api;
+
+#endif /* _KNOTD_ZONE_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c
new file mode 100644
index 0000000..96d1517
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 "tests/libknot/realdata/libknot/zonedb_tests_realdata.h"
+
+
+static int zonedb_tests_count(int argc, char *argv[]);
+static int zonedb_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zonedb_tests_api = {
+ "Zone database", //! Unit name
+ &zonedb_tests_count, //! Count scheduled tests
+ &zonedb_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int zonedb_tests_count(int argc, char *argv[])
+{
+ return 0;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int zonedb_tests_run(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h
new file mode 100644
index 0000000..0c4f8ef
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef _KNOTD_ZONEDB_TESTS_H_
+#define _KNOTD_ZONEDB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zonedb_tests_api;
+
+#endif /* _KNOTD_ZONEDB_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.c b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c
new file mode 100644
index 0000000..71a9c3d
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c
@@ -0,0 +1,1300 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "common/libtap/tap.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/util/descriptor.h"
+
+#include "tests/libknot/realdata/parsed_data.rc"
+#include "tests/libknot/realdata/raw_data.rc"
+TREE_DEFINE(test_node, avl);
+
+/* Virtual I/O over memory. */
+static int mem_read(void *dst, size_t n, const char **src,
+ unsigned *remaining)
+{
+// printf("reading %u\n", n);
+ if (n > *remaining) {
+ return 0;
+ }
+
+
+ memcpy(dst, *src, n);
+ *src += n;
+ *remaining -= n;
+// printf("remaining %u\n", *remaining);
+ return 1;
+}
+
+static int load_raw_packets(test_data_t *data, uint32_t *count,
+ const char *src, unsigned src_size)
+{
+
+ uint16_t tmp_size = 0;
+
+ /* Packets are stored like this: [size][packet_data]+ */
+
+ if(!mem_read(count, sizeof(uint32_t), &src, &src_size)) {
+ return -1;
+ }
+
+ for (int i = 0; i < *count; i++) {
+ uint16_t query = 0;
+ if (!mem_read(&query, sizeof(query), &src, &src_size)) {
+ return -1;
+ }
+
+ if(!mem_read(&tmp_size, sizeof(uint16_t), &src, &src_size)) {
+ return -1;
+ }
+
+ test_raw_packet_t *packet = malloc(sizeof(test_raw_packet_t));
+
+
+ packet->size = tmp_size;
+ packet->data = malloc(sizeof(uint8_t) * (tmp_size));
+ if(!mem_read(packet->data,
+ sizeof(uint8_t) * tmp_size, &src, &src_size)) {
+ return -1;
+ }
+
+ if (query) {
+ add_tail(&data->raw_query_list, (void *)packet);
+ } else {
+ add_tail(&data->raw_response_list, (void *)packet);
+ }
+
+ test_raw_packet_t *new_packet =
+ malloc(sizeof(test_raw_packet_t));
+ assert(new_packet);
+ new_packet->data = packet->data;
+ new_packet->size = packet->size;
+
+ add_tail(&data->raw_packet_list, (void *)new_packet);
+ }
+
+ return 0;
+}
+
+/* Returns size of type where avalailable */
+size_t wireformat_size_load(uint wire_type)
+{
+ switch(wire_type) {
+ case KNOT_RDATA_WF_BYTE:
+ return 1;
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ return 2;
+ break;
+ case KNOT_RDATA_WF_LONG:
+ return 4;
+ break;
+ case KNOT_RDATA_WF_A:
+ return 4;
+ break;
+ case KNOT_RDATA_WF_AAAA:
+ return 16;
+ break;
+ default: /* unknown size */
+ return 0;
+ break;
+ } /* switch */
+}
+
+static int add_label(uint8_t **labels, const uint8_t label,
+ uint *label_count)
+{
+ void *ret = realloc(*labels, sizeof(uint8_t) * (*label_count + 1));
+ if (ret == NULL) {
+ return -1;
+ }
+
+ *labels = ret;
+ (*labels)[(*label_count)++] = label;
+
+ return 0;
+}
+/* Dnames are stored label by label in the dump */
+/* TODO STRING AS WELL */
+static test_dname_t *load_test_dname(const char **src,
+ unsigned *src_size)
+{
+ test_dname_t *ret = malloc(sizeof(test_dname_t));
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ ret->size = 0;
+ ret->str = NULL;
+ ret->labels = NULL;
+ ret->wire = NULL;
+ ret->label_count = 0;
+ ret->next = NULL;
+ ret->prev = NULL;
+
+ uint8_t label_size = 0;
+ uint8_t *label_wire = NULL;
+ uint8_t *labels = NULL;
+ char *dname_str = NULL;
+ uint label_count = 0;
+ uint dname_length = 0;
+ do {
+ /* Read label size */
+ if (!mem_read(&label_size,
+ sizeof(uint8_t),
+ src,
+ src_size)) {
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+
+// diag("%d", label_size);
+
+ add_label(&labels, ret->size, &label_count);
+
+ dname_length += label_size + 1;
+
+ label_wire = malloc(sizeof(uint8_t) * (label_size + 2));
+
+ if (label_wire == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret);
+ return NULL;
+ }
+
+ label_wire[0] = label_size;
+
+ /* Read label wire */
+ if (!mem_read(label_wire + 1,
+ sizeof(uint8_t) *
+ label_size,
+ src,
+ src_size)) {
+ free(label_wire);
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+
+ label_wire[label_size + 1] = '\0';
+
+ dname_str = malloc(sizeof(char) * (label_size + 2));
+
+ if (label_size != 0) {
+ /* n - 1 : . */
+ dname_str[label_size] = '.';
+ dname_str[label_size + 1] = '\0';
+
+ memcpy(dname_str, label_wire + 1, label_size);
+ }
+
+ if (ret->size == 0) {
+ ret->wire = malloc(sizeof(uint8_t) * (label_size + 2));
+ if (ret->wire == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret);
+ return NULL;
+ }
+
+ memcpy(ret->wire, label_wire, label_size + 2);
+
+ if (label_size != 0) {
+
+ ret->str =
+ malloc(sizeof(char) * (label_size + 2));
+ if (ret->str == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret);
+ return NULL;
+ }
+
+ memcpy(ret->str, dname_str, label_size + 2);
+ }
+
+ ret->size = label_size + 2;
+ } else {
+ /* Concatenate */
+ void *p = realloc(ret->wire,
+ ret->size + (label_size + 2));
+ if (p == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret->labels);
+ free(ret);
+ return NULL;
+ }
+ ret->wire = p;
+
+ /* TODO Safe concat? But I set the values myself, right? */
+ /* or maybe memcpy... */
+ strcat((char *)ret->wire, (char *)label_wire);
+ assert(ret->wire);
+
+
+ if (label_size != 0) {
+
+ p = realloc(ret->str,
+ ret->size + (label_size + 2));
+ if (p == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret->str);
+ free(ret->labels);
+ free(ret);
+ return NULL;
+ }
+ ret->str = p;
+
+ strcat(ret->str, dname_str);
+ assert(ret->str);
+ }
+
+ ret->size += label_size + 2;
+ }
+
+ free(label_wire);
+ free(dname_str);
+
+ } while (label_size != 0);
+
+ /*!< \warning even wireformat is ended with 0 every time !!! */
+
+ /* Root domain */
+// if (ret->size == 0) {
+// assert(ret->wire == NULL);
+
+// ret->wire = malloc(sizeof(uint8_t) * 1);
+// if (ret->wire == NULL) {
+// ERR_ALLOC_FAILED;
+// free(ret);
+// return NULL;
+// }
+
+// ret->wire[0] = '\0';
+
+// ret->labels = malloc(sizeof(uint8_t) * 1);
+// if (ret->labels == NULL) {
+// ERR_ALLOC_FAILED;
+// free(ret->wire);
+// free(ret);
+// return NULL;
+// }
+
+// ret->labels[0] = '\0';
+// ret->label_count = 1;
+// }
+
+// printf("OK: %s (%d)\n",ret->str, ret->size);
+
+ ret->labels = labels;
+ ret->size = ret->size - (label_count);
+ ret->label_count = --label_count;
+ ret->next = NULL;
+ ret->prev = NULL;
+
+ assert(ret != NULL);
+
+ return ret;
+}
+
+/*!
+ * \brief Reads dname label by label
+ */
+static test_rdata_t *load_response_rdata(uint16_t type,
+ const char **src,
+ unsigned *src_size)
+{
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "reading rdata for type: %s\n",
+ knot_rrtype_to_string(type));
+#endif
+ /*
+ * Binary format of rdata is as following:
+ * [total_length(except for some types) - see below][rdata_item]+
+ * Dname items are read label by label
+ */
+
+ test_rdata_t *rdata = malloc(sizeof(test_rdata_t));
+
+ CHECK_ALLOC_LOG(rdata, NULL);
+
+ rdata->count = 0;
+ rdata->items = NULL;
+ rdata->type = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+
+ rdata->type = type;
+
+ test_item_t *items =
+ malloc(sizeof(test_item_t) * desc->length);
+
+ if (items == NULL) {
+ ERR_ALLOC_FAILED;
+ free(rdata);
+ return NULL;
+ }
+
+ /* TODO consider realloc */
+
+ uint16_t total_raw_data_length = 0;
+ uint8_t raw_data_length;
+
+ /*
+ * These types have no length, unfortunatelly (python library
+ * does not provide this)
+ */
+ /* TODO the are more types with no length for sure ... */
+
+ if (type != KNOT_RRTYPE_A &&
+ type != KNOT_RRTYPE_NS &&
+ type != KNOT_RRTYPE_AAAA) {
+ if (!mem_read(&total_raw_data_length,
+ sizeof(total_raw_data_length), src, src_size)) {
+ free(rdata);
+ free(items);
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+ }
+
+ size_t total_read = 0;
+
+ int i;
+
+ /*
+ * TODO save number of items
+ * in the dump - of minor importance, however
+ */
+ for (i = 0; i < desc->length; i++) {
+ if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) {
+ unsigned tmp_remaining = *src_size;
+ items[i].dname = load_test_dname(src, src_size);
+
+ if (items[i].dname == NULL) {
+ fprintf(stderr, "Could not load DNAME!\n");
+ free(rdata);
+ free(items);
+
+ /* TODO something like Marek's purge */
+
+ return NULL;
+ }
+
+// diag("Created DNAME %p item: %d %s %s\n",
+// items[i].dname, i, knot_rrtype_to_string(type),
+// items[i].dname->str);
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_DNAME;
+ items[i].raw_data = NULL;
+ total_read += tmp_remaining - *src_size;
+ } else {
+ if (desc->wireformat[i] ==
+ KNOT_RDATA_WF_BINARYWITHLENGTH) {
+ if (!mem_read(&raw_data_length,
+ sizeof(raw_data_length), src, src_size)) {
+ return NULL;
+ }
+
+ total_read++;
+
+ items[i].raw_data =
+ malloc(sizeof(uint8_t) *
+ (raw_data_length + 3));
+
+ items[i].raw_data[0] =
+ (uint16_t) raw_data_length + 1;
+
+ /* let's store the length again */
+
+ ((uint8_t *)items[i].raw_data)[2] =
+ raw_data_length;
+
+ if (!mem_read(((uint8_t *)
+ items[i].raw_data) + 3,
+ sizeof(uint8_t) * (raw_data_length),
+ src, src_size)) {
+ fprintf(stderr, "Wrong read!\n");
+ return NULL;
+ }
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_RAW_DATA;
+ items[i].dname = NULL;
+ total_read += sizeof(uint8_t) * raw_data_length;
+/* printf("read len (from wire): %d\n",
+ items[i].raw_data[0]);
+ hex_print((char *)items[i].raw_data + 1,
+ items[i].raw_data[0]);
+ */
+ } else {
+ /* Other type than dname or BINARYWITHLENGTH */
+ /* Set dname to NULL */
+ items[i].dname = NULL;
+
+ uint16_t size_fr_desc =
+ (uint16_t)
+ wireformat_size_load(desc->wireformat[i]);
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "reading %d\n", size_fr_desc);
+#endif
+
+ if (size_fr_desc == 0) { /* unknown length */
+/* size_fr_desc = wireformat_size_n(type,
+ items,
+ i);
+ */
+ if ((i != desc->length - 1) &&
+ desc->wireformat[i] !=
+ KNOT_RDATA_WF_TEXT ) {
+ fprintf(stderr,
+ "I dont know how "
+ "to parse this type: %d\n",
+ type);
+ return NULL;
+ } else {
+ size_fr_desc =
+ total_raw_data_length -
+ total_read;
+ if (desc->wireformat[i] ==
+ KNOT_RDATA_WF_TEXT) {
+ break;
+ }
+
+// fprintf(stderr,
+// "Guessed size: %d"
+// " for type: %s"
+// " and index: %d\n",
+// size_fr_desc,
+// knot_rrtype_to_string(type),
+// i);
+ }
+ }
+
+ items[i].raw_data =
+ malloc(sizeof(uint8_t) * size_fr_desc + 2);
+
+// diag("creating raw_data for item %d type %s %p\n",
+// i, knot_rrtype_to_string(type),
+// items[i].raw_data);
+
+ if (items[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ free(rdata);
+ free(items);
+ return NULL;
+ }
+
+ items[i].raw_data[0] = size_fr_desc;
+
+ if (!mem_read(items[i].raw_data + 1,
+ size_fr_desc,
+ src, src_size)) {
+ fprintf(stderr, "Wrong read\n!");
+ return NULL;
+ }
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_RAW_DATA;
+ items[i].dname = NULL;
+ total_read += size_fr_desc;
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr,
+ "read len (from descriptor): %d\n",
+ items[i].raw_data[0]);
+/* hex_print((char *)items[i].raw_data + 1,
+ items[i].raw_data[0]); */
+
+ if (desc->zoneformat[i] ==
+ KNOT_RDATA_ZF_ALGORITHM) {
+ hex_print((char *)items[i].raw_data,
+ items[i].raw_data[0] + 2);
+ } else {
+ hex_print((char *)items[i].raw_data,
+ items[i].raw_data[0] + 2);
+ }
+#endif
+ }
+ }
+ }
+
+/* if (knot_rdata_set_items(rdata, items, i) != 0) {
+ diag("Error: could not set items\n");
+ return NULL;
+ } */
+
+ rdata->items = items;
+
+ return rdata;
+}
+
+static test_rrset_t *load_response_rrset(const char **src, unsigned *src_size,
+ char is_question)
+{
+ test_rrset_t *rrset = NULL;
+ uint16_t rrset_type = 0;
+ uint16_t rrset_class = 0;
+ uint32_t rrset_ttl = 0;
+
+ /* Each rrset will only have one rdata entry */
+
+ /*
+ * RRSIGs will be read as separate RRSets because that's the way they
+ * are stored in responses
+ */
+
+ /* Read owner first */
+
+ uint8_t dname_size;
+// uint8_t *dname_wire = NULL;
+
+ rrset = malloc(sizeof(test_rrset_t));
+
+ rrset->rrsigs = NULL;
+
+ CHECK_ALLOC_LOG(rrset, NULL);
+
+ init_list(&rrset->rdata_list);
+
+ /* TODO change in dump, size is useless now! */
+ if (!mem_read(&dname_size, sizeof(dname_size), src, src_size)) {
+ free(rrset);
+ return NULL;
+ }
+
+/* dname_wire = malloc(sizeof(uint8_t) * dname_size);
+
+ CHECK_ALLOC_LOG(dname_wire, NULL);
+
+ if (!mem_read(dname_wire, sizeof(uint8_t) * dname_size, src,
+ src_size)) {
+ free(dname_wire);
+ return NULL;
+ } */
+
+ test_dname_t *owner = load_test_dname(src, src_size);
+
+ if (owner == NULL) {
+ free(rrset);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ {
+ fprintf(stderr, "Got owner: %s", owner->str);
+ }
+#endif
+ /* Read other data */
+
+ if (!mem_read(&rrset_type, sizeof(rrset_type), src, src_size)) {
+ return NULL;
+ }
+
+ if (!mem_read(&rrset_class, sizeof(rrset_class), src, src_size)) {
+ return NULL;
+ }
+
+ if (!is_question) {
+ if (!mem_read(&rrset_ttl, sizeof(rrset_ttl), src, src_size)) {
+ return NULL;
+ }
+ } else {
+ rrset_ttl = 0;
+ }
+
+// rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl);
+
+ rrset->owner = owner;
+ rrset->type = rrset_type;
+ rrset->rclass = rrset_class;
+ rrset->ttl = rrset_ttl;
+
+ /* Question rrsets have no rdata */
+
+ if (!is_question) {
+ test_rdata_t *tmp_rdata;
+
+ tmp_rdata = load_response_rdata(rrset->type, src, src_size);
+
+ if (tmp_rdata == NULL) {
+ fprintf(stderr,
+ "Could not load rrset rdata - type: %d",
+ rrset->type);
+ free(rrset);
+ return NULL;
+ }
+
+ assert(tmp_rdata->type == rrset->type);
+
+ add_tail(&rrset->rdata_list, (node *)tmp_rdata);
+ }
+
+ return rrset;
+}
+
+static test_response_t *load_parsed_response(const char **src,
+ unsigned *src_size)
+{
+ /* Loads parsed response/query from binary format,
+ * which is as following:
+ * [id][qdcount][ancount][nscount][arcount]
+ * [question_rrset+][answer_rrset+][authority_rrset+]
+ * [additional_rrset]+
+ */
+
+ test_response_t *resp = malloc(sizeof(test_response_t));
+
+ CHECK_ALLOC_LOG(resp, NULL);
+
+ if (!mem_read(&resp->id, sizeof(resp->id), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "id %d\n", resp->id);
+#endif
+
+ if (!mem_read(&resp->qdcount, sizeof(resp->qdcount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "qdcount: %d\n", resp->qdcount);
+#endif
+
+ if (!mem_read(&resp->ancount, sizeof(resp->ancount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "ancount: %d\n", resp->ancount);
+#endif
+
+ if (!mem_read(&resp->nscount, sizeof(resp->nscount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "nscount: %d\n", resp->nscount);
+#endif
+
+ if (!mem_read(&resp->arcount, sizeof(resp->arcount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "arcount: %d\n", resp->arcount);
+#endif
+
+ if (!mem_read(&resp->query, sizeof(resp->query), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+ test_rrset_t **question_rrsets;
+
+ question_rrsets = malloc(sizeof(test_rrset_t *) * resp->qdcount);
+
+ for (int i = 0; i < resp->qdcount; i++) {
+ question_rrsets[i] = load_response_rrset(src, src_size, 1);
+ if (question_rrsets[i] == NULL) {
+ fprintf(stderr, "Could not load question rrsets\n");
+
+ for (int j = 0; j < i; j++) {
+ free(question_rrsets[i]);
+ }
+ free(question_rrsets);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ /* only one question in our case */
+
+ resp->qname = question_rrsets[0]->owner;
+ resp->qtype = question_rrsets[0]->type;
+ resp->qclass = question_rrsets[0]->rclass;
+
+ resp->question = NULL;
+
+/* for (int i = 0; i < resp->qdcount; i++) {
+ knot_rrset_free(&(question_rrsets[i]));
+ } */
+
+ free(question_rrsets);
+
+ test_rrset_t *tmp_rrset = NULL;
+
+ if (resp->ancount > 0) {
+ resp->answer =
+ malloc(sizeof(test_rrset_t *) * resp->ancount);
+ } else {
+ resp->answer = NULL;
+ }
+
+ for (int i = 0; i < resp->ancount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ resp->answer[i] = tmp_rrset;
+ if (resp->answer[i] == NULL) {
+ fprintf(stderr, "Could not load answer rrsets\n");
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ if (resp->nscount > 0) {
+ resp->authority =
+ malloc(sizeof(test_rrset_t *) * resp->nscount);
+ } else {
+ resp->authority = NULL;
+ }
+
+ for (int i = 0; i < resp->nscount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ resp->authority[i] = tmp_rrset;
+ if (resp->authority[i] == NULL) {
+ fprintf(stderr, "Could not load authority rrsets\n");
+ free(resp->authority);
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ if (resp->arcount > 0) {
+ resp->additional =
+ malloc(sizeof(test_rrset_t *) * resp->arcount);
+ } else {
+ resp->additional = NULL;
+ }
+
+ for (int i = 0; i < resp->arcount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ if (tmp_rrset == NULL) {
+ fprintf(stderr, "Could not load rrset (additional)\n");
+ free(resp->additional);
+ free(resp->authority);
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+
+ resp->additional[i] = tmp_rrset;
+ }
+
+ /* this will never be used */
+
+ resp->flags1 = 0;
+ resp->flags2 = 0;
+
+ return resp;
+}
+
+static void test_dname_free(test_dname_t **dname)
+{
+ assert(dname != NULL && *dname != NULL);
+ free((*dname)->labels);
+// free((*dname)->str);
+ free((*dname)->wire);
+
+ free(*dname);
+ *dname = NULL;
+}
+
+static int wire_is_dname(uint type)
+{
+ return (type == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ type == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ type == KNOT_RDATA_WF_LITERAL_DNAME);
+}
+
+static void test_rdata_free(test_rdata_t **rdata)
+{
+ assert(rdata != NULL && *rdata != NULL);
+
+ /* Free all the items */
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type((*rdata)->type);
+
+ for (int i = 0; i < (*rdata)->count; i++) {
+ if ((wire_is_dname(desc->wireformat[i])) &&
+ ((*rdata)->items[i].dname != NULL)) {
+ test_dname_free(&(*rdata)->items[i].dname);
+ } else if ((*rdata)->items[i].raw_data != NULL) {
+ free((*rdata)->items[i].raw_data);
+ (*rdata)->items[i].raw_data = NULL;
+ }
+ }
+// free((*rdata)->items);
+// free(*rdata);
+ *rdata = NULL;
+}
+
+static void test_rrset_free(test_rrset_t **rrset)
+{
+ assert(rrset && *rrset);
+
+ test_dname_free(&(*rrset)->owner);
+ /* Free all the rdatas */
+ node *n = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(n, nxt, (*rrset)->rdata_list) {
+ test_rdata_t *tmp_rdata = (test_rdata_t *)n;
+ assert(tmp_rdata);
+ if (tmp_rdata != NULL) {
+ test_rdata_free(&tmp_rdata);
+ }
+ }
+
+ free(*rrset);
+ *rrset = NULL;
+}
+
+static void test_response_free(test_response_t **response)
+{
+ assert(response && *response);
+ if ((*response)->qname != NULL) {
+ test_dname_free(&(*response)->qname);
+ }
+
+ if ((*response)->additional != NULL) {
+ for (int j = 0; j < (*response)->arcount; j++) {
+ test_rrset_free(&((*response)->additional[j]));
+ }
+
+ free((*response)->additional);
+ }
+
+ if ((*response)->answer != NULL) {
+ for (int j = 0; j < (*response)->ancount; j++) {
+ test_rrset_free(&((*response)->answer[j]));
+ }
+
+ free((*response)->answer);
+ }
+
+ if ((*response)->authority != NULL) {
+ for (int j = 0; j < (*response)->nscount; j++) {
+ test_rrset_free(&((*response)->authority[j]));
+ }
+
+ free((*response)->authority);
+ }
+
+ free((*response));
+ *response = NULL;
+}
+
+static void get_and_save_data_from_rdata(test_rdata_t *rdata,
+ test_data_t *data, uint16_t type)
+{
+ /* We only want to extract dnames */
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+
+ if (rdata->count == 0) {
+// diag("Rdata count not set!\n");
+ rdata->count = desc->length;
+ }
+
+ for(int i = 0; i < rdata->count; i++) {
+ if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) {
+ add_tail(&data->dname_list,
+ (node *)rdata->items[i].dname);
+ test_item_t *temp_item = malloc(sizeof(test_item_t));
+ temp_item->dname = rdata->items[i].dname;
+ temp_item->type = TEST_ITEM_DNAME;
+ temp_item->raw_data = NULL;
+ add_tail(&data->item_list, (node *)temp_item);
+ } else {
+ test_item_t *temp_item = malloc(sizeof(test_item_t));
+ temp_item->dname = NULL;
+ temp_item->type = TEST_ITEM_RAW_DATA;
+ temp_item->raw_data = rdata->items[i].raw_data;
+ add_tail(&data->item_list, (node *)temp_item);
+ }
+ }
+}
+
+static void get_and_save_data_from_rrset(const test_rrset_t *rrset,
+ test_data_t *data)
+{
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(rrset->type);
+ /* RDATA are in a list. */
+ node *n = NULL;
+ int i = 0;
+ WALK_LIST(n, rrset->rdata_list) {
+ test_rdata_t *tmp_rdata = (test_rdata_t *)n;
+ assert(tmp_rdata);
+ assert(&data->rdata_list);
+ assert(&data->rdata_list != &rrset->rdata_list);
+ assert(tmp_rdata->type == rrset->type);
+
+ test_rdata_t *new_rdata = malloc(sizeof(test_rdata_t));
+ new_rdata->count = tmp_rdata->count;
+ new_rdata->items = tmp_rdata->items;
+ new_rdata->type = tmp_rdata->type;
+
+ add_tail(&data->rdata_list, (node *)new_rdata);
+ get_and_save_data_from_rdata(tmp_rdata, data, rrset->type);
+ i++;
+ }
+ assert(i == 1);
+}
+
+static int add_rrset_to_node(const test_rrset_t *rrset, test_data_t *data)
+{
+ /* First, create node from rrset */
+ test_node_t *tmp_node = malloc(sizeof(test_node_t));
+ memset(tmp_node, 0, sizeof(test_node_t));
+ CHECK_ALLOC_LOG(tmp_node, -1);
+
+ tmp_node->owner = rrset->owner;
+ tmp_node->parent = NULL;
+ tmp_node->rrset_count = 0;
+
+ /* Will not be used in list now */
+ tmp_node->prev = NULL;
+ tmp_node->next = NULL;
+
+
+// printf("%s\n", rrset->owner->wire);
+// getchar();
+
+/* tmp_node->avl_left = NULL;
+ tmp_node->avl_right = NULL;
+ tmp_node->avl_height = 0; */
+
+ test_node_t *found_node =
+ TREE_FIND(data->node_tree, test_node, avl, tmp_node);
+
+ if (found_node == NULL) {
+ /* Insert new node with current rrset */
+ init_list(&tmp_node->rrset_list);
+ add_tail(&tmp_node->rrset_list, (node *)rrset);
+ tmp_node->rrset_count++;
+
+ TREE_INSERT(data->node_tree, test_node, avl, tmp_node);
+ } else {
+ free(tmp_node);
+ /* append rrset */
+
+ add_tail(&found_node->rrset_list, (node *)rrset);
+ found_node->rrset_count++;
+ }
+
+ return 0;
+}
+
+static void get_and_save_data_from_response(const test_response_t *response,
+ test_data_t *data)
+{
+ /* Go through all the rrsets in the response */
+
+ for (int i = 0; i < response->ancount; i++) {
+ assert(response->answer[i]);
+ /* Add rrset to the list of rrsets - there will be duplicates
+ * But not the same pointers */
+ add_tail(&data->rrset_list, (node *)response->answer[i]);
+ get_and_save_data_from_rrset(response->answer[i], data);
+ if (add_rrset_to_node(response->answer[i], data) != 0) {
+ return;
+ }
+ }
+
+ for (int i = 0; i < response->arcount; i++) {
+ /* Add rrset to the list of rrsets - there will be duplicates */
+ assert(response->additional[i]);
+ add_tail(&data->rrset_list, (node *)response->additional[i]);
+ get_and_save_data_from_rrset(response->additional[i], data);
+ if (add_rrset_to_node(response->additional[i], data) != 0) {
+ return;
+ }
+ }
+
+ for (int i = 0; i < response->nscount; i++) {
+ assert(response->authority[i]);
+ /* Add rrset to the list of rrsets - there will be duplicates */
+ add_tail(&data->rrset_list, (node *)response->authority[i]);
+ get_and_save_data_from_rrset(response->authority[i], data);
+ if (add_rrset_to_node(response->authority[i], data) != 0) {
+ return;
+ }
+ }
+
+// for (int i = 0; i < response->qdcount; i++) {
+// /* Add rrset to the list of rrsets - there will be duplicates */
+// add_tail(&data->rrset_list, (node *)response->question[i]);
+// get_and_save_data_from_rrset(response->question[i], data);
+// }
+}
+
+static int load_parsed_responses(test_data_t *data, uint32_t *count,
+ const char* src, unsigned src_size)
+{
+ if (!mem_read(count, sizeof(*count), &src, &src_size)) {
+ fprintf(stderr, "Wrong read\n");
+ return -1;
+ }
+
+// *responses = malloc(sizeof(test_response_t *) * *count);
+
+ for (int i = 0; i < *count; i++) {
+ test_response_t *tmp_response =
+ load_parsed_response(&src, &src_size);
+
+ if (tmp_response == NULL) {
+ fprintf(stderr, "Could not load response - %d"
+ "- returned NULL\n",
+ i);
+ return -1;
+ }
+
+ if (tmp_response->query) {
+ add_tail(&data->query_list, (node *)tmp_response);
+ } else {
+ add_tail(&data->response_list, (node *)tmp_response);
+ }
+
+ /* Create new node */
+ test_response_t *resp = malloc(sizeof(test_response_t));
+ assert(resp);
+ memcpy(resp, tmp_response, sizeof(test_response_t));
+ add_tail(&data->packet_list,
+ (node *)resp);
+ }
+
+ return 0;
+}
+
+//void free_parsed_responses(test_response_t ***responses, uint32_t *count)
+//{
+// if (*responses != NULL) {
+// for (int i = 0; i < *count; i++) {
+// free_parsed_response((*responses)[i]);
+// }
+// free(*responses);
+// }
+//}
+
+static int compare_nodes(test_node_t *node1, test_node_t *node2)
+{
+ assert(node1->owner && node2->owner);
+ /*!< \warning Wires have to be \0 terminated. */
+ return (strcmp((char *)node1->owner->wire, (char *)node2->owner->wire));
+}
+
+static int init_data(test_data_t *data)
+{
+ if (data == NULL) {
+ return 0;
+ }
+
+ /* Initialize all the lists */
+ init_list(&data->dname_list);
+ init_list(&data->edns_list);
+ init_list(&data->node_list);
+ init_list(&data->response_list);
+ init_list(&data->rdata_list);
+ init_list(&data->rrset_list);
+ init_list(&data->item_list);
+ init_list(&data->raw_response_list);
+ init_list(&data->raw_query_list);
+ init_list(&data->raw_packet_list);
+ init_list(&data->query_list);
+ init_list(&data->packet_list);
+
+ data->node_tree = malloc(sizeof(avl_tree_test_t));
+ CHECK_ALLOC_LOG(data->node_tree, 0);
+
+ TREE_INIT(data->node_tree, compare_nodes);
+
+ return 1;
+}
+
+static void print_stats(test_data_t *data)
+{
+ uint resp_count = 0, dname_count = 0, node_count = 0,
+ rdata_count = 0, rrset_count = 0, item_count = 0, query_count = 0,
+ raw_query_count = 0, response_count = 0, packet_count = 0,
+ raw_packet_count = 0, raw_response_count = 0;
+
+ node *n = NULL; /* Will not be used */
+
+ WALK_LIST(n, data->response_list) {
+ resp_count++;
+ }
+
+ WALK_LIST(n, data->rrset_list) {
+// node *tmp = NULL;
+// assert(((test_rrset_t *)n)->owner);
+// WALK_LIST(tmp, ((test_rrset_t *)n)->rdata_list) {
+// test_rdata_t *rdata = (test_rdata_t *)tmp;
+// assert(rdata->type == ((test_rrset_t *)n)->type);
+// }
+ rrset_count++;
+ }
+
+ WALK_LIST(n, data->rdata_list) {
+ rdata_count++;
+ }
+
+ WALK_LIST(n, data->dname_list) {
+ dname_count++;
+ }
+
+ WALK_LIST(n, data->node_list) {
+ node_count++;
+ }
+
+ WALK_LIST(n, data->item_list) {
+ item_count++;
+ }
+
+ WALK_LIST(n, data->raw_response_list) {
+ raw_response_count++;
+ }
+
+ WALK_LIST(n, data->query_list) {
+ query_count++;
+ }
+
+ WALK_LIST(n, data->response_list) {
+ response_count++;
+ }
+
+ WALK_LIST(n, data->raw_query_list) {
+ raw_query_count++;
+ }
+
+ WALK_LIST(n, data->packet_list) {
+ packet_count++;
+ }
+
+ WALK_LIST(n, data->raw_packet_list) {
+ raw_packet_count++;
+ }
+
+ printf("Loaded: Responses: %d RRSets: %d RDATAs: %d Dnames: %d "
+ "Nodes: %d Items: %d Raw_responses: %d Queries: %d \n"
+ "Raw_queries; %d Total packets: %d Total_raw_packets: %d\n", resp_count, rrset_count,
+ rdata_count, dname_count, node_count, item_count,
+ raw_response_count, query_count, raw_query_count, packet_count,
+ raw_packet_count);
+}
+
+static void save_node_to_list(test_node_t *n, void *p)
+{
+ test_data_t *data = (test_data_t *)p;
+
+ add_tail(&data->node_list, (node *)n);
+}
+
+static void del_node(test_node_t *n, void *p)
+{
+// test_data_t *data = (test_data_t *)p;
+ free(n);
+}
+
+
+void free_data(test_data_t **data)
+{
+ assert(data && *data);
+ /* We will free all the data using responses
+ * (others are just references )*/
+ node *n = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(n, nxt, (*data)->response_list) {
+ test_response_t *tmp_response = (test_response_t *)n;
+ if (tmp_response != NULL) {
+ test_response_free(&tmp_response);
+ }
+ }
+
+ TREE_POST_ORDER_APPLY((*data)->node_tree, test_node, avl, del_node,
+ NULL);
+
+ free((*data)->node_tree);
+
+ free(*data);
+ *data = NULL;
+}
+
+test_data_t *create_test_data_from_dump()
+{
+ test_data_t *ret = malloc(sizeof(test_data_t));
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ if (!init_data(ret)) {
+ free(ret);
+ return NULL;
+ }
+
+ uint32_t raw_packet_count = 0;
+
+ if (load_raw_packets(ret, &raw_packet_count, raw_data_rc,
+ raw_data_rc_size) != 0) {
+ fprintf(stderr, "Could not load raw_data, quitting");
+ /* TODO walk the lists*/
+ free(ret);
+ return NULL;
+ }
+
+ uint32_t response_count = 0;
+
+ if (load_parsed_responses(ret, &response_count, parsed_data_rc,
+ parsed_data_rc_size) != 0) {
+ fprintf(stderr, "Could not load responses, quitting");
+ /* TODO walk the lists*/
+ free(ret);
+ return NULL;
+ }
+
+ /* For each parsed response - create more data from it. */
+ /* Probably not the most effective way, but it is better than to
+ * rewrite most of the code .*/
+
+ node *n = NULL;
+
+ WALK_LIST(n , ret->response_list) {
+ get_and_save_data_from_response((test_response_t *)n, ret);
+ }
+
+ /* Create list from AVL tree */
+
+ TREE_FORWARD_APPLY(ret->node_tree, test_node, avl,
+ save_node_to_list, ret);
+
+ print_stats(ret);
+
+ return ret;
+}
diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.h b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h
new file mode 100644
index 0000000..8f57944
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h
@@ -0,0 +1,179 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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/>.
+ */
+
+#ifndef KNOT_TESTS_LOADER_H
+#define KNOT_TESTS_LOADER_H
+
+#include <stdint.h>
+
+#include "libknot/common.h"
+#include "common/lists.h"
+#include "common/tree.h"
+
+
+/* Parsed raw packet*/
+struct test_raw_packet {
+ struct node *next, *prev;
+ uint size;
+ uint8_t *data;
+};
+
+typedef struct test_raw_packet test_raw_packet_t;
+
+/* Test type definitions */
+
+struct test_dname {
+ struct node *next, *prev;
+ char *str;
+ uint8_t *wire;
+ uint size;
+ uint8_t *labels;
+ short label_count;
+};
+
+typedef struct test_dname test_dname_t;
+
+struct test_edns_options {
+ struct node *next, *prev;
+ uint16_t code;
+ uint16_t length;
+ uint8_t *data;
+};
+
+struct test_edns {
+ struct node *next, *prev;
+ struct test_edns_options *options;
+ uint16_t payload;
+ uint8_t ext_rcode;
+ uint8_t version;
+ uint16_t flags;
+ uint16_t *wire;
+ short option_count;
+ short options_max;
+ short size;
+};
+
+typedef struct test_edns test_edns_t;
+
+typedef TREE_HEAD(avl_tree_test, test_node) avl_tree_test_t;
+
+struct test_node {
+ struct node *next, *prev;
+ test_dname_t *owner;
+ short rrset_count;
+ struct test_node *parent;
+ list rrset_list;
+
+ TREE_ENTRY(test_node) avl;
+};
+
+typedef struct test_node test_node_t;
+
+enum item_type {
+ TEST_ITEM_DNAME,
+ TEST_ITEM_RAW_DATA
+};
+
+typedef enum item_type item_type_t;
+
+struct test_item {
+ uint16_t *raw_data;
+ test_dname_t *dname;
+ item_type_t type;
+};
+
+typedef struct test_item test_item_t;
+
+struct test_rdata {
+ struct node *next, *prev;
+ uint count;
+ uint type; /*!< Might be handy */
+ test_item_t *items;
+};
+
+typedef struct test_rdata test_rdata_t;
+
+struct test_rrset {
+ struct node *next, *prev;
+ test_dname_t *owner;
+ uint16_t type;
+ uint16_t rclass;
+ uint32_t ttl;
+ struct test_rrset *rrsigs;
+ uint16_t *wire;
+ list rdata_list;
+};
+
+typedef struct test_rrset test_rrset_t;
+
+struct test_response {
+ struct node *next, *prev;
+ /* This is basically same thing as actual response structure */
+ uint16_t query;
+ test_dname_t *qname;
+ uint16_t qclass;
+ uint16_t qtype;
+ uint16_t id;
+ uint8_t flags1;
+ uint8_t flags2;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+
+ /* Arrays of rrsets */
+
+ test_rrset_t **question;
+ test_rrset_t **answer;
+ test_rrset_t **authority;
+ test_rrset_t **additional;
+
+ short size;
+
+ /* what about the rest of the values?
+ * they cannot be modified from API, but this is probably the best
+ * place to test them as well */
+};
+
+typedef struct test_response test_response_t;
+
+/*!< \brief contains lists of all the structures */
+struct test_data {
+ list dname_list;
+ list edns_list;
+ list rdata_list;
+ list node_list;
+ list rrset_list;
+ list response_list;
+ list raw_response_list;
+ list query_list;
+ list raw_query_list;
+ list item_list;
+ /* responses and queries together */
+ list packet_list;
+ list raw_packet_list;
+
+ avl_tree_test_t *node_tree;
+};
+
+typedef struct test_data test_data_t;
+
+/*!< \brief Parses resource with data and creates all possible structures. */
+test_data_t *create_test_data_from_dump();
+
+test_data_t *data_for_knot_tests;
+
+#endif // KNOT_TESTS_LOADER_H
diff --git a/src/tests/libknot/realdata/unittests_libknot_realdata.c b/src/tests/libknot/realdata/unittests_libknot_realdata.c
new file mode 100644
index 0000000..e557c43
--- /dev/null
+++ b/src/tests/libknot/realdata/unittests_libknot_realdata.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <config.h>
+//#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+// Units to test
+#include "tests/libknot/realdata/libknot/dname_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/response_tests_realdata.h"
+//#include "libknot/edns_tests.h"
+#include "tests/libknot/realdata/libknot/node_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h"
+//#include "libknot/response_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/rrset_tests_realdata.h"
+//#include "libknot/zone_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/zonedb_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/packet_tests_realdata.h"
+
+#include "common/lists.h"
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ data_for_knot_tests = create_test_data_from_dump();
+
+ if (data_for_knot_tests == NULL) {
+ diag("Data could not be loaded!");
+ return 0;
+ }
+
+ // Open log
+// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+
+ /* DNS units */
+// &cuckoo_tests_api, //! Cuckoo hashing unit
+ &dname_tests_api, //! DNS library (dname) unit
+// &edns_tests_api, //! DNS library (EDNS0) unit
+ &node_tests_api, //! DNS library (node) unit
+ &rdata_tests_api, //! DNS library (rdata) unit
+ &packet_tests_api,
+// &response_tests_api, //! DNS library (response) unit
+ &response_tests_api, //! DNS library (response) unit
+ &rrset_tests_api, //! DNS library (rrset) unit
+// &zone_tests_api, //! DNS library (zone) unit
+// &zonedb_tests_api, //! DNS library (zonedb) unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+// log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/tests/libknot/unittests_libknot.c b/src/tests/libknot/unittests_libknot.c
new file mode 100644
index 0000000..62d4b90
--- /dev/null
+++ b/src/tests/libknot/unittests_libknot.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "tests/libknot/libknot/cuckoo_tests.h"
+#include "tests/libknot/libknot/dname_tests.h"
+#include "tests/libknot/libknot/edns_tests.h"
+#include "tests/libknot/libknot/node_tests.h"
+#include "tests/libknot/libknot/rdata_tests.h"
+#include "tests/libknot/libknot/response_tests.h"
+#include "tests/libknot/libknot/rrset_tests.h"
+#include "tests/libknot/libknot/zone_tests.h"
+#include "tests/libknot/libknot/dname_table_tests.h"
+#include "tests/libknot/libknot/nsec3_tests.h"
+#include "tests/libknot/libknot/packet_tests.h"
+#include "tests/libknot/libknot/query_tests.h"
+#include "tests/libknot/libknot/zonedb_tests.h"
+#include "tests/libknot/libknot/zone_tree_tests.h"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+
+ /* DNS units */
+ &cuckoo_tests_api, //! Cuckoo hashing unit
+ &dname_tests_api, //! DNS library (dname) unit
+ &edns_tests_api, //! DNS library (EDNS0) unit
+ &zone_tests_api, //! DNS library (zone) unit
+ &node_tests_api, //! DNS library (node) unit
+ &rdata_tests_api, //! DNS library (rdata) unit
+ &response_tests_api, //! DNS library (response) unit
+ &rrset_tests_api, //! DNS library (rrset) unit
+ &dname_table_tests_api,
+ &nsec3_tests_api,
+ &packet_tests_api,
+ &query_tests_api,
+ &zonedb_tests_api, //! DNS library (zonedb) unit
+ &zone_tree_tests_api,
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+// log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c
new file mode 100644
index 0000000..2d57ed2
--- /dev/null
+++ b/src/tests/unittests_main.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "tests/common/slab_tests.h"
+#include "tests/common/skiplist_tests.h"
+#include "tests/common/events_tests.h"
+#include "tests/common/da_tests.h"
+#include "tests/common/acl_tests.h"
+#include "tests/common/fdset_tests.h"
+#include "tests/knot/dthreads_tests.h"
+#include "tests/knot/journal_tests.h"
+#include "tests/knot/server_tests.h"
+#include "tests/knot/conf_tests.h"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+ log_init();
+ log_levels_set(LOGT_SYSLOG, LOG_ANY, 0);
+
+ // Build test set
+ unit_api *tests[] = {
+ /* Core data structures. */
+ &journal_tests_api, //! Journal unit
+ &slab_tests_api, //! SLAB allocator unit
+ &skiplist_tests_api, //! Skip list unit
+ &dthreads_tests_api, //! DThreads testing unit
+ &events_tests_api, //! Events testing unit
+ &da_tests_api, //! Dynamic array unit
+ &acl_tests_api, //! ACLs
+ &fdset_tests_api, //! FDSET polling wrapper
+
+ /* Server parts. */
+ &conf_tests_api, //! Configuration parser tests
+ &server_tests_api, //! Server unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+ log_close();
+
+ // Evaluate
+ return exit_status();
+}
+