Ejemplo n.º 1
0
    def test_sending_many_emails(self, exacttarget_mock):
        """Test that we can send emails to a lot of users in the same run. """

        # First add a lot of emails.
        now = utc_now() - datetime.timedelta(minutes=30)

        config_manager = self._setup_storage_config()
        with config_manager.context() as config:
            storage = ElasticSearchCrashStorage(config)

            for i in range(21):
                storage.save_processed({
                    'uuid': 'fake-%s' % i,
                    'email': '*****@*****.**' % i,
                    'product': 'WaterWolf',
                    'version': '20.0',
                    'release_channel': 'Release',
                    'date_processed': now,
                })

            storage.es.refresh()

        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            job.run(utc_now())

            et_mock = exacttarget_mock.return_value
            # Verify that we have the default 4 results + the 21 we added.
            eq_(et_mock.trigger_send.call_count, 25)
Ejemplo n.º 2
0
    def test_correct_email(self):
        domains = ('gmail.com', 'yahoo.com')
        config_manager = self._setup_simple_config(domains=domains)
        with config_manager.context() as config:
            app = automatic_emails.AutomaticEmailsCronApp(config, '')
            # easy corrections
            self.assertEqual(
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )
            self.assertEqual(
                # case insensitive
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('*****@*****.**', typo_correct=True),
                '*****@*****.**'
            )

            # dots here and there
            self.assertEqual(
                app.correct_email('[email protected].'),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('*****@*****.**'),
                '*****@*****.**'
            )
            self.assertEqual(
                app.correct_email('[email protected].'),
                '*****@*****.**'
            )

            # dots and typos
            self.assertEqual(
                # case insensitive
                app.correct_email('[email protected].', typo_correct=True),
                '*****@*****.**'
            )

            # What doesn't work are edit distances greater than 1
            self.assertFalse(app.correct_email('*****@*****.**'))
            self.assertFalse(app.correct_email('*****@*****.**'))
            # and don't mess with @ signs
            self.assertFalse(
                app.correct_email('[email protected]@gamil.com')
            )
Ejemplo n.º 3
0
    def test_error_in_send_email_with_easy_correction(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            return True

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': '',
            })

            eq_(config.logger.error.call_count, 0)

        # note that this means only one attempt was made
        eq_(attempted_emails, ['*****@*****.**'])
Ejemplo n.º 4
0
    def test_update_user(self):
        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            now = utc_now().isoformat()

            es = SuperS().es(
                urls=config.elasticsearch.elasticsearch_urls,
                timeout=config.elasticsearch.elasticsearch_timeout,
            )
            search = es.indexes(
                config.elasticsearch.elasticsearch_emails_index)
            search = search.doctypes('emails')

            connection = es.get_es()

            job.update_user('*****@*****.**', now, connection)
            connection.refresh()

            s = search.filter(_id='*****@*****.**')
            res = list(s.values_list('last_sending'))

            eq_(len(res), 1)
            eq_(res[0][0], now)

            # Test with a non-existing user
            job.update_user('*****@*****.**', now, connection)
            connection.refresh()

            s = search.filter(_id='*****@*****.**')
            res = list(s.values_list('last_sending'))

            eq_(len(res), 1)
            eq_(res[0][0], now)
Ejemplo n.º 5
0
    def test_error_in_send_email_recovery_failing(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            # raise an error no matter what
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            raise exacttarget.NewsletterException('error')

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': '',
            })

            eq_(config.logger.error.call_count, 1)
            config.logger.error.assert_called_with(
                'Unable to send a corrected email to %s, error is: %s',
                '*****@*****.**',
                'error',
                exc_info=True)

        eq_(attempted_emails, ['*****@*****.**', '*****@*****.**'])
Ejemplo n.º 6
0
    def test_send_email_test_mode(self, exacttarget_mock):
        list_service_mock = exacttarget_mock.return_value.list.return_value
        list_service_mock.get_subscriber.return_value = {
            'token': '*****@*****.**'
        }

        config_manager = self._setup_test_mode_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': 'socorro_dev_test',
            })

            fields = {
                'EMAIL_ADDRESS_': config.test_email_address,
                'EMAIL_FORMAT_': 'H',
                'TOKEN': '*****@*****.**'
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test',
                fields
            )
