From ad1935a9dae7cc989babe4b87f76eda84fef7cd4 Mon Sep 17 00:00:00 2001 From: Tim Simmons Date: Wed, 7 Aug 2013 20:27:47 +0000 Subject: [PATCH] Add Description Field to Domains/Records Adds a description field to Domains and Records. Adds accompanying tests to ensure that the field is UTF-8 compatible. Adds databse migration to add the appropriate columns to the database. Change-Id: Iaa1ac6aee01fadc409ea16298c83946f35bdde33 Implements: blueprint resource-notes --- .gitignore | 1 + designate/resources/schemas/v1/domain.json | 5 ++ designate/resources/schemas/v1/record.json | 5 ++ .../020_add_description_domains_records.py | 46 +++++++++++++++++++ designate/storage/impl_sqlalchemy/models.py | 3 ++ .../tests/test_api/test_v1/test_domains.py | 25 ++++++++++ .../tests/test_api/test_v1/test_records.py | 21 +++++++++ 7 files changed, 106 insertions(+) create mode 100644 designate/storage/impl_sqlalchemy/migrate_repo/versions/020_add_description_domains_records.py diff --git a/.gitignore b/.gitignore index 575ab873d..d0bca8320 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ dist designate/versioninfo *.orig *.DS_Store +*.idea /bind9 diff --git a/designate/resources/schemas/v1/domain.json b/designate/resources/schemas/v1/domain.json index fd0fef085..a1b22920d 100644 --- a/designate/resources/schemas/v1/domain.json +++ b/designate/resources/schemas/v1/domain.json @@ -42,6 +42,11 @@ "max": 4294967295, "readonly": true }, + "description": { + "type": ["string", "null"], + "description": "Description for the Domain", + "maxLength": 160 + }, "created_at": { "type": "string", "description": "Date and time of image registration", diff --git a/designate/resources/schemas/v1/record.json b/designate/resources/schemas/v1/record.json index 29b47b81f..c213038d1 100644 --- a/designate/resources/schemas/v1/record.json +++ b/designate/resources/schemas/v1/record.json @@ -51,6 +51,11 @@ "min": 0, "max": 2147483647 }, + "description": { + "type": ["string", "null"], + "description": "Description for the Domain", + "maxLength": 160 + }, "created_at": { "type": "string", "description": "Date and time of image registration", diff --git a/designate/storage/impl_sqlalchemy/migrate_repo/versions/020_add_description_domains_records.py b/designate/storage/impl_sqlalchemy/migrate_repo/versions/020_add_description_domains_records.py new file mode 100644 index 000000000..061b3619b --- /dev/null +++ b/designate/storage/impl_sqlalchemy/migrate_repo/versions/020_add_description_domains_records.py @@ -0,0 +1,46 @@ +# Copyright 2013 Rackspace Hosting +# +# Author: Tim Simmons +# +# 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 designate.openstack.common import log as logging +from sqlalchemy import MetaData, Table, Column, Unicode + +LOG = logging.getLogger(__name__) +meta = MetaData() + + +def upgrade(migrate_engine): + meta.bind = migrate_engine + + domains_table = Table('domains', meta, autoload=True) + records_table = Table('records', meta, autoload=True) + + #Add in description columns in domain/record databases + domain_description = Column('description', Unicode(160), + nullable=True) + domain_description.create(domains_table, populate_default=True) + + record_description = Column('description', Unicode(160), + nullable=True) + record_description.create(records_table, populate_default=True) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + domains_table = Table('domains', meta, autoload=True) + domains_table.c.description.drop() + + record_table = Table('records', meta, autoload=True) + record_table.c.description.drop() diff --git a/designate/storage/impl_sqlalchemy/models.py b/designate/storage/impl_sqlalchemy/models.py index 92c988aaf..4b63e0ad5 100644 --- a/designate/storage/impl_sqlalchemy/models.py +++ b/designate/storage/impl_sqlalchemy/models.py @@ -77,6 +77,7 @@ class Domain(SoftDeleteMixin, Base): name = Column(String(255), nullable=False) email = Column(String(255), nullable=False) + description = Column(Unicode(160), nullable=True) ttl = Column(Integer, default=3600, nullable=False) refresh = Column(Integer, default=3600, nullable=False) @@ -101,6 +102,8 @@ class Record(Base): type = Column(Enum(name='record_types', *RECORD_TYPES), nullable=False) name = Column(String(255), nullable=False) + description = Column(Unicode(160), nullable=True) + data = Column(Text, nullable=False) priority = Column(Integer, default=None, nullable=True) ttl = Column(Integer, default=None, nullable=True) diff --git a/designate/tests/test_api/test_v1/test_domains.py b/designate/tests/test_api/test_v1/test_domains.py index ed029e580..5132ebbd8 100644 --- a/designate/tests/test_api/test_v1/test_domains.py +++ b/designate/tests/test_api/test_v1/test_domains.py @@ -1,3 +1,4 @@ +# coding=utf-8 # Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes @@ -89,6 +90,30 @@ class ApiV1DomainsTest(ApiV1Test): fixture['ttl'] = None self.post('domains', data=fixture, status_code=400) + def test_create_domain_utf_description(self): + # Create a server + self.create_server() + + # Create a domain + fixture = self.get_domain_fixture(0) + + #Give it a UTF-8 filled description + fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ + ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" + #Create the domain, ensuring it suceeds, thus UTF-8 is supported + self.post('domains', data=fixture) + + def test_create_domain_description_too_long(self): + # Create a server + self.create_server() + + # Create a domain + fixture = self.get_domain_fixture(0) + fixture['description'] = "x" * 161 + + #Create the domain, ensuring it fails with a 400 + self.post('domains', data=fixture, status_code=400) + def test_get_domains(self): response = self.get('domains') diff --git a/designate/tests/test_api/test_v1/test_records.py b/designate/tests/test_api/test_v1/test_records.py index 516f7cd47..267309215 100644 --- a/designate/tests/test_api/test_v1/test_records.py +++ b/designate/tests/test_api/test_v1/test_records.py @@ -1,3 +1,4 @@ +# coding=utf-8 # Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes @@ -61,6 +62,26 @@ class ApiV1RecordsTest(ApiV1Test): self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) + def test_create_record_utf_description(self): + fixture = self.get_record_fixture(self.domain['name'], 0) + + #Add a UTF-8 riddled description + fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ + ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" + + # Create a record, Ensuring it succeeds + self.post('domains/%s/records' % self.domain['id'], data=fixture) + + def test_create_record_description_too_long(self): + fixture = self.get_record_fixture(self.domain['name'], 0) + + #Add a description that is too long + fixture['description'] = "x" * 161 + + # Create a record, Ensuring it Fails with a 400 + self.post('domains/%s/records' % self.domain['id'], data=fixture, + status_code=400) + @patch.object(central_service.Service, 'create_record', side_effect=rpc_common.Timeout()) def test_create_domain_timeout(self, _):