Пример #1
0
    def test_relative_reminder_starts_on_appropriate_day(self):
        """Test that a relative reminder with a weekly recurrence actually
        starts on the appropriate day, and not just the very next day after
        it's selected."""

        # Weekly, Wed & Sun at 9am, for 4 occurences.
        default = Trigger.objects.create(
            name="RR-start upon selection",
            time=time(9, 0),
            recurrences="RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=WE,SU",
            start_when_selected=True,
        )

        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 12, 1, 14, 30)  # 2:30pm Dec 1

            # Test some expected "next" values.
            # At Jan 1, 11:45, next should be Jan 1, 9:00
            expected = tzdt(2015, 12, 2, 9, 0,
                            tz=timezone.utc).strftime("%c %z")
            actual = default.next().strftime("%c %z")
            self.assertEqual(actual, expected)

            # Test the occurences
            occurs = default.get_occurences()
            self.assertEqual(len(occurs), 4)
            actual = occurs[0].strftime("%c %z")
            self.assertEqual(actual, expected)
Пример #2
0
    def test_next_with_recurrence_and_time_of_day(self):
        """Test the value of `next` for triggers that have ONLY a `time_of_day`
        and `recurrences` set of days."""

        # 7pm on M, W, Th on Aug 17, 19, 20  (repeat until 8/21/2015)
        rrule = 'RRULE:FREQ=DAILY'
        t = Trigger.objects.create(name="x",
                                   time_of_day='early',
                                   recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: 08/15 at 11:00am, expected: next is Mon 8/16
            mock_now.return_value = tzdt(2015, 8, 15, 11, 0)

            result = t.next()
            self.assertIsNotNone(result)
            self.assertEqual(result.day, 16)
            self.assertIn(result.hour, [6, 7, 8])

            # now: 08/15 at 4:00am, expected: next is Mon 8/15
            mock_now.return_value = tzdt(2015, 8, 15, 4, 0)
            result = t.next()
            self.assertIsNotNone(result)
            self.assertEqual(result.day, 15)
            self.assertIn(result.hour, [6, 7, 8])

        # Clean up
        t.delete()
Пример #3
0
    def test_next_with_future_date(self):
        """Test the value of `next`, when the recurrence has a trigger_date,
        that's set in the future."""

        # Repeat daily at 9:00am, starting Oct 1, 2015
        rrule = 'RRULE:FREQ=DAILY'
        t = Trigger.objects.create(name="x",
                                   time=time(9, 0),
                                   trigger_date=date(2015, 10, 1),
                                   recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: 2015-08-15 at 11:00am, expected: next is 10/1
            mock_now.return_value = tzdt(2015, 8, 15, 11, 0)
            expected = tzdt(2015, 10, 1, 9, 0)
            self.assertEqual(t.next(), expected)

            # Should work as normal after the start date.
            # now: 2015-10-2 at 11:00am, expected next is 10/3 9am
            mock_now.return_value = tzdt(2015, 10, 2, 11, 0)
            expected = tzdt(2015, 10, 3, 9, 0)
            self.assertEqual(t.next(), expected)

        # Clean up
        t.delete()
Пример #4
0
    def test_create_relative_reminder_start_when_selected(self):
        """Creating a UserAction with a default `start_when_selected` trigger
        should result in a new custom trigger with pre-filled data."""
        cat = mommy.make(Category, title="Cat", state='published')
        goal = mommy.make(Goal, title="Goa", state='published')
        goal.categories.add(cat)
        act = mommy.make(Action, title='Act', state='published')
        act.goals.add(goal)

        default = Trigger.objects.create(
            name="Default",
            time=time(13, 30),
            recurrences="RRULE:FREQ=DAILY",
            start_when_selected=True,
        )
        act.default_trigger = default
        act.save()

        user = self.User.objects.create_user("un", "*****@*****.**", 'pass')
        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 1, 11, 45)
            ua = UserAction.objects.create(user=user, action=act)
            # A custom trigger should have been created
            self.assertIsNotNone(ua.custom_trigger)
            self.assertEqual(ua.default_trigger, default)
            self.assertNotEqual(ua.trigger, default)
            custom = ua.trigger

            # expected next trigger should be the same date as the UserAction's
            # creation date, with the Trigger time + the user's timezone
            tz = pytz.timezone(user.userprofile.timezone)
            expected = tzdt(2015, 1, 1, 13, 30, tz=tz)
            expected = expected.strftime("%c %z")
            actual = custom.next().strftime("%c %z")
            self.assertEqual(actual, expected)
Пример #5
0
    def test_create_for_user(self):
        with patch('goals.models.triggers.timezone') as mock_tz:
            mock_tz.is_naive = timezone.is_naive
            mock_tz.is_aware = timezone.is_aware
            mock_tz.make_aware = timezone.make_aware
            mock_tz.make_naive = timezone.make_naive
            mock_tz.utc = timezone.utc
            mock_tz.now.return_value = tzdt(2015, 3, 14, 8, 30)

            # When there's a time & recurrence
            trigger = Trigger.objects.create_for_user(
                self.user,
                "New Trigger",
                time(8, 30),
                None,
                "RRULE:FREQ=WEEKLY;BYDAY=MO",
            )
            self.assertEqual(trigger.recurrences_as_text(),
                             "weekly, each Monday")

            # when there's a time & a date
            trigger = Trigger.objects.create_for_user(self.user,
                                                      "Other New Trigger",
                                                      time(9, 30),
                                                      date(2015, 3, 15), None)
            tz = pytz.timezone(self.user.userprofile.timezone)
            expected = tzdt(2015, 3, 15, 9, 30, tz=tz)
            self.assertEqual(trigger.next().strftime("%c %z"),
                             expected.strftime("%c %z"))
Пример #6
0
    def test_next_with_multiple_rules(self):
        """Test `next` when we have multiple RRULE requirements."""

        # Every Monday. Then every Tuesday until 8/15/2015 (sat)
        rrule = ('RRULE:FREQ=WEEKLY;BYDAY=MO\n'
                 'RRULE:FREQ=WEEKLY;UNTIL=20150815T050000Z;BYDAY=TU')
        t = Trigger.objects.create(
            name="x",
            time=time(9, 0),  # 9am
            trigger_date=date(2015, 8, 1),
            recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: Sat 08/8 at 11:00am, expected: next is Mon 8/10
            mock_now.return_value = tzdt(2015, 8, 8, 11, 0)
            expected = tzdt(2015, 8, 10, 9, 0)
            self.assertEqual(t.next(), expected)

            # now: Mon 8/10 at 11:00am, expected next is Tues 8/11
            mock_now.return_value = tzdt(2015, 8, 10, 11, 0)
            expected = tzdt(2015, 8, 11, 9, 0)
            self.assertEqual(t.next(), expected)

            # now: Wed 8/12 at 11:00am, expected next is Mon 8/17
            mock_now.return_value = tzdt(2015, 8, 12, 11, 0)
            expected = tzdt(2015, 8, 17, 9, 0)
            self.assertEqual(t.next(), expected)

            # now: Mon 8/17 at 11am, expected next is Mon 24 (skipped Tues)
            mock_now.return_value = tzdt(2015, 8, 17, 11, 0)
            expected = tzdt(2015, 8, 24, 9, 0)

        # Clean up
        t.delete()
Пример #7
0
    def test__combine(self):
        """Ensure the Trigger.__combine wrapper works as expected."""

        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 2)
            t = self.trigger._combine(time(13, 30))
            self.assertEqual(t, tzdt(2015, 1, 2, 13, 30))

            t = self.trigger._combine(time(13, 30), date(2015, 2, 3))
            self.assertEqual(t, tzdt(2015, 2, 3, 13, 30))

            tz = pytz.timezone("America/Chicago")
            t = self.trigger._combine(time(13, 30), date(2010, 12, 30), tz)
            self.assertEqual(t, tzdt(2010, 12, 30, 13, 30, tz=tz))
Пример #8
0
    def test_default_trigger_with_user_timezone(self):
        user = self.User.objects.create_user('u', '*****@*****.**', 'pass')
        user.userprofile.timezone = 'America/Chicago'
        user.userprofile.save()

        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 2, 11, 30)
            trigger = Trigger.objects.create(name="Test Default",
                                             time=time(23, 59),
                                             recurrences='RRULE:FREQ=DAILY')

            tz = pytz.timezone('America/Chicago')
            expected = tzdt(2015, 1, 2, 23, 59, tz=tz)
            result = trigger.next(user=user)
            self.assertEqual(result.strftime("%c %z"),
                             expected.strftime("%c %z"))
