From 86b3e4e89ac332e13974547b6e809dde64aef0de Mon Sep 17 00:00:00 2001 From: Benjamin Zengin Date: Thu, 21 Jul 2016 15:37:31 +0200 Subject: [PATCH] Fixes Api-tests and improves performance --- regression-tests.api/runtests.py | 1 + regression-tests.api/test_cryptokeys.py | 218 ++++++++++++------------ regression-tests/zones/cryptokeys.org | 24 +++ 3 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 regression-tests/zones/cryptokeys.org diff --git a/regression-tests.api/runtests.py b/regression-tests.api/runtests.py index 6eb0ee15a..cb66a4880 100755 --- a/regression-tests.api/runtests.py +++ b/regression-tests.api/runtests.py @@ -19,6 +19,7 @@ NAMED_CONF_TPL = """ options { directory "../regression-tests/zones/"; }; zone "example.com" { type master; file "example.com"; }; zone "powerdnssec.org" { type master; file "powerdnssec.org"; }; +zone "cryptokeys.org" { type master; file "cryptokeys.org"; }; """ AUTH_CONF_TPL = """ diff --git a/regression-tests.api/test_cryptokeys.py b/regression-tests.api/test_cryptokeys.py index cec5e3823..c5981def4 100644 --- a/regression-tests.api/test_cryptokeys.py +++ b/regression-tests.api/test_cryptokeys.py @@ -1,56 +1,65 @@ import subprocess import json import unittest +import os from test_helper import ApiTestCase, is_auth @unittest.skipIf(not is_auth(), "Not applicable") class Cryptokeys(ApiTestCase): - zone = "cryptokeyzone" - def setUp(self): - super(Cryptokeys, self).setUp() - try: - subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "create-zone", Cryptokeys.zone]) - except subprocess.CalledProcessError as e: - self.fail("Couldn't create zone: "+e.output) + def __init__(self, *args, **kwds): + super(Cryptokeys, self).__init__(*args, **kwds) + self.keyid = 0 + self.zone = "cryptokeys.org" def tearDown(self): super(Cryptokeys,self).tearDown() + self.remove_zone_key(self.keyid) + + # Adding a key to self.zone using the pdnsutil command + def add_zone_key(self, status='inactive'): try: - subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "delete-zone", Cryptokeys.zone]) + return subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "add-zone-key", self.zone, "ksk", status], stderr=open(os.devnull, 'wb')) except subprocess.CalledProcessError as e: - self.fail("Couldn't delete zone: "+e.output) - + self.fail("pdnsutil add-zone-key failed: "+e.output) - # This methode test the DELETE api call. Sometimes 200 or 422 are valid return codes, - # because it "could" happen that the backend crashes during the test or the remove function returns false. - # In this case 422 is correct. I don't know how to force false backend behavior. So i assume that the backend - # works correct. - def test_delete(self): + # Removes a key from self.zone by id using the pdnsutil command + def remove_zone_key(self, key_id): try: - keyid = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "add-zone-key", Cryptokeys.zone, "ksk"]) + subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "remove-zone-key", self.zone, str(key_id)]) except subprocess.CalledProcessError as e: - self.fail("pdnsutil add-zone-key failed: "+e.output) + self.fail("pdnsutil remove-zone-key failed: "+e.output) + + # This method tests the DELETE api call. + def test_delete(self): + self.keyid = self.add_zone_key() #checks the status code. I don't know how to test explicit that the backend fail removing a key. - r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid)) - self.assertTrue(r.status_code == 200 or r.status_code == 422) + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid)) + self.assertEquals(r.status_code, 200) + self.assertEquals(r.content, "") # Check that the key is actually deleted try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", Cryptokeys.zone]) - self.assertFalse(Cryptokeys.zone in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", self.zone]) + self.assertNotIn(self.zone, out) except subprocess.CalledProcessError as e: self.fail("pdnsutil list-keys failed: " + e.output) + def test_delete_wrong_zone(self): + self.keyid = self.add_zone_key() #checks for not covered zonename - r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"fail/cryptokeys/"+keyid)) + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"fail/cryptokeys/"+self.keyid)) self.assertEquals(r.status_code, 400) + def test_delete_key_is_gone(self): + self.keyid = self.add_zone_key() + self.remove_zone_key(self.keyid) #checks for key is gone. Its ok even if no key had to be deleted. Or something went wrong with the backend. - r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid)) - self.assertTrue(r.status_code == 200 or r.status_code == 422) + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid)) + self.assertEquals(r.status_code, 200) + self.assertEquals(r.content, "") # Prepares the json object for Post and sends it to the server def add_key(self, content='', type='ksk', active='true' , algo='', bits=0): @@ -70,19 +79,13 @@ class Cryptokeys(ApiTestCase): if content != '': payload['content'] = content r = self.session.post( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys"), + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys"), data=json.dumps(payload), headers={'content-type': 'application/json'}) - return r - # Removes a key by id using the pdnsutil command - def remove_key(self, key_id): - try: - subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "remove-zone-key", Cryptokeys.zone, str(key_id)]) - except subprocess.CalledProcessError as e: - self.fail("pdnsutil remove-zone-key failed: "+e.output) + return r - # Tests POST for a positiv result and deletes the added key + # Test POST for a positive result and delete the added key def post_helper(self,content='', algo='', bits=0): r = self.add_key(content=content, algo=algo, bits=bits) self.assert_success_json(r) @@ -90,31 +93,32 @@ class Cryptokeys(ApiTestCase): response = r.json() # Only a ksk added, so expected type is csk self.assertEquals(response['keytype'], 'csk') - key_id = response['id'] + self.keyid = response['id'] # Check if the key is actually added try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", Cryptokeys.zone]) - self.assertTrue(Cryptokeys.zone in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", self.zone]) + self.assertIn(self.zone, out) except subprocess.CalledProcessError as e: self.fail("pdnsutil list-keys failed: " + e.output) - # Remove it for further testing - self.remove_key(key_id) - + # Test POST to add a key with default algorithm def test_post(self): - # Test add a key with default algorithm self.post_helper() - # Test add a key with specific number + # Test POST to add a key with specific algorithm number + def test_post_specific_number(self): self.post_helper(algo=10, bits=512) - # Test add a key with specific name and bits + # Test POST to add a key with specific name and bits + def test_post_specific_name_bits(self): self.post_helper(algo="rsasha256", bits=256) - # Test add a key with specific name + # Test POST to add a key with specific name + def test_post_specific_name(self): self.post_helper(algo='ecdsa256') - # Test add a private key from extern resource + # Test POST to add a private key from external resource + def test_post_content(self): self.post_helper(content="Private-key-format: v1.2\n"+ "Algorithm: 8 (RSASHA256)\n"+ "Modulus: 4GlYLGgDI7ohnP8SmEW8EBERbNRusDcg0VQda/EPVHU=\n"+ @@ -126,144 +130,138 @@ class Cryptokeys(ApiTestCase): "Exponent2: tfh1OMPQKBdnU6iATjNR2w==\n"+ "Coefficient: eVrHe/kauqOewSKndIImrg==)\n") - # Test wrong key format + def test_post_wrong_key_format(self): r = self.add_key(content="trollololoooolll") self.assert_error_json(r) self.assertEquals(r.status_code, 422) - self.assertIn("Wrong key format!",r.json()['error']) + self.assertIn("Key could not be parsed. Make sure your key format is correct.",r.json()['error']) - # Test wrong keytype + def test_post_wrong_keytype(self): r = self.add_key(type='sdfdhhgj') self.assert_error_json(r) self.assertEquals(r.status_code, 422) self.assertIn("Invalid keytype",r.json()['error']) - #Test unsupported algorithem + def test_post_wrong_bits_format(self): + r = self.add_key(bits='sdfdhhgj') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + r = self.add_key(bits='5.5') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + r = self.add_key(bits='-6') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + def test_post_unsupported_algorithm(self): r = self.add_key(algo='lkjhgf') self.assert_error_json(r) self.assertEquals(r.status_code, 422) self.assertIn("Unknown algorithm:",r.json()['error']) - #Test add a key and forgot bits + def test_post_forgot_bits(self): r = self.add_key(algo="rsasha256") self.assert_error_json(r) self.assertEquals(r.status_code, 422) self.assertIn("key requires the size (in bits) to be passed", r.json()['error']) - #Test wrong bit size + def test_post_wrong_bit_size(self): r = self.add_key(algo=10, bits=30) self.assert_error_json(r) self.assertEquals(r.status_code,422) - self.assertIn("Wrong bit size!", r.json()['error']) + self.assertIn("The algorithm does not support the given bit size.", r.json()['error']) - #Test can't guess key size + def test_post_can_not_guess_key_size(self): r = self.add_key(algo=15) self.assert_error_json(r) self.assertEquals(r.status_code,422) - self.assertIn("Can't guess key size for algorithm", r.json()['error']) - - def test_put_activate_deactivate_key(self): + self.assertIn("Can not guess key size for algorithm", r.json()['error']) - #create key - try: - keyid = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "add-zone-key", Cryptokeys.zone, "ksk"]) - except subprocess.CalledProcessError as e: - self.fail("pdnsutil add-zone-key failed: "+e.output) + def test_put_activate_key(self): + self.keyid = self.add_zone_key() - # activate key payload = { 'active': True } - o = self.session.put( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid), + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), data=json.dumps(payload), headers={'content-type': 'application/json'}) - self.assertEquals(o.status_code, 200) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") # check if key is activated try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", Cryptokeys.zone]) - self.assertTrue("Active" in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Active", out) except subprocess.CalledProcessError as e: self.fail("pdnsutil show-zone failed: " + e.output) + def test_put_deactivate_key(self): + self.keyid= self.add_zone_key(status='active') # deactivate key payload2 = { 'active': False } - q = self.session.put( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid), + + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), data=json.dumps(payload2), headers={'content-type': 'application/json'}) - self.assertEquals(q.status_code, 200) - self.assert_success_json(q) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") # check if key is deactivated try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", Cryptokeys.zone]) - self.assertTrue("Inactive" in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Inactive", out) except subprocess.CalledProcessError as e: self.fail("pdnsutil show-zone failed: " + e.output) - # Remove it for further testing - try: - subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "remove-zone-key", Cryptokeys.zone, str(keyid)]) - except subprocess.CalledProcessError as e: - self.fail("pdnsutil remove-zone-key failed: "+e.output) - - def test_put_deactivate_deactivated_activate_activated_key(self): - - #create key - try: - keyid = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "add-zone-key", Cryptokeys.zone, "ksk"]) - except subprocess.CalledProcessError as e: - self.fail("pdnsutil add-zone-key failed: "+e.output) + def test_put_deactivate_inactive_key(self): + self.keyid = self.add_zone_key() # deactivate key payload = { 'active': False } - q = self.session.put( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid), + + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), data=json.dumps(payload), headers={'content-type': 'application/json'}) - self.assertEquals(q.status_code, 200) - self.assert_success_json(q) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") # check if key is still deactivated try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", Cryptokeys.zone]) - self.assertTrue("Inactive" in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Inactive", out) except subprocess.CalledProcessError as e: self.fail("pdnsutil show-zone failed: " + e.output) + def test_put_activate_active_key(self): + self.keyid =self.add_zone_key(status='active') + # activate key payload2 = { 'active': True } - o = self.session.put( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid), + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), data=json.dumps(payload2), headers={'content-type': 'application/json'}) - self.assertEquals(o.status_code, 200) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") # check if key is activated try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", Cryptokeys.zone]) - self.assertTrue("Active" in out) - except subprocess.CalledProcessError as e: - self.fail("pdnsutil show-zone failed: " + e.output) - - #activate again - z = self.session.put( - self.url("/api/v1/servers/localhost/zones/"+Cryptokeys.zone+"/cryptokeys/"+keyid), - data=json.dumps(payload2), - headers={'content-type': 'application/json'}) - self.assertEquals(z.status_code, 200) - - # check if key is still activated - try: - out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", Cryptokeys.zone]) - self.assertTrue("Active" in out) + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Active", out) except subprocess.CalledProcessError as e: self.fail("pdnsutil show-zone failed: " + e.output) \ No newline at end of file diff --git a/regression-tests/zones/cryptokeys.org b/regression-tests/zones/cryptokeys.org new file mode 100644 index 000000000..9e7add45e --- /dev/null +++ b/regression-tests/zones/cryptokeys.org @@ -0,0 +1,24 @@ +cryptokeys.org. 3600 IN SOA cryptokeys.ds9a.nl. ahu.ds9a.nl. ( + 2009071301 ; serial + 14400 ; refresh (2 hours 30 minutes) + 3600 ; retry (7 minutes 30 seconds) + 604800 ; expire (1 week) + 3600 ; minimum (7 minutes 30 seconds) + ) + 3600 NS cryptokeys.ds9a.nl. + 3600 NS cryptokeys.ds9a.nl. + 3600 MX 10 cryptokeys.easy-server.com. + 3600 A 212.123.148.70 +www.cryptokeys.org. 3600 CNAME cryptokeys.org. +webserver 3600 A 1.2.3.4 +smtp 3600 A 4.3.2.1 +localhost 3600 A 127.0.0.1 + 3600 AAAA ::1 +ipv6 3600 AAAA 2001:888:1036:0:208:a1ff:fe19:f000 +zbefore.a.cryptokeys.org. 3600 TXT "before" +after.cryptokeys.org. 3600 TXT "after" +zzz.cryptokeys.org. 3600 TXT "this is the end.." +delegated 3600 IN NS ns1.delegated +delegated 3600 IN NS ns2.delegated +ns1.delegated 3600 IN A 1.2.3.4 +ns2.delegated 3600 IN A 4.3.2.1 \ No newline at end of file -- 2.40.0