Ejemplo n.º 7
0
    def test_send_email_test_mode(self, exacttarget_mock):
        list_service_mock = exacttarget_mock.return_value.list.return_value
        list_service_mock.get_subscriber.return_value = {
            'token': '*****@*****.**'
        }

        config_manager = self._setup_test_mode_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '*****@*****.**',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            fields = {
                'EMAIL_ADDRESS_': config.test_email_address,
                'EMAIL_FORMAT_': 'H',
                'TOKEN': '*****@*****.**'
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test', fields)
Ejemplo n.º 8
0
    def test_error_in_send_email_recovery_failing(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            # raise an error no matter what
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            raise exacttarget.NewsletterException('error')

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '*****@*****.**',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            self.assertEqual(config.logger.error.call_count, 1)
            config.logger.error.assert_called_with(
                'Unable to send a corrected email to %s, error is: %s',
                '*****@*****.**',
                'error',
                exc_info=True)

        self.assertEqual(attempted_emails,
                         ['*****@*****.**', '*****@*****.**'])
Ejemplo n.º 9
0
    def test_update_user(self):
        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            now = utc_now()

            report = {'email': '*****@*****.**'}
            job.update_user(report, now, self.conn)

            cursor = self.conn.cursor()
            cursor.execute(
                """
                SELECT last_sending FROM emails WHERE email=%(email)s
            """, report)

            self.assertEqual(cursor.rowcount, 1)
            row = cursor.fetchone()
            self.assertEqual(row[0], now)

            # Test with a non-existing user
            report = {'email': '*****@*****.**'}
            job.update_user(report, now, self.conn)

            cursor = self.conn.cursor()
            cursor.execute(
                """
                SELECT last_sending FROM emails WHERE email=%(email)s
            """, report)

            self.assertEqual(cursor.rowcount, 1)
            row = cursor.fetchone()
            self.assertEqual(row[0], now)
Ejemplo n.º 10
0
    def test_error_in_send_email_with_clever_recovery(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            if fields['EMAIL_ADDRESS_'].endswith('exampl.com'):
                raise exacttarget.NewsletterException('error')
            else:
                return True

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '*****@*****.**',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            self.assertEqual(config.logger.error.call_count, 0)

        self.assertEqual(attempted_emails,
                         ['*****@*****.**', '*****@*****.**'])
Ejemplo n.º 11
0
    def test_error_in_send_email_with_easy_correction(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            return True

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '[email protected].',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            self.assertEqual(config.logger.error.call_count, 0)

        # note that this means only one attempt was made
        self.assertEqual(attempted_emails, ['*****@*****.**'])
Ejemplo n.º 12
0
    def test_error_in_send_email_with_clever_recovery(self, exacttarget_mock):
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            if fields['EMAIL_ADDRESS_'].endswith('exampl.com'):
                raise exacttarget.NewsletterException('error')
            else:
                return True

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': '',
            })

            eq_(config.logger.error.call_count, 0)

        eq_(attempted_emails, ['*****@*****.**', '*****@*****.**'])
Ejemplo n.º 13
0
    def test_run(self, exacttarget_mock):
        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            job.run(utc_now())

            et_mock = exacttarget_mock.return_value
            eq_(et_mock.trigger_send.call_count, 4)
Ejemplo n.º 14
0
 def test_correct_ambiguous_email(self):
     domains = ('gmail.com', 'yahoo.com', 'mail.com')
     config_manager = self._setup_simple_config(domains=domains)
     with config_manager.context() as config:
         app = automatic_emails.AutomaticEmailsCronApp(config, '')
         # because 'gmail.com' and 'mail.com' is so similar,
         # we don't want correction of 'mail.com' to incorrectly
         # become 'gmail.com'
         eq_(app.correct_email('*****@*****.**', typo_correct=True),
             None)
         eq_(app.correct_email('*****@*****.**', typo_correct=True), None)
Ejemplo n.º 15
0
    def test_run_no_generic_email(self, exacttarget_mock):
        config_manager = self._setup_simple_config(email_template='')
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            job.run(utc_now())

            et_mock = exacttarget_mock.return_value
            # Only 1 crash has a valid classification, the others would
            # be sent the default email and are thus not processed.
            eq_(et_mock.trigger_send.call_count, 1)

        config_manager = self._setup_simple_config(
            email_template='', restrict_products=['NightlyTrain'])
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            job.run(utc_now())

            et_mock = exacttarget_mock.return_value
            # None have a valid classification, all would be sent the default
            # email and are thus not processed. The call count stays the same.
            eq_(et_mock.trigger_send.call_count, 1)
Ejemplo n.º 16
0
    def test_run_with_classifications(self, exacttarget_mock):
        # Verify that classifications work.
        def mocked_trigger_send(email_template, fields):
            if fields['EMAIL_ADDRESS_'] == '*****@*****.**':
                eq_(email_template, 'socorro_bitguard_en')
            else:
                eq_(email_template, 'socorro_dev_test')

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')
            job.run(utc_now())

            et_mock = exacttarget_mock.return_value
            eq_(et_mock.trigger_send.call_count, 4)
Ejemplo n.º 17
0
    def test_error_in_send_email_with_ambiguous_domain(self, exacttarget_mock):
        """try to send to a mail.com but let it fail.
        Because `mail.com` easily is spell corrected to `gmail.com` but
        we add `mail.com` as a common email domain in the config.
        """
        attempted_emails = []

        def mocked_trigger_send(email_template, fields):
            # raise an error no matter what
            attempted_emails.append(fields['EMAIL_ADDRESS_'])
            raise exacttarget.NewsletterException('error')

            if fields['EMAIL_ADDRESS_'].endswith('@mail.com.'):
                raise exacttarget.NewsletterException('error')
            else:
                return True

        exacttarget_mock.return_value.trigger_send.side_effect = \
            mocked_trigger_send

        config_manager = self._setup_simple_config(
            common_email_domains=['example.com', 'gmail.com', 'mail.com']
        )
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': '',
            })

            self.assertEqual(config.logger.error.call_count, 1)
            config.logger.error.assert_called_with(
                'Unable to send an email to %s, error is: %s',
                email, 'error', exc_info=True
            )

        self.assertEqual(
            attempted_emails,
            [email]
        )
