Skip to content

Commit

Permalink
[participant-timezones] timezone test for celery push notification
Browse files Browse the repository at this point in the history
  • Loading branch information
biblicabeebli committed Oct 26, 2023
1 parent 9ff1681 commit bfb0eb6
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 13 deletions.
10 changes: 5 additions & 5 deletions constants/testing_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ def MIDNIGHT_EVERY_DAY():


# we need some moments in space-time, so I guess we will use October Thursdays in New York of 2022
_MERICA_NY = tz.gettz("New_York/America")
OCT_6_NOON_2022 = datetime(2022, 10, 6, 12, ) # Thursday
OCT_13_NOON_2022 = datetime(2022, 10, 13, 12, tzinfo=_MERICA_NY) # Thursday
OCT_20_NOON_2022 = datetime(2022, 10, 20, 12, tzinfo=_MERICA_NY) # Thursday
OCT_27_NOON_2022 = datetime(2022, 10, 27, 12, tzinfo=_MERICA_NY) # Thursday
_MERICA_NY = tz.gettz("America/New_York")
THURS_OCT_6_NOON_2022_NY = datetime(2022, 10, 6, 12, tzinfo=_MERICA_NY) # Thursday
THURS_OCT_13_NOON_2022_NY = datetime(2022, 10, 13, 12, tzinfo=_MERICA_NY) # Thursday
THURS_OCT_20_NOON_2022_NY = datetime(2022, 10, 20, 12, tzinfo=_MERICA_NY) # Thursday
THURS_OCT_27_NOON_2022_NY = datetime(2022, 10, 27, 12, tzinfo=_MERICA_NY) # Thursday
26 changes: 25 additions & 1 deletion services/celery_push_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@

UTC = gettz("UTC")

PUSH_NOTIFICATION_LOGGING_ENABLED = False

def log(*args, **kwargs):
if PUSH_NOTIFICATION_LOGGING_ENABLED:
print(*args, **kwargs)

