From a6d7ee9089160c71db05dffbe0e0f3bf1935ba31 Mon Sep 17 00:00:00 2001 From: Graham Hayes Date: Wed, 15 Jun 2016 19:19:52 +0100 Subject: [PATCH] Fix output of datetime objects in API We accidentally changed formats in the v2 API in a previous commit. This forces all text representations of datetime objects to be '%Y-%m-%dT%H:%M:%S.%f' Change-Id: I2a4b55804d7ed2084d8705844ca63e41ed626bf2 Closes-Bug: #1579844 --- designate/objects/adapters/base.py | 18 +++++++++++ .../tests/unit/test_objects/test_adapters.py | 31 +++++++++++++++++++ designate/utils.py | 5 +++ 3 files changed, 54 insertions(+) diff --git a/designate/objects/adapters/base.py b/designate/objects/adapters/base.py index 220b10b9b..3745cf217 100644 --- a/designate/objects/adapters/base.py +++ b/designate/objects/adapters/base.py @@ -11,11 +11,13 @@ # 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 datetime from oslo_log import log import six from designate import objects +from designate import utils from designate import exceptions from designate.i18n import _LE from designate.i18n import _LI @@ -91,6 +93,18 @@ class DesignateAdapter(object): @classmethod def _render_object(cls, object, *args, **kwargs): + + # We need to findout the type of field sometimes - these are helper + # methods for that. + + def _is_datetime_field(object, key): + field = object.FIELDS.get(key, {}) + return field.get('schema', {}).get('format', '') == 'date-time' + + def _format_datetime_field(obj): + return datetime.datetime.strftime( + obj, utils.DATETIME_FORMAT) + # The dict we will return to be rendered to JSON / output format r_obj = {} # Loop over all fields that are supposed to be output @@ -116,6 +130,10 @@ class DesignateAdapter(object): cls.ADAPTER_FORMAT, object.FIELDS[obj_key].get('relation_cls')).render( cls.ADAPTER_FORMAT, obj, *args, **kwargs) + elif _is_datetime_field(object, obj_key) and obj is not None: + # So, we now have a datetime object to render correctly + # see bug #1579844 + r_obj[key] = _format_datetime_field(obj) else: # Just attach the damn item if there is no weird edge cases r_obj[key] = obj diff --git a/designate/tests/unit/test_objects/test_adapters.py b/designate/tests/unit/test_objects/test_adapters.py index 7cf10b3ab..991ba6daf 100644 --- a/designate/tests/unit/test_objects/test_adapters.py +++ b/designate/tests/unit/test_objects/test_adapters.py @@ -13,10 +13,12 @@ # 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 datetime from mock import Mock from oslo_log import log as logging import oslotest.base +from oslo_utils import timeutils from designate import objects from designate.objects import adapters @@ -35,6 +37,25 @@ class DesignateTestAdapter(adapters.DesignateAdapter): } +class DesignateTestPersistantObject( + objects.DesignateObject, objects.base.PersistentObjectMixin): + pass + + +class DesignateDateTimeAdaptor(adapters.DesignateAdapter): + ADAPTER_OBJECT = DesignateTestPersistantObject + ADAPTER_FORMAT = 'TEST_API' + + MODIFICATIONS = { + 'fields': { + "id": {}, + "created_at": {}, + "updated_at": {}, + }, + 'options': {} + } + + class DesignateAdapterTest(oslotest.base.BaseTestCase): def test_get_object_adapter(self): adapters.DesignateAdapter.get_object_adapter( @@ -43,6 +64,16 @@ class DesignateAdapterTest(oslotest.base.BaseTestCase): def test_object_render(self): adapters.DesignateAdapter.render('TEST_API', objects.DesignateObject()) + def test_datetime_format(self): + test_obj = DesignateTestPersistantObject() + test_obj.created_at = timeutils.utcnow() + + test_dict = adapters.DesignateAdapter.render('TEST_API', test_obj) + + datetime.datetime.strptime( + test_dict['created_at'], + '%Y-%m-%dT%H:%M:%S.%f') + class RecordSetAPIv2AdapterTest(oslotest.base.BaseTestCase): def test_get_path(self): diff --git a/designate/utils.py b/designate/utils.py index 92d68ac3c..4433c5c19 100644 --- a/designate/utils.py +++ b/designate/utils.py @@ -68,6 +68,11 @@ DEFAULT_AGENT_PORT = 5358 DEFAULT_MDNS_PORT = 5354 +# Default datetime format + +DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%f' + + def find_config(config_path): """ Find a configuration file using the given hint.