Added unit tests and common/DigitalOceanBaseDriver - Added 'common' to FIXTURES_ROOT for FileFixtures in test/common - Modified DigitalOceanBaseDriver from compute/drivers/digitalocean into common/digitalocean to support v1 and v2 by initialization - Added dns/driver/digitalocean tests - Added common/digitalocean tests
Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/a3a5f173 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/a3a5f173 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/a3a5f173 Branch: refs/heads/trunk Commit: a3a5f173fe0992de263caff44bc370b051ecefb6 Parents: 66dc7cd Author: Javier Castillo II <[email protected]> Authored: Sun Apr 12 01:57:29 2015 +0000 Committer: Tomaz Muraus <[email protected]> Committed: Sun Jun 14 18:05:58 2015 +0800 ---------------------------------------------------------------------- libcloud/common/digitalocean.py | 112 +++++++++- libcloud/dns/drivers/digitalocean.py | 41 +--- .../digitalocean/_v1_events_12345670.json | 1 + .../_v1_events_12345670_UNAUTHORIZED.json | 1 + .../fixtures/digitalocean/_v2_account.json | 1 + .../digitalocean/_v2_account_UNAUTHORIZED.json | 1 + .../fixtures/digitalocean/_v2_actions.json | 1 + .../digitalocean/_v2_actions_12345670.json | 1 + .../digitalocean/_v2_actions_page_1.json | 1 + .../digitalocean/_v2_actions_page_2.json | 1 + libcloud/test/common/test_digitalocean_v1.py | 82 +++++++ libcloud/test/common/test_digitalocean_v2.py | 105 +++++++++ .../dns/fixtures/digitalocean/_v2_domains.json | 1 + .../digitalocean/_v2_domains_CREATE.json | 1 + .../digitalocean/_v2_domains_EMPTY.json | 1 + .../digitalocean/_v2_domains_UNAUTHORIZED.json | 1 + .../digitalocean/_v2_domains_testdomain.json | 1 + .../_v2_domains_testdomain_NOT_FOUND.json | 1 + .../_v2_domains_testdomain_records.json | 1 + .../_v2_domains_testdomain_records_1234560.json | 1 + .../_v2_domains_testdomain_records_1234561.json | 1 + .../_v2_domains_testdomain_records_1234562.json | 1 + .../_v2_domains_testdomain_records_1234564.json | 1 + ...ns_testdomain_records_1234564_NOT_FOUND.json | 1 + ...mains_testdomain_records_1234564_UPDATE.json | 1 + .../_v2_domains_testdomain_records_CREATE.json | 1 + libcloud/test/dns/test_digitalocean.py | 214 +++++++++++++++++++ libcloud/test/file_fixtures.py | 1 + 28 files changed, 537 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/common/digitalocean.py ---------------------------------------------------------------------- diff --git a/libcloud/common/digitalocean.py b/libcloud/common/digitalocean.py index 097b207..7d46881 100644 --- a/libcloud/common/digitalocean.py +++ b/libcloud/common/digitalocean.py @@ -19,6 +19,7 @@ Common settings and connection objects for DigitalOcean Cloud from libcloud.utils.py3 import httplib +from libcloud.common.base import BaseDriver from libcloud.common.base import ConnectionUserAndKey, ConnectionKey from libcloud.common.base import JsonResponse from libcloud.common.types import InvalidCredsError @@ -26,12 +27,11 @@ from libcloud.common.types import InvalidCredsError __all__ = [ 'DigitalOcean_v1_Response', 'DigitalOcean_v1_Connection', - 'DigitalOcean_v2_Response' + 'DigitalOcean_v2_Response', 'DigitalOcean_v2_Connection', + 'DigitalOceanBaseDriver' ] -AUTH_URL = 'https://api.digitalocean.com' - class DigitalOcean_v1_Response(JsonResponse): def parse_error(self): @@ -118,3 +118,109 @@ class DigitalOceanConnection(DigitalOcean_v2_Connection): class DigitalOceanResponse(DigitalOcean_v2_Response): pass + + +class DigitalOceanBaseDriver(BaseDriver): + """ + DigitalOcean BaseDriver + """ + name = 'DigitalOcean' + website = 'https://www.digitalocean.com' + + def __new__(cls, key, secret=None, api_version='v2', **kwargs): + if cls is DigitalOceanBaseDriver: + if api_version == 'v1' or secret != None: + cls = DigitalOcean_v1_BaseDriver + elif api_version == 'v2': + cls = DigitalOcean_v2_BaseDriver + else: + raise NotImplementedError('Unsupported API version: %s' % + (api_version)) + return super(DigitalOceanBaseDriver, cls).__new__(cls, **kwargs) + + def ex_account_info(self): + raise NotImplementedError( + 'ex_account_info not implemented for this driver') + + def ex_list_events(self): + raise NotImplementedError( + 'ex_list_events not implemented for this driver') + + def ex_get_event(self, event_id): + raise NotImplementedError( + 'ex_get_event not implemented for this driver') + + def _paginated_request(self, event_id): + raise NotImplementedError( + '_paginated_requests not implemented for this driver') + + +class DigitalOcean_v1_BaseDriver(DigitalOceanBaseDriver): + """ + DigitalOcean BaseDriver using v1 of the API. + """ + connectionCls = DigitalOcean_v1_Connection + + def ex_get_event(self, event_id): + """ + Get an event object + + :param event_id: Event id (required) + :type event_id: ``str`` + """ + return self.connection.request('/v1/events/%s' % event_id).object + + +class DigitalOcean_v2_BaseDriver(DigitalOceanBaseDriver): + """ + DigitalOcean BaseDriver using v2 of the API. + """ + connectionCls = DigitalOcean_v2_Connection + + def ex_account_info(self): + return self.connection.request('/v2/account').object['account'] + + def ex_list_events(self): + return self._paginated_request('/v2/actions', 'actions') + + def ex_get_event(self, event_id): + """ + Get an event object + + :param event_id: Event id (required) + :type event_id: ``str`` + """ + params = {} + return self.connection.request('/v2/actions/%s' % event_id, + params=params).object['action'] + + def _paginated_request(self, url, obj): + """ + Perform multiple calls in order to have a full list of elements when + the API responses are paginated. + + :param url: API endpoint + :type url: ``str`` + + :param obj: Result object key + :type obj: ``str`` + + :return: ``list`` of API response objects + """ + params = {} + data = self.connection.request(url) + try: + pages = data.object['links']['pages']['last'].split('=')[-1] + values = data.object[obj] + for page in range(2, int(pages) + 1): + params.update({'page': page}) + new_data = self.connection.request(url, params=params) + + more_values = new_data.object[obj] + for value in more_values: + values.append(value) + data = values + except KeyError: # No pages. + data = data.object[obj] + + return data http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/dns/drivers/digitalocean.py ---------------------------------------------------------------------- diff --git a/libcloud/dns/drivers/digitalocean.py b/libcloud/dns/drivers/digitalocean.py index 7e70f11..81e313f 100644 --- a/libcloud/dns/drivers/digitalocean.py +++ b/libcloud/dns/drivers/digitalocean.py @@ -22,14 +22,15 @@ __all__ = [ from libcloud.utils.py3 import httplib -from libcloud.common.digitalocean import DigitalOceanConnection, DigitalOceanResponse +from libcloud.common.digitalocean import DigitalOcean_v2_BaseDriver +from libcloud.common.digitalocean import DigitalOceanConnection +from libcloud.common.digitalocean import DigitalOceanResponse from libcloud.dns.types import Provider, RecordType from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError from libcloud.dns.base import DNSDriver, Zone, Record -class DigitalOceanDNSDriver(DNSDriver): - connectionCls = DigitalOceanConnection +class DigitalOceanDNSDriver(DigitalOcean_v2_BaseDriver, DNSDriver): type = Provider.DIGITAL_OCEAN name = "DigitalOcean" website = 'https://www.digitalocean.com' @@ -275,40 +276,6 @@ class DigitalOceanDNSDriver(DNSDriver): method='DELETE') return res.status == httplib.NO_CONTENT -# TODO: If there is a way to push this into libcloud.common.digitalocean -# instead of having it in libcloud.dns.digitalocean and -# libcloud.compute.digitalocean - def _paginated_request(self, url, obj): - """ - Perform multiple calls in order to have a full list of elements when - the API responses are paginated. - - :param url: API endpoint - :type url: ``str`` - - :param obj: Result object key - :type obj: ``str`` - - :return: ``list`` of API response objects - """ - params = {} - data = self.connection.request(url) - try: - pages = data.object['links']['pages']['last'].split('=')[-1] - values = data.object[obj] - for page in range(2, int(pages) + 1): - params.update({'page': page}) - new_data = self.connection.request(url, params=params) - - more_values = new_data.object[obj] - for value in more_values: - values.append(value) - data = values - except KeyError: # No pages. - data = data.object[obj] - - return data - def _to_record(self, data, zone=None): extra = {'port' : data['port'], 'priority' : data['priority'], 'weight' : data['weight']} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670.json b/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670.json new file mode 100644 index 0000000..6ff04b5 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670.json @@ -0,0 +1 @@ +{"status":"OK","event":{"id":12345670,"event_type_id":1,"percentage":"100","droplet_id":1234560,"action_status":"done"}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670_UNAUTHORIZED.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670_UNAUTHORIZED.json b/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670_UNAUTHORIZED.json new file mode 100644 index 0000000..0994c93 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v1_events_12345670_UNAUTHORIZED.json @@ -0,0 +1 @@ +{"status":"ERROR","error_message":"Access Denied","message":"Access Denied"} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_account.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_account.json b/libcloud/test/common/fixtures/digitalocean/_v2_account.json new file mode 100644 index 0000000..37083cf --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_account.json @@ -0,0 +1 @@ +{"account":{"droplet_limit":10,"email":"[email protected]","uuid":"a1234567890b1234567890c1234567890d12345","email_verified":true}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_account_UNAUTHORIZED.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_account_UNAUTHORIZED.json b/libcloud/test/common/fixtures/digitalocean/_v2_account_UNAUTHORIZED.json new file mode 100644 index 0000000..415d9ef --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_account_UNAUTHORIZED.json @@ -0,0 +1 @@ +{"id":"unauthorized","message":"Unable to authenticate you."} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_actions.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_actions.json b/libcloud/test/common/fixtures/digitalocean/_v2_actions.json new file mode 100644 index 0000000..3c36117 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_actions.json @@ -0,0 +1 @@ +{"actions":[],"links":{},"meta":{"total":0}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_actions_12345670.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_actions_12345670.json b/libcloud/test/common/fixtures/digitalocean/_v2_actions_12345670.json new file mode 100644 index 0000000..9631675 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_actions_12345670.json @@ -0,0 +1 @@ +{"action":{"id":12345670,"status":"completed","type":"power_on","started_at":"2015-03-28T10:57:40Z","completed_at":"2015-03-28T10:57:42Z","resource_id":1234560,"resource_type":"droplet","region":{"name":"New York 3","slug":"nyc3","sizes":["512mb","1gb","2gb","4gb","8gb","16gb","32gb","48gb","64gb"],"features":["virtio","private_networking","backups","ipv6","metadata"],"available":true},"region_slug":"nyc3"}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_1.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_1.json b/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_1.json new file mode 100644 index 0000000..b9ebd61 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_1.json @@ -0,0 +1 @@ +{"actions":[{"id":12345671,"status":"completed","type":"create","started_at":"2015-04-10T14:09:37Z","completed_at":"2015-04-10T14:10:03Z","resource_id":1234561,"resource_type":"droplet","region":{"name":"Frankfurt 1","slug":"fra1","sizes":["512mb","1gb","2gb","4gb","8gb","16gb","32gb","48gb","64gb"],"features":["virtio","private_networking","backups","ipv6","metadata"],"available":true},"region_slug":"fra1"}],"links":{"pages":{"last":"https://api.digitalocean.com/v2/actions/?page=2","next":"https://api.digitalocean.com/v2/actions/?page=2"}},"meta":{"total":2}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_2.json ---------------------------------------------------------------------- diff --git a/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_2.json b/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_2.json new file mode 100644 index 0000000..3ddfad2 --- /dev/null +++ b/libcloud/test/common/fixtures/digitalocean/_v2_actions_page_2.json @@ -0,0 +1 @@ +{"actions":[{"id":12345670,"status":"completed","type":"create","started_at":"2015-04-10T14:09:12Z","completed_at":"2015-04-10T14:09:38Z","resource_id":1234560,"resource_type":"droplet","region":{"name":"Frankfurt 1","slug":"fra1","sizes":["512mb","1gb","2gb","4gb","8gb","16gb","32gb","48gb","64gb"],"features":["virtio","private_networking","backups","ipv6","metadata"],"available":true},"region_slug":"fra1"}],"links":{"pages":{"first":"https://api.digitalocean.com/v2/actions/?page=1","prev":"https://api.digitalocean.com/v2/actions/?page=1"}},"meta":{"total":2}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/test_digitalocean_v1.py ---------------------------------------------------------------------- diff --git a/libcloud/test/common/test_digitalocean_v1.py b/libcloud/test/common/test_digitalocean_v1.py new file mode 100644 index 0000000..e10f54d --- /dev/null +++ b/libcloud/test/common/test_digitalocean_v1.py @@ -0,0 +1,82 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and + +import os +import sys +import unittest + +from libcloud.common.types import InvalidCredsError +from libcloud.common.digitalocean import DigitalOceanBaseDriver +from libcloud.dns.types import RecordType +from libcloud.test import LibcloudTestCase, MockHttpTestCase +from libcloud.test.file_fixtures import FileFixtures +from libcloud.test.secrets import DIGITALOCEAN_v1_PARAMS +from libcloud.utils.py3 import httplib + + +class DigitalOceanTests(LibcloudTestCase): + + def setUp(self): + DigitalOceanBaseDriver.connectionCls.conn_classes = \ + (None, DigitalOceanMockHttp) + DigitalOceanMockHttp.type = None + self.driver = DigitalOceanBaseDriver(*DIGITALOCEAN_v1_PARAMS) + + def test_authentication(self): + DigitalOceanMockHttp.type = 'UNAUTHORIZED' + self.assertRaises(InvalidCredsError, self.driver.ex_get_event, '12345670') + + def test_ex_account_info(self): + self.assertRaises(NotImplementedError, self.driver.ex_account_info) + + def test_ex_list_events(self): + self.assertRaises(NotImplementedError, self.driver.ex_list_events) + + def test_ex_get_event(self): + action = self.driver.ex_get_event('12345670') + self.assertEqual(action["status"], "OK") + self.assertEqual(action["event"]["id"], 12345670) + self.assertEqual(action["event"]["event_type_id"], 1) + + def test__paginated_request(self): + self.assertRaises(NotImplementedError, self.driver._paginated_request, '/v1/anything') + + +class DigitalOceanMockHttp(MockHttpTestCase): + fixtures = FileFixtures('common', 'digitalocean') + + response = { + None: httplib.OK, + 'CREATE': httplib.CREATED, + 'DELETE': httplib.NO_CONTENT, + 'EMPTY': httplib.OK, + 'NOT_FOUND': httplib.NOT_FOUND, + 'UNAUTHORIZED': httplib.UNAUTHORIZED, + 'UPDATE': httplib.OK + } + + def _v1_events_12345670_UNAUTHORIZED(self, method, url, body, headers): + body = self.fixtures.load( + '_v1_events_12345670_UNAUTHORIZED.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v1_events_12345670(self, method, url, body, headers): + body = self.fixtures.load('_v1_events_12345670.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/common/test_digitalocean_v2.py ---------------------------------------------------------------------- diff --git a/libcloud/test/common/test_digitalocean_v2.py b/libcloud/test/common/test_digitalocean_v2.py new file mode 100644 index 0000000..c530b5b --- /dev/null +++ b/libcloud/test/common/test_digitalocean_v2.py @@ -0,0 +1,105 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and + +import os +import sys +import unittest + +from libcloud.common.types import InvalidCredsError +from libcloud.common.digitalocean import DigitalOceanBaseDriver +from libcloud.dns.types import RecordType +from libcloud.test import LibcloudTestCase, MockHttpTestCase +from libcloud.test.file_fixtures import FileFixtures +from libcloud.test.secrets import DIGITALOCEAN_v2_PARAMS +from libcloud.utils.py3 import httplib + + +class DigitalOceanTests(LibcloudTestCase): + + def setUp(self): + DigitalOceanBaseDriver.connectionCls.conn_classes = \ + (None, DigitalOceanMockHttp) + DigitalOceanMockHttp.type = None + self.driver = DigitalOceanBaseDriver(*DIGITALOCEAN_v2_PARAMS) + + def test_authentication(self): + DigitalOceanMockHttp.type = 'UNAUTHORIZED' + self.assertRaises(InvalidCredsError, self.driver.ex_account_info) + + def test_ex_account_info(self): + account_info = self.driver.ex_account_info() + self.assertEqual(account_info['uuid'], 'a1234567890b1234567890c1234567890d12345') + self.assertTrue(account_info['email_verified']) + self.assertEqual(account_info['email'], '[email protected]') + self.assertEqual(account_info['droplet_limit'], 10) + + def test_ex_list_events(self): + events = self.driver.ex_list_events() + self.assertEqual(events, []) + + def test_ex_get_event(self): + action = self.driver.ex_get_event('12345670') + self.assertEqual(action["id"], 12345670) + self.assertEqual(action["status"], "completed") + self.assertEqual(action["type"], "power_on") + + def test__paginated_request(self): + DigitalOceanMockHttp.type = 'page_1' + actions = self.driver._paginated_request('/v2/actions', 'actions') + self.assertEqual(actions[0]['id'], 12345671) + self.assertEqual(actions[0]['status'], 'completed') + + +class DigitalOceanMockHttp(MockHttpTestCase): + fixtures = FileFixtures('common', 'digitalocean') + + response = { + None: httplib.OK, + 'CREATE': httplib.CREATED, + 'DELETE': httplib.NO_CONTENT, + 'EMPTY': httplib.OK, + 'NOT_FOUND': httplib.NOT_FOUND, + 'UNAUTHORIZED': httplib.UNAUTHORIZED, + 'UPDATE': httplib.OK + } + + def _v2_account(self, method, url, body, headers): + body = self.fixtures.load('_v2_account.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_account_UNAUTHORIZED(self, method, url, body, headers): + body = self.fixtures.load( + '_v2_account_UNAUTHORIZED.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_actions(self, method, url, body, headers): + body = self.fixtures.load('_v2_actions.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_actions_12345670(self, method, url, body, headers): + body = self.fixtures.load('_v2_actions_12345670.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_actions_page_1(self, method, url, body, headers): + body = self.fixtures.load('_v2_actions_page_1.json') + return (self.response[None], body, {}, + httplib.responses[self.response[None]]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains.json new file mode 100644 index 0000000..f00d3a3 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains.json @@ -0,0 +1 @@ +{"domains":[{"name":"testdomain","ttl":1800,"zone_file":"$ORIGIN testdomain.\n$TTL 1800\ntestdomain. IN SOA ns1.digitalocean.com. hostmaster.testdomain. 1428768671 10800 3600 604800 1800\ntestdomain. 1800 IN NS ns1.digitalocean.com.\ntestdomain. 1800 IN NS ns2.digitalocean.com.\ntestdomain. 1800 IN NS ns3.digitalocean.com.\ntestdomain. 1800 IN A 123.45.67.89\n"}],"links":{},"meta":{"total":1}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_CREATE.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_CREATE.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_CREATE.json new file mode 100644 index 0000000..b5b37f0 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_CREATE.json @@ -0,0 +1 @@ +{"domain":{"name":"testdomain","ttl":null,"zone_file":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_EMPTY.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_EMPTY.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_EMPTY.json new file mode 100644 index 0000000..2b7209c --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_EMPTY.json @@ -0,0 +1 @@ +{"domains":[],"links":{},"meta":{"total":0}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_UNAUTHORIZED.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_UNAUTHORIZED.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_UNAUTHORIZED.json new file mode 100644 index 0000000..415d9ef --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_UNAUTHORIZED.json @@ -0,0 +1 @@ +{"id":"unauthorized","message":"Unable to authenticate you."} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain.json new file mode 100644 index 0000000..cf6cf37 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain.json @@ -0,0 +1 @@ +{"domain":{"name":"testdomain","ttl":1800,"zone_file":"$ORIGIN testdomain.\n$TTL 1800\ntestdomain. IN SOA ns1.digitalocean.com. hostmaster.testdomain. 1428768671 10800 3600 604800 1800\ntestdomain. 1800 IN NS ns1.digitalocean.com.\ntestdomain. 1800 IN NS ns2.digitalocean.com.\ntestdomain. 1800 IN NS ns3.digitalocean.com.\ntestdomain. 1800 IN A 123.45.67.89\n"}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_NOT_FOUND.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_NOT_FOUND.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_NOT_FOUND.json new file mode 100644 index 0000000..fa61040 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_NOT_FOUND.json @@ -0,0 +1 @@ +{"id":"not_found","message":"The resource you were accessing could not be found."} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records.json new file mode 100644 index 0000000..53093f6 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records.json @@ -0,0 +1 @@ +{"domain_records":[{"id":1234560,"type":"NS","name":"@","data":"ns1.digitalocean.com","priority":null,"port":null,"weight":null},{"id":1234561,"type":"NS","name":"@","data":"ns2.digitalocean.com","priority":null,"port":null,"weight":null},{"id":1234562,"type":"NS","name":"@","data":"ns3.digitalocean.com","priority":null,"port":null,"weight":null},{"id":1234564,"type":"A","name":"@","data":"123.45.67.89","priority":null,"port":null,"weight":null}],"links":{},"meta":{"total":4}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234560.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234560.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234560.json new file mode 100644 index 0000000..4e629dd --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234560.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234560,"type":"NS","name":"@","data":"ns1.digitalocean.com","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234561.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234561.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234561.json new file mode 100644 index 0000000..4218337 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234561.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234561,"type":"NS","name":"@","data":"ns2.digitalocean.com","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234562.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234562.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234562.json new file mode 100644 index 0000000..307218d --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234562.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234563,"type":"NS","name":"@","data":"ns3.digitalocean.com","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564.json new file mode 100644 index 0000000..8d34cca --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234564,"type":"A","name":"@","data":"123.45.67.89","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_NOT_FOUND.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_NOT_FOUND.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_NOT_FOUND.json new file mode 100644 index 0000000..fa61040 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_NOT_FOUND.json @@ -0,0 +1 @@ +{"id":"not_found","message":"The resource you were accessing could not be found."} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_UPDATE.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_UPDATE.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_UPDATE.json new file mode 100644 index 0000000..8401c43 --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_1234564_UPDATE.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234564,"type":"A","name":"@","data":"234.56.78.90","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_CREATE.json ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_CREATE.json b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_CREATE.json new file mode 100644 index 0000000..4c032ab --- /dev/null +++ b/libcloud/test/dns/fixtures/digitalocean/_v2_domains_testdomain_records_CREATE.json @@ -0,0 +1 @@ +{"domain_record":{"id":1234565,"type":"A","name":"sub","data":"234.56.78.90","priority":null,"port":null,"weight":null}} http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/dns/test_digitalocean.py ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/test_digitalocean.py b/libcloud/test/dns/test_digitalocean.py new file mode 100644 index 0000000..7557db0 --- /dev/null +++ b/libcloud/test/dns/test_digitalocean.py @@ -0,0 +1,214 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and + +import sys +import unittest + +from libcloud.common.types import InvalidCredsError +from libcloud.dns.drivers.digitalocean import DigitalOceanDNSDriver +from libcloud.dns.types import RecordType +from libcloud.test import LibcloudTestCase, MockHttpTestCase +from libcloud.test.file_fixtures import DNSFileFixtures +from libcloud.test.secrets import DIGITALOCEAN_v2_PARAMS +from libcloud.utils.py3 import httplib + + +class DigitalOceanDNSTests(LibcloudTestCase): + + def setUp(self): + DigitalOceanDNSDriver.connectionCls.conn_classes = \ + (None, DigitalOceanDNSMockHttp) + DigitalOceanDNSMockHttp.type = None + self.driver = DigitalOceanDNSDriver(*DIGITALOCEAN_v2_PARAMS) + + def test_authentication(self): + DigitalOceanDNSMockHttp.type = 'UNAUTHORIZED' + self.assertRaises(InvalidCredsError, self.driver.list_zones) + + def test_list_zones(self): + zones = self.driver.list_zones() + self.assertTrue(len(zones) >= 1) + + def test_get_zone(self): + zone = self.driver.get_zone('testdomain') + self.assertEqual(zone.id, 'testdomain') + + def test_get_zone_not_found(self): + DigitalOceanDNSMockHttp.type = 'NOT_FOUND' + self.assertRaises(Exception, self.driver.get_zone, 'testdomain') + + def test_list_records(self): + zone = self.driver.get_zone('testdomain') + records = self.driver.list_records(zone) + self.assertTrue(len(records) >= 1) + + def test_get_record(self): + record = self.driver.get_record('testdomain', '1234564') + self.assertEqual(record.id, '1234564') + self.assertEqual(record.type, RecordType.A) + self.assertEqual(record.data, '123.45.67.89') + + def test_get_record_not_found(self): + DigitalOceanDNSMockHttp.type = 'NOT_FOUND' + self.assertRaises(Exception, self.driver.get_zone, 'testdomain') + + def test_create_zone(self): + DigitalOceanDNSMockHttp.type = 'CREATE' + zone = self.driver.create_zone('testdomain') + self.assertEqual(zone.id, 'testdomain') + + def test_create_record(self): + zone = self.driver.get_zone('testdomain') + + DigitalOceanDNSMockHttp.type = 'CREATE' + record = self.driver.create_record('sub', zone, RecordType.A, '234.56.78.90') + self.assertEqual(record.id, '1234565') + self.assertEqual(record.type, RecordType.A) + self.assertEqual(record.data, '234.56.78.90') + + def test_update_record(self): + record = self.driver.get_record('testdomain', '1234564') + + DigitalOceanDNSMockHttp.type = 'UPDATE' + record = self.driver.update_record(record, data="234.56.78.90") + self.assertEqual(record.id, '1234564') + self.assertEqual(record.data, "234.56.78.90") + + def test_delete_zone(self): + zone = self.driver.get_zone('testdomain') + + DigitalOceanDNSMockHttp.type = 'DELETE' + self.assertTrue(self.driver.delete_zone(zone)) + + def test_delete_record(self): + record = self.driver.get_record('testdomain', '1234564') + + DigitalOceanDNSMockHttp.type = 'DELETE' + self.assertTrue(self.driver.delete_record(record)) + + +class DigitalOceanDNSMockHttp(MockHttpTestCase): + fixtures = DNSFileFixtures('digitalocean') + + response = { + None: httplib.OK, + 'CREATE': httplib.CREATED, + 'DELETE': httplib.NO_CONTENT, + 'EMPTY': httplib.OK, + 'NOT_FOUND': httplib.NOT_FOUND, + 'UNAUTHORIZED': httplib.UNAUTHORIZED, + 'UPDATE': httplib.OK + } + + def _v2_domains(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_CREATE(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_CREATE.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_EMPTY(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_EMPTY.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_UNAUTHORIZED(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_UNAUTHORIZED.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_testdomain.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_DELETE(self, method, url, body, headers): + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_NOT_FOUND(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_testdomain_NOT_FOUND.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_testdomain_records.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_CREATE(self, method, url, body, headers): + body = self.fixtures.load('_v2_domains_testdomain_records_CREATE.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234560( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234560.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234561( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234561.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234562( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234562.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234563( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234563.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234564( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234564.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234564_DELETE( + self, method, url, body, headers): + self.type = 'DELETE' + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234564_NOT_FOUND( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234564_NOT_FOUND.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + + def _v2_domains_testdomain_records_1234564_UPDATE( + self, method, url, body, headers): + body = self.fixtures.load( + '_v2_domains_testdomain_records_1234564_UPDATE.json') + return (self.response[self.type], body, {}, + httplib.responses[self.response[self.type]]) + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3a5f173/libcloud/test/file_fixtures.py ---------------------------------------------------------------------- diff --git a/libcloud/test/file_fixtures.py b/libcloud/test/file_fixtures.py index 42e3d36..a09639c 100644 --- a/libcloud/test/file_fixtures.py +++ b/libcloud/test/file_fixtures.py @@ -22,6 +22,7 @@ from libcloud.utils.py3 import PY3 from libcloud.utils.py3 import u FIXTURES_ROOT = { + 'common': 'common/fixtures', 'compute': 'compute/fixtures', 'storage': 'storage/fixtures', 'loadbalancer': 'loadbalancer/fixtures',
