Add TimeFixture

There was no fixture for using the functions related to
timeutils.set_time_override. A fixture is handy because
clear_time_override must be done for cleanup.

Change-Id: Ifef8d9f20fa9e5aa96ebf5040f290f65b503f0bd
This commit is contained in:
Brant Knudson 2015-01-12 18:16:32 -06:00
parent 659e12bddd
commit 89d0c2a88c
4 changed files with 141 additions and 5 deletions

View File

@ -0,0 +1,6 @@
=============
fixture
=============
.. automodule:: oslo_utils.fixture
:members:

45
oslo_utils/fixture.py Normal file
View File

@ -0,0 +1,45 @@
# Copyright 2015 OpenStack Foundation
# 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.
import fixtures
from oslo_utils import timeutils
class TimeFixture(fixtures.Fixture):
"""A fixture for overriding the time returned by timeutils.utcnow().
:param override_time: datetime instance or list thereof. If not given,
defaults to the current UTC time.
"""
def __init__(self, override_time=None):
super(TimeFixture, self).__init__()
self._override_time = override_time
def setUp(self):
super(TimeFixture, self).setUp()
timeutils.set_time_override(self._override_time)
self.addCleanup(timeutils.clear_time_override)
def advance_time_delta(self, timedelta):
"""Advance overridden time using a datetime.timedelta."""
timeutils.advance_time_delta(timedelta)
def advance_time_seconds(self, seconds):
"""Advance overridden time by seconds."""
timeutils.advance_time_seconds(seconds)

View File

@ -0,0 +1,63 @@
# Copyright 2015 OpenStack Foundation
# 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.
import datetime
from oslotest import base as test_base
from oslo_utils import fixture
from oslo_utils import timeutils
class TimeFixtureTest(test_base.BaseTestCase):
def test_set_time_override_using_default(self):
# When the fixture is used with its default constructor, the
# override_time is set to the current timestamp.
# Also, when the fixture is cleaned up, the override_time is reset.
self.assertIsNone(timeutils.utcnow.override_time)
with fixture.TimeFixture():
self.assertIsNotNone(timeutils.utcnow.override_time)
self.assertIsNone(timeutils.utcnow.override_time)
def test_set_time_override(self):
# When the fixture is used to set a time, utcnow returns that time.
new_time = datetime.datetime(2015, 1, 2, 3, 4, 6, 7)
self.useFixture(fixture.TimeFixture(new_time))
self.assertEqual(new_time, timeutils.utcnow())
# Call again to make sure it keeps returning the same time.
self.assertEqual(new_time, timeutils.utcnow())
def test_advance_time_delta(self):
# advance_time_delta() advances the overridden time by some timedelta.
new_time = datetime.datetime(2015, 1, 2, 3, 4, 6, 7)
time_fixture = self.useFixture(fixture.TimeFixture(new_time))
time_fixture.advance_time_delta(datetime.timedelta(seconds=1))
expected_time = datetime.datetime(2015, 1, 2, 3, 4, 7, 7)
self.assertEqual(expected_time, timeutils.utcnow())
def test_advance_time_seconds(self):
# advance_time_seconds() advances the overridden time by some number of
# seconds.
new_time = datetime.datetime(2015, 1, 2, 3, 4, 6, 7)
time_fixture = self.useFixture(fixture.TimeFixture(new_time))
time_fixture.advance_time_seconds(2)
expected_time = datetime.datetime(2015, 1, 2, 3, 4, 8, 7)
self.assertEqual(expected_time, timeutils.utcnow())

View File

@ -94,7 +94,11 @@ def is_newer_than(after, seconds):
def utcnow_ts(microsecond=False):
"""Timestamp version of our utcnow function."""
"""Timestamp version of our utcnow function.
See :py:class:`oslo_utils.fixture.TimeFixture`.
"""
if utcnow.override_time is None:
# NOTE(kgriffs): This is several times faster
# than going through calendar.timegm(...)
@ -113,7 +117,11 @@ def utcnow_ts(microsecond=False):
def utcnow():
"""Overridable version of utils.utcnow."""
"""Overridable version of utils.utcnow.
See :py:class:`oslo_utils.fixture.TimeFixture`.
"""
if utcnow.override_time:
try:
return utcnow.override_time.pop(0)
@ -135,6 +143,8 @@ def set_time_override(override_time=None):
Make it return a constant time or a list thereof, one at a time.
See :py:class:`oslo_utils.fixture.TimeFixture`.
:param override_time: datetime instance or list thereof. If not
given, defaults to the current UTC time.
"""
@ -142,7 +152,11 @@ def set_time_override(override_time=None):
def advance_time_delta(timedelta):
"""Advance overridden time using a datetime.timedelta."""
"""Advance overridden time using a datetime.timedelta.
See :py:class:`oslo_utils.fixture.TimeFixture`.
"""
assert utcnow.override_time is not None
try:
for dt in utcnow.override_time:
@ -152,12 +166,20 @@ def advance_time_delta(timedelta):
def advance_time_seconds(seconds):
"""Advance overridden time by seconds."""
"""Advance overridden time by seconds.
See :py:class:`oslo_utils.fixture.TimeFixture`.
"""
advance_time_delta(datetime.timedelta(0, seconds))
def clear_time_override():
"""Remove the overridden time."""
"""Remove the overridden time.
See :py:class:`oslo_utils.fixture.TimeFixture`.
"""
utcnow.override_time = None