Skip to content

Commit c9d88ad

Browse files
committed
test(logging): assert daily log files are generated per configured timezone
Fix a fixed instant on a day boundary and show two timezones produce two differently-dated daily log files on disk, driven by logging.channels.timezone. Verified via mutation testing: hardcoding UTC in BaseChannel.get_time (filename) and BaseDriver.get_time (get_time) each fails its corresponding assertion.
1 parent 6f72304 commit c9d88ad

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

‎fastapi_startkit/tests/logging/test_logging.py‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,66 @@ def test_levels_route_to_the_underlying_logger(self):
337337
driver.log.critical.assert_called_once_with("halt")
338338

339339

340+
class TimezoneAwareLogFileTest(unittest.TestCase):
341+
"""The daily log file name comes from get_time(), which resolves
342+
`logging.channels.timezone` — so the file that gets generated on disk must
343+
follow the application's configured timezone, not the machine/UTC clock."""
344+
345+
def setUp(self):
346+
self.config = get_app().make("config")
347+
self.root_named = logging.getLogger("root")
348+
self._propagate = self.root_named.propagate
349+
self.root_named.propagate = False
350+
self._existing_handlers = list(self.root_named.handlers)
351+
352+
def tearDown(self):
353+
for handler in list(self.root_named.handlers):
354+
if handler not in self._existing_handlers:
355+
self.root_named.removeHandler(handler)
356+
handler.close()
357+
self.root_named.propagate = self._propagate
358+
# Restore to the code's default so other tests' get_time() keeps working.
359+
self.config.set("logging.channels.timezone", "UTC")
360+
361+
def _daily_path(self, directory, tz, fixed_instant):
362+
self.config.set("logging.channels.timezone", tz)
363+
with patch("pendulum.now", return_value=fixed_instant):
364+
return DailyChannel(driver="daily", path=directory).driver.path
365+
366+
def test_daily_file_date_follows_configured_timezone(self):
367+
import os
368+
import tempfile
369+
370+
import pendulum
371+
372+
# 23:30 UTC sits on a day boundary: timezones ahead of UTC are already on
373+
# the next calendar day, timezones behind are still on the previous one.
374+
fixed = pendulum.datetime(2026, 7, 8, 23, 30, 0, tz="UTC")
375+
directory = tempfile.mkdtemp()
376+
377+
ahead = self._daily_path(directory, "Pacific/Kiritimati", fixed) # UTC+14
378+
behind = self._daily_path(directory, "Pacific/Honolulu", fixed) # UTC-10
379+
380+
# File names differ purely because of the configured timezone.
381+
self.assertTrue(ahead.endswith("2026-07-09.log"), ahead)
382+
self.assertTrue(behind.endswith("2026-07-08.log"), behind)
383+
self.assertNotEqual(ahead, behind)
384+
385+
# And both files are actually created on disk with the tz-derived names.
386+
self.assertTrue(os.path.isfile(os.path.join(directory, "2026-07-09.log")))
387+
self.assertTrue(os.path.isfile(os.path.join(directory, "2026-07-08.log")))
388+
389+
def test_get_time_reflects_configured_timezone(self):
390+
import pendulum
391+
392+
fixed = pendulum.datetime(2026, 7, 8, 23, 30, 0, tz="UTC")
393+
self.config.set("logging.channels.timezone", "Pacific/Kiritimati")
394+
with patch("pendulum.now", return_value=fixed):
395+
now = BaseDriver().get_time()
396+
self.assertEqual(now.to_date_string(), "2026-07-09")
397+
self.assertEqual(now.timezone_name, "Pacific/Kiritimati")
398+
399+
340400
class ChannelConstructionTest(unittest.TestCase):
341401
def test_terminal_channel_uses_terminal_driver(self):
342402
channel = TerminalChannel()

0 commit comments

Comments
 (0)