def test_alerts_have_correct_from_email(self):
        payload = self.create_notices_and_users(n_notices=2, n_users=1)
        notices = payload['notices']
        n1 = notices[0]
        n2 = notices[1]

        prepare_and_send_alerts(True)
        msg1 = mail.outbox[0]
        msg2 = mail.outbox[1]
        self.assertEqual(msg1.from_email, from_address['notifications'])
        self.assertEqual(msg2.from_email, from_address['notifications'])
    def test_bulk_sendout_does_not_run_if_no_unsent(self, mock_send_alerts):
        # Create a single OutageNotice instance
        payload = self.create_notices_and_users(n_notices=1, n_users=3)
        notice = payload['notices'].first()
        users = payload['users']

        # Make it a sent OutageNotice instance
        for user in users:
            user.email_alerts_received.create(outage=notice)

        prepare_and_send_alerts(scraper_success=True)
        self.assertEqual(mock_send_alerts.called, False)
    def test_send_alerts_only_to_active_users(self):
        payload = self.create_notices_and_users(n_notices=10, n_users=20)
        notices = payload['notices']
        users = payload['users']

        # Turn two Subscriber instances into inactive users
        user_1 = users.first()
        user_1.is_active = False
        user_1.save()

        user_2 = users.last()
        user_2.is_active = False
        user_2.save()

        active_users = users.filter(is_active=True)
        active_users_count = active_users.count()
        unsent_notices_count = notices.filter(email_alerts=None).count()
        processed_notices_count = prepare_and_send_alerts(scraper_success=True)
        total_alerts_sent = active_users_count * unsent_notices_count
        self.assertEqual(
            total_alerts_sent,  # supposedly sent
            len(mail.outbox)  # actually sent
        )

        # These two lists should contain the exact same unique elements:
        active_users_email_addresses = [u.email for u in active_users]
        alert_recipients = [msg.recipients()[0] for msg in mail.outbox]
        self.assertListEqual(
            sorted(active_users_email_addresses),  # supposed recipients
            sorted(list(set(alert_recipients)))  # actual recipients
        )
    def test_only_upcoming_outages_are_sent(self):
        payload = self.create_notices_and_users(n_notices=5, n_users=10)
        notices = payload['notices']
        users = payload['users']

        # Make one of the notices  outdated
        n = notices.last()
        n.scheduled_for = timezone.now() - timedelta(days=10)
        n.scheduled_until = timezone.now() - timedelta(days=10)
        n.save()

        upcoming_alerts = notices.filter(scheduled_until__gt=timezone.now())
        processed_notices_count = prepare_and_send_alerts(scraper_success=True)

        # Expected vs actual number of email alerts sent
        self.assertEqual(upcoming_alerts.count() * users.count(),
                         len(mail.outbox))

        # Expected vs actual number of notices processed
        self.assertEqual(upcoming_alerts.count(), processed_notices_count)

        # The outdated notice should not be in any active user's
        # alerts received queryset
        Subscriber = apps.get_model('subscribers', 'Subscriber')
        for subscriber in Subscriber.objects.filter(is_active=True):
            self.assertIs(n.is_unsent(subscriber), True)
    def test_subject_character_limit(self):
        payload = self.create_notices_and_users(n_notices=2, n_users=1)
        notices = payload['notices']
        n1 = notices[0]
        n2 = notices[1]

        # Modify headline to make email alert subject
        # longer than 50 characters
        n1.headline = 'This is a very long headline to be trimmed somewhere.'
        n1.save()

        # Shorten headline to keep subject under 50 characters:
        n2.headline = 'short'
        n2.save()

        prepare_and_send_alerts(True)
        msg1 = mail.outbox[0]
        msg2 = mail.outbox[1]

        self.assertLessEqual(len(msg1.subject), 50)
        self.assertLessEqual(len(msg2.subject), 50)
        self.assertIn('...', msg1.subject)
        self.assertNotIn('...', msg2.subject)
    def test_do_not_send_alerts_to_users_who_already_received_them(self):
        payload = self.create_notices_and_users(3, 10)
        notices = payload['notices']
        users = payload['users']

        # Send an alert to two users
        n = notices.first()
        user_1 = users.first()
        user_1.email_alerts_received.create(outage=n)
        user_2 = users.last()
        user_2.email_alerts_received.create(outage=n)

        processed_notices_count = prepare_and_send_alerts(True)
        self.assertEqual(notices.count() * users.count() - 2, len(mail.outbox))
    def test_no_alert_creation_if_no_pending_notice(self, mock_create_alerts):
        payload = self.create_notices_and_users(n_notices=3, n_users=15)
        notices = payload['notices']
        users = payload['users']

        # Make all notices outdated
        for n in notices:
            days_ago = timedelta(days=10)
            n.scheduled_for = timezone.now() - days_ago
            n.scheduled_until = timezone.now() - days_ago
            n.save()

        processed_notices_count = prepare_and_send_alerts(scraper_success=True)
        self.assertIs(mock_create_alerts.called, False)
        self.assertEqual(processed_notices_count, 0)
 def test_valid_conditions_for_bulk_sendout(self, mock_send_alerts):
     # Condition 1: There are unsent notices
     # Condition 2: scraper_success is True (returned by previous task)
     self.create_notices_and_users()
     prepare_and_send_alerts(scraper_success=True)
     self.assertEqual(mock_send_alerts.called, True)