Пример #9
0
    def test_get_alert_time(self):
        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 2)

            # No date, should combine "now" + time
            self.assertEqual(self.trigger.get_alert_time(),
                             tzdt(2015, 1, 2, 12, 34))

            # Date + time should get combined.
            self.trigger.trigger_date = date(2015, 3, 15)
            self.trigger.save()
            self.assertEqual(self.trigger.get_alert_time(),
                             tzdt(2015, 3, 15, 12, 34))

            # No date or time should return None
            self.assertIsNone(Trigger().get_alert_time())
Пример #10
0
    def test_next_with_stop_on_complete(self):
        """Ensure that a trigger a stop_on_complete set will no longer return
        dates after it has "stopped"."""
        trigger = Trigger.objects.create(name="Stop-Trigger",
                                         time=time(12, 34),
                                         trigger_date=date(2015, 1, 1),
                                         stop_on_complete=True)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 1, 9, 0)

            # First, when the trigger hasn't been stopped.
            trigger._stopped_by_completion = Mock(return_value=False)
            expected = tzdt(2015, 1, 1, 12, 34)
            expected = expected.strftime("%c %z")
            actual = trigger.next().strftime("%c %z")
            self.assertEqual(actual, expected)

            # Now once the trigger has been completed
            trigger._stopped_by_completion = Mock(return_value=True)
            self.assertIsNone(trigger.next())
