def test_categorize_advice_missing(self): """Test that the advisor does not choke on an ancient advice that does not exist anymore.""" project = project_pb2.Project( project_id='1234', target_job=job_pb2.Job( name='Steward/ Hôtesse', feminine_name='Hôtesse', masculine_name='Steward', ), advices=[ project_pb2.Advice(advice_id='spontaneous-application', status=project_pb2.ADVICE_RECOMMENDED, num_stars=2), project_pb2.Advice(advice_id='advice-does-no-exist-anymore', status=project_pb2.ADVICE_RECOMMENDED, num_stars=2), ]) self.database.advice_modules.insert_many([ { 'adviceId': 'spontaneous-application', 'categories': ['first', 'second'], 'triggerScoringModel': 'constant(2)', 'isReadyForProd': True, }, ]) advisor.maybe_categorize_advice(self.user, project, self.database) # Point check that some categorization happened. self.assertEqual(['spontaneous-application'], project.advice_categories[0].advice_ids)
def test_categorize_all_pieces_of_advice(self): """Test that the advisor categorize all advice modules.""" project = project_pb2.Project( project_id='1234', target_job=job_pb2.Job( name='Steward/ Hôtesse', feminine_name='Hôtesse', masculine_name='Steward', ), advices=[ project_pb2.Advice(advice_id='spontaneous-application', status=project_pb2.ADVICE_RECOMMENDED, num_stars=3), project_pb2.Advice(advice_id='other-work-env', status=project_pb2.ADVICE_RECOMMENDED, num_stars=2), project_pb2.Advice(advice_id='one-star', status=project_pb2.ADVICE_RECOMMENDED, num_stars=1), ]) self.database.advice_modules.insert_many([ { 'adviceId': 'spontaneous-application', 'categories': ['first', 'second'], 'triggerScoringModel': 'constant(2)', 'isReadyForProd': True, }, { 'adviceId': 'other-work-env', 'categories': ['second'], 'triggerScoringModel': 'constant(0)', 'isReadyForProd': True, }, { 'adviceId': 'one-star', 'categories': ['second'], 'triggerScoringModel': 'constant(0)', 'isReadyForProd': True, }, ]) advisor.maybe_categorize_advice(self.user, project, self.database) # First category is the category with all the 3-stars advice. self.assertEqual(['spontaneous-application'], project.advice_categories[0].advice_ids) self.assertEqual('three-stars', project.advice_categories[0].category_id) self.assertEqual( ['other-work-env', 'spontaneous-application', 'one-star'], project.advice_categories[1].advice_ids) self.assertEqual('second', project.advice_categories[1].category_id)
def test_no_categories_if_already_categorized(self): """The advice_categories field does not get computed again.""" project = project_pb2.Project( advice_categories=[ project_pb2.AdviceCategory(category_id='very-old-category') ], advices=[ project_pb2.Advice(advice_id='spontaneous-application', status=project_pb2.ADVICE_RECOMMENDED, num_stars=3) ]) self.database.advice_modules.insert_one({ 'adviceId': 'spontaneous-application', 'categories': ['first', 'second'], 'triggerScoringModel': 'constant(2)', 'isReadyForProd': True, }) self.assertFalse( advisor.maybe_categorize_advice(self.user, project, self.database)) self.assertEqual(['very-old-category'], [c.category_id for c in project.advice_categories])
def test_no_categories_if_project_incomplete(self): """The advice_categorues field does not get populated when the project is marked as incomplete.""" project = project_pb2.Project(is_incomplete=True) self.assertFalse( advisor.maybe_categorize_advice(self.user, project, self.database))
def test_avoid_double_first_advice(self): """The advisor avoids having the same first advice for two neighbor categories.""" project = project_pb2.Project( project_id='1234', target_job=job_pb2.Job( name='Steward/ Hôtesse', feminine_name='Hôtesse', masculine_name='Steward', ), advices=[ project_pb2.Advice(advice_id='spontaneous-application', status=project_pb2.ADVICE_RECOMMENDED, num_stars=2), project_pb2.Advice(advice_id='other-work-env', status=project_pb2.ADVICE_RECOMMENDED, num_stars=1) ]) self.database.advice_modules.insert_many([ { 'adviceId': 'spontaneous-application', 'categories': ['first', 'second', 'third'], 'triggerScoringModel': 'constant(2)', 'isReadyForProd': True, }, { 'adviceId': 'other-work-env', 'categories': ['first', 'second', 'third'], 'triggerScoringModel': 'constant(0)', 'isReadyForProd': True, }, ]) advisor.maybe_categorize_advice(self.user, project, self.database) # First category is the category with all the 3-stars advice. self.assertEqual(3, len(project.advice_categories), msg=project.advice_categories) self.assertEqual(['spontaneous-application', 'other-work-env'], project.advice_categories[0].advice_ids) self.assertEqual(['other-work-env', 'spontaneous-application'], project.advice_categories[1].advice_ids) self.assertEqual(['spontaneous-application', 'other-work-env'], project.advice_categories[2].advice_ids)
def _save_user(user_data, is_new_user): _tick('Save user start') if is_new_user: previous_user_data = user_data else: _tick('Load old user data') previous_user_data = _get_user_data(user_data.user_id) if user_data.revision and previous_user_data.revision > user_data.revision: # Do not overwrite newer data that was saved already: just return it. return previous_user_data if not previous_user_data.registered_at.seconds: user_data.registered_at.FromDatetime(now.get()) # No need to pollute our DB with super precise timestamps. user_data.registered_at.nanos = 0 # Enable Advisor for new users. if not ADVISOR_DISABLED_FOR_TESTING: user_data.features_enabled.advisor = user_pb2.ACTIVE user_data.features_enabled.advisor_email = user_pb2.ACTIVE user_data.profile.email_days.extend( [user_pb2.MONDAY, user_pb2.WEDNESDAY, user_pb2.FRIDAY]) elif not _is_test_user(previous_user_data): user_data.registered_at.CopyFrom(previous_user_data.registered_at) user_data.features_enabled.advisor = previous_user_data.features_enabled.advisor _tick('Unverified data zone check start') # TODO(guillaume): Check out how we could not recompute that every time gracefully. if _is_in_unverified_data_zone(user_data.profile, user_data.projects): user_data.app_not_available = True _tick('Unverified data zone check end') _populate_feature_flags(user_data) for project in user_data.projects: if project.is_incomplete: continue _tick('Process project start') rome_id = project.target_job.job_group.rome_id if not project.project_id: # Add ID, timestamp and stats to new projects project.project_id = _create_new_project_id(user_data) project.created_at.FromDatetime(now.get()) previous_project = next((p for p in previous_user_data.projects if p.project_id == project.project_id), project_pb2.Project()) if project.job_search_length_months != previous_project.job_search_length_months: if project.job_search_length_months < 0: project.job_search_has_not_started = True else: job_search_length_days = 30.5 * project.job_search_length_months job_search_length_duration = datetime.timedelta( days=job_search_length_days) project.job_search_started_at.FromDatetime( project.created_at.ToDatetime() - job_search_length_duration) project.job_search_started_at.nanos = 0 _tick('Populate local stats') if not project.HasField('local_stats'): _populate_job_stats_dict({rome_id: project.local_stats}, project.mobility.city) _tick('Diagnostic') advisor.maybe_diagnose(user_data, project, _DB) _tick('Advisor') advisor.maybe_advise(user_data, project, _DB, parse.urljoin(flask.request.base_url, '/')[:-1]) _tick('Categorizer') advisor.maybe_categorize_advice(user_data, project, _DB) _tick('New feedback') if not is_new_user and (project.feedback.text or project.feedback.score): if project.feedback.text and not previous_project.feedback.text: _give_feedback( feedback_pb2.Feedback( user_id=str(user_data.user_id), project_id=str(project.project_id), feedback=project.feedback.text, source=feedback_pb2.PROJECT_FEEDBACK)) _tick('Process project end') if not is_new_user: _assert_no_credentials_change(previous_user_data, user_data) _copy_unmodifiable_fields(previous_user_data, user_data) _populate_feature_flags(user_data) user_data.revision += 1 _tick('Save user') _save_low_level(user_data, is_new_user=is_new_user) _tick('Return user proto') return user_data
def test_no_categories_if_no_advice(self): """The advice_categories field does not get populated when advice aren't.""" project = project_pb2.Project() self.assertFalse( advisor.maybe_categorize_advice(self.user, project, self.database))