Source code for testsuite.plugins.mocked_time
import datetime
import typing
import dateutil.parser
import pytest
from testsuite import utils
MOCK_TIME_DISABLED_MESSAGE = (
'Mock time is disabled. Use @pytest.mark.now to enable mock '
'time for a particular test'
)
UTC = datetime.timezone.utc
class BaseError(Exception):
"""Base class for errors in this module"""
class DisabledUsageError(BaseError):
"""Raised when attempting to use a disabled feature"""
[docs]class MockedTime:
def __init__(self, time: datetime.datetime, *, is_enabled: bool):
self._now = time
self._is_enabled = is_enabled
[docs] def sleep(self, delta: float) -> None:
"""Increase mock time value
:param delta: increase value in seconds
"""
if not self._is_enabled:
__tracebackhide__ = True
raise DisabledUsageError(MOCK_TIME_DISABLED_MESSAGE)
self._now += datetime.timedelta(seconds=delta)
[docs] def now(
self, tz: typing.Optional[datetime.tzinfo] = None
) -> datetime.datetime:
""":returns: current value of mock time"""
now = None
if self._is_enabled:
now = self._now
else:
now = utils.utcnow()
if tz:
now = now.replace(tzinfo=UTC).astimezone(tz=tz)
return now
[docs] def set(self, time: datetime.datetime):
"""Set mock time value"""
if not self._is_enabled:
__tracebackhide__ = True
raise DisabledUsageError(MOCK_TIME_DISABLED_MESSAGE)
self._now = utils.to_utc(time)
@property
def is_enabled(self) -> bool:
return self._is_enabled
def pytest_addoption(parser):
parser.addini(
name='mocked-time-enabled',
type='bool',
default=True,
help='Set false to disable mocked time by default',
)
def pytest_configure(config):
config.addinivalue_line(
'markers',
'now: specify current time mocked value',
)
def pytest_register_object_hooks():
return {
'$dateDiff': {'$fixture': '_date_diff_hook'},
'$timeDelta': _time_delta_hook,
}
def pytest_servicetest_modifyitem(session, item):
item.add_marker(pytest.mark.now(enabled=False))
[docs]@pytest.fixture
def mocked_time(
_mocked_time_enabled: bool,
now: datetime.datetime,
) -> MockedTime:
""":returns: :py:class:`MockedTime`"""
return MockedTime(now, is_enabled=_mocked_time_enabled)
@pytest.fixture
def now(request) -> datetime.datetime:
marker = request.node.get_closest_marker('now')
if not marker or not marker.args:
return utils.utcnow()
stamp = marker.args[0]
if isinstance(stamp, int):
return utils.utcfromtimestamp(stamp)
return utils.to_utc(dateutil.parser.parse(stamp))
@pytest.fixture
def _mocked_time_enabled(request, pytestconfig) -> bool:
now_marker_exists = False
for marker in request.node.iter_markers(name='now'):
if 'enabled' in marker.kwargs:
return marker.kwargs['enabled']
now_marker_exists = True
if now_marker_exists:
return True
return pytestconfig.getini('mocked-time-enabled')
@pytest.fixture
def _date_diff_hook(now: datetime.datetime):
def wrapper(doc: dict):
seconds = float(doc['$dateDiff'])
return now + datetime.timedelta(seconds=seconds)
return wrapper
def _time_delta_hook(doc: dict):
delta = float(doc['$timeDelta'])
return datetime.timedelta(seconds=delta)