def test_unique_allegation_and_email(self): allegation = AllegationFactory() email = '*****@*****.**' AttachmentRequestFactory(email=email, allegation=allegation) expect(lambda: AttachmentRequestFactory( email=email, allegation=allegation)).to.throw(ValidationError) expect(len(AttachmentRequest.objects.all())).to.eq(1)
def test_investigator_names(self): allegation = AllegationFactory() investigator = InvestigatorFactory(first_name='Jerome', last_name='Finnigan') InvestigatorAllegationFactory(allegation=allegation, investigator=investigator) attachment_request = AttachmentRequestFactory(allegation=allegation) expect( attachment_request.investigator_names()).to.eq('Jerome Finnigan')
def test_get_queryset(self): allegation_1 = AllegationFactory(incident_date=datetime(2005, 12, 31, tzinfo=pytz.utc)) allegation_2 = AllegationFactory(incident_date=datetime(2007, 12, 31, tzinfo=pytz.utc)) attachment_request_1 = AttachmentRequestFactory(allegation=allegation_1) attachment_request_2 = AttachmentRequestFactory(allegation=allegation_2) expect(list(self.attachment_admin.get_queryset(self.request))).to.eq( [attachment_request_1, attachment_request_2] )
def test_investigated_by_cpd(self): allegation_1 = AllegationFactory(incident_date=datetime(2005, 12, 31, tzinfo=pytz.utc)) allegation_2 = AllegationFactory(incident_date=datetime(2007, 12, 31, tzinfo=pytz.utc)) AttachmentRequestFactory(allegation=allegation_1) AttachmentRequestFactory(allegation=allegation_2) investigated_by_cpd_1 = self.attachment_admin.get_queryset(self.request)[0] investigated_by_cpd_2 = self.attachment_admin.get_queryset(self.request)[1] expect(self.attachment_admin.investigated_by_cpd(investigated_by_cpd_1)).to.be.true() expect(self.attachment_admin.investigated_by_cpd(investigated_by_cpd_2)).to.be.false()
def test_upload_cr_attachment_request_to_foia_with_cpd_after_2006_has_badge_number( self, airtable_mock): airtable_mock.insert.return_value = {'id': 'some_airtable_record_id'} allegation = AllegationFactory(crid='123456', incident_date=datetime(2007, 12, 31, tzinfo=pytz.utc)) attachment_request = AttachmentRequestFactory( allegation=allegation, email='*****@*****.**') officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerBadgeNumberFactory(officer=officer_1, star='12345') OfficerBadgeNumberFactory(officer=officer_2, star='56789') investigator_1 = InvestigatorFactory(officer=officer_1) investigator_2 = InvestigatorFactory(officer=officer_1) InvestigatorAllegationFactory(allegation=allegation, current_star=None, investigator=investigator_1) InvestigatorAllegationFactory(allegation=allegation, current_star=None, investigator=investigator_2) OfficerAllegationFactory(allegation=allegation, officer=officer_1) OfficerAllegationFactory(allegation=allegation, officer=officer_2) expected_airtable_data = { 'Explanation': 'Officers: John Henry(ID 2), Marry Jane(ID 1)', 'Project': ['CPDP'], 'Agency': ['CPD_AGENCY_ID'], 'Requested For': 'CR 123456', 'Requestor': [{ 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' }], 'Date requested by user': attachment_request.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**' } CRRequestAirTableUploader.upload() attachment_request.refresh_from_db() airtable_mock.insert.assert_called_with(expected_airtable_data) expect( attachment_request.airtable_id).to.be.eq('some_airtable_record_id')
def test_logging_when_sending_cr_attachment_available_email_raise_error( self, mock_send_email, mock_logger): mock_send_email.side_effect = SMTPException('Sending failed') EmailTemplateFactory( subject='To {name}', body='This message is related to crid {pk} with url {url}', from_email='*****@*****.**', type=CR_ATTACHMENT_AVAILABLE) allegation_123 = AllegationFactory(crid='123') AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=False) AttachmentFileFactory(allegation=allegation_123) new_attachments = AttachmentFile.objects.all() send_cr_attachment_available_email(new_attachments) expect(AttachmentRequest.objects.filter( noti_email_sent=True).count()).to.eq(0) expect( AttachmentRequest.objects.filter( noti_email_sent=False).count()).to.eq(1) expect(mock_logger.info).to.be.called_with( 'Cannot send notification email for crid 123 to [email protected]' )
def test_update_cr_attachment_request_to_foia_with_invalid_airtable_id( self, airtable_mock): airtable_mock.update = Mock(side_effect=[HTTPError('404')]) airtable_mock.insert.return_value = {'id': 'airtable_id'} allegation = AllegationFactory(crid='123456', incident_date=datetime(2010, 1, 1, tzinfo=pytz.utc)) attachment_request = AttachmentRequestFactory( allegation=allegation, email='*****@*****.**', airtable_id='invalid_airtable_id') officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation, officer=officer_1) OfficerAllegationFactory(allegation=allegation, officer=officer_2) expected_airtable_data = { 'Explanation': 'Officers: John Henry(ID 2), Marry Jane(ID 1)', 'Project': ['CPDP'], 'Agency': ['COPA_AGENCY_ID'], 'Requested For': 'CR 123456', 'Requestor': [{ 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' }], 'Date requested by user': attachment_request.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**' } CRRequestAirTableUploader.upload(update_all_records=True) attachment_request.refresh_from_db() airtable_mock.update.assert_called_with('invalid_airtable_id', expected_airtable_data) airtable_mock.insert.assert_called_with(expected_airtable_data) expect(attachment_request.airtable_id).to.be.eq('airtable_id')
def test_AirTableUploader_raise_NotImplementedError(self, airtable_mock): airtable_mock.insert.return_value = {'id': 'some_airtable_record_id'} allegation123 = AllegationFactory(crid='123', incident_date=datetime( 2010, 1, 1, tzinfo=pytz.utc)) officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation123, officer=officer_1) OfficerAllegationFactory(allegation=allegation123, officer=officer_2) investigator = InvestigatorFactory(officer=officer_1) InvestigatorAllegationFactory(allegation=allegation123, investigator=investigator) cr_request_1 = AttachmentRequestFactory(allegation=allegation123, email='*****@*****.**', airtable_id='') allegation456 = AllegationFactory(crid='456') officer_3 = OfficerFactory(id=3, first_name='Marry', last_name='Jane') officer_4 = OfficerFactory(id=4, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation456, officer=officer_3) OfficerAllegationFactory(allegation=allegation456, officer=officer_4) cr_request_2 = AttachmentRequestFactory(allegation=allegation456, email='*****@*****.**', airtable_id='') expect(AirTableUploader.upload).to.throw(NotImplementedError) with patch( 'airtable_integration.services.document_request_service.AirTableUploader._get_uploaded_objects', return_value=[cr_request_1, cr_request_2]): expect(AirTableUploader.upload).to.throw(NotImplementedError) with patch( 'airtable_integration.services.document_request_service.' 'AirTableUploader._build_data', return_value=('', '', [])): expect(AirTableUploader.upload).to.throw(NotImplementedError) with patch( 'airtable_integration.services.document_request_service.' 'AirTableUploader._post_handle'): AirTableUploader.upload()
def test_upload_cr_attachment_request_to_foia_with_cpd_for_pre_2006_but_no_incident_date( self, airtable_mock): airtable_mock.insert.return_value = {'id': 'some_airtable_record_id'} allegation = AllegationFactory(crid='123456', incident_date=None) attachment_request = AttachmentRequestFactory( allegation=allegation, email='*****@*****.**') officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation, officer=officer_1) OfficerAllegationFactory(allegation=allegation, officer=officer_2) expected_airtable_data = { 'Explanation': 'Officers: John Henry(ID 2), Marry Jane(ID 1)', 'Project': ['CPDP'], 'Agency': ['COPA_AGENCY_ID'], 'Requested For': 'CR 123456', 'Requestor': [{ 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' }], 'Date requested by user': attachment_request.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**' } expect(attachment_request.airtable_id).to.be.eq('') CRRequestAirTableUploader.upload() attachment_request.refresh_from_db() airtable_mock.insert.assert_called_with(expected_airtable_data) expect( attachment_request.airtable_id).to.be.eq('some_airtable_record_id')
def test_upload_document_requests(self, airtable_mock): airtable_mock.insert.return_value = {'id': 'airtable_id'} allegation123 = AllegationFactory(crid='123', incident_date=datetime(2005, 1, 1, tzinfo=pytz.utc)) officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation123, officer=officer_1) OfficerAllegationFactory(allegation=allegation123, officer=officer_2) investigator = InvestigatorFactory(officer=officer_1) InvestigatorAllegationFactory(allegation=allegation123, investigator=investigator) cr_request_1 = AttachmentRequestFactory( allegation=allegation123, email='*****@*****.**', airtable_id='') AttachmentRequestFactory( allegation=allegation123, email='*****@*****.**', airtable_id='cr2222') allegation456 = AllegationFactory(crid='456', incident_date=datetime(2010, 1, 1, tzinfo=pytz.utc)) officer_3 = OfficerFactory(id=3, first_name='Marry', last_name='Jane') officer_4 = OfficerFactory(id=4, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation456, officer=officer_3) OfficerAllegationFactory(allegation=allegation456, officer=officer_4) cr_request_2 = AttachmentRequestFactory( allegation=allegation456, email='*****@*****.**', airtable_id='') AttachmentRequestFactory( allegation=allegation456, email='*****@*****.**', airtable_id='cr4444') trr = TRRFactory(id='123456', officer=officer_1) trr_request = TRRAttachmentRequestFactory( trr=trr, email='*****@*****.**', airtable_id='') TRRAttachmentRequestFactory( trr=trr, email='*****@*****.**', airtable_id='trr2222') expect(AttachmentRequest.objects.filter(airtable_id='').count()).to.eq(2) expect(TRRAttachmentRequest.objects.filter(airtable_id='').count()).to.eq(1) management.call_command('upload_document_requests') expected_calls = [ call({ 'Explanation': 'Officers: John Henry(ID 2), Marry Jane(ID 1)', 'Project': [ 'CPDP' ], 'Agency': ['CPD_AGENCY_ID'], 'Requested For': 'CR 123', 'Requestor': [ { 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' } ], 'Date requested by user': cr_request_1.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**', }), call({ 'Explanation': 'Officers: John Henry(ID 4), Marry Jane(ID 3)', 'Project': [ 'CPDP' ], 'Agency': ['COPA_AGENCY_ID'], 'Requested For': 'CR 456', 'Requestor': [ { 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' } ], 'Date requested by user': cr_request_2.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**', }), call({ 'Explanation': 'Officer: Marry Jane(ID 1)', 'Project': [ 'CPDP' ], 'Agency': [], 'Requested For': 'TRR 123456', 'Requestor': [ { 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' } ], 'Date requested by user': trr_request.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**', }) ] airtable_mock.insert.assert_has_calls(expected_calls, any_order=True) expect(AttachmentRequest.objects.filter(airtable_id='').count()).to.eq(0) expect(TRRAttachmentRequest.objects.filter(airtable_id='').count()).to.eq(0)
def test_email_validation(self): expect(lambda: AttachmentRequestFactory(email='foo')).to.throw( ValidationError)
def test_crid(self): attachment_request = AttachmentRequestFactory.build( allegation=AllegationFactory(crid='1111'), ) expect(attachment_request.crid).to.eq('1111')
def test_str(self): attachment_request = AttachmentRequestFactory.build( allegation=AllegationFactory(crid='1111'), email='*****@*****.**') expect(str(attachment_request)).to.eq('[email protected] - 1111')
def test_default_status(self): attachment_request = AttachmentRequestFactory() expect(attachment_request.status).to.be.false()
def test_send_cr_attachment_available_email(self, MockEmailMultiAlternatives): EmailTemplateFactory( subject='To {name}', body='This message is related to crid {pk} with url {url}', from_email='*****@*****.**', type=CR_ATTACHMENT_AVAILABLE) allegation_123 = AllegationFactory(crid='123') allegation_456 = AllegationFactory(crid='456') allegation_789 = AllegationFactory(crid='789') AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=True) AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_456, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_456, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_789, email='*****@*****.**', noti_email_sent=False) attachment_file_123_a = AttachmentFileFactory( allegation=allegation_123) attachment_file_123_b = AttachmentFileFactory( allegation=allegation_123) attachment_file_789 = AttachmentFileFactory(allegation=allegation_789) send_cr_attachment_available_email([ attachment_file_123_a, attachment_file_123_b, attachment_file_789 ]) expect(MockEmailMultiAlternatives).to.be.any_call( subject='To to.be.notified', body= 'This message is related to crid 123 with url http://foo.com/complaint/123/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 123 with url http://foo.com/complaint/123/</p>\n', 'text/html') expect(MockEmailMultiAlternatives).to.be.any_call( subject='To to.be.notified', body= 'This message is related to crid 789 with url http://foo.com/complaint/789/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 789 with url http://foo.com/complaint/789/</p>\n', 'text/html') expect(MockEmailMultiAlternatives).to.be.any_call( subject='To another.to.be.notified', body= 'This message is related to crid 123 with url http://foo.com/complaint/123/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 123 with url http://foo.com/complaint/123/</p>\n', 'text/html') expect(MockEmailMultiAlternatives().send.call_count).to.be.eq(3) expect( AttachmentRequest.objects.get(allegation=allegation_123, email='*****@*****.**'). noti_email_sent).to.be.true() expect( AttachmentRequest.objects.get( allegation=allegation_123, email='*****@*****.**').noti_email_sent ).to.be.true() expect( AttachmentRequest.objects.get(allegation=allegation_789, email='*****@*****.**'). noti_email_sent).to.be.true() expect( AttachmentRequest.objects.get(allegation=allegation_456, email='*****@*****.**'). noti_email_sent).to.be.false() attachment_file_123_a.refresh_from_db() attachment_file_123_b.refresh_from_db() attachment_file_789.refresh_from_db() expect(attachment_file_123_a.notifications_count).to.eq(2) expect(attachment_file_123_b.notifications_count).to.eq(2) expect(attachment_file_789.notifications_count).to.eq(1)
def test_annotate_investigated_by_cpd(self): allegation_1 = AllegationFactory(crid='001', incident_date=datetime( 2005, 12, 31, tzinfo=pytz.utc)) allegation_2 = AllegationFactory(crid='002', incident_date=datetime( 2007, 12, 31, tzinfo=pytz.utc)) allegation_3 = AllegationFactory(crid='003', incident_date=datetime( 2007, 12, 31, tzinfo=pytz.utc)) allegation_4 = AllegationFactory(crid='004', incident_date=datetime( 2007, 12, 31, tzinfo=pytz.utc)) allegation_5 = AllegationFactory(crid='005', incident_date=datetime( 2007, 12, 31, tzinfo=pytz.utc)) allegation_6 = AllegationFactory(crid='006', incident_date=datetime( 2007, 12, 31, tzinfo=pytz.utc)) attachment_request_1 = AttachmentRequestFactory( allegation=allegation_1) attachment_request_2 = AttachmentRequestFactory( allegation=allegation_2) attachment_request_3 = AttachmentRequestFactory( allegation=allegation_3) attachment_request_4 = AttachmentRequestFactory( allegation=allegation_4) attachment_request_5 = AttachmentRequestFactory( allegation=allegation_5) attachment_request_6 = AttachmentRequestFactory( allegation=allegation_6) officer_1 = OfficerFactory() officer_2 = OfficerFactory() OfficerBadgeNumberFactory(officer=officer_2, star='12345') investigator_1 = InvestigatorFactory(officer=officer_1) investigator_2 = InvestigatorFactory(officer=officer_2) InvestigatorAllegationFactory(allegation=allegation_3, current_star='123456') InvestigatorAllegationFactory(allegation=allegation_5, current_star=None, investigator=investigator_1) InvestigatorAllegationFactory(allegation=allegation_6, current_star=None, investigator=investigator_2) expected_results = { attachment_request_1.id: True, attachment_request_2.id: False, attachment_request_3.id: True, attachment_request_4.id: False, attachment_request_5.id: False, attachment_request_6.id: True, } for attachment_request in AttachmentRequest.objects.annotate_investigated_by_cpd( ): expect(attachment_request.investigated_by_cpd).to.be.eq( expected_results[attachment_request.id])
def test_Airtable_insert_raise_HTTPError(self, airtable_mock): AirTableUploader._get_foia_airtable().insert = Mock( side_effect=[{ 'id': 'some_airtable_record_id' }, HTTPError]) allegation123 = AllegationFactory(crid='123', incident_date=datetime( 2005, 1, 1, tzinfo=pytz.utc)) officer_1 = OfficerFactory(id=1, first_name='Marry', last_name='Jane') officer_2 = OfficerFactory(id=2, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation123, officer=officer_1) OfficerAllegationFactory(allegation=allegation123, officer=officer_2) investigator = InvestigatorFactory(officer=officer_1) InvestigatorAllegationFactory(allegation=allegation123, investigator=investigator) attachment_request_1 = AttachmentRequestFactory( allegation=allegation123, email='*****@*****.**') allegation456 = AllegationFactory(crid='456', incident_date=datetime( 2011, 1, 1, tzinfo=pytz.utc)) officer_3 = OfficerFactory(id=3, first_name='Marry', last_name='Jane') officer_4 = OfficerFactory(id=4, first_name='John', last_name='Henry') OfficerAllegationFactory(allegation=allegation456, officer=officer_3) OfficerAllegationFactory(allegation=allegation456, officer=officer_4) attachment_request_2 = AttachmentRequestFactory( allegation=allegation456, email='*****@*****.**') expect(attachment_request_1.airtable_id).to.eq('') expect(attachment_request_2.airtable_id).to.eq('') CRRequestAirTableUploader.upload() attachment_request_1.refresh_from_db() attachment_request_2.refresh_from_db() expected_calls = [ call({ 'Explanation': 'Officers: John Henry(ID 2), Marry Jane(ID 1)', 'Project': ['CPDP'], 'Agency': ['CPD_AGENCY_ID'], 'Requested For': 'CR 123', 'Requestor': [{ 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' }], 'Date requested by user': attachment_request_1.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**' }), call({ 'Explanation': 'Officers: John Henry(ID 4), Marry Jane(ID 3)', 'Project': ['CPDP'], 'Agency': ['COPA_AGENCY_ID'], 'Requested For': 'CR 456', 'Requestor': [{ 'id': 'usrGiZFcyZ6wHTYWd', 'email': '*****@*****.**', 'name': 'Rajiv Sinclair' }], 'Date requested by user': attachment_request_2.created_at.strftime('%Y-%m-%d'), 'Requester Email': '*****@*****.**' }) ] airtable_mock.insert.assert_has_calls(expected_calls, any_order=True) expect( attachment_request_1.airtable_id).to.eq('some_airtable_record_id') expect(attachment_request_2.airtable_id).to.eq('')
def test_send_cr_attachment_available_email_raise_error( self, MockEmailMultiAlternatives): MockEmailMultiAlternatives().send.side_effect = [ None, SMTPException('Sending failed'), None ] EmailTemplateFactory( subject='To {name}', body='This message is related to crid {pk} with url {url}', from_email='*****@*****.**', type=CR_ATTACHMENT_AVAILABLE) allegation_123 = AllegationFactory(crid='123') allegation_456 = AllegationFactory(crid='456') allegation_789 = AllegationFactory(crid='789') AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_456, email='*****@*****.**', noti_email_sent=False) AttachmentRequestFactory(allegation=allegation_789, email='*****@*****.**', noti_email_sent=False) AttachmentFileFactory.create_batch(2, allegation=allegation_123) AttachmentFileFactory.create_batch(2, allegation=allegation_456) AttachmentFileFactory(allegation=allegation_789) new_attachments = AttachmentFile.objects.all() send_cr_attachment_available_email(new_attachments) expect(AttachmentRequest.objects.filter( noti_email_sent=True).count()).to.eq(2) expect( AttachmentRequest.objects.filter( noti_email_sent=False).count()).to.eq(1) expect(MockEmailMultiAlternatives).to.be.any_call( subject='To to.be.notified', body= 'This message is related to crid 123 with url http://foo.com/complaint/123/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 123 with url http://foo.com/complaint/123/</p>\n', 'text/html') expect(MockEmailMultiAlternatives).to.be.any_call( subject='To to.be.notified', body= 'This message is related to crid 456 with url http://foo.com/complaint/456/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 456 with url http://foo.com/complaint/456/</p>\n', 'text/html') expect(MockEmailMultiAlternatives).to.be.any_call( subject='To to.be.notified', body= 'This message is related to crid 789 with url http://foo.com/complaint/789/\n', from_email='*****@*****.**', to=['*****@*****.**'], cc=['*****@*****.**'], ) expect(MockEmailMultiAlternatives().attach_alternative).to.be.any_call( '<p>This message is related to crid 789 with url http://foo.com/complaint/789/</p>\n', 'text/html') expect(MockEmailMultiAlternatives().send.call_count).to.be.eq(3)