| @ -0,0 +1,16 @@ | |||
| { | |||
| "totalPages": 1, | |||
| "totalRecords": 1, | |||
| "data": [{ | |||
| "created": 1511740800000, | |||
| "folderId": 1990, | |||
| "gtdEnabled": false, | |||
| "pendingActionId": 0, | |||
| "updated": 1511766661574, | |||
| "processMulti": false, | |||
| "activeThirdParties": [], | |||
| "name": "unit.tests", | |||
| "id": 123123 | |||
| }], | |||
| "page": 0 | |||
| } | |||
| @ -0,0 +1,312 @@ | |||
| { | |||
| "totalPages": 1, | |||
| "totalRecords": 21, | |||
| "data": [{ | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "caaType": "issue", | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "issuerCritical": 0, | |||
| "ttl": 3600, | |||
| "source": 1, | |||
| "name": "", | |||
| "value": "\"ca.unit.tests\"", | |||
| "id": 11189874, | |||
| "type": "CAA" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "", | |||
| "value": "1.2.3.4", | |||
| "id": 11189875, | |||
| "type": "A" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "", | |||
| "value": "1.2.3.5", | |||
| "id": 11189876, | |||
| "type": "A" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "weight": 20, | |||
| "source": 1, | |||
| "name": "_srv._tcp", | |||
| "value": "foo-1.unit.tests.", | |||
| "id": 11189877, | |||
| "priority": 10, | |||
| "type": "SRV", | |||
| "port": 30 | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "weight": 20, | |||
| "source": 1, | |||
| "name": "_srv._tcp", | |||
| "value": "foo-2.unit.tests.", | |||
| "id": 11189878, | |||
| "priority": 12, | |||
| "type": "SRV", | |||
| "port": 30 | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "source": 1, | |||
| "name": "aaaa", | |||
| "value": "2601:644:500:e210:62f8:1dff:feb8:947a", | |||
| "id": 11189879, | |||
| "type": "AAAA" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "cname", | |||
| "value": "", | |||
| "id": 11189880, | |||
| "type": "CNAME" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 3600, | |||
| "source": 1, | |||
| "name": "included", | |||
| "value": "", | |||
| "id": 11189881, | |||
| "type": "CNAME" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "mxLevel": 30, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "mx", | |||
| "value": "smtp-3.unit.tests.", | |||
| "id": 11189882, | |||
| "type": "MX" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "mxLevel": 20, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "mx", | |||
| "value": "smtp-2.unit.tests.", | |||
| "id": 11189883, | |||
| "type": "MX" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "mxLevel": 10, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "mx", | |||
| "value": "smtp-4.unit.tests.", | |||
| "id": 11189884, | |||
| "type": "MX" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "mxLevel": 40, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "mx", | |||
| "value": "smtp-1.unit.tests.", | |||
| "id": 11189885, | |||
| "type": "MX" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "source": 1, | |||
| "name": "spf", | |||
| "value": "\"v=spf1 ip4:192.168.0.1/16-all\"", | |||
| "id": 11189886, | |||
| "type": "SPF" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "source": 1, | |||
| "name": "txt", | |||
| "value": "\"Bah bah black sheep\"", | |||
| "id": 11189887, | |||
| "type": "TXT" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "source": 1, | |||
| "name": "txt", | |||
| "value": "\"have you any wool.\"", | |||
| "id": 11189888, | |||
| "type": "TXT" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 600, | |||
| "source": 1, | |||
| "name": "txt", | |||
| "value": "\"v=DKIM1;k=rsa;s=email;h=sha256;p=A/kinda+of/long/string+with+numb3rs\"", | |||
| "id": 11189889, | |||
| "type": "TXT" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 3600, | |||
| "source": 1, | |||
| "name": "under", | |||
| "value": "ns1.unit.tests.", | |||
| "id": 11189890, | |||
| "type": "NS" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 3600, | |||
| "source": 1, | |||
| "name": "under", | |||
| "value": "ns2", | |||
| "id": 11189891, | |||
| "type": "NS" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "www", | |||
| "value": "2.2.3.6", | |||
| "id": 11189892, | |||
| "type": "A" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "www.sub", | |||
| "value": "2.2.3.6", | |||
| "id": 11189893, | |||
| "type": "A" | |||
| }, { | |||
| "failover": false, | |||
| "monitor": false, | |||
| "sourceId": 123123, | |||
| "dynamicDns": false, | |||
| "failed": false, | |||
| "gtdLocation": "DEFAULT", | |||
| "hardLink": false, | |||
| "ttl": 300, | |||
| "source": 1, | |||
| "name": "ptr", | |||
| "value": "foo.bar.com.", | |||
| "id": 11189894, | |||
| "type": "PTR" | |||
| }], | |||
| "page": 0 | |||
| } | |||
| @ -0,0 +1,202 @@ | |||
| # | |||
| # | |||
| # | |||
| from __future__ import absolute_import, division, print_function, \ | |||
| unicode_literals | |||
| 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.dnsmadeeasy import DnsMadeEasyClientNotFound, \ | |||
| DnsMadeEasyProvider | |||
| from octodns.provider.yaml import YamlProvider | |||
| from octodns.zone import Zone | |||
| import json | |||
| class TestDnsMadeEasyProvider(TestCase): | |||
| expected = Zone('unit.tests.', []) | |||
| source = YamlProvider('test', join(dirname(__file__), 'config')) | |||
| source.populate(expected) | |||
| # Our test suite differs a bit, add our NS and remove the simple one | |||
| expected.add_record(Record.new(expected, 'under', { | |||
| 'ttl': 3600, | |||
| 'type': 'NS', | |||
| 'values': [ | |||
| 'ns1.unit.tests.', | |||
| 'ns2.unit.tests.', | |||
| ] | |||
| })) | |||
| for record in list(expected.records): | |||
| if record.name == 'sub' and record._type == 'NS': | |||
| expected._remove_record(record) | |||
| break | |||
| def test_populate(self): | |||
| provider = DnsMadeEasyProvider('test', 'api', 'secret') | |||
| # Bad auth | |||
| with requests_mock() as mock: | |||
| mock.get(ANY, status_code=401, | |||
| text='{"error": ["API key not found"]}') | |||
| with self.assertRaises(Exception) as ctx: | |||
| zone = Zone('unit.tests.', []) | |||
| provider.populate(zone) | |||
| self.assertEquals('Unauthorized', ctx.exception.message) | |||
| # Bad request | |||
| with requests_mock() as mock: | |||
| mock.get(ANY, status_code=400, | |||
| text='{"error": ["Rate limit exceeded"]}') | |||
| with self.assertRaises(Exception) as ctx: | |||
| zone = Zone('unit.tests.', []) | |||
| provider.populate(zone) | |||
| self.assertEquals('\n - Rate limit exceeded', | |||
| ctx.exception.message) | |||
| # 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-existant zone doesn't populate anything | |||
| with requests_mock() as mock: | |||
| mock.get(ANY, status_code=404, | |||
| text='<html><head></head><body></body></html>') | |||
| zone = Zone('unit.tests.', []) | |||
| provider.populate(zone) | |||
| self.assertEquals(set(), zone.records) | |||
| # No diffs == no changes | |||
| with requests_mock() as mock: | |||
| base = 'https://api.dnsmadeeasy.com/V2.0/dns/managed' | |||
| with open('tests/fixtures/dnsmadeeasy-domains.json') as fh: | |||
| mock.get('{}{}'.format(base, '/'), text=fh.read()) | |||
| with open('tests/fixtures/dnsmadeeasy-records.json') as fh: | |||
| mock.get('{}{}'.format(base, '/123123/records'), | |||
| text=fh.read()) | |||
| zone = Zone('unit.tests.', []) | |||
| provider.populate(zone) | |||
| self.assertEquals(13, 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(13, len(again.records)) | |||
| # bust the cache | |||
| del provider._zone_records[zone.name] | |||
| def test_apply(self): | |||
| # Create provider with sandbox enabled | |||
| provider = DnsMadeEasyProvider('test', 'api', 'secret', True) | |||
| resp = Mock() | |||
| resp.json = Mock() | |||
| provider._client._request = Mock(return_value=resp) | |||
| with open('tests/fixtures/dnsmadeeasy-domains.json') as fh: | |||
| domains = json.load(fh) | |||
| # non-existant domain, create everything | |||
| resp.json.side_effect = [ | |||
| DnsMadeEasyClientNotFound, # no zone in populate | |||
| DnsMadeEasyClientNotFound, # no domain during apply | |||
| domains | |||
| ] | |||
| plan = provider.plan(self.expected) | |||
| # No root NS, no ignored, no excluded, no unsupported | |||
| n = len(self.expected.records) - 5 | |||
| self.assertEquals(n, len(plan.changes)) | |||
| self.assertEquals(n, provider.apply(plan)) | |||
| provider._client._request.assert_has_calls([ | |||
| # created the domain | |||
| call('POST', '/', data={'name': 'unit.tests'}), | |||
| # get all domains to build the cache | |||
| call('GET', '/'), | |||
| # created at least one of the record with expected data | |||
| call('POST', '/123123/records', data={ | |||
| 'name': '_srv._tcp', | |||
| 'weight': 20, | |||
| 'value': 'foo-1.unit.tests.', | |||
| 'priority': 10, | |||
| 'ttl': 600, | |||
| 'type': 'SRV', | |||
| 'port': 30 | |||
| }), | |||
| ]) | |||
| 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': 11189897, | |||
| 'name': 'www', | |||
| 'value': '1.2.3.4', | |||
| 'ttl': 300, | |||
| 'type': 'A', | |||
| }, | |||
| { | |||
| 'id': 11189898, | |||
| 'name': 'www', | |||
| 'value': '2.2.3.4', | |||
| 'ttl': 300, | |||
| 'type': 'A', | |||
| }, | |||
| { | |||
| 'id': 11189899, | |||
| 'name': 'ttl', | |||
| 'value': '3.2.3.4', | |||
| 'ttl': 600, | |||
| 'type': 'A', | |||
| } | |||
| ]) | |||
| # Domain exists, we don't care about return | |||
| resp.json.side_effect = ['{}'] | |||
| wanted = Zone('unit.tests.', []) | |||
| wanted.add_record(Record.new(wanted, 'ttl', { | |||
| 'ttl': 300, | |||
| 'type': 'A', | |||
| 'value': '3.2.3.4' | |||
| })) | |||
| plan = provider.plan(wanted) | |||
| self.assertEquals(2, len(plan.changes)) | |||
| self.assertEquals(2, provider.apply(plan)) | |||
| # recreate for update, and deletes for the 2 parts of the other | |||
| provider._client._request.assert_has_calls([ | |||
| call('POST', '/123123/records', data={ | |||
| 'value': '3.2.3.4', | |||
| 'type': 'A', | |||
| 'name': 'ttl', | |||
| 'ttl': 300 | |||
| }), | |||
| call('DELETE', '/123123/records/11189899'), | |||
| call('DELETE', '/123123/records/11189897'), | |||
| call('DELETE', '/123123/records/11189898') | |||
| ], any_order=True) | |||