Skip to content

Commit e290d9e

Browse files
test: avoid local times near midnight for test_past_swap_days_buttons() (ietf-tools#4642)
* test: avoid local times near midnight for test_past_swap_days_buttons() * test: use timezone_options variable consistently * test: add test of timezone_not_near_midnight() method * fix: ensure that timezone_not_near_midnight() always exits
1 parent 6503e57 commit e290d9e

3 files changed

Lines changed: 71 additions & 1 deletion

File tree

ietf/meeting/tests_js.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from ietf.utils.test_utils import assert_ical_response_is_valid
3535
from ietf.utils.jstest import ( IetfSeleniumTestCase, ifSeleniumEnabled, selenium_enabled,
3636
presence_of_element_child_by_css_selector )
37+
from ietf.utils.timezone import timezone_not_near_midnight
3738

3839
if selenium_enabled():
3940
from selenium.webdriver.common.action_chains import ActionChains
@@ -392,7 +393,12 @@ def test_past_flags(self):
392393
def test_past_swap_days_buttons(self):
393394
"""Swap days buttons should be hidden for past items"""
394395
wait = WebDriverWait(self.driver, 2)
395-
meeting = MeetingFactory(type_id='ietf', date=datetime.datetime.today() - datetime.timedelta(days=3), days=7)
396+
meeting = MeetingFactory(
397+
type_id='ietf',
398+
date=datetime.datetime.today() - datetime.timedelta(days=3),
399+
days=7,
400+
time_zone=timezone_not_near_midnight(),
401+
)
396402
room = RoomFactory(meeting=meeting)
397403

398404
# get current time in meeting time zone

ietf/utils/tests.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
# -*- coding: utf-8 -*-
33

44

5+
import datetime
56
import io
67
import json
78
import os.path
9+
import pytz
810
import shutil
911
import types
1012

13+
from mock import patch
1114
from pyquery import PyQuery
1215
from typing import Dict, List # pyflakes:ignore
1316

@@ -39,6 +42,7 @@
3942
from ietf.utils.test_runner import get_template_paths, set_coverage_checking
4043
from ietf.utils.test_utils import TestCase, unicontent
4144
from ietf.utils.text import parse_unicode
45+
from ietf.utils.timezone import timezone_not_near_midnight
4246
from ietf.utils.xmldraft import XMLDraft
4347

4448
class SendingMail(TestCase):
@@ -476,3 +480,40 @@ def test_manifest(self):
476480
manifest = json.loads(unicontent(r))
477481
self.assertTrue('name' in manifest)
478482
self.assertTrue('theme_color' in manifest)
483+
484+
485+
class TimezoneTests(TestCase):
486+
"""Tests of the timezone utilities"""
487+
@patch(
488+
'ietf.utils.timezone.timezone.now',
489+
return_value=pytz.timezone('America/Chicago').localize(datetime.datetime(2022, 7, 1, 23, 15, 0)), # 23:15:00
490+
)
491+
def test_timezone_not_near_midnight(self, mock):
492+
# give it several choices that should be rejected and one that should be accepted
493+
with patch(
494+
'ietf.utils.timezone.pytz.common_timezones',
495+
[
496+
'America/Chicago', # time is 23:15, should be rejected
497+
'America/Lima', # time is 23:15, should be rejected
498+
'America/New_York', # time is 00:15, should be rejected
499+
'Europe/Riga', # time is 07:15, acceptable
500+
],
501+
):
502+
# check a few times (will pass by chance < 0.1% of the time)
503+
self.assertEqual(timezone_not_near_midnight(), 'Europe/Riga')
504+
self.assertEqual(timezone_not_near_midnight(), 'Europe/Riga')
505+
self.assertEqual(timezone_not_near_midnight(), 'Europe/Riga')
506+
self.assertEqual(timezone_not_near_midnight(), 'Europe/Riga')
507+
self.assertEqual(timezone_not_near_midnight(), 'Europe/Riga')
508+
509+
# now give it no valid choice
510+
with patch(
511+
'ietf.utils.timezone.pytz.common_timezones',
512+
[
513+
'America/Chicago', # time is 23:15, should be rejected
514+
'America/Lima', # time is 23:15, should be rejected
515+
'America/New_York', # time is 00:15, should be rejected
516+
],
517+
):
518+
with self.assertRaises(RuntimeError):
519+
timezone_not_near_midnight()

ietf/utils/timezone.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import pytz
22
import email.utils
33
import datetime
4+
import random
45

56
from django.conf import settings
7+
from django.utils import timezone
8+
69

710
def local_timezone_to_utc(d):
811
"""Takes a naive datetime in the local timezone and returns a
@@ -37,3 +40,23 @@ def email_time_to_local_timezone(date_string):
3740
def date2datetime(date, tz=pytz.utc):
3841
return datetime.datetime(*(date.timetuple()[:6]), tzinfo=tz)
3942

43+
44+
def timezone_not_near_midnight():
45+
"""Get the name of a random timezone where it's not close to midnight
46+
47+
Avoids midnight +/- 1 hour. Raises RuntimeError if it is unable to find
48+
a time zone satisfying this constraint.
49+
"""
50+
timezone_options = pytz.common_timezones
51+
tzname = random.choice(timezone_options)
52+
right_now = timezone.now().astimezone(pytz.timezone(tzname))
53+
# Avoid the remote possibility of an infinite loop (might come up
54+
# if there is a problem with the time zone library)
55+
tries_left = 20
56+
while right_now.hour < 1 or right_now.hour >= 23:
57+
tzname = random.choice(timezone_options)
58+
right_now = right_now.astimezone(pytz.timezone(tzname))
59+
tries_left -= 1
60+
if tries_left <= 0:
61+
raise RuntimeError('Unable to find a time zone not near midnight')
62+
return tzname

0 commit comments

Comments
 (0)