# Copyright 2015 Google Inc. All rights reserved. # # Licensed 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 # limitations under the License. import unittest2 class TestManagedZone(unittest2.TestCase): PROJECT = 'project' ZONE_NAME = 'zone-name' DESCRIPTION = 'ZONE DESCRIPTION' DNS_NAME = 'test.example.com' def _getTargetClass(self): from gcloud.dns.zone import ManagedZone return ManagedZone def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def _setUpConstants(self): import datetime from gcloud._helpers import UTC year = 2015 month = 7 day = 24 hour = 19 minute = 53 seconds = 19 micros = 6000 self.WHEN_STR = '%d-%02d-%02dT%02d:%02d:%02d.%06dZ' % ( year, month, day, hour, minute, seconds, micros) self.WHEN = datetime.datetime( year, month, day, hour, minute, seconds, micros, tzinfo=UTC) self.ZONE_ID = 12345 def _makeResource(self): self._setUpConstants() return { 'name': self.ZONE_NAME, 'dnsName': self.DNS_NAME, 'description': self.DESCRIPTION, 'id': self.ZONE_ID, 'creationTime': self.WHEN_STR, 'nameServers': [ 'ns-cloud1.googledomains.com', 'ns-cloud2.googledomains.com', ], } def _verifyReadonlyResourceProperties(self, zone, resource): self.assertEqual(zone.zone_id, resource.get('id')) if 'creationTime' in resource: self.assertEqual(zone.created, self.WHEN) else: self.assertEqual(zone.created, None) if 'nameServers' in resource: self.assertEqual(zone.name_servers, resource['nameServers']) else: self.assertEqual(zone.name_servers, None) def _verifyResourceProperties(self, zone, resource): self._verifyReadonlyResourceProperties(zone, resource) self.assertEqual(zone.name, resource.get('name')) self.assertEqual(zone.dns_name, resource.get('dnsName')) self.assertEqual(zone.description, resource.get('description')) self.assertEqual(zone.zone_id, resource.get('id')) self.assertEqual(zone.name_server_set, resource.get('nameServerSet')) def test_ctor_defaults(self): zone = self._makeOne(self.ZONE_NAME) self.assertEqual(zone.name, self.ZONE_NAME) self.assertEqual(zone.dns_name, None) self.assertTrue(zone._client is None) with self.assertRaises(AttributeError): _ = zone.project with self.assertRaises(AttributeError): _ = zone.path self.assertEqual(zone.zone_id, None) self.assertEqual(zone.created, None) self.assertEqual(zone.description, None) def test_ctor_wo_description(self): client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) self.assertEqual(zone.name, self.ZONE_NAME) self.assertEqual(zone.dns_name, self.DNS_NAME) self.assertTrue(zone._client is client) self.assertEqual(zone.project, client.project) self.assertEqual( zone.path, '/projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME)) self.assertEqual(zone.zone_id, None) self.assertEqual(zone.created, None) self.assertEqual(zone.description, self.DNS_NAME) def test_ctor_explicit(self): DESCRIPTION = 'DESCRIPTION' client = _Client(self.PROJECT) zone = self._makeOne( self.ZONE_NAME, self.DNS_NAME, client, DESCRIPTION) self.assertEqual(zone.name, self.ZONE_NAME) self.assertEqual(zone.dns_name, self.DNS_NAME) self.assertTrue(zone._client is client) self.assertEqual(zone.project, client.project) self.assertEqual( zone.path, '/projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME)) self.assertEqual(zone.zone_id, None) self.assertEqual(zone.created, None) self.assertEqual(zone.description, DESCRIPTION) def test_from_api_repr_missing_identity(self): self._setUpConstants() client = _Client(self.PROJECT) RESOURCE = {} klass = self._getTargetClass() with self.assertRaises(KeyError): klass.from_api_repr(RESOURCE, client=client) def test_from_api_repr_bare(self): self._setUpConstants() client = _Client(self.PROJECT) RESOURCE = { 'name': self.ZONE_NAME, 'dnsName': self.DNS_NAME, } klass = self._getTargetClass() zone = klass.from_api_repr(RESOURCE, client=client) self.assertTrue(zone._client is client) self._verifyResourceProperties(zone, RESOURCE) def test_from_api_repr_w_properties(self): self._setUpConstants() client = _Client(self.PROJECT) RESOURCE = self._makeResource() klass = self._getTargetClass() zone = klass.from_api_repr(RESOURCE, client=client) self.assertTrue(zone._client is client) self._verifyResourceProperties(zone, RESOURCE) def test_description_setter_bad_value(self): client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) with self.assertRaises(ValueError): zone.description = 12345 def test_description_setter(self): client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) zone.description = 'DESCRIPTION' self.assertEqual(zone.description, 'DESCRIPTION') def test_name_server_set_setter_bad_value(self): client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) with self.assertRaises(ValueError): zone.name_server_set = 12345 def test_name_server_set_setter(self): client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) zone.name_server_set = 'NAME_SERVER_SET' self.assertEqual(zone.name_server_set, 'NAME_SERVER_SET') def test_resource_record_set(self): from gcloud.dns.resource_record_set import ResourceRecordSet RRS_NAME = 'other.example.com' RRS_TYPE = 'CNAME' TTL = 3600 RRDATAS = ['www.example.com'] client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) rrs = zone.resource_record_set(RRS_NAME, RRS_TYPE, TTL, RRDATAS) self.assertTrue(isinstance(rrs, ResourceRecordSet)) self.assertEqual(rrs.name, RRS_NAME) self.assertEqual(rrs.record_type, RRS_TYPE) self.assertEqual(rrs.ttl, TTL) self.assertEqual(rrs.rrdatas, RRDATAS) self.assertTrue(rrs.zone is zone) def test_changes(self): from gcloud.dns.changes import Changes client = _Client(self.PROJECT) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) changes = zone.changes() self.assertTrue(isinstance(changes, Changes)) self.assertTrue(changes.zone is zone) def test_create_w_bound_client(self): PATH = 'projects/%s/managedZones' % self.PROJECT RESOURCE = self._makeResource() conn = _Connection(RESOURCE) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) zone.create() self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'POST') self.assertEqual(req['path'], '/%s' % PATH) SENT = { 'name': self.ZONE_NAME, 'dnsName': self.DNS_NAME, 'description': self.DNS_NAME, } self.assertEqual(req['data'], SENT) self._verifyResourceProperties(zone, RESOURCE) def test_create_w_alternate_client(self): PATH = 'projects/%s/managedZones' % self.PROJECT DESCRIPTION = 'DESCRIPTION' NAME_SERVER_SET = 'NAME_SERVER_SET' RESOURCE = self._makeResource() RESOURCE['nameServerSet'] = NAME_SERVER_SET RESOURCE['description'] = DESCRIPTION conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection(RESOURCE) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) zone.name_server_set = NAME_SERVER_SET zone.description = DESCRIPTION zone.create(client=client2) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'POST') self.assertEqual(req['path'], '/%s' % PATH) SENT = { 'name': self.ZONE_NAME, 'dnsName': self.DNS_NAME, 'nameServerSet': NAME_SERVER_SET, 'description': DESCRIPTION, } self.assertEqual(req['data'], SENT) self._verifyResourceProperties(zone, RESOURCE) def test_create_wo_dns_name_or_description(self): from gcloud.exceptions import BadRequest PATH = 'projects/%s/managedZones' % self.PROJECT _requested = [] def _api_request(**kw): _requested.append(kw) raise BadRequest('missing dns_name / description') conn = _Connection() conn.api_request = _api_request client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, client=client) with self.assertRaises(BadRequest): zone.create() self.assertEqual(len(_requested), 1) req = _requested[0] self.assertEqual(req['method'], 'POST') self.assertEqual(req['path'], '/%s' % PATH) SENT = { 'name': self.ZONE_NAME, } self.assertEqual(req['data'], SENT) def test_create_w_missing_output_properties(self): # In the wild, the resource returned from 'zone.create' sometimes # lacks 'creationTime' / 'lastModifiedTime' PATH = 'projects/%s/managedZones' % (self.PROJECT,) RESOURCE = self._makeResource() del RESOURCE['creationTime'] del RESOURCE['id'] del RESOURCE['nameServers'] self.WHEN = None conn = _Connection(RESOURCE) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) zone.create() self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'POST') self.assertEqual(req['path'], '/%s' % PATH) SENT = { 'name': self.ZONE_NAME, 'dnsName': self.DNS_NAME, 'description': self.DNS_NAME, } self.assertEqual(req['data'], SENT) self._verifyResourceProperties(zone, RESOURCE) def test_exists_miss_w_bound_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) conn = _Connection() client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) self.assertFalse(zone.exists()) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self.assertEqual(req['query_params'], {'fields': 'id'}) def test_exists_hit_w_alternate_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection({}) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) self.assertTrue(zone.exists(client=client2)) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self.assertEqual(req['query_params'], {'fields': 'id'}) def test_reload_w_bound_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) RESOURCE = self._makeResource() conn = _Connection(RESOURCE) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, client=client) zone.reload() self.assertEqual(zone.dns_name, self.DNS_NAME) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self._verifyResourceProperties(zone, RESOURCE) def test_reload_w_alternate_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) RESOURCE = self._makeResource() conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection(RESOURCE) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) zone.reload(client=client2) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self._verifyResourceProperties(zone, RESOURCE) def test_delete_w_bound_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) conn = _Connection({}) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) zone.delete() self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'DELETE') self.assertEqual(req['path'], '/%s' % PATH) def test_delete_w_alternate_client(self): PATH = 'projects/%s/managedZones/%s' % (self.PROJECT, self.ZONE_NAME) conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection({}) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) zone.delete(client=client2) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'DELETE') self.assertEqual(req['path'], '/%s' % PATH) def test_list_resource_record_sets_defaults(self): from gcloud.dns.resource_record_set import ResourceRecordSet PATH = 'projects/%s/managedZones/%s/rrsets' % ( self.PROJECT, self.ZONE_NAME) TOKEN = 'TOKEN' NAME_1 = 'www.example.com' TYPE_1 = 'A' TTL_1 = '86400' RRDATAS_1 = ['123.45.67.89'] NAME_2 = 'alias.example.com' TYPE_2 = 'CNAME' TTL_2 = '3600' RRDATAS_2 = ['www.example.com'] DATA = { 'nextPageToken': TOKEN, 'rrsets': [ {'kind': 'dns#resourceRecordSet', 'name': NAME_1, 'type': TYPE_1, 'ttl': TTL_1, 'rrdatas': RRDATAS_1}, {'kind': 'dns#resourceRecordSet', 'name': NAME_2, 'type': TYPE_2, 'ttl': TTL_2, 'rrdatas': RRDATAS_2}, ] } conn = _Connection(DATA) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) rrsets, token = zone.list_resource_record_sets() self.assertEqual(len(rrsets), len(DATA['rrsets'])) for found, expected in zip(rrsets, DATA['rrsets']): self.assertTrue(isinstance(found, ResourceRecordSet)) self.assertEqual(found.name, expected['name']) self.assertEqual(found.record_type, expected['type']) self.assertEqual(found.ttl, int(expected['ttl'])) self.assertEqual(found.rrdatas, expected['rrdatas']) self.assertEqual(token, TOKEN) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) def test_list_resource_record_sets_explicit(self): from gcloud.dns.resource_record_set import ResourceRecordSet PATH = 'projects/%s/managedZones/%s/rrsets' % ( self.PROJECT, self.ZONE_NAME) TOKEN = 'TOKEN' NAME_1 = 'www.example.com' TYPE_1 = 'A' TTL_1 = '86400' RRDATAS_1 = ['123.45.67.89'] NAME_2 = 'alias.example.com' TYPE_2 = 'CNAME' TTL_2 = '3600' RRDATAS_2 = ['www.example.com'] DATA = { 'rrsets': [ {'kind': 'dns#resourceRecordSet', 'name': NAME_1, 'type': TYPE_1, 'ttl': TTL_1, 'rrdatas': RRDATAS_1}, {'kind': 'dns#resourceRecordSet', 'name': NAME_2, 'type': TYPE_2, 'ttl': TTL_2, 'rrdatas': RRDATAS_2}, ] } conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection(DATA) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) rrsets, token = zone.list_resource_record_sets( max_results=3, page_token=TOKEN, client=client2) self.assertEqual(len(rrsets), len(DATA['rrsets'])) for found, expected in zip(rrsets, DATA['rrsets']): self.assertTrue(isinstance(found, ResourceRecordSet)) self.assertEqual(found.name, expected['name']) self.assertEqual(found.record_type, expected['type']) self.assertEqual(found.ttl, int(expected['ttl'])) self.assertEqual(found.rrdatas, expected['rrdatas']) self.assertEqual(token, None) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self.assertEqual(req['query_params'], {'maxResults': 3, 'pageToken': TOKEN}) def test_list_changes_defaults(self): from gcloud._helpers import _datetime_to_rfc3339 from gcloud.dns.changes import Changes from gcloud.dns.resource_record_set import ResourceRecordSet self._setUpConstants() PATH = 'projects/%s/managedZones/%s/changes' % ( self.PROJECT, self.ZONE_NAME) TOKEN = 'TOKEN' NAME_1 = 'www.example.com' TYPE_1 = 'A' TTL_1 = '86400' RRDATAS_1 = ['123.45.67.89'] NAME_2 = 'alias.example.com' TYPE_2 = 'CNAME' TTL_2 = '3600' RRDATAS_2 = ['www.example.com'] CHANGES_NAME = 'changeset_id' DATA = { 'nextPageToken': TOKEN, 'changes': [{ 'kind': 'dns#change', 'id': CHANGES_NAME, 'status': 'pending', 'startTime': _datetime_to_rfc3339(self.WHEN), 'additions': [ {'kind': 'dns#resourceRecordSet', 'name': NAME_1, 'type': TYPE_1, 'ttl': TTL_1, 'rrdatas': RRDATAS_1}], 'deletions': [ {'kind': 'dns#change', 'name': NAME_2, 'type': TYPE_2, 'ttl': TTL_2, 'rrdatas': RRDATAS_2}], }] } conn = _Connection(DATA) client = _Client(project=self.PROJECT, connection=conn) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client) changes, token = zone.list_changes() self.assertEqual(len(changes), len(DATA['changes'])) for found, expected in zip(changes, DATA['changes']): self.assertTrue(isinstance(found, Changes)) self.assertEqual(found.name, CHANGES_NAME) self.assertEqual(found.status, 'pending') self.assertEqual(found.started, self.WHEN) self.assertEqual(len(found.additions), len(expected['additions'])) for found_rr, expected_rr in zip(found.additions, expected['additions']): self.assertTrue(isinstance(found_rr, ResourceRecordSet)) self.assertEqual(found_rr.name, expected_rr['name']) self.assertEqual(found_rr.record_type, expected_rr['type']) self.assertEqual(found_rr.ttl, int(expected_rr['ttl'])) self.assertEqual(found_rr.rrdatas, expected_rr['rrdatas']) self.assertEqual(len(found.deletions), len(expected['deletions'])) for found_rr, expected_rr in zip(found.deletions, expected['deletions']): self.assertTrue(isinstance(found_rr, ResourceRecordSet)) self.assertEqual(found_rr.name, expected_rr['name']) self.assertEqual(found_rr.record_type, expected_rr['type']) self.assertEqual(found_rr.ttl, int(expected_rr['ttl'])) self.assertEqual(found_rr.rrdatas, expected_rr['rrdatas']) self.assertEqual(token, TOKEN) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) def test_list_changes_explicit(self): from gcloud._helpers import _datetime_to_rfc3339 from gcloud.dns.changes import Changes from gcloud.dns.resource_record_set import ResourceRecordSet self._setUpConstants() PATH = 'projects/%s/managedZones/%s/changes' % ( self.PROJECT, self.ZONE_NAME) TOKEN = 'TOKEN' NAME_1 = 'www.example.com' TYPE_1 = 'A' TTL_1 = '86400' RRDATAS_1 = ['123.45.67.89'] NAME_2 = 'alias.example.com' TYPE_2 = 'CNAME' TTL_2 = '3600' RRDATAS_2 = ['www.example.com'] CHANGES_NAME = 'changeset_id' DATA = { 'changes': [{ 'kind': 'dns#change', 'id': CHANGES_NAME, 'status': 'pending', 'startTime': _datetime_to_rfc3339(self.WHEN), 'additions': [ {'kind': 'dns#resourceRecordSet', 'name': NAME_1, 'type': TYPE_1, 'ttl': TTL_1, 'rrdatas': RRDATAS_1}], 'deletions': [ {'kind': 'dns#change', 'name': NAME_2, 'type': TYPE_2, 'ttl': TTL_2, 'rrdatas': RRDATAS_2}], }] } conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) conn2 = _Connection(DATA) client2 = _Client(project=self.PROJECT, connection=conn2) zone = self._makeOne(self.ZONE_NAME, self.DNS_NAME, client1) changes, token = zone.list_changes( max_results=3, page_token=TOKEN, client=client2) self.assertEqual(len(changes), len(DATA['changes'])) for found, expected in zip(changes, DATA['changes']): self.assertTrue(isinstance(found, Changes)) self.assertEqual(found.name, CHANGES_NAME) self.assertEqual(found.status, 'pending') self.assertEqual(found.started, self.WHEN) self.assertEqual(len(found.additions), len(expected['additions'])) for found_rr, expected_rr in zip(found.additions, expected['additions']): self.assertTrue(isinstance(found_rr, ResourceRecordSet)) self.assertEqual(found_rr.name, expected_rr['name']) self.assertEqual(found_rr.record_type, expected_rr['type']) self.assertEqual(found_rr.ttl, int(expected_rr['ttl'])) self.assertEqual(found_rr.rrdatas, expected_rr['rrdatas']) self.assertEqual(len(found.deletions), len(expected['deletions'])) for found_rr, expected_rr in zip(found.deletions, expected['deletions']): self.assertTrue(isinstance(found_rr, ResourceRecordSet)) self.assertEqual(found_rr.name, expected_rr['name']) self.assertEqual(found_rr.record_type, expected_rr['type']) self.assertEqual(found_rr.ttl, int(expected_rr['ttl'])) self.assertEqual(found_rr.rrdatas, expected_rr['rrdatas']) self.assertEqual(token, None) self.assertEqual(len(conn1._requested), 0) self.assertEqual(len(conn2._requested), 1) req = conn2._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) self.assertEqual(req['query_params'], {'maxResults': 3, 'pageToken': TOKEN}) class _Client(object): def __init__(self, project='project', connection=None): self.project = project self.connection = connection class _Connection(object): def __init__(self, *responses): self._responses = responses self._requested = [] def api_request(self, **kw): from gcloud.exceptions import NotFound self._requested.append(kw) try: response, self._responses = self._responses[0], self._responses[1:] except: raise NotFound('miss') else: return response