def test_clients_for_officer(self) -> None: officer_1 = generate_fake_officer("id_1") officer_2 = generate_fake_officer("id_2") officer_3 = generate_fake_officer("id_3") client_1 = generate_fake_client("client_1", "id_1") client_2 = generate_fake_client("client_2", "id_1") client_3 = generate_fake_client("client_3", "id_2") session = SessionFactory.for_schema_base(CaseTriageBase) session.add(officer_1) session.add(officer_2) session.add(officer_3) session.add(client_1) session.add(client_2) session.add(client_3) session.commit() read_session = SessionFactory.for_schema_base(CaseTriageBase) self.assertEqual( len(CaseTriageQuerier.clients_for_officer(read_session, officer_1)), 2, ) self.assertEqual( len(CaseTriageQuerier.clients_for_officer(read_session, officer_2)), 1, ) self.assertEqual( len(CaseTriageQuerier.clients_for_officer(read_session, officer_3)), 0, )
def test_clients_for_officer(self) -> None: officer_1 = generate_fake_officer("id_1") officer_2 = generate_fake_officer("id_2") officer_3 = generate_fake_officer("id_3") auth_store = AuthorizationStore() user_context_1 = UserContext( email=officer_1.email_address, authorization_store=auth_store, current_user=officer_1, ) user_context_2 = UserContext( email=officer_2.email_address, authorization_store=auth_store, current_user=officer_2, ) user_context_3 = UserContext( email=officer_3.email_address, authorization_store=auth_store, current_user=officer_3, ) client_1 = generate_fake_client("client_1", supervising_officer_id="id_1") client_2 = generate_fake_client("client_2", supervising_officer_id="id_1") client_3 = generate_fake_client("client_3", supervising_officer_id="id_2") with SessionFactory.using_database(self.database_key) as session: session.expire_on_commit = False session.add(officer_1) session.add(officer_2) session.add(officer_3) session.add(client_1) session.add(client_2) session.add(client_3) with SessionFactory.using_database(self.database_key, autocommit=False) as read_session: self.assertEqual( len( CaseTriageQuerier.clients_for_officer( read_session, user_context_1)), 2, ) self.assertEqual( len( CaseTriageQuerier.clients_for_officer( read_session, user_context_2)), 1, ) self.assertEqual( len( CaseTriageQuerier.clients_for_officer( read_session, user_context_3)), 0, )
def test_contact(self) -> None: today = date.today() overdue_date = today - timedelta(days=50) upcoming_date = today - timedelta(days=40) no_opp_date = today - timedelta(days=10) client = generate_fake_client("abc", last_face_to_face_date=overdue_date) opp = ComputedOpportunity.build_all_for_client(client).get( OpportunityType.CONTACT) assert opp is not None self.assertIsInstance(opp, ComputedOpportunity) self.assertEqual(opp.opportunity_metadata, { "status": "OVERDUE", "daysUntilDue": -5 }) client.most_recent_face_to_face_date = upcoming_date opp = ComputedOpportunity.build_all_for_client(client).get( OpportunityType.CONTACT) assert opp is not None self.assertIsInstance(opp, ComputedOpportunity) self.assertEqual(opp.opportunity_metadata, { "status": "UPCOMING", "daysUntilDue": 5 }) client.most_recent_face_to_face_date = no_opp_date self.assertIsNone( ComputedOpportunity.build_all_for_client(client).get( OpportunityType.CONTACT))
def test_assessment(self) -> None: today = date.today() overdue_date = today - timedelta(days=500) upcoming_date = today - timedelta(days=335) no_opp_date = today - timedelta(days=334) client = generate_fake_client("abc", last_assessment_date=overdue_date) opp = ComputedOpportunity.build_all_for_client(client).get( OpportunityType.ASSESSMENT) assert opp is not None self.assertIsInstance(opp, ComputedOpportunity) self.assertEqual(opp.opportunity_metadata, { "status": "OVERDUE", "daysUntilDue": -135 }) client.most_recent_assessment_date = upcoming_date opp = ComputedOpportunity.build_all_for_client(client).get( OpportunityType.ASSESSMENT) assert opp is not None self.assertIsInstance(opp, ComputedOpportunity) self.assertEqual(opp.opportunity_metadata, { "status": "UPCOMING", "daysUntilDue": 30 }) client.most_recent_assessment_date = no_opp_date self.assertIsNone( ComputedOpportunity.build_all_for_client(client).get( OpportunityType.ASSESSMENT))
def setUp(self) -> None: local_postgres_helpers.use_on_disk_postgresql_database(CaseTriageBase) self.mock_officer = generate_fake_officer("id_1") self.mock_client = generate_fake_client( "person_id_1", last_assessment_date=date(2021, 2, 1), )
def setUp(self) -> None: self.mock_officer = generate_fake_officer("officer_id_1") self.mock_client = generate_fake_client( "person_id_1", supervising_officer_id=self.mock_officer.external_id, last_assessment_date=date(2021, 2, 1), last_face_to_face_date=date(2021, 1, 15), ) self.mock_client.case_updates = []
def test_etl_client_with_id_and_state_code(self) -> None: client_1 = generate_fake_client("client_1") session = SessionFactory.for_schema_base(CaseTriageBase) session.add(client_1) session.commit() read_session = SessionFactory.for_schema_base(CaseTriageBase) with self.assertRaises(PersonDoesNotExistError): CaseTriageQuerier.etl_client_with_id_and_state_code( read_session, "nonexistent", "US_XX") # Should not raise an error CaseTriageQuerier.etl_client_with_id_and_state_code( read_session, "client_1", "US_XX")
def setUp(self) -> None: self.database_key = SQLAlchemyDatabaseKey.for_schema( SchemaType.CASE_TRIAGE) local_postgres_helpers.use_on_disk_postgresql_database( self.database_key) self.mock_officer = generate_fake_officer("id_1") self.mock_client = generate_fake_client( "person_id_1", last_assessment_date=date(2021, 2, 1), ) self.mock_context = UserContext( email=self.mock_officer.email_address, authorization_store=AuthorizationStore(), current_user=self.mock_officer, )
def test_opportunities_for_officer(self) -> None: officer = generate_fake_officer("officer_1") user_context = UserContext( current_user=officer, authorization_store=AuthorizationStore(), email=officer.email_address, ) client = generate_fake_client( "client_1", supervising_officer_id=officer.external_id) etl_opp = generate_fake_etl_opportunity( officer_id=officer.external_id, person_external_id=client.person_external_id) etl_reminder = generate_fake_reminder(etl_opp) with SessionFactory.using_database(self.database_key) as session: session.expire_on_commit = False session.add(officer) session.add(client) session.add(etl_opp) session.add(etl_reminder) with SessionFactory.using_database(self.database_key) as read_session: # expect a non-etl opportunity that we want to mark as deferred reminder = generate_fake_reminder( opportunity=CaseTriageQuerier.opportunities_for_officer( read_session, user_context)[1].opportunity) with SessionFactory.using_database(self.database_key) as session: session.add(reminder) with SessionFactory.using_database(self.database_key) as read_session: queried_opps = CaseTriageQuerier.opportunities_for_officer( read_session, user_context) self.assertEqual(len(queried_opps), 2) employment_opp = queried_opps[1] self.assertEqual( employment_opp.opportunity.opportunity_type, OpportunityType.EMPLOYMENT.value, ) self.assertTrue(employment_opp.is_deferred())
def test_employment(self) -> None: client = generate_fake_client("abc") client.client_info = generate_fake_client_info(client) opp = ComputedOpportunity.build_all_for_client(client).get( OpportunityType.EMPLOYMENT) assert opp is not None self.assertIsInstance(opp, ComputedOpportunity) # no unemployment alert if client is on SSI/Disability client.client_info.receiving_ssi_or_disability_income = True self.assertIsNone( ComputedOpportunity.build_all_for_client(client).get( OpportunityType.EMPLOYMENT)) client.client_info.receiving_ssi_or_disability_income = False client.employer = "Test Company Ltd." self.assertIsNone( ComputedOpportunity.build_all_for_client(client).get( OpportunityType.EMPLOYMENT))
def test_newest_5_mismatches_reported(self) -> None: # Since all opportunities are sooner than the cutoff, we take the 5 oldest. many_opportunities_officer = generate_fake_officer( "many_opportunities_officer", "*****@*****.**" ) many_opportunity_clients = [ generate_fake_client( client_id=f"many_opportunities_client_{i}", supervising_officer_id=many_opportunities_officer.external_id, supervision_level=StateSupervisionLevel.MEDIUM, last_assessment_date=date(2021, 1, i + 1), assessment_score=1, ) for i in range(6) ] opportunities = [ generate_fake_etl_opportunity( officer_id=many_opportunities_officer.external_id, person_external_id=client.person_external_id, opportunity_type=OpportunityType.OVERDUE_DOWNGRADE, opportunity_metadata={ "assessmentScore": client.assessment_score, "latestAssessmentDate": str(client.most_recent_assessment_date), "recommendedSupervisionLevel": "MINIMUM", }, ) for client in many_opportunity_clients ] with SessionFactory.using_database(self.database_key) as session: session.expire_on_commit = False session.add_all( [many_opportunities_officer, *many_opportunity_clients, *opportunities] ) mismatches = _get_mismatch_data_for_officer( many_opportunities_officer.email_address ) self.assertCountEqual( [mismatch["person_external_id"] for mismatch in mismatches], [client.person_external_id for client in many_opportunity_clients[:5]], )
def test_etl_client_for_officer(self) -> None: officer_1 = generate_fake_officer("officer_1") officer_2 = generate_fake_officer("officer_2") auth_store = AuthorizationStore() user_context_1 = UserContext( email=officer_1.email_address, authorization_store=auth_store, current_user=officer_1, ) user_context_2 = UserContext( email=officer_2.email_address, authorization_store=auth_store, current_user=officer_2, ) client_1 = generate_fake_client( "client_1", supervising_officer_id=officer_1.external_id) with SessionFactory.using_database(self.database_key) as session: session.expire_on_commit = False session.add(officer_1) session.add(officer_2) session.add(client_1) with SessionFactory.using_database(self.database_key, autocommit=False) as read_session: # Client does not exist at all with self.assertRaises(PersonDoesNotExistError): CaseTriageQuerier.etl_client_for_officer( read_session, user_context_1, "nonexistent") # Client does not exist for the officer with self.assertRaises(PersonDoesNotExistError): CaseTriageQuerier.etl_client_for_officer( read_session, user_context_2, "client_1") # Should not raise an error CaseTriageQuerier.etl_client_for_officer(read_session, user_context_1, "client_1")
def setUp(self) -> None: self.test_app = Flask(__name__) self.helpers = CaseTriageTestHelpers.from_test(self, self.test_app) self.test_client = self.helpers.test_client self.mock_segment_client = self.helpers.mock_segment_client self.database_key = SQLAlchemyDatabaseKey.for_schema( SchemaType.CASE_TRIAGE) self.overridden_env_vars = ( local_postgres_helpers.update_local_sqlalchemy_postgres_env_vars()) db_url = local_postgres_helpers.postgres_db_url_from_env_vars() engine = setup_scoped_sessions(self.test_app, db_url) # Auto-generate all tables that exist in our schema in this database self.database_key.declarative_meta.metadata.create_all(engine) self.session = self.test_app.scoped_session # Add seed data self.officer = generate_fake_officer("officer_id_1", "*****@*****.**") self.officer_without_clients = generate_fake_officer( "officer_id_2", "*****@*****.**") self.client_1 = generate_fake_client( client_id="client_1", supervising_officer_id=self.officer.external_id, ) self.client_2 = generate_fake_client( client_id="client_2", supervising_officer_id=self.officer.external_id, last_assessment_date=date(2021, 2, 2), ) self.client_3 = generate_fake_client( client_id="client_3", supervising_officer_id=self.officer.external_id, ) self.client_info_3 = generate_fake_client_info( client=self.client_3, preferred_name="Alex", ) self.case_update_1 = generate_fake_case_update( self.client_1, self.officer.external_id, action_type=CaseUpdateActionType.COMPLETED_ASSESSMENT, last_version=serialize_client_case_version( CaseUpdateActionType.COMPLETED_ASSESSMENT, self.client_1).to_json(), ) self.case_update_2 = generate_fake_case_update( self.client_2, self.officer_without_clients.external_id, action_type=CaseUpdateActionType.COMPLETED_ASSESSMENT, last_version=serialize_client_case_version( CaseUpdateActionType.COMPLETED_ASSESSMENT, self.client_2).to_json(), ) self.case_update_3 = generate_fake_case_update( self.client_1, self.officer.external_id, action_type=CaseUpdateActionType.NOT_ON_CASELOAD, last_version=serialize_client_case_version( CaseUpdateActionType.NOT_ON_CASELOAD, self.client_1).to_json(), ) self.client_2.most_recent_assessment_date = date(2022, 2, 2) self.opportunity_1 = generate_fake_etl_opportunity( officer_id=self.officer.external_id, person_external_id=self.client_1.person_external_id, ) tomorrow = datetime.now() + timedelta(days=1) self.deferral_1 = generate_fake_reminder(self.opportunity_1, tomorrow) self.opportunity_2 = generate_fake_etl_opportunity( officer_id=self.officer.external_id, person_external_id=self.client_2.person_external_id, ) # all generated fake clients have no employer self.num_unemployed_opportunities = 3 self.session.add_all([ self.officer, self.officer_without_clients, self.client_1, self.client_2, self.client_3, self.client_info_3, self.case_update_1, self.case_update_2, self.case_update_3, self.opportunity_1, self.deferral_1, self.opportunity_2, ]) self.session.commit()
def setUp(self) -> None: self.mock_client = generate_fake_client( "person_id_1", last_assessment_date=date(2021, 2, 1), last_face_to_face_date=date(2021, 1, 15), )
def setUp(self) -> None: self.project_id_patcher = patch("recidiviz.utils.metadata.project_id") self.email_generation_patcher = patch( "recidiviz.reporting.email_generation.generate" ) self.gcs_file_system_patcher = patch( "recidiviz.cloud_storage.gcsfs_factory.GcsfsFactory.build" ) self.project_id_patcher.start().return_value = "recidiviz-test" self.mock_email_generation = self.email_generation_patcher.start() self.gcs_file_system = FakeGCSFileSystem() self.mock_gcs_file_system = self.gcs_file_system_patcher.start() self.mock_gcs_file_system.return_value = self.gcs_file_system self.get_secret_patcher = patch("recidiviz.utils.secrets.get_secret") self.get_secret_patcher.start() self.state_code = StateCode.US_ID self.database_key = SQLAlchemyDatabaseKey.for_schema(SchemaType.CASE_TRIAGE) local_postgres_helpers.use_on_disk_postgresql_database(self.database_key) self.officer = generate_fake_officer("officer_id_1", "*****@*****.**") self.client_downgradable_high = generate_fake_client( client_id="client_1", supervising_officer_id=self.officer.external_id, supervision_level=StateSupervisionLevel.HIGH, last_assessment_date=date(2021, 1, 2), assessment_score=1, ) self.client_downgradable_medium_1 = generate_fake_client( client_id="client_2", supervising_officer_id=self.officer.external_id, supervision_level=StateSupervisionLevel.MEDIUM, last_assessment_date=date(2021, 1, 2), assessment_score=1, ) self.client_downgradable_medium_2 = generate_fake_client( client_id="client_3", supervising_officer_id=self.officer.external_id, supervision_level=StateSupervisionLevel.MEDIUM, last_assessment_date=date(2021, 1, 2), assessment_score=1, ) self.client_no_downgrade = generate_fake_client( client_id="client_4", supervising_officer_id=self.officer.external_id, supervision_level=StateSupervisionLevel.HIGH, last_assessment_date=date(2021, 1, 2), assessment_score=100, ) self.opportunities = [ generate_fake_etl_opportunity( officer_id=self.officer.external_id, person_external_id=client.person_external_id, opportunity_type=OpportunityType.OVERDUE_DOWNGRADE, opportunity_metadata={ "assessmentScore": client.assessment_score, "latestAssessmentDate": str(client.most_recent_assessment_date), "recommendedSupervisionLevel": "MINIMUM", }, ) for client in [ self.client_downgradable_high, self.client_downgradable_medium_1, self.client_downgradable_medium_2, ] ] with SessionFactory.using_database(self.database_key) as session: session.expire_on_commit = False session.add_all( [ self.officer, self.client_downgradable_high, self.client_downgradable_medium_1, self.client_downgradable_medium_2, self.client_no_downgrade, *self.opportunities, ] ) self.top_opps_email_recipient_patcher = patch( "recidiviz.reporting.data_retrieval._top_opps_email_recipient_addresses" ) self.top_opps_email_recipient_patcher.start().return_value = [ self.officer.email_address ]
def setUp(self) -> None: self.test_app = Flask(__name__) self.test_app.register_blueprint(api) self.test_client = self.test_app.test_client() @self.test_app.errorhandler(FlaskException) def _handle_auth_error(ex: FlaskException) -> Response: response = jsonify({ "code": ex.code, "description": ex.description, }) response.status_code = ex.status_code return response self.overridden_env_vars = ( local_postgres_helpers.update_local_sqlalchemy_postgres_env_vars()) db_url = local_postgres_helpers.postgres_db_url_from_env_vars() setup_scoped_sessions(self.test_app, db_url) # Add seed data self.officer_1 = generate_fake_officer("officer_id_1") self.officer_2 = generate_fake_officer("officer_id_2") self.client_1 = generate_fake_client( client_id="client_1", supervising_officer_id=self.officer_1.external_id, ) self.client_2 = generate_fake_client( client_id="client_2", supervising_officer_id=self.officer_1.external_id, last_assessment_date=date(2021, 2, 2), ) self.case_update_1 = CaseUpdate( person_external_id=self.client_1.person_external_id, officer_external_id=self.client_1.supervising_officer_external_id, state_code=self.client_1.state_code, update_metadata={ "actions": CaseUpdatesInterface.serialize_actions( self.client_1, [CaseUpdateActionType.COMPLETED_ASSESSMENT], ), }, ) self.case_update_2 = CaseUpdate( person_external_id=self.client_2.person_external_id, officer_external_id=self.client_2.supervising_officer_external_id, state_code=self.client_2.state_code, update_metadata={ "actions": CaseUpdatesInterface.serialize_actions( self.client_2, [CaseUpdateActionType.COMPLETED_ASSESSMENT], ), }, ) self.client_2.most_recent_assessment_date = date(2022, 2, 2) sess = SessionFactory.for_schema_base(CaseTriageBase) sess.add(self.officer_1) sess.add(self.client_1) sess.add(self.client_2) sess.add(self.case_update_1) sess.add(self.case_update_2) sess.commit()