diff --git a/designateclient/functionaltests/client.py b/designateclient/functionaltests/client.py index 2c959ba..70c8e17 100644 --- a/designateclient/functionaltests/client.py +++ b/designateclient/functionaltests/client.py @@ -47,6 +47,26 @@ def build_option_string(options): if value is not None) +def build_flags_string(flags): + """Format a string of value-less flags. + + Pass in a dictionary mapping flags to booleans. Those flags set to true + are included in the returned string. + + Usage: + build_flags_string({ + '--no-ttl': True, + '--no-name': False, + '--verbose': True, + }) + + Returns: + '--no-ttl --verbose' + """ + flags = {flag: is_set for flag, is_set in flags.items() if is_set} + return " ".join(flags.keys()) + + class ZoneCommands(object): """This is a mixin that provides zone commands to DesignateCLI""" @@ -128,7 +148,51 @@ class ZoneTransferCommands(object): return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) -class DesignateCLI(base.CLIClient, ZoneCommands, ZoneTransferCommands): +class RecordsetCommands(object): + + def recordset_show(self, zone_id, id, *args, **kwargs): + cmd = 'recordset show {0} {1}'.format(zone_id, id) + return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) + + def recordset_list(self, zone_id, *args, **kwargs): + cmd = 'recordset list {0}'.format(zone_id) + return self.parsed_cmd(cmd, ListModel, *args, **kwargs) + + def recordset_create(self, zone_id, name, records=None, type=None, + description=None, ttl=None, *args, **kwargs): + options_str = build_option_string({ + '--records': records, + '--type': type, + '--description': description, + '--ttl': ttl, + }) + cmd = 'recordset create {0} {1} {2}'.format(zone_id, name, options_str) + return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) + + def recordset_set(self, zone_id, id, records=None, type=None, + description=None, ttl=None, no_description=False, + no_ttl=False, *args, **kwargs): + options_str = build_option_string({ + '--records': records, + '--type': type, + '--description': description, + '--ttl': ttl, + }) + flags_str = build_flags_string({ + '--no-description': no_description, + '--no-ttl': no_ttl, + }) + cmd = 'recordset set {0} {1} {2} {3}'.format( + zone_id, id, flags_str, options_str) + return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) + + def recordset_delete(self, zone_id, id, *args, **kwargs): + cmd = 'recordset delete {0} {1}'.format(zone_id, id) + return self.parsed_cmd(cmd, *args, **kwargs) + + +class DesignateCLI(base.CLIClient, ZoneCommands, ZoneTransferCommands, + RecordsetCommands): # instantiate this once to minimize requests to keystone _CLIENTS = None diff --git a/designateclient/functionaltests/datagen.py b/designateclient/functionaltests/datagen.py index 9fd8bde..7ae7178 100644 --- a/designateclient/functionaltests/datagen.py +++ b/designateclient/functionaltests/datagen.py @@ -17,6 +17,13 @@ import random import string +def random_digits(n=8): + return "".join([random.choice(string.digits) for _ in range(n)]) + + def random_zone_name(name='testdomain'): - digits = "".join([random.choice(string.digits) for _ in range(8)]) - return "{0}{1}.com.".format(name, digits) + return "{0}{1}.com.".format(name, random_digits()) + + +def random_a_recordset_name(zone_name, recordset_name='testrecord'): + return "{0}{1}.{2}".format(recordset_name, random_digits(), zone_name) diff --git a/designateclient/functionaltests/v2/fixtures.py b/designateclient/functionaltests/v2/fixtures.py index 7bb096a..1b6894c 100644 --- a/designateclient/functionaltests/v2/fixtures.py +++ b/designateclient/functionaltests/v2/fixtures.py @@ -78,3 +78,21 @@ class TransferRequestFixture(BaseFixture): client.zone_transfer_request_delete(transfer_request_id) except CommandFailed: pass + + +class RecordsetFixture(BaseFixture): + """See DesignateCLI.recordset_create for __init__ args""" + + def _setUp(self): + super(RecordsetFixture, self)._setUp() + self.recordset = self.client.recordset_create( + *self.args, **self.kwargs) + self.addCleanup(self.cleanup_recordset, self.client, + self.recordset.zone_id, self.recordset.id) + + @classmethod + def cleanup_recordset(cls, client, zone_id, recordset_id): + try: + client.recordset_delete(zone_id, recordset_id) + except CommandFailed: + pass diff --git a/designateclient/functionaltests/v2/test_recordsets.py b/designateclient/functionaltests/v2/test_recordsets.py new file mode 100644 index 0000000..8712c23 --- /dev/null +++ b/designateclient/functionaltests/v2/test_recordsets.py @@ -0,0 +1,113 @@ +""" +Copyright 2015 Rackspace + +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. +""" +from tempest_lib.exceptions import CommandFailed + +from designateclient.functionaltests.base import BaseDesignateTest +from designateclient.functionaltests.datagen import random_a_recordset_name +from designateclient.functionaltests.datagen import random_zone_name +from designateclient.functionaltests.v2.fixtures import RecordsetFixture +from designateclient.functionaltests.v2.fixtures import ZoneFixture + + +class TestRecordset(BaseDesignateTest): + + def setUp(self): + super(TestRecordset, self).setUp() + self.zone = self.useFixture(ZoneFixture( + name=random_zone_name(), + email='test@example.com', + )).zone + + name = random_a_recordset_name(self.zone.name) + self.recordset = self.useFixture(RecordsetFixture( + zone_id=self.zone.id, + name=name, + records='1.2.3.4', + description='An a recordset', + type='A', + ttl=1234, + )).recordset + + self.assertEqual(self.recordset.name, name) + self.assertEqual(self.recordset.records, '1.2.3.4') + self.assertEqual(self.recordset.description, 'An a recordset') + self.assertEqual(self.recordset.type, 'A') + self.assertEqual(self.recordset.ttl, '1234') + + def test_recordset_list(self): + rsets = self.clients.recordset_list(self.zone.id) + self.assertGreater(len(rsets), 0) + + def test_recordset_create_and_show(self): + rset = self.clients.recordset_show(self.zone.id, self.recordset.id) + self.assertTrue(hasattr(self.recordset, 'action')) + self.assertTrue(hasattr(rset, 'action')) + self.assertEqual(self.recordset.created_at, rset.created_at) + self.assertEqual(self.recordset.description, rset.description) + self.assertEqual(self.recordset.id, rset.id) + self.assertEqual(self.recordset.name, rset.name) + self.assertEqual(self.recordset.records, rset.records) + self.assertEqual(self.recordset.status, rset.status) + self.assertEqual(self.recordset.ttl, rset.ttl) + self.assertEqual(self.recordset.type, rset.type) + self.assertEqual(self.recordset.updated_at, rset.updated_at) + self.assertEqual(self.recordset.version, rset.version) + self.assertEqual(self.recordset.zone_id, self.zone.id) + + def test_recordset_delete(self): + self.clients.recordset_delete(self.zone.id, self.recordset.id) + self.assertRaises( + CommandFailed, + self.clients.recordset_delete, + self.zone.id, + self.recordset.id, + ) + + def test_recordset_set(self): + rset = self.clients.recordset_set( + self.zone.id, + self.recordset.id, + records='2.3.4.5', + ttl=2345, + description='Updated description', + ) + + self.assertEqual(rset.records, '2.3.4.5') + self.assertEqual(rset.ttl, '2345') + self.assertEqual(rset.description, 'Updated description') + + def test_recordset_set_clear_ttl_and_description(self): + rset = self.clients.recordset_set( + self.zone.id, + self.recordset.id, + no_description=True, + no_ttl=True, + ) + + self.assertEqual(rset.description, 'None') + self.assertEqual(rset.ttl, 'None') + + +class TestRecordsetNegative(object): + + def test_invalid_option_on_recordset_create(self): + cmd = 'recordset create {0} aaa.{1} --type A --records 1.2.3.4 ' \ + '--invalid "not valid"'.format(self.zone.id, self.zone.name) + self.assertRaises(CommandFailed, self.clients.openstack, cmd) + + def test_invalid_recordset_command(self): + cmd = 'recordset hopefullynotvalid' + self.assertRaises(CommandFailed, self.clients.openstack, cmd)