def test_blast_hash_start(self, mock_hasher: mock.MagicMock, 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( 1, len(sent_messages), msg= f'1 email expected: only for the user whith hash starting with 1\n{sent_messages}' ) mock_logging.assert_any_call('Email sent to %s', '*****@*****.**')
def _assert_user_receives_campaign(self, mock_mail=None, should_be_sent=True): json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.user.insert_one(json_user) mock_mail().status_code = 200 mock_mail().json.return_value = { 'Sent': [{ 'MessageID': 18014679230180635 }] } mock_mail.reset_mock() year = self.user.registered_at.ToDatetime().year mail_blast.main([ self._campaign_id, 'send', '--disable-sentry', '--registered-from', str(year), '--registered-to', str(year + 1), ]) if not should_be_sent: self.assertFalse(mock_mail.called) return mock_mail.assert_called_once() self._variables = mock_mail.call_args[0][2]
def test_list(self, mock_logging: mock.MagicMock) -> None: """Test a list for documents blast.""" mail_blast.main(['fake-document', 'list']) messages = mailjetmock.get_all_sent_messages() self.assertFalse(messages) mock_logging.assert_any_call('%s: %s %s', 'fake-document', '5b2173b9362bf80840db6c2a', '*****@*****.**')
def test_send(self) -> None: """Test really sending to a document owner.""" mail_blast.main(['fake-document', 'send', '--disable-sentry']) messages = mailjetmock.get_all_sent_messages() self.assertTrue(messages) self.assertEqual(1, len(messages)) message = messages.pop() self.assertEqual('Nathalie ', message.recipient['Name']) self.assertEqual('*****@*****.**', message.recipient['Email'])
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 test_dry_run(self) -> None: """Test a dry run for documents.""" mail_blast.main([ 'fake-document', 'dry-run', '--dry-run-email', '*****@*****.**' ]) messages = mailjetmock.get_all_sent_messages() self.assertTrue(messages) self.assertEqual(1, len(messages)) message = messages.pop() self.assertEqual('Nathalie ', message.recipient['Name']) self.assertEqual('*****@*****.**', message.recipient['Email'])
def test_stop_seeking(self, mock_user_db, mock_db, mock_mail, mock_logging): """Basic test.""" mock_mail().status_code = 200 mock_mail().json.return_value = { 'Sent': [{ 'MessageID': 18014679230180635 }] } mock_mail.reset_mock() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.insert_many([{ '_id': '%s' % seeking, 'registeredAt': '2017-04-15T00:00:00Z', 'profile': { 'name': '{} user'.format(seeking), 'email': 'email{}@corpet.net'.format(seeking), }, '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( 1, mock_mail.call_count, msg='1 email expected: only for the user who is still seeking\n{}'. format(mock_mail.call_args_list)) mock_logging.assert_any_call('Email sent to %s', '*****@*****.**')
def test_change_policy(self, mock_user_db, mock_mail, mock_now, unused_mock_db): """Test with non-default emailing policy.""" mock_mail().status_code = 200 mock_mail().json.return_value = { 'Sent': [{ 'MessageID': 18014679230180635 }] } mock_mail.reset_mock() 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' ]) self.assertEqual(1, mock_mail.call_count, msg='1 emails expected:\n{}'.format( mock_mail.call_args_list))
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 = mail_blast.auth with mock.patch(auth.__name__ + '.SECRET_SALT', new=auth.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_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_bounced(self) -> None: """Do not send emails if the user had a 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_BOUNCE' }], }) 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_stop_seeking(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([{ '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() ]) mock_logging.assert_any_call('Email sent to %s', '*****@*****.**')
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_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 mock.patch(mail_blast.now.__name__ + '.get') 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 _assert_user_receives_campaign(self, should_be_sent: bool = True) -> None: json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.get_collection( self.mongo_collection).insert_one(json_user) if self.mongo_collection == 'cvs_and_cover_letters': # This is not actually needed, we just need to avoid calling self.user.registered_at. year = 2018 else: year = self.user.registered_at.ToDatetime().year mail_blast.main([ self.campaign_id, 'send', '--disable-sentry', '--registered-from', str(year), '--registered-to', str(year + 1), ]) 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'] # Test that variables used in the template are populated. template_id = str(all_sent_messages[0].properties['TemplateID']) template_path = campaign.get_template_folder(template_id) self.assertTrue(template_path, msg=f'No template for campaign "{self.campaign_id}"') assert template_path with open(os_path.join(template_path, 'vars.txt'), 'r') as vars_file: template_vars = {v.strip() for v in vars_file} 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_blast_campaign(self, mock_db, mock_user_db, mock_mail, mock_logging): """Basic test.""" mock_mail().status_code = 200 mock_mail().json.return_value = { 'Sent': [{ 'MessageID': 18014679230180635 }] } mock_mail.reset_mock() mock_db.job_group_info.insert_one({ '_id': 'A1234', 'inDomain': 'dans la vie', }) mock_user_db.user.insert_many([{ '_id': '%d' % month, 'registeredAt': '2017-%02d-15T00:00:00Z' % month, 'profile': { 'name': '{} user'.format(month), 'email': 'email{}@corpet.net'.format(month), }, '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' ]) self.assertEqual( 3, mock_mail.call_count, msg='3 emails expected: one per month from April to June\n{}'. format(mock_mail.call_args_list)) self.assertEqual( { 'sender_email': '*****@*****.**', 'sender_name': 'Margaux de Bob' }, mock_mail.call_args[1]) february_user = mock_user_db.user.find_one({'_id': '2'}) self.assertFalse(february_user.get('emailsSent')) april_user = mock_user_db.user.find_one({'_id': '4'}) self.assertEqual( [{'sentAt', 'mailjetTemplate', 'campaignId', 'mailjetMessageId'}], [e.keys() for e in april_user.get('emailsSent', [])]) self.assertEqual('focus-network', april_user['emailsSent'][0]['campaignId']) self.assertEqual(18014679230180635, int(april_user['emailsSent'][0]['mailjetMessageId'])) mock_logging.assert_any_call('Email sent to %s', '*****@*****.**') mock_logging.assert_called_with('%d emails sent.', 3)
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('7b18313aa35d807e631ea3d%d' % month), 'registeredAt': '2017-%02d-15T00:00:00Z' % month, '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'}], [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', '*****@*****.**') mock_logging.assert_called_with('%d emails sent.', 3)