From: Jan Hák Date: Fri, 18 Jul 2025 13:03:11 +0000 (+0200) Subject: tests-redis: introduce redis module unit tests X-Git-Tag: v3.5.0~11^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4ce32753212e304a98f926f6120abaa91bbe57b6;p=thirdparty%2Fknot-dns.git tests-redis: introduce redis module unit tests --- diff --git a/Makefile.am b/Makefile.am index e0960c7387..2250c77653 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src src/redis tests tests-fuzz python samples distro doc +SUBDIRS = src src/redis tests tests-fuzz tests-redis python samples distro doc EXTRA_DIST = README.md diff --git a/configure.ac b/configure.ac index 58121cebf5..545dbd82d9 100644 --- a/configure.ac +++ b/configure.ac @@ -832,6 +832,7 @@ AC_CONFIG_FILES([Makefile doc/Makefile tests/Makefile tests-fuzz/Makefile + tests-redis/Makefile samples/Makefile distro/Makefile python/Makefile diff --git a/src/redis/Makefile.am b/src/redis/Makefile.am index 3cea3c8319..3141f34891 100644 --- a/src/redis/Makefile.am +++ b/src/redis/Makefile.am @@ -1,4 +1,4 @@ -AM_CPPFLAGS = -include $(top_builddir)/src/config.h +AM_CPPFLAGS = -I$(top_srcdir)/src -include $(top_builddir)/src/config.h AM_LDFLAGS = $(LT_NO_UNDEFINED) pkglibdir = ${libdir}/knot/redis diff --git a/tests-redis/.gitignore b/tests-redis/.gitignore new file mode 100644 index 0000000000..b6d592eb2a --- /dev/null +++ b/tests-redis/.gitignore @@ -0,0 +1 @@ +/logs diff --git a/tests-redis/Makefile.am b/tests-redis/Makefile.am new file mode 100644 index 0000000000..a83b0ef57f --- /dev/null +++ b/tests-redis/Makefile.am @@ -0,0 +1,12 @@ +# Useful commands: +# python3 -m venv .venv +# source .venv/bin/activate +# pip3 install -r requirements.txt +# make test + +EXTRA_DIST = config.txt requirements.txt test.py + +.PHONY: test + +test: + RLTest --randomize-ports --clear-logs --parallelism 4 diff --git a/tests-redis/config.txt b/tests-redis/config.txt new file mode 100644 index 0000000000..139be53768 --- /dev/null +++ b/tests-redis/config.txt @@ -0,0 +1,3 @@ +--module ../src/redis/.libs/knot.so +--no-progress +--use-valgrind diff --git a/tests-redis/requirements.txt b/tests-redis/requirements.txt new file mode 100644 index 0000000000..bd5f38ffed --- /dev/null +++ b/tests-redis/requirements.txt @@ -0,0 +1,2 @@ +rltest +setuptools<=80.0.0 diff --git a/tests-redis/test.py b/tests-redis/test.py new file mode 100644 index 0000000000..8f4542e065 --- /dev/null +++ b/tests-redis/test.py @@ -0,0 +1,482 @@ +from math import floor +from RLTest import Env + + +def txn_get_instance(txn : int) -> int: + return floor(txn / 10) + +def test_zone_begin(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # basic transaction + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10, message="Wrong transaction number") + + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Fail while aborting transaction") + + # multiple zones + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn1, 10, message="Wrong transaction number") + + txn2 = env.cmd('KNOT.ZONE.BEGIN', 'example.net', 1) + env.assertEqual(txn2, 10, message="Wrong transaction number") + + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', txn1) + env.assertEqual(resp, b'OK', message="Fail while aborting transaction") + + resp = env.cmd('KNOT.ZONE.ABORT', 'example.net', txn2) + env.assertEqual(resp, b'OK', message="Fail while aborting transaction") + + # multiple transactions + for i in range(9): + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10 + i, message="Wrong transaction number") + + with env.assertResponseError(msg="Should not allow so much transactions"): + env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + + for i in range(9): + env.cmd('KNOT.ZONE.ABORT', 'example.com', 10 + i) + env.assertEqual(resp, b'OK', message="Fail while aborting transaction") + + # multiple instances + with env.assertResponseError(msg="Wrong instance number"): + env.cmd('KNOT.ZONE.BEGIN', 'example.com', 0) + + for i in range(1, 9): + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', i) + env.assertEqual(txn, i * 10, message="Wrong transaction number") + + with env.assertResponseError(msg="Should not allow so much instances"): + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 9) + + for i in range(1, 9): + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', i * 10) + env.assertEqual(resp, b'OK', message="Fail while aborting transaction") + + # wrong argument number + with env.assertResponseError(msg="Wrong argument number"): + env.cmd('KNOT.ZONE.BEGIN', 'example.com') + + with env.assertResponseError(msg="Wrong argument number"): + env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1, 2) + +def test_zone_store(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # without transaction + with env.assertResponseError(msg="Transaction should not be opened"): + env.cmd('KNOT.ZONE.STORE', 'example.com', 10, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + + # basic + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.assertEqual(resp, b'OK', message="Fail while store SOA") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns1.example.com. IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Fail while store A") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns1.example.com. IN A 2.2.2.2") + env.assertEqual(resp, b'OK', message="Fail while store secondary A") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns2 IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Fail while store implicit A") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns3 123 IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Fail while store TTL") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns4 A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Fail while store without class") + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "mail MX 10 dns1.example.com.") + env.assertEqual(resp, b'OK', message="Fail while store MX") + + with env.assertResponseError(msg="Malformed data"): + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "malformed IN 123 C 1.1.1.1") + + ZONE1=[[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 1 7200 3600 1209600 3600'], + [b'dns1.example.com.', b'3600', b'A', b'1.1.1.1'], + [b'dns1.example.com.', b'3600', b'A', b'2.2.2.2'], + [b'dns2.example.com.', b'3600', b'A', b'1.1.1.1'], + [b'dns3.example.com.', b'123', b'A', b'1.1.1.1'], + [b'dns4.example.com.', b'3600', b'A', b'1.1.1.1'], + [b'mail.example.com.', b'3600', b'MX', b'10 dns1.example.com.']] + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + env.assertEqual(resp, ZONE1, message="Basic store") + + # multiple transactions + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 2) + + resp = env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.assertEqual(resp, b'OK', message="Fail while store") + + ZONE2=[[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 1 7200 3600 1209600 3600']] + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn1) + env.assertEqual(resp, ZONE2, message="Mixed zones") + + env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + env.cmd('KNOT.ZONE.ABORT', 'example.com', txn1) + +def test_zone_commit(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # non-existent transaction + with env.assertResponseError(msg="Should not commit non-existent transaction"): + env.cmd('KNOT.ZONE.COMMIT', 'example.com', 10) + + # without SOA + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + with env.assertResponseError(msg="Should not commit zone without SOA"): + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + + # with fake SOA + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "soa.example.com IN SOA ns.icann.org. noc.dns.icann.org. ( 3 7200 3600 1209600 3600 )") + with env.assertResponseError(msg="Should not commit zone without SOA"): + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + # with SOA + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + resp = env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit") + + # multiple SOA + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns1.example.com. IN SOA ns.icann.org. noc.dns.icann.org. ( 2 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 3 7200 3600 1209600 3600 )") + + resp = env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit") + + resp = env.cmd('KNOT_BIN.ZONE.EXISTS', '\aexample\x03com\x00', '\x01') + env.assertEqual(resp, 3, message="Failed to commit") + + # new transaction with active zone + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10, message="Wrong implicit instance transaction number") + + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn1, 12, message="Wrong implicit instance transaction number") + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 3 7200 3600 1209600 3600 )") + + old_zone = env.cmd('KNOT.ZONE.LOAD', 'example.com', 1) + + resp = env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn1) + env.assertEqual(resp, b'OK', message="Failed to commit") + + new_zone =env.cmd('KNOT.ZONE.LOAD', 'example.com', 1) + env.assertNotEqual(old_zone, new_zone) + + +def test_zone_abort(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # basic + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + resp = env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to abort") + with env.assertResponseError(msg="Should not be available after abort"): + env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + + # after abort + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10, message="Wrong implicit instance transaction number") + + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + with env.assertResponseError(msg="Should not be able to abort commited zone"): + env.cmd('KNOT.ZONE.ABORT', 'example.com', txn) + +def test_zone_load(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + + ZONE = [[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 1 7200 3600 1209600 3600']] + + # load uncommited + zone_txn = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + env.assertEqual(zone_txn, ZONE, message="Zone is not equals to template") + + # load commited + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn_get_instance(txn)) + env.assertEqual(resp, ZONE, message="Zone is not equals to template") + env.assertEqual(resp, zone_txn, message="Zones from transaction and instance does not equals") + +def test_zone_purge(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + + txn2 = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + txn3 = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + + env.cmd('KNOT.UPD.ADD', 'example.com', txn2, "dns IN A 1.1.1.1") + env.cmd('KNOT.UPD.COMMIT','example.com', txn2) + + env.cmd('KNOT.UPD.ADD', 'example.com', txn3, "dns IN A 2.2.2.2") + + # basic + resp = env.cmd('KNOT.ZONE.PURGE', 'example.com', txn_get_instance(txn)) + env.assertEqual(resp, b'OK', message="Failed to purge zone") + + with env.assertResponseError(msg="Zone has not been purged"): + env.cmd('KNOT.ZONE.LOAD', 'example.com', txn_get_instance(txn)) + with env.assertResponseError(msg="Zone has not been purged"): + env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + with env.assertResponseError(msg="Update has not been purged"): + env.cmd('KNOT.UPD.DIFF', 'example.com', txn2) + + # test whether uncommitted update transaction remains available before commit + with env.assertResponseError(msg="Zone should not be available anymore"): + env.cmd('KNOT.UPD.COMMIT','example.com', txn3) + + # test whether uncommitted zone transaction remains available + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "dns IN A 1.1.1.1") + resp = env.cmd('KNOT.ZONE.COMMIT','example.com', txn1) + ZONE = [[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 1 7200 3600 1209600 3600'], + [b'dns.example.com.', b'3600', b'A', b'1.1.1.1']] + env.assertEqual(resp, b'OK', message="Failed to commit after purge") + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn_get_instance(txn1)) + env.assertEqual(resp, ZONE, message="Zone does not equals template") + + # test whether uncommitted update transaction remains available after commit + resp = env.cmd('KNOT.UPD.COMMIT','example.com', txn3) + env.assertEqual(resp, b'OK', message="Failed to commit update") + +def test_zone_list(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # First zone + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) + env.assertEqual(len(resp), 1, message="Failed to purge zone") + + # Rewrite zone + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) + env.assertEqual(len(resp), 1, message="Failed to purge zone") + + # Second zone + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.net', 1) + env.cmd('KNOT.ZONE.STORE', 'example.net', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.net', txn) + + resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) + env.assertEqual(len(resp), 2, message="Failed to purge zone") + +def test_upd_begin(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + # missing zone + with env.assertResponseError(msg="Update on non-existent zone"): + env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + # missing zone at instance + with env.assertResponseError(msg="Update on non-existent zone"): + env.cmd('KNOT.UPD.BEGIN', 'example.com', 2) + + # basic + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10, message="Wrong implicit instance transaction number") + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + + # multiple transactions + for i in range(0, 9): + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.assertEqual(txn, 10 + i, message="Wrong transaction number") + + for i in range(0, 9): + env.cmd('KNOT.UPD.ABORT', 'example.com', 10 + i) + +def test_upd_add_rem(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns IN A 1.1.1.1") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + # add/remove nonexistent transaction + with env.assertResponseError(msg="Should not add to nonexistent transaction"): + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "dns 600 IN A 2.2.2.2") + with env.assertResponseError(msg="Should not add to nonexistent transaction"): + env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "dns 600 IN A 2.2.2.2") + + # basic + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + resp = env.cmd('KNOT.UPD.ADD', 'example.com', txn, "dns 600 IN A 2.2.2.2") + env.assertEqual(resp, b'OK', message="Failed to add record into update") + + resp = env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "dns IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Failed to remove record from update") + + UPD = [[ + [[b'dns.example.com.', b'NONE', b'A', b'1.1.1.1']], + [[b'dns.example.com.', b'600', b'A', b'2.2.2.2']] + ]] + + resp = env.cmd('KNOT.UPD.DIFF', 'example.com', txn) + env.assertEqual(resp, UPD, message="Wrong update output") + + resp = env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit update") + + ZONE = [ + [b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 2 7200 3600 1209600 3600'], + [b'dns.example.com.', b'600', b'A', b'2.2.2.2'] + ] + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', 1) + env.assertEqual(resp, ZONE, message="Wrong update output") + +def test_upd_commit(): + UPD_HIST_LEN = 10 + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600', 'max-update-depth', f'{UPD_HIST_LEN}']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns IN A 1.1.1.1") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + # commit non-existent + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.PURGE', 'example.com', 1) + with env.assertResponseError(msg="Should not commit, zone doesn't exists"): + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn1) + + # basic add + resp = env.cmd('KNOT.UPD.ADD', 'example.com', txn, "example IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Failed to add record into update") + resp = env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit update") + + # basic remove + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + resp = env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "example IN A 1.1.1.1") + env.assertEqual(resp, b'OK', message="Failed to add record into update") + resp = env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit update") + + # update depth trimmig + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn1) + + for i in range(1, UPD_HIST_LEN + 2): + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + resp = env.cmd('KNOT.UPD.ADD', 'example.com', txn, f"dns{i} IN A {i}.{i}.{i}.{i}") + resp = env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to commit update") + + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, max(1, i + 1 - UPD_HIST_LEN)) + env.assertEqual(len(resp), min(i, UPD_HIST_LEN), message="Failed to commit update") + + # update serial collisions + txn1 = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn1, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn1) + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 2147483648 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, 1) + env.assertEqual(len(resp), 1, message="Failed to commit update") + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 2147483648 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 4294967295 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, 1) + env.assertEqual(len(resp), 2, message="Failed to commit update") + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 4294967295 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, 1) + env.assertEqual(len(resp), 3, message="Failed to commit update") + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.REMOVE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 2147483648 7200 3600 1209600 3600 )") + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, 1) + env.assertEqual(len(resp), 1, message="Failed to commit update") + +def test_upd_abort(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns IN A 1.1.1.1") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + old_zone = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "dns 600 IN A 2.2.2.2") + resp = env.cmd('KNOT.UPD.ABORT', 'example.com', txn) + env.assertEqual(resp, b'OK', message="Failed to abort update") + + with env.assertResponseError(msg="Should be aborted"): + env.cmd('KNOT.UPD.DIFF', 'example.com', txn) + resp = env.cmd('KNOT.ZONE.LOAD', 'example.com', txn) + env.assertEqual(resp, old_zone, message="Zone should not be changed after abort of update") + +def test_upd_diff_load(): + env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) + + txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") + env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "dns IN A 1.1.1.1") + env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) + + txn = env.cmd('KNOT.UPD.BEGIN', 'example.com', 1) + env.cmd('KNOT.UPD.ADD', 'example.com', txn, "dns IN A 2.2.2.2") + resp = env.cmd('KNOT.UPD.DIFF', 'example.com', txn) + env.cmd('KNOT.UPD.COMMIT', 'example.com', txn) + + with env.assertResponseError(msg="Should be commited"): + env.cmd('KNOT.UPD.DIFF', 'example.com', txn) + + UPD = [[], [[b'dns.example.com.', b'3600', b'A', b'2.2.2.2']]] + env.assertEqual([UPD], resp, message="Update doesn't match template") + + TRANSFER = [ + [ + [ + [[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 1 7200 3600 1209600 3600']], + [[b'example.com.', b'3600', b'SOA', b'ns.icann.org. noc.dns.icann.org. 2 7200 3600 1209600 3600']] + ], UPD + ] + ] + + resp = env.cmd('KNOT.UPD.LOAD', 'example.com', 1, 1) + env.assertEqual(resp, TRANSFER, message="Wrong update output")