Пример #11
0
    def test_next(self):
        trigger = Trigger.objects.create(
            name="Daily Test Trigger",
            time=time(12, 34),
            recurrences="RRULE:FREQ=DAILY",
        )
        with patch("goals.models.triggers.timezone.now") as mock_now:
            # Ensure we get the *today* if it's scheduled later in the day
            # now is 9:30 am, trigger is for 12:34pm
            mock_now.return_value = tzdt(1000, 10, 20, 9, 30)
            expected = tzdt(1000, 10, 20, 12, 34)
            self.assertEqual(trigger.next(), expected)

            # Ensure we get the next day's trigger if later than *now*
            # now is 1:30pm, trigger is for 12:34pm
            mock_now.return_value = tzdt(1000, 10, 20, 13, 30)
            expected = tzdt(1000, 10, 21, 12, 34)
            self.assertEqual(trigger.next(), expected)

            # Ensure we get the same day's trigger if the times matche
            # now is 12:34pm, trigger is for 12:34pm
            mock_now.return_value = tzdt(1000, 10, 20, 12, 34)
            expected = tzdt(1000, 10, 20, 12, 34)
            self.assertEqual(trigger.next(), expected)

        # Clean up
        trigger.delete()
Пример #12
0
    def test_relative_reminder_start_when_selected_series(self):
        """Test a series of generated relative reminder times."""
        cat = mommy.make(Category, title="Cat", state='published')
        goal = mommy.make(Goal, title="Goa", state='published')
        goal.categories.add(cat)
        act = mommy.make(Action, title='Act', state='published')
        act.goals.add(goal)

        default = Trigger.objects.create(
            name="RR-start upon selection",
            time=time(9, 0),
            recurrences="RRULE:FREQ=DAILY;INTERVAL=2;COUNT=2",
            start_when_selected=True,
        )
        act.default_trigger = default
        act.save()

        user = self.User.objects.create_user("un", "*****@*****.**", 'pass')
        custom_trigger = None
        with patch("goals.models.triggers.timezone.now") as mock_now:
            mock_now.return_value = tzdt(2015, 1, 1, 11, 45)
            ua = UserAction.objects.create(user=user, action=act)

            # A custom trigger should have been created
            self.assertIsNotNone(ua.custom_trigger)
            self.assertEqual(ua.default_trigger, default)
            self.assertNotEqual(ua.trigger, default)
            custom_trigger = ua.trigger

            # Get the user's timezone
            tz = pytz.timezone(user.userprofile.timezone)

            # Test some expected "next" values.
            # At Jan 1, 11:45, next should be Jan 1, 9:00
            expected = tzdt(2015, 1, 1, 9, 0, tz=tz).strftime("%c %z")
            actual = custom_trigger.next().strftime("%c %z")
            self.assertEqual(actual, expected)

            # On Jan 2, next should be Jan 3, 9:00
            mock_now.return_value = tzdt(2015, 1, 2, 12, 0)
            expected = tzdt(2015, 1, 3, 9, 0, tz=tz).strftime("%c %z")
            actual = custom_trigger.next().strftime("%c %z")
            self.assertEqual(actual, expected)

            # On Jan 3, 7:15, next should be Jan 3, 9:00
            mock_now.return_value = tzdt(2015, 1, 3, 7, 15)
            expected = tzdt(2015, 1, 3, 9, 0, tz=tz).strftime("%c %z")
            actual = custom_trigger.next().strftime("%c %z")
            self.assertEqual(actual, expected)

            # On Jan 3, 4pm, next should be None since COUNT=2
            mock_now.return_value = tzdt(2015, 1, 3, 16, 0)
            self.assertIsNone(custom_trigger.next())
