Replaced hand-rolled time freezing in tests with freezegun.
This commit is contained in:
@@ -25,6 +25,7 @@ Repository = "https://git.logal.dev/LogalDeveloper/Owlbot"
|
|||||||
dev = [
|
dev = [
|
||||||
"pytest>=9.0.2",
|
"pytest>=9.0.2",
|
||||||
"pytest-asyncio>=1.3.0",
|
"pytest-asyncio>=1.3.0",
|
||||||
|
"freezegun>=1.5.5",
|
||||||
"mypy>=1.18.1",
|
"mypy>=1.18.1",
|
||||||
"types-PyYAML>=6.0.12.20250915",
|
"types-PyYAML>=6.0.12.20250915",
|
||||||
"ruff>=0.15.1",
|
"ruff>=0.15.1",
|
||||||
|
|||||||
+13
-39
@@ -19,46 +19,16 @@ templates and user scenarios.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import random
|
import random
|
||||||
from contextlib import contextmanager
|
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
import pytest
|
import pytest
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
import owlbot.builtin_modules.custom_commands.placeholder_handlers as _ph
|
|
||||||
from owlbot.builtin_modules.custom_commands.placeholder_handlers import _format_duration
|
from owlbot.builtin_modules.custom_commands.placeholder_handlers import _format_duration
|
||||||
from owlbot.builtin_modules.custom_commands.placeholders import process_placeholders
|
from owlbot.builtin_modules.custom_commands.placeholders import process_placeholders
|
||||||
|
|
||||||
_real_datetime = datetime
|
|
||||||
|
|
||||||
|
|
||||||
class _FrozenDatetime(datetime):
|
|
||||||
"""datetime subclass whose now() returns a fixed instant."""
|
|
||||||
|
|
||||||
_frozen: datetime
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def now(cls, tz=None):
|
|
||||||
return cls._frozen
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def freeze_time(year, month, day, hour=0, minute=0, second=0):
|
|
||||||
"""Temporarily replace datetime in placeholder_handlers with a frozen clock."""
|
|
||||||
_FrozenDatetime._frozen = _real_datetime(
|
|
||||||
year,
|
|
||||||
month,
|
|
||||||
day,
|
|
||||||
hour,
|
|
||||||
minute,
|
|
||||||
second,
|
|
||||||
tzinfo=UTC,
|
|
||||||
)
|
|
||||||
with patch.object(_ph, "datetime", _FrozenDatetime):
|
|
||||||
yield _FrozenDatetime._frozen
|
|
||||||
|
|
||||||
|
|
||||||
class MockStorage:
|
class MockStorage:
|
||||||
"""In-memory SQLite storage that executes real SQL queries."""
|
"""In-memory SQLite storage that executes real SQL queries."""
|
||||||
@@ -583,17 +553,19 @@ class TestCountdownCountup:
|
|||||||
|
|
||||||
async def test_countdown_future_date(self):
|
async def test_countdown_future_date(self):
|
||||||
"""$(countdown) with a future date returns the formatted duration."""
|
"""$(countdown) with a future date returns the formatted duration."""
|
||||||
with freeze_time(2026, 6, 15, 12, 0, 0) as now:
|
with freeze_time("2026-06-15 12:00:00", tz_offset=0):
|
||||||
|
now = datetime.now(UTC)
|
||||||
# Dec 25 2099 00:00:00 EST = Dec 25 2099 05:00:00 UTC
|
# Dec 25 2099 00:00:00 EST = Dec 25 2099 05:00:00 UTC
|
||||||
target = _real_datetime(2099, 12, 25, 5, 0, 0, tzinfo=UTC)
|
target = datetime(2099, 12, 25, 5, 0, 0, tzinfo=UTC)
|
||||||
expected = _format_duration(int((target - now).total_seconds()))
|
expected = _format_duration(int((target - now).total_seconds()))
|
||||||
result = await process("$(countdown Dec 25 2099 12:00:00 AM EST)")
|
result = await process("$(countdown Dec 25 2099 12:00:00 AM EST)")
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
async def test_countup_past_date(self):
|
async def test_countup_past_date(self):
|
||||||
"""$(countup) with a past date returns the formatted elapsed duration."""
|
"""$(countup) with a past date returns the formatted elapsed duration."""
|
||||||
with freeze_time(2026, 6, 15, 12, 0, 0) as now:
|
with freeze_time("2026-06-15 12:00:00", tz_offset=0):
|
||||||
target = _real_datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
|
now = datetime.now(UTC)
|
||||||
|
target = datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
|
||||||
expected = _format_duration(int((now - target).total_seconds()))
|
expected = _format_duration(int((now - target).total_seconds()))
|
||||||
result = await process("$(countup Jan 1 2020 12:00:00 AM UTC)")
|
result = await process("$(countup Jan 1 2020 12:00:00 AM UTC)")
|
||||||
assert result == expected
|
assert result == expected
|
||||||
@@ -642,9 +614,10 @@ class TestCountdownCountup:
|
|||||||
|
|
||||||
async def test_fractional_timezone_offset(self):
|
async def test_fractional_timezone_offset(self):
|
||||||
"""A fractional timezone offset like IST (UTC+5:30) is applied correctly."""
|
"""A fractional timezone offset like IST (UTC+5:30) is applied correctly."""
|
||||||
with freeze_time(2026, 6, 15, 12, 0, 0) as now:
|
with freeze_time("2026-06-15 12:00:00", tz_offset=0):
|
||||||
|
now = datetime.now(UTC)
|
||||||
# Jan 1 2020 12:00:00 AM IST = Dec 31 2019 18:30:00 UTC
|
# Jan 1 2020 12:00:00 AM IST = Dec 31 2019 18:30:00 UTC
|
||||||
target = _real_datetime(2019, 12, 31, 18, 30, 0, tzinfo=UTC)
|
target = datetime(2019, 12, 31, 18, 30, 0, tzinfo=UTC)
|
||||||
expected = _format_duration(int((now - target).total_seconds()))
|
expected = _format_duration(int((now - target).total_seconds()))
|
||||||
result = await process("$(countup Jan 1 2020 12:00:00 AM IST)")
|
result = await process("$(countup Jan 1 2020 12:00:00 AM IST)")
|
||||||
assert result == expected
|
assert result == expected
|
||||||
@@ -905,8 +878,9 @@ class TestCaseInsensitivity:
|
|||||||
|
|
||||||
async def test_countup_case_insensitive(self):
|
async def test_countup_case_insensitive(self):
|
||||||
"""$(COUNTUP) resolves the same as $(countup)."""
|
"""$(COUNTUP) resolves the same as $(countup)."""
|
||||||
with freeze_time(2026, 6, 15, 12, 0, 0) as now:
|
with freeze_time("2026-06-15 12:00:00", tz_offset=0):
|
||||||
target = _real_datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
|
now = datetime.now(UTC)
|
||||||
|
target = datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
|
||||||
expected = _format_duration(int((now - target).total_seconds()))
|
expected = _format_duration(int((now - target).total_seconds()))
|
||||||
result = await process("$(COUNTUP Jan 1 2020 12:00:00 AM UTC)")
|
result = await process("$(COUNTUP Jan 1 2020 12:00:00 AM UTC)")
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|||||||
@@ -109,6 +109,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl", hash = "sha256:1e1431fa08c51dc7f72e67e571c7c7a09af26420169b607badd4ca9677ffad1e", size = 14213, upload-time = "2025-10-21T16:38:20.431Z" },
|
{ url = "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl", hash = "sha256:1e1431fa08c51dc7f72e67e571c7c7a09af26420169b607badd4ca9677ffad1e", size = 14213, upload-time = "2025-10-21T16:38:20.431Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "freezegun"
|
||||||
|
version = "1.5.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "python-dateutil" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/95/dd/23e2f4e357f8fd3bdff613c1fe4466d21bfb00a6177f238079b17f7b1c84/freezegun-1.5.5.tar.gz", hash = "sha256:ac7742a6cc6c25a2c35e9292dfd554b897b517d2dec26891a2e8debf205cb94a", size = 35914, upload-time = "2025-08-09T10:39:08.338Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/2e/b41d8a1a917d6581fc27a35d05561037b048e47df50f27f8ac9c7e27a710/freezegun-1.5.5-py3-none-any.whl", hash = "sha256:cd557f4a75cf074e84bc374249b9dd491eaeacd61376b9eb3c423282211619d2", size = 19266, upload-time = "2025-08-09T10:39:06.636Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frozenlist"
|
name = "frozenlist"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@@ -332,6 +344,7 @@ dependencies = [
|
|||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
|
{ name = "freezegun" },
|
||||||
{ name = "mypy" },
|
{ name = "mypy" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
@@ -350,6 +363,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
|
{ name = "freezegun", specifier = ">=1.5.5" },
|
||||||
{ name = "mypy", specifier = ">=1.18.1" },
|
{ name = "mypy", specifier = ">=1.18.1" },
|
||||||
{ name = "pytest", specifier = ">=9.0.2" },
|
{ name = "pytest", specifier = ">=9.0.2" },
|
||||||
{ name = "pytest-asyncio", specifier = ">=1.3.0" },
|
{ name = "pytest-asyncio", specifier = ">=1.3.0" },
|
||||||
@@ -460,6 +474,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
|
{ url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dateutil"
|
||||||
|
version = "2.9.0.post0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyyaml"
|
name = "pyyaml"
|
||||||
version = "6.0.3"
|
version = "6.0.3"
|
||||||
@@ -511,6 +537,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" },
|
{ url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "types-pyyaml"
|
name = "types-pyyaml"
|
||||||
version = "6.0.12.20250915"
|
version = "6.0.12.20250915"
|
||||||
|
|||||||
Reference in New Issue
Block a user