def test_talent_manager_can_get_company_feedback_stats_csv( ldap_mocked_app_with_users ): # noqa: E501 app = successfully_login(ldap_mocked_app_with_users, TEST_TALENT_MANAGER_USERNAME) dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) response = app.get("/api/v1/company-feedback-stats.csv") assert response.content_type == "text/csv" assert response.body == open(TEST_CSV_FILEPATH, "rb").read()
def test_talent_manager_can_get_company_raw_feedback( ldap_mocked_app_with_users ): # noqa: E501 app = successfully_login(ldap_mocked_app_with_users, TEST_TALENT_MANAGER_USERNAME) dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) with transaction.manager: form = FeedbackForm( to_username=TEST_EMPLOYEE_3_USERNAME, from_username=TEST_TALENT_MANAGER_USERNAME, period_id=TEST_PREVIOUS_PERIOD_ID, is_summary=True, ) answers = [ FeedbackAnswer(question_id=QUESTION_IDS_AND_TEMPLATES[0][0], content="Foo"), FeedbackAnswer(question_id=QUESTION_IDS_AND_TEMPLATES[1][0], content="Bar"), FeedbackAnswer(question_id=QUESTION_IDS_AND_TEMPLATES[2][0], content="Tom"), ] form.answers = answers dbsession.add(form) response = app.get("/api/v1/company-raw-feedback.csv") assert response.content_type == "text/csv" num_q = 3 nominee_1_answers = ( (7 * num_q) + (3 * num_q) + (2 * num_q) + (TEST_NUM_FORMS_RECEIVED * num_q) ) nominee_2_answers = 2 * num_q nominee_3_answers = (3 * num_q) + (8 * num_q) + (10 * num_q) + (2 * num_q) summary_answers = 3 * len(TEST_STATS_NOMINATED_USERS) num_expected = ( nominee_1_answers + nominee_2_answers + nominee_3_answers + summary_answers ) # remove csv header and trailing newline body = response.body.decode() num_generated = len(body.split("\n")) - 2 assert num_expected == num_generated assert body.count(",True,") == summary_answers assert ( body.count( "to_username,from_username,is_summary,name," "question_template,content" ) == 1 ) raw_answer_row = ( "{to_username},{from_username},True,{period_name}," "{template},{answer}" "".format( to_username=TEST_EMPLOYEE_3_USERNAME, from_username=TEST_TALENT_MANAGER_USERNAME, period_name=TEST_PREVIOUS_PERIOD_NAME, template=QUESTION_IDS_AND_TEMPLATES[1][1], answer="Bar", ) ) assert body.count(raw_answer_row) == 1
def test_employee_can_view_feedback_received_for_all_periods( ldap_mocked_app_with_users): # noqa: E501 app = successfully_login(ldap_mocked_app_with_users, TEST_EMPLOYEE_2_USERNAME) dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) add_previous_test_summary(dbsession) add_extra_feedback_histories(dbsession, num=10) resp = app.get("/api/v1/feedback-about-me") assert len(resp.json_body["feedback"]["items"]) == 12 items_payload = deepcopy(resp.json_body) items_payload["feedback"]["items"] = items_payload["feedback"]["items"][:2] assert EMPLOYEE_2_EXPECTED_HISTORY_HEAD == items_payload
def test_employee_can_list_nominees_inside_entry_subperiod_2( ldap_mocked_app_with_users): # noqa: E501 """A particular DB state that caused failure in the past but is not working""" app = successfully_login(ldap_mocked_app_with_users, TEST_EMPLOYEE_USERNAME) dbsession = get_dbsession(app) add_test_data_for_stats(dbsession, Period.ENTRY_SUBPERIOD) response = app.get("/api/v1/nominees") assert response.status_code == 200 assert TEST_PERIOD_NAME == response.json_body["period"] # logged in user should not see their own name in nomination list nominees = [("bboggs", True), ("llovelace", False)] expected = [] for un, has_manager_in_database in nominees: data = TEST_LDAP_FULL_DETAILS[un] un_name = data[TEST_USERNAME_KEY] # if they are not in the User database, then they don't exist so # can't put up a display name if has_manager_in_database: manager = TEST_LDAP_FULL_DETAILS.get(data[MANAGER_KEY]) manager_display_name = " ".join( [manager["givenName"], manager["sn"]]) else: manager_display_name = "-" expected.append({ "username": un_name, "displayName": data["givenName"] + " " + data["sn"], "position": data["title"], "managerDisplayName": manager_display_name, "department": data["department"], "hasExistingFeedback": True if un_name == EXISTING_FEEDBACK_FORM_USERNAME else False, }) sorted_response = sorted(response.json_body["nominees"], key=lambda x: x["displayName"]) assert len(expected) == len(sorted_response) assert expected == sorted_response
def test_talent_manager_can_correct_summarised_feedback_from_another_manager( ldap_mocked_app_with_users ): # noqa: E501 app = successfully_login(ldap_mocked_app_with_users, TEST_TALENT_MANAGER_USERNAME) dbsession = get_dbsession(app) add_test_data_for_stats(dbsession, current_subperiod=Period.REVIEW_SUBPERIOD) response = app.get("/api/v1/summarise/%s/" % TEST_EMPLOYEE_2_USERNAME) items = response.json_body["summary"]["items"] expected = [ {"questionId": QUESTION_IDS_AND_TEMPLATES[0][0], "answer": TEST_SUMMARY_1}, {"questionId": QUESTION_IDS_AND_TEMPLATES[1][0], "answer": TEST_SUMMARY_2}, {"questionId": QUESTION_IDS_AND_TEMPLATES[2][0], "answer": TEST_SUMMARY_3}, ] generated = sorted(items, key=lambda k: k["questionId"]) for exp, gen in zip(expected, generated): assert exp["questionId"] == gen["questionId"] assert exp["answer"] == gen["answer"]
def test_hostname_override_works(ldap_mocked_app_with_users, ldapsource, with_envvar): app = ldap_mocked_app_with_users dbsession = get_dbsession(app) add_test_data_for_stats(dbsession, current_subperiod=Period.ENROLLMENT_SUBPERIOD) displayed_hostname = "notfoobar.com" assert displayed_hostname != TEST_PRODUCTION_HOSTNAME settings = { "adaero.talent_manager_usernames": [TEST_OTHER_MANAGER_USERNAME], "adaero.served_on_https": True, "adaero.homebase_location": "London", "adaero.production_hostname": TEST_PRODUCTION_HOSTNAME, "adaero.production_user": TEST_PRODUCTION_USER, "adaero.enable_send_email": True, } if with_envvar: os.environ["DISPLAYED_HOSTNAME"] = displayed_hostname else: settings[DISPLAYED_HOSTNAME_KEY] = displayed_hostname with patch("smtplib.SMTP") as smtp_mock, patch( "socket.gethostname") as gethostname_mock, patch( "getpass.getuser") as getuser_mock: sendmail_mock = smtp_mock().sendmail gethostname_mock.return_value = TEST_PRODUCTION_HOSTNAME getuser_mock.return_value = TEST_PRODUCTION_USER mail.check_and_send_email(dbsession, ldapsource, settings, template_key=ENROL_START, force=True) generated_raw_message = sendmail_mock.call_args_list[0][0][2] normal_app_link = "https://%s" % TEST_PRODUCTION_HOSTNAME overridden_app_link = "https://%s" % displayed_hostname parser = Parser() message_root = parser.parsestr(generated_raw_message) messages = message_root.get_payload() plain = b64decode(messages[0].get_payload()).decode("utf-8") assert plain.count(normal_app_link) == 0 assert plain.count(overridden_app_link) > 0
def test_do_not_send_emails_when_not_in_production(ldap_mocked_app_with_users, ldapsource): app = ldap_mocked_app_with_users dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) settings = { "adaero.talent_manager_usernames": [TEST_TALENT_MANAGER_USERNAME], "adaero.homebase_location": "London", } with patch("smtplib.SMTP") as smtp_mock, patch( "socket.gethostname") as gethostname_mock, patch( "getpass.getuser") as getuser_mock: sendmail_mock = smtp_mock().sendmail gethostname_mock.return_value = "foo" getuser_mock.return_value = "bar" mail.check_and_send_email(dbsession, ldapsource, settings, delay_s=0, delay_between_s=0) assert 0 == len(sendmail_mock.call_args_list)
def test_emailing_works_with_different_tm_username_config( ldap_mocked_app_with_users, ldapsource): # noqa: E501 app = ldap_mocked_app_with_users dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) json_str = '["%s"]' % TEST_OTHER_MANAGER_USERNAME settings = { "adaero.talent_manager_usernames": json_str, "adaero.homebase_location": "London", } with patch("smtplib.SMTP") as smtp_mock, patch( "socket.gethostname") as gethostname_mock, patch( "getpass.getuser") as getuser_mock: sendmail_mock = smtp_mock().sendmail gethostname_mock.return_value = "foo" getuser_mock.return_value = "bar" mail.check_and_send_email(dbsession, ldapsource, settings, delay_s=0, delay_between_s=0) assert 0 == len(sendmail_mock.call_args_list)
def test_get_summarised_users(ldap_mocked_app_with_users): app = ldap_mocked_app_with_users dbsession = get_dbsession(app) add_test_data_for_stats(dbsession) users = mail.get_summarised_users(dbsession) assert {u.username for u in users} == {k for k in SUMMARISED_USERNAMES}
def test_send_emails_according_to_configured_location( ldap_mocked_app_with_users, # noqa: E501 ldapsource, subperiod, location, utc_offset_tuples, ): app = ldap_mocked_app_with_users dbsession = get_dbsession(app) # so date saved in database is TEST_UTCNOW freezer = freeze_time(TEST_UTCNOW) freezer.start() add_test_data_for_stats(dbsession, current_subperiod=subperiod, days_in=0) freezer.stop() # needs to be outside configured employees at a minimum settings = { "adaero.talent_manager_usernames": [TEST_OTHER_MANAGER_USERNAME], "adaero.served_on_https": True, "adaero.homebase_location": location, "adaero.enable_send_email": True, } with patch("smtplib.SMTP") as smtp_mock, patch( "socket.gethostname") as gethostname_mock, patch( "getpass.getuser") as getuser_mock: gethostname_mock.return_value = TEST_PRODUCTION_HOSTNAME sendmail_mock = smtp_mock().sendmail getuser_mock.return_value = TEST_PRODUCTION_USER date_ = TEST_UTCNOW.date() def check_sent(num, t): assert num == sendmail_mock.call_count, ( "Incorrect number of emails sent for time %s" % t) for time_, num_sent in utc_offset_tuples: new_dt = datetime.combine(date_, time_) freezer = freeze_time(new_dt) freezer.start() mail.check_and_send_email( dbsession, ldapsource, settings, force=False, delay_s=0, delay_between_s=0, ) check_sent(num_sent, time_) # email has already sent, won't send again mail.check_and_send_email( dbsession, ldapsource, settings, force=False, delay_s=0, delay_between_s=0, ) check_sent(num_sent, time_) freezer.stop() sendmail_mock.reset_mock() period = Period.get_current_period(dbsession) period.enrol_email_last_sent = None period.enrol_reminder_email_last_sent = None period.entry_email_last_sent = None period.entry_reminder_email_last_sent = None period.review_email_last_sent = None period.feedback_available_mail_last_sent = None with transaction.manager: dbsession.merge(period)
def test_send_correct_emails_are_sent_during_subperiods( ldap_mocked_app_with_users, # noqa: E501 ldapsource, subperiod, num_times, last_sent_email_code, last_sent_template_key, force, last_users, ): app = ldap_mocked_app_with_users dbsession = get_dbsession(app) add_test_data_for_stats(dbsession, current_subperiod=subperiod) settings = { "adaero.load_talent_managers_on_app_start": False, "adaero.talent_manager_usernames": [TEST_TALENT_MANAGER_USERNAME], "adaero.served_on_https": True, "adaero.homebase_location": "London", "adaero.production_hostname": TEST_PRODUCTION_HOSTNAME, "adaero.production_user": TEST_PRODUCTION_USER, "adaero.enable_send_email": True, } with patch("smtplib.SMTP") as smtp_mock, patch( "socket.gethostname") as gethostname_mock, patch( "getpass.getuser") as getuser_mock: sendmail_mock = smtp_mock().sendmail gethostname_mock.return_value = TEST_PRODUCTION_HOSTNAME getuser_mock.return_value = TEST_PRODUCTION_USER for i in range(num_times): kwargs = {"force": force, "delay_s": 0, "delay_between_s": 0} if force: kwargs["template_key"] = last_sent_template_key mail.check_and_send_email(dbsession, ldapsource, settings, **kwargs) if i < num_times - 1: sendmail_mock.reset_mock() with transaction.manager: period = Period.get_current_period(dbsession) assert period.get_email_flag_by_code( last_sent_email_code) == TEST_UTCNOW for code in EMAIL_CODES.difference({last_sent_email_code}): assert period.get_email_flag_by_code(code) != TEST_UTCNOW if not len(last_users): assert 0 == len(sendmail_mock.call_args_list) return # TODO: why is email a list now? confirm_email_call = sendmail_mock.call_args_list.pop(-1) normal_emails_calls = sorted(sendmail_mock.call_args_list, key=lambda c: c[0][1][0]) sorted_by_email_users = sorted(last_users, key=lambda v: v["mail"]) app_link = "https://%s" % TEST_PRODUCTION_HOSTNAME assert len(normal_emails_calls) == len( normal_emails_calls), "Incorrect number of normal emails sent" parser = Parser() # normal_emails_calls = sorted_by_email_calls[:-1] # confirm_email_call = sorted_by_email_calls[-1] for u, c in zip(sorted_by_email_users, normal_emails_calls): args = c[0] assert u["mail"] == args[1][0] generated_raw_message = args[2] message_root = parser.parsestr(generated_raw_message) messages = message_root.get_payload() assert len(messages) == 2 plain = b64decode(messages[0].get_payload()).decode("utf-8") html = b64decode(messages[1].get_payload()).decode("utf-8") # assert no non interpolated variables assert plain.count("{") == 0 assert plain.count(u["givenName"]) > 0 assert plain.count(app_link) > 0 assert html.count("{") == 0 assert html.count(u["givenName"]) > 0 assert html.count(app_link) > 1 assert html.count(app_link) % 2 == 0 assert html.count("</html>") == 1 num_normal_emails = len(normal_emails_calls) tm_details = TEST_LDAP_FULL_DETAILS[TEST_TALENT_MANAGER_USERNAME] assert tm_details["mail"] == confirm_email_call[0][1][0] # Deal with confirm email sent to talent managers confirm_raw_message = confirm_email_call[0][2] confirm_root = parser.parsestr(confirm_raw_message) confirm_messages = confirm_root.get_payload() assert len(confirm_messages) == 2 confirm_plain = b64decode( confirm_messages[0].get_payload()).decode("utf-8") confirm_html = b64decode( confirm_messages[1].get_payload()).decode("utf-8") for m in [confirm_plain, confirm_html]: assert m.count( EMAIL_TEMPLATE_MAP[last_sent_template_key]["summary"]) == 1 # exclude confirmation email from count assert m.count("%s email addresses" % num_normal_emails) == 1 assert confirm_html.count("</html>") == 1