Пример #13
0
    def test_relative_reminder_daily_with_count(self):
        """A relative reminder that repeats daily for a set number of days"""

        t = Trigger.objects.create(
            name="Daily with Count",
            time=time(12, 0),
            trigger_date=date(2016, 1, 4),  # Monday, Jan 4
            recurrences='RRULE:FREQ=DAILY;COUNT=3',  # Repeats 3 times
            start_when_selected=True,
            stop_on_complete=True,
            relative_value=1,  # NOTE: 1 day after selected.
            relative_units='days',
        )

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # Day of selection: Sat Jan 2, 2016
            selection_date = tzdt(2016, 1, 2, 14, 30)
            mock_now.return_value = tzdt(2016, 1, 2, 14, 30)
            t.trigger_date = selection_date + timedelta(days=1)  # 1 day later
            t.save()

            # Now selection should start the next day, Jan 3
            expected = tzdt(2016, 1, 3, 12, 0)
            self.assertEqual(t.next(), expected)

            # That afternoon, we expect another on the next day
            mock_now.return_value = tzdt(2016, 1, 3, 20, 22)
            expected = tzdt(2016, 1, 4, 12, 0)
            self.assertEqual(t.next(), expected)

            # Jan 5 (day 3 after selection) in the morning
            mock_now.return_value = tzdt(2016, 1, 5, 9, 0)
            expected = tzdt(2016, 1, 5, 12, 0)
            self.assertEqual(t.next(), expected)

            # in the afternoon, we should be done.
            mock_now.return_value = tzdt(2016, 1, 5, 13, 0)
            self.assertIsNone(t.next())

        t.delete()  # Clean up
