def test_sync(self, execute_mock): provider = DynProvider('test', 'cust', 'user', 'pass') # Test Zone create execute_mock.side_effect = [ # No such zone, during populate DynectGetError('foo'), # No such zone, during sync DynectGetError('foo'), # get empty Zone { 'data': {} }, # get zone we can modify & delete with { 'data': { # A top-level to delete 'a_records': [{ 'fqdn': 'www.unit.tests', 'rdata': { 'address': '1.2.3.4' }, 'record_id': 1, 'record_type': 'A', 'ttl': 300, 'zone': 'unit.tests', }], # A node to delete 'alias_records': [{ 'fqdn': 'unit.tests', 'rdata': { 'alias': 'www.unit.tests.' }, 'record_id': 2, 'record_type': 'ALIAS', 'ttl': 300, 'zone': 'unit.tests', }], } } ] # No existing records, create all with patch('dyn.tm.zones.Zone.add_record') as add_mock: with patch('dyn.tm.zones.Zone._update') as update_mock: plan = provider.plan(self.expected) update_mock.assert_not_called() provider.apply(plan) update_mock.assert_called() add_mock.assert_called() # Once for each dyn record self.assertEquals(2, len(add_mock.call_args_list)) execute_mock.assert_has_calls([ call('/Zone/unit.tests/', 'GET', {}), call('/Zone/unit.tests/', 'GET', {}) ]) self.assertEquals(2, len(plan.changes))
def _process_response(self, response, method, final=False): """Process an API response for failure, incomplete, or success and throw any appropriate errors :param response: the JSON response from the request being processed :param method: the HTTP method :param final: boolean flag representing whether or not to continue polling """ status = response['status'] self.logger.debug(status) if status == 'success': return response elif status == 'failure': msgs = response['msgs'] if method == 'POST' and 'login' in msgs[0]['INFO']: raise DynectAuthError(response['msgs']) if method == 'POST': raise DynectCreateError(response['msgs']) elif method == 'GET': raise DynectGetError(response['msgs']) elif method == 'PUT': raise DynectUpdateError(response['msgs']) else: raise DynectDeleteError(response['msgs']) else: # Status was incomplete job_id = response['job_id'] if not final: response = self.wait_for_job_to_complete(job_id) return self._process_response(response, method, True) else: raise DynectQueryTimeout({})
def test_populate_non_existent(self, execute_mock): provider = DynProvider('test', 'cust', 'user', 'pass') # Test Zone create execute_mock.side_effect = [ DynectGetError('foo'), ] got = Zone('unit.tests.', []) provider.populate(got) execute_mock.assert_has_calls([ call('/Zone/unit.tests/', 'GET', {}), ]) self.assertEquals(set(), got.records)
def test_sync(self, execute_mock): provider = DynProvider('test', 'cust', 'user', 'pass') # Test Zone create execute_mock.side_effect = [ # No such zone, during populate DynectGetError('foo'), # No such zone, during sync DynectGetError('foo'), # get empty Zone { 'data': {} }, # get zone we can modify & delete with { 'data': { # A top-level to delete 'a_records': [{ 'fqdn': 'unit.tests', 'rdata': { 'address': '1.2.3.4' }, 'record_id': 1, 'record_type': 'A', 'ttl': 30, 'zone': 'unit.tests', }, { 'fqdn': 'a.unit.tests', 'rdata': { 'address': '2.3.4.5' }, 'record_id': 2, 'record_type': 'A', 'ttl': 30, 'zone': 'unit.tests', }], # A node to delete 'cname_records': [{ 'fqdn': 'cname.unit.tests', 'rdata': { 'cname': 'unit.tests.' }, 'record_id': 3, 'record_type': 'CNAME', 'ttl': 30, 'zone': 'unit.tests', }], # A record to leave alone 'ptr_records': [{ 'fqdn': 'ptr.unit.tests', 'rdata': { 'ptrdname': 'xx.unit.tests.' }, 'record_id': 4, 'record_type': 'PTR', 'ttl': 30, 'zone': 'unit.tests', }], # A record to modify 'srv_records': [{ 'fqdn': '_srv._tcp.unit.tests', 'rdata': { 'port': 10, 'priority': 11, 'target': 'foo-1.unit.tests.', 'weight': 12 }, 'record_id': 5, 'record_type': 'SRV', 'ttl': 30, 'zone': 'unit.tests', }, { 'fqdn': '_srv._tcp.unit.tests', 'rdata': { 'port': 20, 'priority': 21, 'target': 'foo-2.unit.tests.', 'weight': 22 }, 'record_id': 6, 'record_type': 'SRV', 'ttl': 30, 'zone': 'unit.tests', }], } } ] # No existing records, create all with patch('dyn.tm.zones.Zone.add_record') as add_mock: with patch('dyn.tm.zones.Zone._update') as update_mock: plan = provider.plan(self.expected) update_mock.assert_not_called() provider.apply(plan) update_mock.assert_called() add_mock.assert_called() # Once for each dyn record (8 Records, 2 of which have dual values) self.assertEquals(15, len(add_mock.call_args_list)) execute_mock.assert_has_calls([ call('/Zone/unit.tests/', 'GET', {}), call('/Zone/unit.tests/', 'GET', {}) ]) self.assertEquals(10, len(plan.changes)) execute_mock.reset_mock() # Delete one and modify another new = Zone('unit.tests.', []) for name, data in (('a', { 'type': 'A', 'ttl': 30, 'value': '2.3.4.5' }), ('ptr', { 'type': 'PTR', 'ttl': 30, 'value': 'xx.unit.tests.' }), ('_srv._tcp', { 'type': 'SRV', 'ttl': 30, 'values': [{ 'priority': 31, 'weight': 12, 'port': 10, 'target': 'foo-1.unit.tests.' }, { 'priority': 21, 'weight': 22, 'port': 20, 'target': 'foo-2.unit.tests.' }] })): new.add_record(Record.new(new, name, data)) with patch('dyn.tm.zones.Zone.add_record') as add_mock: with patch('dyn.tm.records.DNSRecord.delete') as delete_mock: with patch('dyn.tm.zones.Zone._update') as update_mock: plan = provider.plan(new) provider.apply(plan) update_mock.assert_called() # we expect 4 deletes, 2 from actual deletes and 2 from # updates which delete and recreate self.assertEquals(4, len(delete_mock.call_args_list)) # the 2 (re)creates self.assertEquals(2, len(add_mock.call_args_list)) execute_mock.assert_has_calls([ call('/AllRecord/unit.tests/unit.tests./', 'GET', {'detail': 'Y'}) ]) self.assertEquals(3, len(plan.changes))