def test_blast_hash_start(self, mock_hasher: mock.MagicMock, unused_mock_logging: mock.MagicMock) -> None: """Send mail to users with given hash start.""" mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_user_db.user.drop() hash_values = ['12345', '01234'] mock_hasher.reset_mock() mock_hasher().hexdigest.side_effect = hash_values mock_user_db.user.insert_many([{ 'registeredAt': '2017-04-15T00:00:00Z', 'profile': { 'name': f'user {hash_value}', 'email': f'email{hash_value}@corpet.net', }, } for hash_value in hash_values]) mail_blast.main([ 'fake-user-campaign', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry', '--user-hash', '1' ]) sent_messages = mailjetmock.get_all_sent_messages() self.assertEqual( ['*****@*****.**'], [m.recipient['Email'] for m in sent_messages], msg= f'1 email expected: only for the user whith hash starting with 1\n{sent_messages}' )
def test_missing_sentry_dsn(self, mock_error: mock.MagicMock) -> None: """Log an error when used without SENTRY_DSN env var.""" mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10' ]) self.assertFalse(mailjetmock.get_all_sent_messages()) mock_error.assert_called_with( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' )
def _assert_user_receives_campaign( self, should_be_sent: bool = True, blast_from: Optional[str] = None, blast_to: Optional[str] = None, extra_args: Optional[list[str]] = None) -> None: json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.user.insert_one(json_user) year = self.user.registered_at.ToDatetime().year if self.now: now_patcher = nowmock.patch(new=mock.MagicMock( return_value=self.now)) now_patcher.start() self.addCleanup(now_patcher.stop) mail_blast.main([ self.campaign_id, 'send', '--disable-sentry', '--registered-from', blast_from or str(year), '--registered-to', blast_to or str(year + 1), '--log-reason-on-error', ] + (extra_args or [])) all_sent_messages = mailjetmock.get_all_sent_messages() if not should_be_sent: self.assertFalse(all_sent_messages) return self.assertEqual(1, len(all_sent_messages), msg=all_sent_messages) self.assertEqual(self.campaign_id, all_sent_messages[0].properties['CustomCampaign']) self._variables = all_sent_messages[0].properties['Variables'] self._from = all_sent_messages[0].properties['From'] self.assertEqual(self._from['Name'], self._variables.pop('senderName')) # Test that variables used in the template are populated. template_id = str(all_sent_messages[0].properties['TemplateID']) template_path = campaign.get_campaign_folder( typing.cast(mailjet_templates.Id, self.campaign_id)) self.assertTrue(template_path, msg=f'No template for campaign "{self.campaign_id}"') assert template_path vars_filename = os.path.join(template_path, 'vars-example.json') with open(vars_filename, 'r', encoding='utf-8') as vars_file: template_vars = json.load(vars_file).keys() for template_var in template_vars: self.assertIn( template_var, self._variables, msg=f'Template error for campaign {self.campaign_id}, see ' f'https://app.mailjet.com/template/{template_id}/build')
def test_incoherent_policy_durations(self, mock_error: mock.MagicMock) -> None: """Log an error when flags to define policy are not coherent.""" mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry', '--days-since-same-campaign', '7', '--days-since-same-campaign-unread', '15' ]) self.assertFalse(mailjetmock.get_all_sent_messages()) mock_error.assert_called_with( 'Please use coherent values in the policy durations.')
def test_fake_secret_salt(self) -> None: """Raise an error when using the fake secret salt when trying to send.""" auth_token = mail_blast.auth_token with mock.patch(auth_token.__name__ + '.SECRET_SALT', new=auth_token.FAKE_SECRET_SALT): with self.assertRaises(ValueError): mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) self.assertFalse(mailjetmock.get_all_sent_messages())
def test_no_reply(self) -> None: """Set sender as no-reply.""" product.bob.load_from_env() mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_many([{ '_id': objectid.ObjectId(f'7b18313aa35d807e631ea3d{month}'), 'registeredAt': f'2017-{month:02d}-15T00:00:00Z', 'profile': { 'name': f'{month} user', 'email': f'email{month}@corpet.net', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], } for month in range(2, 9)]) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) mails_sent = mailjetmock.get_all_sent_messages() self.assertEqual( ['*****@*****.**', '*****@*****.**', '*****@*****.**'], sorted(m.recipient['Email'] for m in mails_sent), msg= f'3 emails expected: one per month from April to June\n{mails_sent}' ) self.assertEqual({'*****@*****.**'}, {m.properties['From']['Email'] for m in mails_sent})
def test_wrong_email(self) -> None: """Users with wrong email don't get sent an email.""" mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_user_db.user.drop() mock_user_db.user.insert_many([ { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': 'the-user@gmail .com', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': 'the-user@gmail', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, ]) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) self.assertFalse(mailjetmock.get_all_sent_messages())
def test_error_while_sending(self, mock_warning: mock.MagicMock, mock_send_template: mock.MagicMock) -> None: """Error when sending an email get caught and logged as warning.""" mock_send_template( ).raise_for_status.side_effect = requests.exceptions.HTTPError mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_one({ 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) self.assertFalse(mailjetmock.get_all_sent_messages()) user = mock_user_db.user.find_one({}) assert user self.assertEqual( [], [e.get('campaignId') for e in user.get('emailsSent', [])]) mock_warning.assert_called_once() self.assertEqual('Error while sending an email: %s', mock_warning.call_args[0][0])
def test_days_from(self) -> None: """Compute from and to date relatively to today.""" mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_one({ 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }) with nowmock.patch() as mock_now: mock_now.return_value = datetime.datetime(2017, 7, 11, 12, 0, 0, 0) mail_blast.main([ 'focus-network', 'send', '--registered-from-days-ago', '90', '--registered-to-days-ago', '1', '--disable-sentry' ]) self.assertEqual(['*****@*****.**'], [ m.recipient['Email'] for m in mailjetmock.get_all_sent_messages() ]) user = mock_user_db.user.find_one({}) assert user self.assertEqual( ['focus-network'], [e.get('campaignId') for e in user.get('emailsSent', [])])
def test_hard_bounced(self) -> None: """Do not send emails if the user had a hard bounce.""" mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_one({ 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], 'emailsSent': [{ 'campaignId': 'other-email', 'status': 'EMAIL_SENT_HARDBOUNCED' }], }) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) self.assertFalse(mailjetmock.get_all_sent_messages()) user = mock_user_db.user.find_one({}) assert user self.assertEqual( ['other-email'], [e.get('campaignId') for e in user.get('emailsSent', [])])
def test_change_policy(self, mock_now: mock.MagicMock) -> None: """Test with non-default emailing policy.""" mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_user_db.user.drop() mock_now.return_value = datetime.datetime(2017, 5, 24) mock_user_db.user.insert_many([ { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'Sent other mail recently', 'email': '*****@*****.**', 'frustrations': ['MOTIVATION'], }, 'projects': [{}], 'emailsSent': [{ 'campaignId': 'focus-network', 'sentAt': '2017-05-15T00:00:00Z', }], }, { 'registeredAt': '2017-04-15T00:00:00Z', 'profile': { 'name': 'Sent other mail less recently', 'email': '*****@*****.**', 'frustrations': ['MOTIVATION'], }, 'projects': [{}], 'emailsSent': [{ 'campaignId': 'focus-network', 'sentAt': '2017-04-15T00:00:00Z', }], }, ]) mail_blast.main([ 'galita-1', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--days-since-any-email', '10', '--disable-sentry' ]) emails_sent = mailjetmock.get_all_sent_messages() self.assertEqual(1, len(emails_sent), msg=emails_sent)
def test_stop_seeking(self, unused_mock_logging: mock.MagicMock) -> None: """Basic test.""" mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_many([{ 'registeredAt': '2017-04-15T00:00:00Z', 'profile': { 'name': f'{seeking} user', 'email': f'email{seeking}@corpet.net', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], 'employmentStatus': [{ 'seeking': seeking, 'createdAt': '2017-06-15T00:00:00Z' }] } for seeking in ('STILL_SEEKING', 'STOP_SEEKING')]) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) self.assertEqual(['*****@*****.**'], [ m.recipient['Email'] for m in mailjetmock.get_all_sent_messages() ])
def test_collection_prefix(self) -> None: """Test the --user-collection-prefix option.""" mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_user_db.jobflix_user.insert_many([ { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, ]) user_collection = list(mock_user_db.user.find({})) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--user-collection-prefix', 'jobflix_', '--disable-sentry' ]) messages = mailjetmock.get_all_sent_messages() self.assertEqual(['*****@*****.**'], [m.recipient['Email'] for m in messages], msg=messages) self.assertEqual(user_collection, list(mock_user_db.user.find({})))
def test_wrong_id(self) -> None: """Filter based on ID.""" mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_many([ { '_id': objectid.ObjectId('444444444444444444444444'), 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, { '_id': objectid.ObjectId('5b2173b9362bf80840db6c2a'), 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'The filtered user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, ]) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry', '--user-id-start', '44' ]) self.assertEqual(['*****@*****.**'], [ m.recipient['Email'] for m in mailjetmock.get_all_sent_messages() ]) users = mock_user_db.user.find({}) self.assertEqual( { '*****@*****.**': ['focus-network'], '*****@*****.**': [], }, { u['profile']['email']: [e.get('campaignId') for e in u.get('emailsSent', [])] for u in users })
def test_blast_campaign(self, mock_logging: mock.MagicMock) -> None: """Basic test.""" mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test mock_user_db = pymongo.MongoClient( 'mongodb://myprivatedata.com/user_test').user_test mock_db.job_group_info.drop() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.drop() mock_user_db.user.insert_many([{ '_id': objectid.ObjectId(f'7b18313aa35d807e631ea3d{month}'), 'registeredAt': f'2017-{month:02d}-15T00:00:00Z', 'profile': { 'name': f'{month} user', 'email': f'email{month}@corpet.net', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], } for month in range(2, 9)]) mock_user_db.user.insert_many([ { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'Already sent', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], 'emailsSent': [{ 'campaignId': 'focus-network' }], }, { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'Test user', 'email': '*****@*****.**', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, { 'registeredAt': '2017-05-15T00:00:00Z', 'profile': { 'name': 'REDACTED', 'email': 'REDACTED', }, 'projects': [ { 'networkEstimate': 1, 'targetJob': { 'jobGroup': { 'romeId': 'A1234' } } }, ], }, ]) mail_blast.main([ 'focus-network', 'send', '--registered-from', '2017-04-01', '--registered-to', '2017-07-10', '--disable-sentry' ]) mails_sent = mailjetmock.get_all_sent_messages() self.assertEqual( ['*****@*****.**', '*****@*****.**', '*****@*****.**'], sorted(m.recipient['Email'] for m in mails_sent), msg= f'3 emails expected: one per month from April to June\n{mails_sent}' ) self.assertEqual({'*****@*****.**'}, {m.properties['From']['Email'] for m in mails_sent}) february_user = mock_user_db.user.find_one( {'_id': objectid.ObjectId('7b18313aa35d807e631ea3d2')}) assert february_user self.assertFalse(february_user.get('emailsSent')) april_user = mock_user_db.user.find_one( {'_id': objectid.ObjectId('7b18313aa35d807e631ea3d4')}) assert april_user self.assertEqual([{ 'sentAt', 'mailjetTemplate', 'campaignId', 'mailjetMessageId', 'subject', 'isCoaching', }], [e.keys() for e in april_user.get('emailsSent', [])]) self.assertEqual('focus-network', april_user['emailsSent'][0]['campaignId']) self.assertEqual( next(mailjetmock.get_messages_sent_to( '*****@*****.**')).message_id, int(april_user['emailsSent'][0]['mailjetMessageId'])) mock_logging.assert_any_call('Email sent to %s', '7b18313aa35d807e631ea3d4') mailjet_campaign_id = mailjetmock.get_mailjet_campaign_id( 'focus-network') mock_logging.assert_any_call( "Report for %s blast: I've sent %d emails (and got %d errors).%s", 'focus-network', 3, 0, ' You can check opening and click stats on ' f'<https://app.mailjet.com/stats/campaigns/{mailjet_campaign_id}/overview|Mailjet>' ) mock_logging.assert_called_with('%d emails sent.', 3)