1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00
Files
github-octodns/tests/test_octodns_provider_easydns.py
2021-09-17 07:10:07 -07:00

446 lines
16 KiB
Python

#
#
#
from __future__ import absolute_import, division, print_function, \
unicode_literals
import json
from mock import Mock, call
from os.path import dirname, join
from requests import HTTPError
from requests_mock import ANY, mock as requests_mock
from unittest import TestCase
from octodns.record import Record
from octodns.provider.easydns import EasyDNSClientNotFound, \
EasyDNSProvider
from octodns.provider.yaml import YamlProvider
from octodns.zone import Zone
class TestEasyDNSProvider(TestCase):
expected = Zone('unit.tests.', [])
source = YamlProvider('test', join(dirname(__file__), 'config'))
source.populate(expected)
def test_populate(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
# Bad auth
with requests_mock() as mock:
mock.get(ANY, status_code=401,
text='{"id":"unauthorized",'
'"message":"Unable to authenticate you."}')
with self.assertRaises(Exception) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEquals('Unauthorized', str(ctx.exception))
# Bad request
with requests_mock() as mock:
mock.get(ANY, status_code=400,
text='{"id":"invalid",'
'"message":"Bad request"}')
with self.assertRaises(Exception) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEquals('Bad request', str(ctx.exception))
# General error
with requests_mock() as mock:
mock.get(ANY, status_code=502, text='Things caught fire')
with self.assertRaises(HTTPError) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEquals(502, ctx.exception.response.status_code)
# Non-existent zone doesn't populate anything
with requests_mock() as mock:
mock.get(ANY, status_code=404,
text='{"id":"not_found","message":"The resource you '
'were accessing could not be found."}')
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEquals(set(), zone.records)
# No diffs == no changes
with requests_mock() as mock:
base = 'https://rest.easydns.net/zones/records/'
with open('tests/fixtures/easydns-records.json') as fh:
mock.get(f'{base}parsed/unit.tests', text=fh.read())
with open('tests/fixtures/easydns-records.json') as fh:
mock.get(f'{base}all/unit.tests', text=fh.read())
provider.populate(zone)
self.assertEquals(15, len(zone.records))
changes = self.expected.changes(zone, provider)
self.assertEquals(0, len(changes))
# 2nd populate makes no network calls/all from cache
again = Zone('unit.tests.', [])
provider.populate(again)
self.assertEquals(15, len(again.records))
# bust the cache
del provider._zone_records[zone.name]
def test_domain(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
with requests_mock() as mock:
base = 'https://rest.easydns.net/'
mock.get(f'{base}domain/unit.tests', status_code=400,
text='{"id":"not_found","message":"The resource you '
'were accessing could not be found."}')
with self.assertRaises(Exception) as ctx:
provider._client.domain('unit.tests')
self.assertEquals('Not Found', str(ctx.exception))
def test_apply_not_found(self):
provider = EasyDNSProvider('test', 'token', 'apikey',
domain_create_sleep=0)
wanted = Zone('unit.tests.', [])
wanted.add_record(Record.new(wanted, 'test1', {
"name": "test1",
"ttl": 300,
"type": "A",
"value": "1.2.3.4",
}))
with requests_mock() as mock:
base = 'https://rest.easydns.net/'
mock.get(f'{base}domain/unit.tests', status_code=404,
text='{"id":"not_found","message":"The resource you '
'were accessing could not be found."}')
mock.put(f'{base}domains/add/unit.tests', status_code=200,
text='{"id":"OK","message":"Zone created."}')
mock.get(f'{base}zones/records/parsed/unit.tests',
status_code=404,
text='{"id":"not_found","message":"The resource you '
'were accessing could not be found."}')
mock.get(f'{base}zones/records/all/unit.tests', status_code=404,
text='{"id":"not_found","message":"The resource you '
'were accessing could not be found."}')
plan = provider.plan(wanted)
self.assertFalse(plan.exists)
self.assertEquals(1, len(plan.changes))
with self.assertRaises(Exception) as ctx:
provider.apply(plan)
self.assertEquals('Not Found', str(ctx.exception))
def test_domain_create(self):
provider = EasyDNSProvider('test', 'token', 'apikey',
domain_create_sleep=0)
domain_after_creation = {
"tm": 1000000000,
"data": [{
"id": "12341001",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "SOA",
"rdata": "dns1.easydns.com. zone.easydns.com. "
"2020010101 3600 600 604800 0",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12341002",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "NS",
"rdata": "LOCAL.",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12341003",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "MX",
"rdata": "LOCAL.",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}],
"count": 3,
"total": 3,
"start": 0,
"max": 1000,
"status": 200
}
with requests_mock() as mock:
base = 'https://rest.easydns.net/'
mock.put(f'{base}domains/add/unit.tests',
status_code=201, text='{"id":"OK"}')
mock.get(f'{base}zones/records/all/unit.tests',
text=json.dumps(domain_after_creation))
mock.delete(ANY, text='{"id":"OK"}')
provider._client.domain_create('unit.tests')
def test_caa(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
# Invalid rdata records
caa_record_invalid = [{
"domain": "unit.tests",
"host": "@",
"ttl": "3600",
"prio": "0",
"type": "CAA",
"rdata": "0",
}]
# Valid rdata records
caa_record_valid = [{
"domain": "unit.tests",
"host": "@",
"ttl": "3600",
"prio": "0",
"type": "CAA",
"rdata": "0 issue ca.unit.tests",
}]
provider._data_for_CAA('CAA', caa_record_invalid)
provider._data_for_CAA('CAA', caa_record_valid)
def test_naptr(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
# Invalid rdata records
naptr_record_invalid = [{
"domain": "unit.tests",
"host": "naptr",
"ttl": "600",
"prio": "10",
"type": "NAPTR",
"rdata": "100",
}]
# Valid rdata records
naptr_record_valid = [{
"domain": "unit.tests",
"host": "naptr",
"ttl": "600",
"prio": "10",
"type": "NAPTR",
"rdata": "10 10 'U' 'SIP+D2U' '!^.*$!sip:info@bar.example.com!' .",
}]
provider._data_for_NAPTR('NAPTR', naptr_record_invalid)
provider._data_for_NAPTR('NAPTR', naptr_record_valid)
def test_srv(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
# Invalid rdata records
srv_invalid = [{
"domain": "unit.tests",
"host": "_srv._tcp",
"ttl": "600",
"type": "SRV",
"rdata": "",
}]
srv_invalid2 = [{
"domain": "unit.tests",
"host": "_srv._tcp",
"ttl": "600",
"type": "SRV",
"rdata": "11",
}]
srv_invalid3 = [{
"domain": "unit.tests",
"host": "_srv._tcp",
"ttl": "600",
"type": "SRV",
"rdata": "12 30",
}]
srv_invalid4 = [{
"domain": "unit.tests",
"host": "_srv._tcp",
"ttl": "600",
"type": "SRV",
"rdata": "13 40 1234",
}]
# Valid rdata
srv_valid = [{
"domain": "unit.tests",
"host": "_srv._tcp",
"ttl": "600",
"type": "SRV",
"rdata": "100 20 5678 foo-2.unit.tests.",
}]
srv_invalid_content = provider._data_for_SRV('SRV', srv_invalid)
srv_invalid_content2 = provider._data_for_SRV('SRV', srv_invalid2)
srv_invalid_content3 = provider._data_for_SRV('SRV', srv_invalid3)
srv_invalid_content4 = provider._data_for_SRV('SRV', srv_invalid4)
srv_valid_content = provider._data_for_SRV('SRV', srv_valid)
self.assertEqual(srv_valid_content['values'][0]['priority'], 100)
self.assertEqual(srv_invalid_content['values'][0]['priority'], 0)
self.assertEqual(srv_invalid_content2['values'][0]['priority'], 11)
self.assertEqual(srv_invalid_content3['values'][0]['priority'], 12)
self.assertEqual(srv_invalid_content4['values'][0]['priority'], 13)
self.assertEqual(srv_valid_content['values'][0]['weight'], 20)
self.assertEqual(srv_invalid_content['values'][0]['weight'], 0)
self.assertEqual(srv_invalid_content2['values'][0]['weight'], 0)
self.assertEqual(srv_invalid_content3['values'][0]['weight'], 30)
self.assertEqual(srv_invalid_content4['values'][0]['weight'], 40)
self.assertEqual(srv_valid_content['values'][0]['port'], 5678)
self.assertEqual(srv_invalid_content['values'][0]['port'], 0)
self.assertEqual(srv_invalid_content2['values'][0]['port'], 0)
self.assertEqual(srv_invalid_content3['values'][0]['port'], 0)
self.assertEqual(srv_invalid_content4['values'][0]['port'], 1234)
self.assertEqual(srv_valid_content['values'][0]['target'],
'foo-2.unit.tests.')
self.assertEqual(srv_invalid_content['values'][0]['target'], '')
self.assertEqual(srv_invalid_content2['values'][0]['target'], '')
self.assertEqual(srv_invalid_content3['values'][0]['target'], '')
self.assertEqual(srv_invalid_content4['values'][0]['target'], '')
def test_apply(self):
provider = EasyDNSProvider('test', 'token', 'apikey')
resp = Mock()
resp.json = Mock()
provider._client._request = Mock(return_value=resp)
domain_after_creation = {
"tm": 1000000000,
"data": [{
"id": "12341001",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "SOA",
"rdata": "dns1.easydns.com. zone.easydns.com. 2020010101"
" 3600 600 604800 0",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12341002",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "NS",
"rdata": "LOCAL.",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12341003",
"domain": "unit.tests",
"host": "@",
"ttl": "0",
"prio": "0",
"type": "MX",
"rdata": "LOCAL.",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}],
"count": 3,
"total": 3,
"start": 0,
"max": 1000,
"status": 200
}
# non-existent domain, create everything
resp.json.side_effect = [
EasyDNSClientNotFound, # no zone in populate
domain_after_creation
]
plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded, no unsupported
n = len(self.expected.records) - 9
self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan))
self.assertFalse(plan.exists)
self.assertEquals(25, provider._client._request.call_count)
provider._client._request.reset_mock()
# delete 1 and update 1
provider._client.records = Mock(return_value=[
{
"id": "12342001",
"domain": "unit.tests",
"host": "www",
"ttl": "300",
"prio": "0",
"type": "A",
"rdata": "2.2.3.9",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12342002",
"domain": "unit.tests",
"host": "www",
"ttl": "300",
"prio": "0",
"type": "A",
"rdata": "2.2.3.8",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}, {
"id": "12342003",
"domain": "unit.tests",
"host": "test1",
"ttl": "3600",
"prio": "0",
"type": "A",
"rdata": "1.2.3.4",
"geozone_id": "0",
"last_mod": "2020-01-01 01:01:01"
}
])
# Domain exists, we don't care about return
resp.json.side_effect = ['{}']
wanted = Zone('unit.tests.', [])
wanted.add_record(Record.new(wanted, 'test1', {
"name": "test1",
"ttl": 300,
"type": "A",
"value": "1.2.3.4",
}))
plan = provider.plan(wanted)
self.assertTrue(plan.exists)
self.assertEquals(2, len(plan.changes))
self.assertEquals(2, provider.apply(plan))
# recreate for update, and delete for the 2 parts of the other
provider._client._request.assert_has_calls([
call('PUT', '/zones/records/add/unit.tests/A', data={
'rdata': '1.2.3.4',
'name': 'test1',
'ttl': 300,
'type': 'A',
'host': 'test1',
}),
call('DELETE', '/zones/records/unit.tests/12342001'),
call('DELETE', '/zones/records/unit.tests/12342002'),
call('DELETE', '/zones/records/unit.tests/12342003')
], any_order=True)