Ejemplo n.º 18
0
    def test_error_in_send_email(self, exacttarget_mock):
        list_service_mock = exacttarget_mock.return_value.list.return_value
        list_service_mock.get_subscriber.return_value = {
            'token': '*****@*****.**'
        }

        exacttarget_mock.return_value.trigger_send.side_effect = (
            exacttarget.NewsletterException('error'))

        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '*****@*****.**',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            fields = {
                'EMAIL_ADDRESS_': '*****@*****.**',
                'EMAIL_FORMAT_': 'H',
                'TOKEN': '*****@*****.**'
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test', fields)
            self.assertEqual(config.logger.error.call_count, 1)
            config.logger.error.assert_called_with(
                'Unable to send an email to %s, error is: %s',
                '*****@*****.**',
                'error',
                exc_info=True)

        list_service = exacttarget_mock.return_value.list.return_value
        list_service.get_subscriber.side_effect = (Exception(
            404, 'Bad Request'))

        exacttarget_mock.return_value.trigger_send.side_effect = (Exception(
            404, 'Bad Request'))

        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            report = {
                'email': '*****@*****.**',
                'product': 'WaterWolf',
                'version': '20.0',
                'release_channel': 'Release',
            }
            job.send_email(report)

            fields = {
                'EMAIL_ADDRESS_': u'*****@*****.**',
                'EMAIL_FORMAT_': 'H',
                'TOKEN': u'*****@*****.**'
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test', fields)
            self.assertEqual(config.logger.error.call_count, 2)
            config.logger.error.assert_called_with(
                'Unable to send an email to %s, fields are %s, error is: %s',
                u'*****@*****.**',
                str(fields),
                "(404, 'Bad Request')",
                exc_info=True)
Ejemplo n.º 19
0
    def test_error_in_send_email(self, exacttarget_mock):
        list_service_mock = exacttarget_mock.return_value.list.return_value
        list_service_mock.get_subscriber.return_value = {
            'token': '*****@*****.**'
        }

        exacttarget_mock.return_value.trigger_send.side_effect = (
            exacttarget.NewsletterException('error'))

        config_manager = self._setup_simple_config()
        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': 'socorro_dev_test',
            })

            fields = {
                'EMAIL_ADDRESS_': email,
                'EMAIL_FORMAT_': 'H',
                'TOKEN': email
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test', fields)
            eq_(config.logger.error.call_count, 1)
            config.logger.error.assert_called_with(
                'Unable to send an email to %s, error is: %s',
                email,
                'error',
                exc_info=True)

        list_service = exacttarget_mock.return_value.list.return_value
        list_service.get_subscriber.side_effect = (Exception(
            404, 'Bad Request'))

        exacttarget_mock.return_value.trigger_send.side_effect = (Exception(
            404, 'Bad Request'))

        with config_manager.context() as config:
            job = automatic_emails.AutomaticEmailsCronApp(config, '')

            email = '*****@*****.**'
            job.send_email({
                'processed_crash.email': email,
                'email_template': 'socorro_dev_test',
            })

            fields = {
                'EMAIL_ADDRESS_': '*****@*****.**',
                'EMAIL_FORMAT_': 'H',
                'TOKEN': '*****@*****.**'
            }
            exacttarget_mock.return_value.trigger_send.assert_called_with(
                'socorro_dev_test', fields)
            eq_(config.logger.error.call_count, 2)
            config.logger.error.assert_called_with(
                'Unable to send an email to %s, fields are %s, error is: %s',
                '*****@*****.**',
                str(fields),
                "(404, 'Bad Request')",
                exc_info=True)