diff options
Diffstat (limited to 'src/tests')
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 Binary files differnew file mode 100644 index 0000000..4027c92 --- /dev/null +++ b/src/tests/libknot/files/parsed_data diff --git a/src/tests/libknot/files/parsed_data_queries b/src/tests/libknot/files/parsed_data_queries Binary files differnew file mode 100644 index 0000000..5857c87 --- /dev/null +++ b/src/tests/libknot/files/parsed_data_queries diff --git a/src/tests/libknot/files/raw_data b/src/tests/libknot/files/raw_data Binary files differnew file mode 100644 index 0000000..f94236b --- /dev/null +++ b/src/tests/libknot/files/raw_data diff --git a/src/tests/libknot/files/raw_data_queries b/src/tests/libknot/files/raw_data_queries Binary files differnew file mode 100644 index 0000000..9062d5a --- /dev/null +++ b/src/tests/libknot/files/raw_data_queries 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(¶m1, 0, sizeof(struct zone_test_param)); + + knot_zone_contents_tree_apply_inorder(from, tree_node_to_array, + (void *)¶m1); + + struct zone_test_param param2; + memset(¶m2, 0, sizeof(struct zone_test_param)); + + knot_zone_contents_tree_apply_inorder(to, tree_node_to_array, + (void *)¶m2); + + 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 *)¶m1); + + param2.count = 0; + knot_dname_table_tree_inorder_apply(to->dname_table, + tree_dname_node_to_array, + (void *)¶m2); + + 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 Binary files differnew file mode 100644 index 0000000..fe22b90 --- /dev/null +++ b/src/tests/libknot/realdata/files/parsed_data diff --git a/src/tests/libknot/realdata/files/parsed_data_queries b/src/tests/libknot/realdata/files/parsed_data_queries Binary files differnew file mode 100644 index 0000000..5857c87 --- /dev/null +++ b/src/tests/libknot/realdata/files/parsed_data_queries diff --git a/src/tests/libknot/realdata/files/raw_data b/src/tests/libknot/realdata/files/raw_data Binary files differnew file mode 100644 index 0000000..502005e --- /dev/null +++ b/src/tests/libknot/realdata/files/raw_data diff --git a/src/tests/libknot/realdata/files/raw_data_queries b/src/tests/libknot/realdata/files/raw_data_queries Binary files differnew file mode 100644 index 0000000..9062d5a --- /dev/null +++ b/src/tests/libknot/realdata/files/raw_data_queries 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(); +} + |