def test_coaccused_counts(self): officer = OfficerFactory() OfficerAllegationFactory.create_batch(2, officer=officer, final_finding='SU') OfficerAllegationFactory(officer=officer, final_finding='NS') rows = self.extract_data() expect(rows).to.have.length(3) for row in rows: expect(row['coaccused']).to.have.length(1) expect(row['coaccused'][0]['allegation_count']).to.eq(3) expect(row['coaccused'][0]['sustained_count']).to.eq(2)
def test_export_xlsx_empty(self): officer = OfficerFactory(id=1) writer = AccusedXlsxWriter(officer, self.test_output_dir) writer.export_xlsx() self.covert_xlsx_to_csv('accused.xlsx') self.assert_csv_files_equal('empty', [ 'Allegation', 'Coaccused Officer', 'Beat', 'Police Witness', 'Victim' ])
def test_complainant_gender_aggregation_with_duplicated_allegation(self): unit = PoliceUnitFactory() officer1 = OfficerFactory() officer2 = OfficerFactory() allegation = AllegationFactory() OfficerHistoryFactory(officer=officer1, unit=unit) OfficerHistoryFactory(officer=officer2, unit=unit) OfficerAllegationFactory(officer=officer1, allegation=allegation, final_finding='SU') OfficerAllegationFactory(officer=officer2, allegation=allegation, final_finding='SU') ComplainantFactory(allegation=allegation, gender='F') expect(unit.complainant_gender_aggregation).to.eq([{ 'name': 'Female', 'count': 1, 'sustained_count': 1 }])
def test_relevant_complaints_via_police_witnesses(self): pinned_officer_1 = OfficerFactory(id=1) pinned_officer_2 = OfficerFactory(id=2) not_relevant_officer = OfficerFactory(id=999) relevant_allegation_11 = AllegationFactory(crid='11', incident_date=datetime( 2002, 2, 21, tzinfo=pytz.utc)) relevant_allegation_12 = AllegationFactory(crid='12', incident_date=datetime( 2002, 2, 22, tzinfo=pytz.utc)) relevant_allegation_21 = AllegationFactory(crid='21', incident_date=datetime( 2002, 2, 23, tzinfo=pytz.utc)) not_relevant_allegation = AllegationFactory(crid='999') pinboard = PinboardFactory( title='Test pinboard', description='Test description', ) pinboard.officers.set([pinned_officer_1, pinned_officer_2]) PoliceWitnessFactory(allegation=relevant_allegation_11, officer=pinned_officer_1) PoliceWitnessFactory(allegation=relevant_allegation_12, officer=pinned_officer_1) PoliceWitnessFactory(allegation=relevant_allegation_21, officer=pinned_officer_2) PoliceWitnessFactory(allegation=not_relevant_allegation, officer=not_relevant_officer) relevant_complaints = list(pinboard.relevant_complaints) expect(relevant_complaints).to.have.length(3) expect(relevant_complaints[0].crid).to.eq('21') expect(relevant_complaints[1].crid).to.eq('12') expect(relevant_complaints[2].crid).to.eq('11')
def test_extract_datum(self): officer = OfficerFactory(rank='Police Officer', active=ACTIVE_YES_CHOICE) SalaryFactory(rank='Police Officer', officer=officer) expect(RankIndexer().extract_datum('Police Officer')).to.eq({ 'rank': 'Police Officer', 'tags': ['rank'], 'active_officers_count': 1, 'officers_most_complaints': [] })
def test_lastmod(self): officer = OfficerFactory(id=123) with freeze_time(datetime(2018, 4, 4, 12, 0, 1, tzinfo=pytz.utc)): officer.allegation_count = 2 officer.save() officer.refresh_from_db() expect(OfficerSitemap().lastmod(officer)).to.eq( datetime(2018, 4, 4, 12, 0, 1, tzinfo=pytz.utc))
def test_update_cr_attachment_request_to_foia_with_valid_airtable_id_with_error( self, airtable_mock): airtable_mock.update.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='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('airtable_id', expected_airtable_data) expect(attachment_request.airtable_id).to.be.eq('airtable_id')
def test_process_single_officer_response(self): officer = OfficerFactory() updater = ActivityGridUpdater() response = { 'entity': {'id': officer.id}, 'type': 'single_officer' } self.refresh_index() updater.process(response) expect(ActivityCard.objects.get(officer=officer).last_activity).to.eq( datetime.datetime(2017, 9, 14, 12, 0, 1, tzinfo=pytz.utc))
def test_member_age_aggregation_in_case_officer_left_and_rejoin(self): unit1 = PoliceUnitFactory() unit2 = PoliceUnitFactory() officer = OfficerFactory(birth_year='1980') OfficerHistoryFactory(officer=officer, unit=unit1) OfficerHistoryFactory(officer=officer, unit=unit2) OfficerHistoryFactory(officer=officer, unit=unit1) OfficerHistoryFactory(officer=OfficerFactory(birth_year='1985'), unit=unit1) OfficerHistoryFactory(officer=OfficerFactory(birth_year=None), unit=unit1) expect(sorted(unit1.member_age_aggregation, key=itemgetter('name'))).to.eq([ { 'name': '31-40', 'count': 2 }, { 'name': 'Unknown', 'count': 1 } ])
def test_member_race_aggregation_in_case_officer_left_and_rejoin(self): unit1 = PoliceUnitFactory() unit2 = PoliceUnitFactory() officer = OfficerFactory(race='White') OfficerHistoryFactory(officer=officer, unit=unit1) OfficerHistoryFactory(officer=officer, unit=unit2) OfficerHistoryFactory(officer=officer, unit=unit1) OfficerHistoryFactory(officer=OfficerFactory(race='White'), unit=unit1) OfficerHistoryFactory(officer=OfficerFactory(race=''), unit=unit1) expect(sorted(unit1.member_race_aggregation, key=itemgetter('name'))).to.eq([ { 'name': 'Unknown', 'count': 1 }, { 'name': 'White', 'count': 2 } ])
def test_new_timeline_item_no_join(self): officer = OfficerFactory(id=123, appointed_date=None, rank='Police Officer') unit = PoliceUnitFactory(unit_name='001', description='unit_001') OfficerHistoryFactory(officer=officer, unit=unit, effective_date=date(2010, 1, 1), end_date=date(2011, 12, 31)) allegation = AllegationFactory( crid='123456', coaccused_count=4, incident_date=datetime(2011, 8, 23, tzinfo=pytz.utc) ) OfficerAllegationFactory( final_finding='UN', final_outcome='Unknown', officer=officer, allegation=allegation, allegation_category=AllegationCategoryFactory(category='category', allegation_name='sub category') ) OfficerAllegationFactory.create_batch(3, allegation=allegation) SalaryFactory(officer=officer, year=2001, rank='Police Officer', spp_date=date(2001, 9, 23)) cache_managers.cache_all() response = self.client.get(reverse('api-v2:officers-new-timeline-items', kwargs={'pk': 123})) expect(response.status_code).to.eq(status.HTTP_200_OK) expect(response.data).to.eq([ { 'date': '2011-08-23', 'kind': 'CR', 'crid': '123456', 'category': 'category', 'subcategory': 'sub category', 'finding': 'Unfounded', 'outcome': 'Unknown', 'coaccused': 4, 'unit_name': '001', 'unit_description': 'unit_001', 'rank': 'Police Officer', 'victims': [], 'attachments': [], }, { 'date': '2010-01-01', 'kind': 'UNIT_CHANGE', 'unit_name': '001', 'unit_description': 'unit_001', 'rank': 'Police Officer', }, { 'date': '2001-09-23', 'kind': 'RANK_CHANGE', 'unit_name': '', 'unit_description': '', 'rank': 'Police Officer', } ])
def test_search_date_trr_result(self): officer = OfficerFactory( id=123456, rank='Sergeant of Police', first_name='Jesse', last_name='Pinkman', complaint_percentile=4.4, civilian_allegation_percentile=1.1, internal_allegation_percentile=2.2, trr_percentile=3.3, allegation_count=1, resignation_date=date(2015, 4, 14) ) TRRFactory( id='123', trr_datetime=datetime(2007, 12, 27, tzinfo=pytz.utc), ) TRRFactory( id='456', trr_datetime=datetime(2008, 12, 27, tzinfo=pytz.utc), block='3000', street='Michigan Ave', taser=False, firearm_used=True, officer=officer ) self.rebuild_index() self.refresh_index() url = reverse('api:suggestion-list') response = self.client.get(url, { 'term': '2008-12-27', }) results = response.data['DATE > TRR'] expect(results).to.have.length(1) expect(results[0]['id']).to.eq('456') expect(results[0]).to.eq({ 'id': '456', 'trr_datetime': '2008-12-27', 'to': '/trr/456/', 'category': 'Firearm', 'address': '3000 Michigan Ave', 'officer': { 'id': 123456, 'full_name': 'Jesse Pinkman', 'percentile_allegation': '4.4000', 'percentile_trr': '3.3000', 'percentile_allegation_civilian': '1.1000', 'percentile_allegation_internal': '2.2000', 'allegation_count': 1 } })
def test_extract_datum_investigator_officer_name(self): InvestigatorAllegationFactory( investigator__officer=OfficerFactory(first_name='Jerome', last_name='Finnigan'), investigator__first_name='German', investigator__last_name='Lauren' ) rows = self.extract_data() expect(rows).to.have.length(1) expect(rows[0]['involvements'][0]['abbr_name']).to.eq('J. Finnigan') expect(rows[0]['involvements'][0]['full_name']).to.eq('Jerome Finnigan')
def test_export_xlsx_empty(self): officer = OfficerFactory(id=1) writer = InvestigatorXlsxWriter(officer, self.test_output_dir) writer.export_xlsx() self.covert_xlsx_to_csv('investigator.xlsx') self.assert_csv_files_equal(expectation_dir='empty', sheet_names=[ 'Allegation', 'Accused Officer', 'Beat', 'Police Witness', 'Victim' ])
def test_check_zip_file_exist_return_false(self, aws_mock): exception = botocore.exceptions.ClientError( error_response={'Error': { 'Code': 'NoSuchKey' }}, operation_name='get_object') aws_mock.s3.get_object.side_effect = exception officer = OfficerFactory(first_name='Jerome', last_name='Finnigan') expect(officer.check_zip_file_exist(with_docs=False)).to.be.false() expect(officer.check_zip_file_exist(with_docs=True)).to.be.false()
def test_coaccusals(self): officer0 = OfficerFactory() officer1 = OfficerFactory() officer2 = OfficerFactory() allegation0 = AllegationFactory() allegation1 = AllegationFactory() allegation2 = AllegationFactory() OfficerAllegationFactory(officer=officer0, allegation=allegation0) OfficerAllegationFactory(officer=officer0, allegation=allegation1) OfficerAllegationFactory(officer=officer0, allegation=allegation2) OfficerAllegationFactory(officer=officer1, allegation=allegation0) OfficerAllegationFactory(officer=officer1, allegation=allegation1) OfficerAllegationFactory(officer=officer2, allegation=allegation2) coaccusals = list(officer0.coaccusals) expect(coaccusals).to.have.length(2) expect(coaccusals).to.contain(officer1) expect(coaccusals).to.contain(officer2) expect(coaccusals[coaccusals.index(officer1)].coaccusal_count).to.eq(2) expect(coaccusals[coaccusals.index(officer2)].coaccusal_count).to.eq(1)
def test_retrieve_missing_percentile(self): officer = OfficerFactory( civilian_allegation_percentile=None, internal_allegation_percentile=None, trr_percentile=None ) trr = TRRFactory(officer=officer) self.refresh_index() response = self.client.get(reverse('api-v2:trr-detail', kwargs={'pk': trr.id})) expect(response.status_code).to.eq(status.HTTP_200_OK)
def test_extract_info_coaccusals(self): officer = OfficerFactory(id=1101) other_officer = OfficerFactory(id=1102) allegation1 = AllegationFactory() OfficerAllegationFactory(officer=officer, allegation=allegation1) OfficerAllegationFactory(officer=other_officer, allegation=allegation1) allegation2 = AllegationFactory() OfficerAllegationFactory(officer=officer, allegation=allegation2) OfficerAllegationFactory(officer=other_officer, allegation=allegation2) rows = sorted(self.extract_data(), key=itemgetter('id')) expect(rows).to.have.length(2) expect(rows[0]['coaccusals']).to.eq([{ 'id': 1102, 'coaccusal_count': 2 }]) expect(rows[1]['coaccusals']).to.eq([{ 'id': 1101, 'coaccusal_count': 2 }])
def test_historic_units(self): officer = OfficerFactory() unithistory1 = OfficerHistoryFactory(officer=officer, unit__unit_name='1', unit__description='Unit 1', effective_date=date(2000, 1, 1)) unithistory2 = OfficerHistoryFactory(officer=officer, unit__unit_name='2', unit__description='Unit 2', effective_date=date(2000, 1, 2)) expect(officer.historic_units).to.eq( [unithistory2.unit, unithistory1.unit])
def test_last_unit(self): officer = OfficerFactory() expect(officer.last_unit).to.equal(None) last_unit = PoliceUnitFactory(unit_name='BDCH') OfficerHistoryFactory(officer=officer, unit=PoliceUnitFactory(unit_name='CAND'), end_date=date(2000, 1, 1)) OfficerHistoryFactory(officer=officer, unit=last_unit, end_date=date(2002, 1, 1)) officer_cache_manager.build_cached_columns() officer.refresh_from_db() expect(officer.last_unit).to.eq(last_unit)
def test_complainant_race_aggregation(self): unit = PoliceUnitFactory() officer = OfficerFactory() allegation = AllegationFactory() OfficerHistoryFactory(unit=unit, officer=officer) OfficerAllegationFactory(officer=officer, allegation=allegation, final_finding='NS') ComplainantFactory(allegation=allegation, race='White') expect(unit.complainant_race_aggregation).to.eq([{ 'name': 'White', 'count': 1, 'sustained_count': 0 }])
def test_search_investigator_cr_results(self): allegation_1 = AllegationFactory(crid='123456', incident_date=datetime( 2002, 2, 3, tzinfo=pytz.utc)) allegation_2 = AllegationFactory(crid='654321', incident_date=datetime( 2005, 2, 3, tzinfo=pytz.utc)) officer = OfficerFactory(id=123, first_name='Edward', last_name='May') investigator_1 = InvestigatorFactory(first_name='Jerome', last_name='Finnigan') investigator_2 = InvestigatorFactory(officer=officer) InvestigatorAllegationFactory(investigator=investigator_1, allegation=allegation_1) InvestigatorAllegationFactory(investigator=investigator_2, allegation=allegation_1) InvestigatorAllegationFactory(investigator=investigator_1, allegation=allegation_2) OfficerAllegationFactory( allegation=allegation_1, allegation_category__category='Illegal Search') OfficerAllegationFactory(allegation=allegation_2, allegation_category__category='') allegation_cache_manager.cache_data() self.rebuild_index() self.refresh_index() url = reverse('api-v2:search-mobile-list') response = self.client.get(url, { 'term': 'Jerome', }) results = response.data['INVESTIGATOR > CR'] expect(results).to.have.length(2) expected_results = { '123456': { 'id': '123456', 'crid': '123456', 'category': 'Illegal Search', 'incident_date': '2002-02-03' }, '654321': { 'id': '654321', 'crid': '654321', 'category': 'Unknown', 'incident_date': '2005-02-03' } } for cr_data in results: expect(cr_data).to.eq(expected_results[cr_data['id']])
def test_complaint_category_aggregation(self): unit = PoliceUnitFactory() officer = OfficerFactory() OfficerHistoryFactory(unit=unit, officer=officer) OfficerAllegationFactory(officer=officer, allegation_category=AllegationCategoryFactory( category='Use of Force'), final_finding='NS') expect(unit.complaint_category_aggregation).to.eq([{ 'name': 'Use of Force', 'count': 1, 'sustained_count': 0 }])
def test_top_percentile_type_not_found(self): officer = OfficerFactory(id=1, appointed_date=date(2016, 1, 1)) OfficerAllegationFactory(officer=officer, allegation__incident_date=datetime( 2013, 1, 1, tzinfo=pytz.utc), start_date=datetime(2014, 1, 1, tzinfo=pytz.utc), allegation__is_officer_complaint=False) with self.assertRaisesRegex(ValueError, 'group is invalid'): officer_percentile.top_percentile(2017, percentile_groups=['not_exist'])
def test_complaint_category_aggregation_with_duplicated_allegation(self): unit = PoliceUnitFactory() officer1 = OfficerFactory() officer2 = OfficerFactory() allegation = AllegationFactory() allegation_category = AllegationCategoryFactory( category='Use of Force') OfficerHistoryFactory(officer=officer1, unit=unit) OfficerHistoryFactory(officer=officer2, unit=unit) OfficerAllegationFactory(officer=officer1, allegation=allegation, allegation_category=allegation_category, final_finding='NS') OfficerAllegationFactory(officer=officer2, allegation=allegation, allegation_category=allegation_category, final_finding='NS') expect(unit.complaint_category_aggregation).to.eq([{ 'name': 'Use of Force', 'count': 1, 'sustained_count': 0 }])
def test_active_member_count(self): unit1 = PoliceUnitFactory() unit2 = PoliceUnitFactory() officer = OfficerFactory() OfficerHistoryFactory(officer=officer, unit=unit1, end_date=datetime(2011, 1, 1, tzinfo=pytz.utc)) OfficerHistoryFactory(officer=officer, unit=unit2, end_date=datetime(2011, 2, 1, tzinfo=pytz.utc)) OfficerHistoryFactory(officer=officer, unit=unit1, end_date=None) expect(unit1.active_member_count).to.eq(1) expect(unit2.active_member_count).to.eq(0)
def test_rank_change_timeline_no_officer_appointed_date(self, rank_change_new_timeline_serializer_mock): officer = OfficerFactory(id=123, appointed_date=None) salary = SalaryFactory( year=2001, rank='Police Officer', officer=officer, rank_changed=True, spp_date=date(2001, 5, 3) ) expect(OfficerTimelineQuery(officer)._rank_change_timeline).to.eq([{'id': 1}]) rank_change_timeline_queryset_arg = rank_change_new_timeline_serializer_mock.call_args[0][0] salary_arg, = rank_change_timeline_queryset_arg expect(salary_arg.id).to.eq(salary.id)
def test_generate_presigned_zip_url_without_docs(self, aws_mock): aws_mock.s3.generate_presigned_url.return_value = 'presigned_url' officer = OfficerFactory(first_name='Jerome', last_name='Finnigan') expect(officer.generate_presigned_zip_url( with_docs=False)).to.eq('presigned_url') expect(aws_mock.s3.generate_presigned_url).to.be.called_with( ClientMethod='get_object', Params={ 'Bucket': 'officer_content_bucket', 'Key': 'zip/Jerome_Finnigan.zip', })
def test_cr_timeline(self, cr_new_timeline_serializer_mock): officer = OfficerFactory(id=123) OfficerAllegationFactory(id=1, officer=officer, allegation__incident_date=datetime(2002, 2, 3, tzinfo=pytz.utc)) OfficerAllegationFactory(id=2, officer=officer, allegation__incident_date=datetime(2003, 1, 5, tzinfo=pytz.utc)) OfficerAllegationFactory(id=3, officer=officer, allegation__incident_date=None) unit_1 = PoliceUnitFactory(unit_name='001', description='District 001') unit_2 = PoliceUnitFactory(unit_name='002', description='District 002') OfficerHistoryFactory( officer=officer, unit=unit_1, effective_date=date(2002, 1, 3), end_date=date(2003, 1, 2) ) OfficerHistoryFactory( officer=officer, unit=unit_2, effective_date=date(2003, 1, 3), end_date=date(2018, 1, 3) ) SalaryFactory( year=2001, rank='Police Officer', officer=officer, rank_changed=True, spp_date=date(2001, 5, 3) ) SalaryFactory( year=2002, rank='Senior Police Officer', officer=officer, rank_changed=True, spp_date=date(2002, 5, 3) ) other_officer = OfficerFactory(id=456) OfficerAllegationFactory(id=4, officer=other_officer, start_date=date(2003, 1, 5)) expect(OfficerTimelineQuery(officer)._cr_timeline).to.eq([{'id': 1}, {'id': 2}]) cr_timeline_queryset_arg = cr_new_timeline_serializer_mock.call_args[0][0] officer_allegation_1_arg, officer_allegation_2_arg = sorted(cr_timeline_queryset_arg, key=attrgetter('id')) expect(officer_allegation_1_arg.id).to.eq(1) expect(officer_allegation_1_arg.unit_name).to.eq('001') expect(officer_allegation_1_arg.unit_description).to.eq('District 001') expect(officer_allegation_1_arg.rank_name).to.eq('Police Officer') expect(officer_allegation_2_arg.id).to.eq(2) expect(officer_allegation_2_arg.unit_name).to.eq('002') expect(officer_allegation_2_arg.unit_description).to.eq('District 002') expect(officer_allegation_2_arg.rank_name).to.eq('Senior Police Officer')
def test_clone(self): officer_1 = OfficerFactory(id=1) officer_2 = OfficerFactory(id=2) allegation_1 = AllegationFactory(crid='123abc') allegation_2 = AllegationFactory(crid='456def') trr_1 = TRRFactory(id=1, officer=OfficerFactory(id=3)) trr_2 = TRRFactory(id=2, officer=OfficerFactory(id=4)) pinboard = PinboardFactory( title='Pinboard title', description='Pinboard title', officers=(officer_1, officer_2), allegations=(allegation_1, allegation_2), trrs=(trr_1, trr_2), ) cloned_pinboard = pinboard.clone() cloned_pinboard.refresh_from_db() officers = set(pinboard.officers.all().values_list('id', flat=True)) allegations = set(pinboard.allegations.all().values_list('crid', flat=True)) trrs = set(pinboard.trrs.all().values_list('id', flat=True)) cloned_officers = set(cloned_pinboard.officers.all().values_list( 'id', flat=True)) cloned_allegations = set(cloned_pinboard.allegations.all().values_list( 'crid', flat=True)) cloned_trrs = set(cloned_pinboard.trrs.all().values_list('id', flat=True)) expect(pinboard.title).to.eq(cloned_pinboard.title) expect(pinboard.description).to.eq(cloned_pinboard.description) expect(officers).to.eq(cloned_officers) expect(allegations).to.eq(cloned_allegations) expect(trrs).to.eq(cloned_trrs) expect(cloned_pinboard.source_pinboard).to.eq(pinboard)