################################################################E###############
############################# PUSH NOTIFICATIONS ###############################
################################################################################
Expand All @@ -36,6 +42,7 @@ def get_surveys_and_schedules(now: datetime) -> Tuple[DictOfStrToListOfStr, Dict
a mapping of fcm tokens to list of survey object ids
a mapping of fcm tokens to list of schedule ids
a mapping of fcm tokens to patient ids """
log(f"\nchecking if any scheduled events are in the past (before {now})")

# we need to find all possible events and convert them on a per-participant-timezone basis.
# The largest timezone offset is +14?, but we will do one whole day and manually filter.
Expand Down Expand Up @@ -84,8 +91,20 @@ def get_surveys_and_schedules(now: datetime) -> Tuple[DictOfStrToListOfStr, Dict
participant_tz_name: str
participant_has_bad_tz: bool
for scheduled_time, survey_obj_id, study_tz_name, fcm, schedule_id, patient_id, unregistered, participant_tz_name, participant_has_bad_tz in query:
log("\nchecking scheduled event:")
log("unregistered:", unregistered)
log("fcm:", fcm)
log("patient_id:", patient_id)
log("survey_obj_id:", survey_obj_id)
log("scheduled_time:", scheduled_time)
log("schedule_id:", schedule_id)
log("study_tz_name:", study_tz_name)
log("participant_tz_name:", participant_tz_name)
log("participant_has_bad_tz:", participant_has_bad_tz)

# case: this instance has an outdated FCM credential, skip it.
if unregistered:
log("nope, unregistered fcm token")
continue

# The participant and study timezones REALLY SHOULD be valid timezone names. If they aren't
Expand All @@ -102,9 +121,14 @@ def get_surveys_and_schedules(now: datetime) -> Tuple[DictOfStrToListOfStr, Dict
# participant's timezone, and check if That value is in the past.
canonical_time = scheduled_time.astimezone(study_tz)
participant_time = canonical_time.replace(tzinfo=participant_tz)
log("canonical_time:", canonical_time)
log("participant_time:", participant_time)
if participant_time > now:
log("nope, participant time is considered in the future")
log(f"{now} > {participant_time}")
continue

log("yup, participant time is considered in the past")
log(f"{now} <= {participant_time}")
surveys[fcm].append(survey_obj_id)
schedules[fcm].append(schedule_id)
patient_ids[fcm] = patient_id
Expand Down
1 change: 1 addition & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ def generate_a_real_weekly_schedule_event_with_schedule(
""" The creation of weekly events is weird, it best to use the real machinery and build
some unit tests for it. At time of documenting none exist, but there are some integration
tests. """
# 0 indexes to sunday, 6 indexes to saturday.
self.generate_weekly_schedule(self.default_survey, day_of_week, hour, minute)
return set_next_weekly(self.default_participant, self.default_survey)

Expand Down
50 changes: 46 additions & 4 deletions tests/test_celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
from unittest.mock import MagicMock, patch

import time_machine
from dateutil.tz import gettz
from django.utils import timezone

from constants.testing_constants import OCT_6_NOON_2022, OCT_20_NOON_2022
from constants.testing_constants import (THURS_OCT_6_NOON_2022_NY, THURS_OCT_13_NOON_2022_NY,
THURS_OCT_20_NOON_2022_NY)
from database.schedule_models import ScheduledEvent
from services.celery_push_notifications import get_surveys_and_schedules
from tests.common import CommonTestCase
Expand All @@ -17,6 +19,7 @@ class TestCelery(CommonTestCase):
class TestGetSurveysAndSchedules(TestCelery):

def test_empty_db(self):
self.assertEqual(ScheduledEvent.objects.count(), 0)
self.validate_no_schedules()

def validate_no_schedules(self):
Expand Down Expand Up @@ -62,19 +65,58 @@ def test_relative_failure(self):
self.generate_easy_relative_schedule_event_with_schedule(timedelta(days=5))
self.validate_no_schedules()

@time_machine.travel(OCT_6_NOON_2022)
@time_machine.travel(THURS_OCT_6_NOON_2022_NY)
def test_weekly_success(self):
self.populate_default_fcm_token
# TODO: why is this passing
# a weekly survey, on a friday, sunday is the zero-index; I hate it more than you.
schedule, count_created = self.generate_a_real_weekly_schedule_event_with_schedule(5)
self.assertEqual(count_created, 1)
with time_machine.travel(OCT_20_NOON_2022):
with time_machine.travel(THURS_OCT_20_NOON_2022_NY):
self.validate_basics(schedule)

@time_machine.travel(OCT_6_NOON_2022)
@time_machine.travel(THURS_OCT_6_NOON_2022_NY)
def test_weekly_in_future_fails(self):
self.populate_default_fcm_token
# TODO: why is this passing
# a weekly survey, on a friday, sunday is the zero-index; I hate it more than you.
schedule, count_created = self.generate_a_real_weekly_schedule_event_with_schedule(5)
self.assertEqual(count_created, 1)
self.validate_no_schedules()

@time_machine.travel(THURS_OCT_13_NOON_2022_NY)
def test_time_zones(self):
self.populate_default_fcm_token
self.default_study.update_only(timezone_name='America/New_York') # default in tests is normally UTC.

# need to time travel to the past to get the weekly logic to produce the correct time
with time_machine.travel(THURS_OCT_6_NOON_2022_NY):
# creates a weekly survey for 2022-10-13 12:00:00-04:00
schedule, count_created = self.generate_a_real_weekly_schedule_event_with_schedule(4, 12, 0)
self.assertEqual(count_created, 1)

# assert schedule time is equal to 2022-10-13 12:00:00-04:00, then assert components are equal.
self.assertEqual(schedule.scheduled_time, THURS_OCT_13_NOON_2022_NY)
self.assertEqual(schedule.scheduled_time.year, 2022)
self.assertEqual(schedule.scheduled_time.month, 10)
self.assertEqual(schedule.scheduled_time.day, 13)
self.assertEqual(schedule.scheduled_time.hour, 12)
self.assertEqual(schedule.scheduled_time.minute, 0)
self.assertEqual(schedule.scheduled_time.second, 0)
self.assertEqual(schedule.scheduled_time.tzinfo, gettz("America/New_York"))

# set default participant to pacific time, assert that no push notification is calculated.
self.default_participant.try_set_timezone('America/Los_Angeles')
self.validate_no_schedules()

# set the time zone to mountain time, assert that no push notification is calculated.
self.default_participant.try_set_timezone('America/Denver')
self.validate_no_schedules()

# set the time zone to central time, assert that no push notification is calculated.
self.default_participant.try_set_timezone('America/Chicago')
self.validate_no_schedules()

# but if you set the time zone to New_York the push notification is calculated!
self.default_participant.try_set_timezone('America/New_York')
self.validate_basics(schedule)
6 changes: 3 additions & 3 deletions tests/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from constants.schedule_constants import EMPTY_WEEKLY_SURVEY_TIMINGS
from constants.security_constants import MFA_CREATED
from constants.testing_constants import (ADMIN_ROLES, ALL_TESTING_ROLES, ANDROID_CERT, BACKEND_CERT,
IOS_CERT, MIDNIGHT_EVERY_DAY, OCT_6_NOON_2022)
IOS_CERT, MIDNIGHT_EVERY_DAY, THURS_OCT_6_NOON_2022_NY)
from constants.url_constants import LOGIN_REDIRECT_SAFE, urlpatterns
from constants.user_constants import ALL_RESEARCHER_TYPES, IOS_API, ResearcherRole
from database.data_access_models import ChunkRegistry, FileToProcess
Expand Down Expand Up @@ -4053,7 +4053,7 @@ def test_weekly_basics2(self):
output_survey = json.loads(resp.content.decode())
self.assertEqual(output_survey, reference_output)

@time_machine.travel(OCT_6_NOON_2022)
@time_machine.travel(THURS_OCT_6_NOON_2022_NY)
def test_absolute_schedule_basics(self):
# test for absolute surveys that they show up regardless of the day of the week they fall on,
# as long as that day is within the current week.
Expand Down Expand Up @@ -4094,7 +4094,7 @@ def test_absolute_schedule_out_of_range_past(self):
output_survey = json.loads(resp.content.decode())
self.assertEqual(output_survey, self.BASIC_SURVEY_CONTENT)

@time_machine.travel(OCT_6_NOON_2022)
@time_machine.travel(THURS_OCT_6_NOON_2022_NY)
def test_relative_schedule_basics(self):
# this test needds to run on a thursday
# test that a relative survey creates schedules that get output in survey timings at all
Expand Down

0 comments on commit bfb0eb6

Please sign in to comment.