From bbe442dddb6427fa5039ac9dd9ce47b6a5feda36 Mon Sep 17 00:00:00 2001 From: Zhongyue Luo Date: Tue, 5 Jun 2012 14:02:43 +0800 Subject: [PATCH] Glance should use openstack.common.timeutils Implements blueprint use-common-timeutils 1. Edit openstack-common.conf and import glance/openstack/common/timeutils.py 2. Replace datetime.utcnow with timeutils.utcnow 3. Replace utils.isotime with timeutils.isotime 4. Replace utils.parse_isotime with timeutils.parse_isotime 5. Replace utils.normalize_time with timeutils.normalize_time 6. Remove datetime related functions and datetime related unittests Change-Id: I014548848f738b00c670be3d372b16f47f6dee96 --- glance/api/v2/images.py | 3 +- glance/common/utils.py | 29 ------ glance/db/api.py | 6 +- glance/db/models.py | 11 +-- glance/notifier/__init__.py | 4 +- glance/openstack/common/timeutils.py | 73 ++++++++++++++ glance/registry/api/v1/images.py | 3 +- glance/tests/functional/test_bin_glance.py | 10 +- glance/tests/functional/v1/test_api.py | 14 +-- glance/tests/functional/v1/test_ssl.py | 9 +- glance/tests/unit/test_clients.py | 53 +++++----- glance/tests/unit/test_db.py | 7 +- glance/tests/unit/test_misc.py | 8 -- glance/tests/unit/test_utils.py | 107 --------------------- glance/tests/unit/v1/test_api.py | 65 +++++++------ openstack-common.conf | 2 +- 16 files changed, 169 insertions(+), 235 deletions(-) create mode 100644 glance/openstack/common/timeutils.py diff --git a/glance/api/v2/images.py b/glance/api/v2/images.py index eb782fd0..6e52e030 100644 --- a/glance/api/v2/images.py +++ b/glance/api/v2/images.py @@ -23,6 +23,7 @@ from glance.common import exception from glance.common import utils from glance.common import wsgi import glance.db.api +from glance.openstack.common import timeutils class ImagesController(base.Controller): @@ -198,7 +199,7 @@ class ResponseSerializer(wsgi.JSONResponseSerializer): def _serialize_datetimes(image): for (key, value) in image.iteritems(): if isinstance(value, datetime.datetime): - image[key] = utils.isotime(value) + image[key] = timeutils.isotime(value) def create(self, response, image): response.body = json.dumps({'image': self._format_image(image)}) diff --git a/glance/common/utils.py b/glance/common/utils.py index c86ff9df..d70fc43f 100644 --- a/glance/common/utils.py +++ b/glance/common/utils.py @@ -20,7 +20,6 @@ System-level utilities and helper functions. """ -import datetime import errno import functools import logging @@ -38,8 +37,6 @@ from glance.common import exception logger = logging.getLogger(__name__) -TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" - def chunkreadable(iter, chunk_size=65536): """ @@ -161,32 +158,6 @@ def is_uuid_like(value): return False -def isotime(at=None): - """Stringify time in ISO 8601 format""" - if not at: - at = datetime.datetime.utcnow() - str = at.strftime(TIME_FORMAT) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - str += ('Z' if tz == 'UTC' else tz) - return str - - -def parse_isotime(timestr): - """Parse time from ISO 8601 format""" - try: - return iso8601.parse_date(timestr) - except iso8601.ParseError as e: - raise ValueError(e.message) - except TypeError as e: - raise ValueError(e.message) - - -def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC""" - offset = timestamp.utcoffset() - return timestamp.replace(tzinfo=None) - offset if offset else timestamp - - def safe_mkdirs(path): try: os.makedirs(path) diff --git a/glance/db/api.py b/glance/db/api.py index cf408272..aeff0ff8 100644 --- a/glance/db/api.py +++ b/glance/db/api.py @@ -35,11 +35,11 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.sql import or_, and_ from glance.common import exception -from glance.common import utils -from glance.openstack.common import cfg from glance import db from glance.db import migration from glance.db import models +from glance.openstack.common import cfg +from glance.openstack.common import timeutils _ENGINE = None _MAKER = None @@ -410,7 +410,7 @@ def image_get_all(context, filters=None, marker=None, limit=None, if 'changes-since' in filters: # normalize timestamp to UTC, as sqlalchemy doesn't appear to # respect timezone offsets - changes_since = utils.normalize_time(filters.pop('changes-since')) + changes_since = timeutils.normalize_time(filters.pop('changes-since')) query = query.filter(models.Image.updated_at > changes_since) showing_deleted = True diff --git a/glance/db/models.py b/glance/db/models.py index d709e61b..b70c7651 100644 --- a/glance/db/models.py +++ b/glance/db/models.py @@ -20,8 +20,6 @@ SQLAlchemy models for glance data """ -import datetime - from sqlalchemy.orm import relationship, backref, object_mapper from sqlalchemy import Column, Integer, String, BigInteger from sqlalchemy import ForeignKey, DateTime, Boolean, Text @@ -31,6 +29,7 @@ from sqlalchemy.ext.declarative import declarative_base import glance.db.api from glance.common import utils +from glance.openstack.common import timeutils BASE = declarative_base() @@ -47,10 +46,10 @@ class ModelBase(object): __protected_attributes__ = set([ "created_at", "updated_at", "deleted_at", "deleted"]) - created_at = Column(DateTime, default=datetime.datetime.utcnow, + created_at = Column(DateTime, default=timeutils.utcnow, nullable=False) - updated_at = Column(DateTime, default=datetime.datetime.utcnow, - nullable=False, onupdate=datetime.datetime.utcnow) + updated_at = Column(DateTime, default=timeutils.utcnow, + nullable=False, onupdate=timeutils.utcnow) deleted_at = Column(DateTime) deleted = Column(Boolean, nullable=False, default=False) @@ -63,7 +62,7 @@ class ModelBase(object): def delete(self, session=None): """Delete this object""" self.deleted = True - self.deleted_at = datetime.datetime.utcnow() + self.deleted_at = timeutils.utcnow() self.save(session=session) def update(self, values): diff --git a/glance/notifier/__init__.py b/glance/notifier/__init__.py index 120d0d65..5aae0cce 100644 --- a/glance/notifier/__init__.py +++ b/glance/notifier/__init__.py @@ -16,13 +16,13 @@ # under the License. -import datetime import socket import uuid from glance.common import exception from glance.openstack.common import cfg from glance.openstack.common import importutils +from glance.openstack.common import timeutils notifier_opts = [ cfg.StrOpt('notifier_strategy', default='default') @@ -59,7 +59,7 @@ class Notifier(object): "event_type": event_type, "priority": priority, "payload": payload, - "timestamp": str(datetime.datetime.utcnow()), + "timestamp": str(timeutils.utcnow()), } def warn(self, event_type, payload): diff --git a/glance/openstack/common/timeutils.py b/glance/openstack/common/timeutils.py new file mode 100644 index 00000000..c536cb24 --- /dev/null +++ b/glance/openstack/common/timeutils.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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. + +""" +Time related utilities and helper functions. +""" + +import datetime + +import iso8601 + + +TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" + + +def isotime(at=None): + """Stringify time in ISO 8601 format""" + if not at: + at = datetime.datetime.utcnow() + str = at.strftime(TIME_FORMAT) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + str += ('Z' if tz == 'UTC' else tz) + return str + + +def parse_isotime(timestr): + """Parse time from ISO 8601 format""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(e.message) + except TypeError as e: + raise ValueError(e.message) + + +def normalize_time(timestamp): + """Normalize time in arbitrary timezone to UTC""" + offset = timestamp.utcoffset() + return timestamp.replace(tzinfo=None) - offset if offset else timestamp + + +def utcnow(): + """Overridable version of utils.utcnow.""" + if utcnow.override_time: + return utcnow.override_time + return datetime.datetime.utcnow() + + +utcnow.override_time = None + + +def set_time_override(override_time=datetime.datetime.utcnow()): + """Override utils.utcnow to return a constant time.""" + utcnow.override_time = override_time + + +def clear_time_override(): + """Remove the overridden time.""" + utcnow.override_time = None diff --git a/glance/registry/api/v1/images.py b/glance/registry/api/v1/images.py index a70571f5..0c527ae2 100644 --- a/glance/registry/api/v1/images.py +++ b/glance/registry/api/v1/images.py @@ -27,6 +27,7 @@ from glance.common import exception from glance.common import utils from glance.common import wsgi from glance.openstack.common import cfg +from glance.openstack.common import timeutils from glance.db import api as db_api logger = logging.getLogger('glance.registry.api.v1.images') @@ -167,7 +168,7 @@ class Controller(object): if 'changes-since' in filters: isotime = filters['changes-since'] try: - filters['changes-since'] = utils.parse_isotime(isotime) + filters['changes-since'] = timeutils.parse_isotime(isotime) except ValueError: raise exc.HTTPBadRequest(_("Unrecognized changes-since value")) diff --git a/glance/tests/functional/test_bin_glance.py b/glance/tests/functional/test_bin_glance.py index 518bf7a4..d5095340 100644 --- a/glance/tests/functional/test_bin_glance.py +++ b/glance/tests/functional/test_bin_glance.py @@ -26,7 +26,7 @@ import tempfile import thread import time -from glance.common import utils +from glance.openstack.common import timeutils from glance.tests import functional from glance.tests.utils import execute, requires, minimal_add_command from glance.tests.functional.store_utils import (setup_http, @@ -785,8 +785,8 @@ class TestBinGlance(functional.FunctionalTest): self.assertEqual(image_lines[0].split()[0], image_ids[1]) # 9. Check past changes-since - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) cmd = "changes-since=%s" % iso1 exitcode, out, err = execute("%s %s" % (_index_cmd, cmd)) @@ -798,8 +798,8 @@ class TestBinGlance(functional.FunctionalTest): self.assertEqual(image_lines[2].split()[0], image_ids[0]) # 10. Check future changes-since - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) cmd = "changes-since=%s" % iso2 exitcode, out, err = execute("%s %s" % (_index_cmd, cmd)) diff --git a/glance/tests/functional/v1/test_api.py b/glance/tests/functional/v1/test_api.py index b22e88f9..86b0776c 100644 --- a/glance/tests/functional/v1/test_api.py +++ b/glance/tests/functional/v1/test_api.py @@ -24,7 +24,7 @@ import tempfile import httplib2 -from glance.common import utils +from glance.openstack.common import timeutils from glance.tests import functional from glance.tests.utils import skip_if_disabled, minimal_headers @@ -740,8 +740,8 @@ class TestApi(functional.FunctionalTest): self.assertEqual(image['name'], "My Image!") # 16. GET /images with past changes-since filter - yesterday = utils.isotime(datetime.datetime.utcnow() - - datetime.timedelta(1)) + yesterday = timeutils.isotime(timeutils.utcnow() - + datetime.timedelta(1)) params = "changes-since=%s" % yesterday path = "http://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) response, content = http.request(path, 'GET') @@ -754,7 +754,7 @@ class TestApi(functional.FunctionalTest): # '+' is wrongly decoded as a space # TODO(eglynn): investigate '+' --> decoding, an artifact # of WSGI/webob dispatch? - now = datetime.datetime.utcnow() + now = timeutils.utcnow() hour_ago = now.strftime('%Y-%m-%dT%H:%M:%S%%2B01:00') params = "changes-since=%s" % hour_ago path = "http://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) @@ -764,8 +764,8 @@ class TestApi(functional.FunctionalTest): self.assertEqual(len(data['images']), 3) # 17. GET /images with future changes-since filter - tomorrow = utils.isotime(datetime.datetime.utcnow() + - datetime.timedelta(1)) + tomorrow = timeutils.isotime(timeutils.utcnow() + + datetime.timedelta(1)) params = "changes-since=%s" % tomorrow path = "http://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) response, content = http.request(path, 'GET') @@ -774,7 +774,7 @@ class TestApi(functional.FunctionalTest): self.assertEqual(len(data['images']), 0) # one timezone east of Greenwich equates to an hour from now - now = datetime.datetime.utcnow() + now = timeutils.utcnow() hour_hence = now.strftime('%Y-%m-%dT%H:%M:%S-01:00') params = "changes-since=%s" % hour_hence path = "http://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) diff --git a/glance/tests/functional/v1/test_ssl.py b/glance/tests/functional/v1/test_ssl.py index b0565d94..6bc414cf 100644 --- a/glance/tests/functional/v1/test_ssl.py +++ b/glance/tests/functional/v1/test_ssl.py @@ -40,6 +40,7 @@ import tempfile from glance import client as glance_client from glance.common import exception from glance.common import utils +from glance.openstack.common import timeutils from glance.tests import functional from glance.tests.utils import skip_if_disabled, minimal_headers @@ -911,8 +912,8 @@ class TestSSL(functional.FunctionalTest): self.assertEqual(image['name'], "My Image!") # 14. GET /images with past changes-since filter - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) params = "changes-since=%s" % iso1 path = "https://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) @@ -922,8 +923,8 @@ class TestSSL(functional.FunctionalTest): self.assertEqual(len(data['images']), 3) # 15. GET /images with future changes-since filter - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) params = "changes-since=%s" % iso2 path = "https://%s:%d/v1/images?%s" % ("0.0.0.0", self.api_port, params) diff --git a/glance/tests/unit/test_clients.py b/glance/tests/unit/test_clients.py index 83edfc99..edb08131 100644 --- a/glance/tests/unit/test_clients.py +++ b/glance/tests/unit/test_clients.py @@ -26,6 +26,7 @@ from glance.common import exception from glance.common import utils from glance.db import api as db_api from glance.db import models as db_models +from glance.openstack.common import timeutils from glance.registry import client as rclient from glance.tests.unit import base from glance.tests import utils as test_utils @@ -154,8 +155,8 @@ class TestRegistryClient(base.IsolatedUnitTest): 'disk_format': 'ami', 'container_format': 'ami', 'is_public': False, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -168,8 +169,8 @@ class TestRegistryClient(base.IsolatedUnitTest): 'disk_format': 'vhd', 'container_format': 'ovf', 'is_public': True, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -416,7 +417,7 @@ class TestRegistryClient(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images sorted by created_at in ascending order. """ - now = datetime.datetime.utcnow() + now = timeutils.utcnow() time1 = now + datetime.timedelta(seconds=5) time2 = now @@ -458,7 +459,7 @@ class TestRegistryClient(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images sorted by updated_at in descending order. """ - now = datetime.datetime.utcnow() + now = timeutils.utcnow() time1 = now + datetime.timedelta(seconds=5) time2 = now @@ -814,17 +815,17 @@ class TestRegistryClient(base.IsolatedUnitTest): def test_get_image_details_with_changes_since(self): """Tests that a detailed call can be filtered by size_min""" - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) - dt3 = datetime.datetime.utcnow() + datetime.timedelta(2) - iso3 = utils.isotime(dt3) + dt3 = timeutils.utcnow() + datetime.timedelta(2) + iso3 = timeutils.isotime(dt3) - dt4 = datetime.datetime.utcnow() + datetime.timedelta(3) - iso4 = utils.isotime(dt4) + dt4 = timeutils.utcnow() + datetime.timedelta(3) + iso4 = timeutils.isotime(dt4) UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, @@ -1208,8 +1209,8 @@ class TestClient(base.IsolatedUnitTest): 'disk_format': 'ami', 'container_format': 'ami', 'is_public': False, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -1222,8 +1223,8 @@ class TestClient(base.IsolatedUnitTest): 'disk_format': 'vhd', 'container_format': 'ovf', 'is_public': True, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -1537,17 +1538,17 @@ class TestClient(base.IsolatedUnitTest): def test_get_image_details_with_changes_since(self): """Tests that a detailed call can be filtered by size_min""" - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) - dt3 = datetime.datetime.utcnow() + datetime.timedelta(2) - iso3 = utils.isotime(dt3) + dt3 = timeutils.utcnow() + datetime.timedelta(2) + iso3 = timeutils.isotime(dt3) - dt4 = datetime.datetime.utcnow() + datetime.timedelta(3) - iso4 = utils.isotime(dt4) + dt4 = timeutils.utcnow() + datetime.timedelta(3) + iso4 = timeutils.isotime(dt4) UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, diff --git a/glance/tests/unit/test_db.py b/glance/tests/unit/test_db.py index 82e1a3e7..483753bb 100644 --- a/glance/tests/unit/test_db.py +++ b/glance/tests/unit/test_db.py @@ -24,6 +24,7 @@ from glance.common import exception from glance.common import utils from glance.db import api as db_api from glance.db import models as db_models +from glance.openstack.common import timeutils from glance.tests.unit import base from glance.tests import utils as test_utils @@ -109,7 +110,7 @@ class TestRegistryDb(BaseDBTestCase): db_api.image_create(self.adm_context, fixture) def build_fixtures(self): - t1 = datetime.datetime.utcnow() + t1 = timeutils.utcnow() t2 = t1 + datetime.timedelta(microseconds=1) return build_fixtures(t1, t2) @@ -204,7 +205,7 @@ class TestDBImageTags(BaseDBTestCase): class TestRegistryDbWithSameTime(TestRegistryDb): def build_fixtures(self): - t1 = datetime.datetime.utcnow() + t1 = timeutils.utcnow() t2 = t1 # Same timestamp! return build_fixtures(t1, t2) @@ -267,7 +268,7 @@ class TestPagingOrder(base.IsolatedUnitTest): def build_fixtures(self): self.images = [] - t0 = datetime.datetime.utcnow() + t0 = timeutils.utcnow() for _ in xrange(0, self.ITEM_COUNT): tdelta = random.uniform(0, self.TIME_VALUES) min_disk = random.uniform(0, self.MINDISK_VALUES) diff --git a/glance/tests/unit/test_misc.py b/glance/tests/unit/test_misc.py index 41ce66cd..922b8a1d 100644 --- a/glance/tests/unit/test_misc.py +++ b/glance/tests/unit/test_misc.py @@ -46,14 +46,6 @@ class UtilsTestCase(test_utils.BaseTestCase): self.assertFalse(utils.bool_from_string(value), "Got True for value: %r" % value) - def test_isotime(self): - dt1 = datetime.datetime(2001, 11, 10, 1, 2, 3) - self.assertEqual('2001-11-10T01:02:03Z', utils.isotime(dt1)) - - iso_re = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z') - now_iso = utils.isotime() - self.assertTrue(iso_re.match(now_iso) is not None) - def test_encryption(self): # Check that original plaintext and unencrypted ciphertext match # Check keys of the three allowed lengths diff --git a/glance/tests/unit/test_utils.py b/glance/tests/unit/test_utils.py index d2f7240c..2cb20e5c 100644 --- a/glance/tests/unit/test_utils.py +++ b/glance/tests/unit/test_utils.py @@ -15,8 +15,6 @@ # License for the specific language governing permissions and limitations # under the License. -import iso8601 - from glance.common import utils from glance.tests import utils as test_utils @@ -46,108 +44,3 @@ class TestUtils(test_utils.BaseTestCase): def test_is_uuid_like_fails(self): fixture = 'pants' self.assertFalse(utils.is_uuid_like(fixture)) - - -class TestIso8601Time(test_utils.BaseTestCase): - - def _instaneous(self, timestamp, yr, mon, day, hr, min, sec, micro): - self.assertEquals(timestamp.year, yr) - self.assertEquals(timestamp.month, mon) - self.assertEquals(timestamp.day, day) - self.assertEquals(timestamp.hour, hr) - self.assertEquals(timestamp.minute, min) - self.assertEquals(timestamp.second, sec) - self.assertEquals(timestamp.microsecond, micro) - - def _do_test(self, str, yr, mon, day, hr, min, sec, micro, shift): - DAY_SECONDS = 24 * 60 * 60 - timestamp = utils.parse_isotime(str) - self._instaneous(timestamp, yr, mon, day, hr, min, sec, micro) - offset = timestamp.tzinfo.utcoffset(None) - self.assertEqual(offset.seconds + offset.days * DAY_SECONDS, shift) - - def test_zulu(self): - str = '2012-02-14T20:53:07Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, 0) - - def test_zulu_micros(self): - str = '2012-02-14T20:53:07.123Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 123000, 0) - - def test_offset_east(self): - str = '2012-02-14T20:53:07+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_east_micros(self): - str = '2012-02-14T20:53:07.42+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 420000, offset) - - def test_offset_west(self): - str = '2012-02-14T20:53:07-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_west_micros(self): - str = '2012-02-14T20:53:07.654321-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 654321, offset) - - def test_compare(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07') - east = utils.parse_isotime('2012-02-14T20:53:07-01:00') - west = utils.parse_isotime('2012-02-14T20:53:07+01:00') - self.assertTrue(east > west) - self.assertTrue(east > zulu) - self.assertTrue(zulu > west) - - def test_compare_micros(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07.6544') - east = utils.parse_isotime('2012-02-14T19:53:07.654321-01:00') - west = utils.parse_isotime('2012-02-14T21:53:07.655+01:00') - self.assertTrue(east < west) - self.assertTrue(east < zulu) - self.assertTrue(zulu < west) - - def test_zulu_roundtrip(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - self.assertEquals(zulu.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(zulu), str) - - def test_east_roundtrip(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - self.assertEquals(east.tzinfo.tzname(None), '-07:00') - self.assertEquals(utils.isotime(east), str) - - def test_west_roundtrip(self): - str = '2012-02-14T20:53:07+11:30' - west = utils.parse_isotime(str) - self.assertEquals(west.tzinfo.tzname(None), '+11:30') - self.assertEquals(utils.isotime(west), str) - - def test_now_roundtrip(self): - str = utils.isotime() - now = utils.parse_isotime(str) - self.assertEquals(now.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(now), str) - - def test_zulu_normalize(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - normed = utils.normalize_time(zulu) - self._instaneous(normed, 2012, 2, 14, 20, 53, 07, 0) - - def test_east_normalize(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - normed = utils.normalize_time(east) - self._instaneous(normed, 2012, 2, 15, 03, 53, 07, 0) - - def test_west_normalize(self): - str = '2012-02-14T20:53:07+21:00' - west = utils.parse_isotime(str) - normed = utils.normalize_time(west) - self._instaneous(normed, 2012, 2, 13, 23, 53, 07, 0) diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py index 7bf9e456..57f256eb 100644 --- a/glance/tests/unit/v1/test_api.py +++ b/glance/tests/unit/v1/test_api.py @@ -28,6 +28,7 @@ from glance.api.v1 import images from glance.api.v1 import router from glance.common import context from glance.common import utils +from glance.openstack.common import timeutils from glance.registry.api import v1 as rserver from glance.db import api as db_api from glance.db import models as db_models @@ -100,8 +101,8 @@ class TestRegistryAPI(base.IsolatedUnitTest): 'disk_format': 'ami', 'container_format': 'ami', 'is_public': False, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -116,8 +117,8 @@ class TestRegistryAPI(base.IsolatedUnitTest): 'disk_format': 'vhd', 'container_format': 'ovf', 'is_public': True, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -231,9 +232,9 @@ class TestRegistryAPI(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images that conforms to a marker query param """ - time1 = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) - time2 = datetime.datetime.utcnow() + datetime.timedelta(seconds=4) - time3 = datetime.datetime.utcnow() + time1 = timeutils.utcnow() + datetime.timedelta(seconds=5) + time2 = timeutils.utcnow() + datetime.timedelta(seconds=4) + time3 = timeutils.utcnow() UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, @@ -451,9 +452,9 @@ class TestRegistryAPI(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images that conforms to a default sort key/dir """ - time1 = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) - time2 = datetime.datetime.utcnow() + datetime.timedelta(seconds=4) - time3 = datetime.datetime.utcnow() + time1 = timeutils.utcnow() + datetime.timedelta(seconds=5) + time2 = timeutils.utcnow() + datetime.timedelta(seconds=4) + time3 = timeutils.utcnow() UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, @@ -729,7 +730,7 @@ class TestRegistryAPI(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images sorted by created_at in ascending order. """ - now = datetime.datetime.utcnow() + now = timeutils.utcnow() time1 = now + datetime.timedelta(seconds=5) time2 = now @@ -775,7 +776,7 @@ class TestRegistryAPI(base.IsolatedUnitTest): Tests that the /images registry API returns list of public images sorted by updated_at in descending order. """ - now = datetime.datetime.utcnow() + now = timeutils.utcnow() time1 = now + datetime.timedelta(seconds=5) time2 = now @@ -1257,18 +1258,18 @@ class TestRegistryAPI(base.IsolatedUnitTest): Tests that the /images/detail registry API returns list of public images that have a size less than or equal to size_max """ - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) - image_ts = datetime.datetime.utcnow() + datetime.timedelta(2) + image_ts = timeutils.utcnow() + datetime.timedelta(2) hour_before = image_ts.strftime('%Y-%m-%dT%H:%M:%S%%2B01:00') hour_after = image_ts.strftime('%Y-%m-%dT%H:%M:%S-01:00') - dt4 = datetime.datetime.utcnow() + datetime.timedelta(3) - iso4 = utils.isotime(dt4) + dt4 = timeutils.utcnow() + datetime.timedelta(3) + iso4 = timeutils.isotime(dt4) UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, @@ -1969,8 +1970,8 @@ class TestGlanceAPI(base.IsolatedUnitTest): 'disk_format': 'ami', 'container_format': 'ami', 'is_public': False, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -1983,8 +1984,8 @@ class TestGlanceAPI(base.IsolatedUnitTest): 'disk_format': 'vhd', 'container_format': 'ovf', 'is_public': True, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, @@ -2519,18 +2520,18 @@ class TestGlanceAPI(base.IsolatedUnitTest): Tests that the /images/detail registry API returns list of public images that have a size less than or equal to size_max """ - dt1 = datetime.datetime.utcnow() - datetime.timedelta(1) - iso1 = utils.isotime(dt1) + dt1 = timeutils.utcnow() - datetime.timedelta(1) + iso1 = timeutils.isotime(dt1) - dt2 = datetime.datetime.utcnow() + datetime.timedelta(1) - iso2 = utils.isotime(dt2) + dt2 = timeutils.utcnow() + datetime.timedelta(1) + iso2 = timeutils.isotime(dt2) - image_ts = datetime.datetime.utcnow() + datetime.timedelta(2) + image_ts = timeutils.utcnow() + datetime.timedelta(2) hour_before = image_ts.strftime('%Y-%m-%dT%H:%M:%S%%2B01:00') hour_after = image_ts.strftime('%Y-%m-%dT%H:%M:%S-01:00') - dt4 = datetime.datetime.utcnow() + datetime.timedelta(3) - iso4 = utils.isotime(dt4) + dt4 = timeutils.utcnow() + datetime.timedelta(3) + iso4 = timeutils.isotime(dt4) UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, @@ -3011,8 +3012,8 @@ class TestImageSerializer(base.IsolatedUnitTest): 'disk_format': 'vhd', 'container_format': 'ovf', 'is_public': True, - 'created_at': datetime.datetime.utcnow(), - 'updated_at': datetime.datetime.utcnow(), + 'created_at': timeutils.utcnow(), + 'updated_at': timeutils.utcnow(), 'deleted_at': None, 'deleted': False, 'checksum': None, diff --git a/openstack-common.conf b/openstack-common.conf index cf0f3e28..7b280562 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -1,7 +1,7 @@ [DEFAULT] # The list of modules to copy from openstack-common -modules=cfg,importutils,iniparser,setup +modules=cfg,importutils,iniparser,setup,timeutils # The base module to hold the copy of openstack.common base=glance