Пример #14
0
    def test_next_with_a_count(self):
        """Test the value of `next`, when the recurrence is set to occure a
        set number of times (with COUNT in the RRULE)."""
        # daily, occuring once
        rrule = 'RRULE:FREQ=DAILY;COUNT=1'
        t = Trigger.objects.create(name="x",
                                   time=time(12, 30),
                                   trigger_date=date(2015, 8, 2),
                                   recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: 2015-08-01 at 11:00am
            # expected: 2015-08-02, at 12:30pm
            mock_now.return_value = tzdt(2015, 8, 1, 11, 0)
            expected = tzdt(2015, 8, 2, 12, 30)
            self.assertEqual(t.next(), expected)

            # now: 2015-08-02 at 9:00am
            # expected: 2015-08-02 at 12:30pm
            mock_now.return_value = tzdt(2015, 8, 2, 9, 0)
            expected = tzdt(2015, 8, 2, 12, 30)
            self.assertEqual(t.next(), expected)

            # now: 2015-08-02 at 12:30pm
            # expected: 2015-08-02 at 12:30pm
            mock_now.return_value = tzdt(2015, 8, 2, 12, 30)
            expected = tzdt(2015, 8, 2, 12, 30)
            self.assertEqual(t.next(), expected)

            # now: 2015-08-03 at 9:00am  (the day after)
            # expected: None because it's already fired once.
            mock_now.return_value = tzdt(2015, 8, 3, 9, 0)
            self.assertIsNone(t.next())

        # Clean up
        t.delete()
Пример #15
0
    def test_weekly_recurrences(self):
        """Test the value of `next` for recurrences that specify a distinct
        a weekly recurrence."""

        # Weekly until Sept 1, 2016 (starting Aug 1)
        rrule = 'RRULE:FREQ=WEEKLY;UNTIL=20160901T050000Z'
        t = Trigger.objects.create(
            time=time(13, 30),
            trigger_date=date(2016, 8, 1),  # Mon, 8/1/2016
            recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: 08/01 at 11:00am, expected: next is Mon 8/01, 1:30pm
            mock_now.return_value = tzdt(2016, 8, 1, 11, 0)
            expected = tzdt(2016, 8, 1, 13, 30)
            self.assertEqual(t.next(), expected)

            # now: Sun, 8/07 at 11:00am, expected next is 8/09 at 1:30pm
            mock_now.return_value = tzdt(2016, 8, 7, 11, 0)
            expected = tzdt(2016, 8, 8, 13, 30)
            self.assertEqual(t.next(), expected)

            # now: Sun, 8/14 at 11:00am, expected next is 8/15 at 1:30pm
            mock_now.return_value = tzdt(2016, 8, 14, 11, 0)
            expected = tzdt(2016, 8, 15, 13, 30)
            self.assertEqual(t.next(), expected)

            # now: Sat, 8/20 at 11:00am, expected next is 8/22 at 1:30pm
            mock_now.return_value = tzdt(2016, 8, 20, 11, 0)
            expected = tzdt(2016, 8, 22, 13, 30)
            self.assertEqual(t.next(), expected)

            # now: Thurs, 8/25 at 11:00am, expected next is 8/29 at 1:30pm
            mock_now.return_value = tzdt(2016, 8, 25, 11, 0)
            expected = tzdt(2016, 8, 29, 13, 30)
            self.assertEqual(t.next(), expected)

            # now: 8/30, we should be done.
            mock_now.return_value = tzdt(2016, 8, 30, 22, 0)
            self.assertIsNone(t.next())

        # Clean up
        t.delete()
Пример #16
0
    def test_dynamic_range(self):
        """Ensure we get the correct range of valid dates for dynamic triggers"""

        # None when not dynamic
        self.assertIsNone(self.trigger.dynamic_range())

        # None when no user
        trigger = mommy.make(Trigger, frequency='daily', time_of_day='early')
        self.assertIsNone(trigger.dynamic_range())

        # When we have a user...
        trigger.user = mommy.make(self.User)
        trigger.save()

        with patch("goals.models.triggers.local_now") as mock_now:
            mock_now.return_value = tzdt(2016, 4, 1, 12, 34, 56)

            # Daily - 1 day
            expected = (tzdt(2016, 4, 1, 5,
                             0), tzdt(2016, 4, 3, 4, 59, 59, 999999))
            self.assertEqual(trigger.dynamic_range(), expected)

            # Weekly - 7 days
            trigger.frequency = 'weekly'
            trigger.save()
            expected = (tzdt(2016, 4, 1, 5,
                             0), tzdt(2016, 4, 9, 4, 59, 59, 999999))
            self.assertEqual(trigger.dynamic_range(), expected)

            # Biweekly - 5 days
            trigger.frequency = 'biweekly'
            trigger.save()
            expected = (tzdt(2016, 4, 1, 5,
                             0), tzdt(2016, 4, 7, 4, 59, 59, 999999))
            self.assertEqual(trigger.dynamic_range(), expected)

            # Multiweekly - 5 days
            trigger.frequency = 'multiweekly'
            trigger.save()
            expected = (tzdt(2016, 4, 1, 5,
                             0), tzdt(2016, 4, 7, 4, 59, 59, 999999))
            self.assertEqual(trigger.dynamic_range(), expected)

            # Weekends - Depends on the day, but encompases the updcoming weekend.
            # April, 2016, 1st = Friday, Sunday = 3rd
            trigger.frequency = 'weekends'
            trigger.save()
            expected = (tzdt(2016, 4, 1, 5,
                             0), tzdt(2016, 4, 4, 4, 59, 59, 999999))
            self.assertEqual(trigger.dynamic_range(), expected)
Пример #17
0
    def test_next_for_three_days(self):
        """Test the value of `next` for recurrences that specify a distinct
        set of days."""

        # 7pm on M, W, Th on Aug 17, 19, 20  (repeat until 8/21/2015)
        rrule = 'RRULE:FREQ=WEEKLY;UNTIL=20150821T050000Z;BYDAY=MO,WE,TH'
        t = Trigger.objects.create(name="x",
                                   time=time(19, 0),
                                   trigger_date=date(2015, 8, 17),
                                   recurrences=rrule)

        with patch("goals.models.triggers.timezone.now") as mock_now:
            # now: 08/15 at 11:00am, expected: next is Mon 8/17
            mock_now.return_value = tzdt(2015, 8, 15, 11, 0)
            expected = tzdt(2015, 8, 17, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 8/17 at 11:00pm, expected next is 8/19 at 7pm
            mock_now.return_value = tzdt(2015, 8, 17, 23, 0)
            expected = tzdt(2015, 8, 19, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 8/18 at 9am, expected next is 8/19 at 7pm
            mock_now.return_value = tzdt(2015, 8, 18, 9, 0)
            expected = tzdt(2015, 8, 19, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 8/19 at 9am, expected next is 8/19 at 7pm
            mock_now.return_value = tzdt(2015, 8, 19, 9, 0)
            expected = tzdt(2015, 8, 19, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 2015-8-19 at 10pm, expected next is 8/20 at 7pm
            mock_now.return_value = tzdt(2015, 8, 19, 22, 0)
            expected = tzdt(2015, 8, 20, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 2015-8-20 at 10am, expected next is 8/20 at 7pm
            mock_now.return_value = tzdt(2015, 8, 20, 10, 0)
            expected = tzdt(2015, 8, 20, 19, 0)
            self.assertEqual(t.next(), expected)

            # now: 2015-8-20 at 10pm, we're done
            mock_now.return_value = tzdt(2015, 8, 20, 22, 0)
            self.assertIsNone(t.next())

        # Clean up
        t.delete()