diff --git a/OpenOversight/app/models/database.py b/OpenOversight/app/models/database.py index d3f0f52fe..75b8ab18e 100644 --- a/OpenOversight/app/models/database.py +++ b/OpenOversight/app/models/database.py @@ -140,7 +140,7 @@ class Job(BaseModel): ) def __repr__(self): - return f"" + return f"" def __str__(self): return self.job_title diff --git a/OpenOversight/app/utils/constants.py b/OpenOversight/app/utils/constants.py index 316fd6471..54d39a78e 100644 --- a/OpenOversight/app/utils/constants.py +++ b/OpenOversight/app/utils/constants.py @@ -30,7 +30,3 @@ MEGABYTE = 1024 * KILOBYTE MINUTE = 60 HOUR = 60 * MINUTE - -# Test Constants -ADMIN_EMAIL = "test@example.org" -ADMIN_PASSWORD = "testtest" diff --git a/OpenOversight/tests/conftest.py b/OpenOversight/tests/conftest.py index 22151e299..9831a4072 100644 --- a/OpenOversight/tests/conftest.py +++ b/OpenOversight/tests/conftest.py @@ -19,7 +19,7 @@ from sqlalchemy.orm import scoped_session, sessionmaker from xvfbwrapper import Xvfb -from OpenOversight.app import create_app +from OpenOversight.app import EmailClient, create_app from OpenOversight.app.models.database import ( Assignment, Department, @@ -40,13 +40,31 @@ from OpenOversight.app.models.database import db as _db from OpenOversight.app.utils.choices import DEPARTMENT_STATE_CHOICES from OpenOversight.app.utils.constants import ( - ADMIN_EMAIL, - ADMIN_PASSWORD, ENCODING_UTF_8, KEY_ENV_TESTING, KEY_NUM_OFFICERS, ) from OpenOversight.app.utils.general import merge_dicts +from OpenOversight.tests.constants import ( + AC_USER_EMAIL, + AC_USER_PASSWORD, + AC_USER_USERNAME, + ADMIN_USER_EMAIL, + ADMIN_USER_PASSWORD, + ADMIN_USER_USER_NAME, + DISABLED_USER_EMAIL, + DISABLED_USER_PASSWORD, + DISABLED_USER_USERNAME, + GENERAL_USER_EMAIL, + GENERAL_USER_PASSWORD, + GENERAL_USER_USERNAME, + MOD_DISABLED_USER_EMAIL, + MOD_DISABLED_USER_PASSWORD, + MOD_DISABLED_USER_USERNAME, + UNCONFIRMED_USER_EMAIL, + UNCONFIRMED_USER_PASSWORD, + UNCONFIRMED_USER_USERNAME, +) factory = Faker() @@ -263,6 +281,11 @@ def app(request): yield app +@pytest.fixture(autouse=True) +def email_client(): + EmailClient(testing=True) + + @pytest.fixture(autouse=True) def ctx(app): with app.app_context(): @@ -337,29 +360,35 @@ def add_mockdata(session): assert current_app.config[KEY_NUM_OFFICERS] >= 5 test_user = User( - email="jen@example.org", username="test_user", password="dog", confirmed=True + email=GENERAL_USER_EMAIL, + username=GENERAL_USER_USERNAME, + password=GENERAL_USER_PASSWORD, + confirmed=True, ) session.add(test_user) test_admin = User( - email=ADMIN_EMAIL, - username="test_admin", - password=ADMIN_PASSWORD, + email=ADMIN_USER_EMAIL, + username=ADMIN_USER_USER_NAME, + password=ADMIN_USER_PASSWORD, confirmed=True, is_administrator=True, ) session.add(test_admin) test_unconfirmed_user = User( - email="freddy@example.org", username="b_meson", password="dog", confirmed=False + email=UNCONFIRMED_USER_EMAIL, + username=UNCONFIRMED_USER_USERNAME, + password=UNCONFIRMED_USER_PASSWORD, + confirmed=False, ) session.add(test_unconfirmed_user) session.commit() test_disabled_user = User( - email="may@example.org", - username="may", - password="yam", + email=DISABLED_USER_EMAIL, + username=DISABLED_USER_USERNAME, + password=DISABLED_USER_PASSWORD, confirmed=True, is_disabled=True, ) @@ -367,9 +396,9 @@ def add_mockdata(session): session.commit() test_modified_disabled_user = User( - email="sam@example.org", - username="sam", - password="the yam", + email=MOD_DISABLED_USER_EMAIL, + username=MOD_DISABLED_USER_USERNAME, + password=MOD_DISABLED_USER_PASSWORD, confirmed=True, is_disabled=True, ) @@ -401,9 +430,9 @@ def add_mockdata(session): session.commit() test_area_coordinator = User( - email="raq929@example.org", - username="test_ac", - password="horse", + email=AC_USER_EMAIL, + username=AC_USER_USERNAME, + password=AC_USER_PASSWORD, confirmed=True, is_area_coordinator=True, ac_department_id=AC_DEPT, diff --git a/OpenOversight/tests/constants.py b/OpenOversight/tests/constants.py new file mode 100644 index 000000000..2cfd5b88d --- /dev/null +++ b/OpenOversight/tests/constants.py @@ -0,0 +1,19 @@ +# User Constants +AC_USER_EMAIL = "raq929@example.org" +AC_USER_PASSWORD = "horse" +AC_USER_USERNAME = "test_ac" +ADMIN_USER_EMAIL = "test@example.org" +ADMIN_USER_PASSWORD = "testtest" +ADMIN_USER_USER_NAME = "test_admin" +GENERAL_USER_EMAIL = "jen@example.org" +GENERAL_USER_PASSWORD = "dog" +GENERAL_USER_USERNAME = "test_user" +DISABLED_USER_EMAIL = "may@example.org" +DISABLED_USER_PASSWORD = "yam" +DISABLED_USER_USERNAME = "may" +MOD_DISABLED_USER_EMAIL = "sam@example.org" +MOD_DISABLED_USER_PASSWORD = "the yam" +MOD_DISABLED_USER_USERNAME = "sam" +UNCONFIRMED_USER_EMAIL = "freddy@example.org" +UNCONFIRMED_USER_PASSWORD = "dog" +UNCONFIRMED_USER_USERNAME = "b_meson" diff --git a/OpenOversight/tests/routes/route_helpers.py b/OpenOversight/tests/routes/route_helpers.py index 5069dea27..53fad2cdb 100644 --- a/OpenOversight/tests/routes/route_helpers.py +++ b/OpenOversight/tests/routes/route_helpers.py @@ -2,49 +2,69 @@ from OpenOversight.app.auth.forms import LoginForm from OpenOversight.app.models.database import User -from OpenOversight.app.utils.constants import ADMIN_PASSWORD -from OpenOversight.tests.conftest import AC_DEPT +from OpenOversight.tests.constants import ( + AC_USER_EMAIL, + AC_USER_PASSWORD, + ADMIN_USER_EMAIL, + ADMIN_USER_PASSWORD, + DISABLED_USER_EMAIL, + DISABLED_USER_PASSWORD, + GENERAL_USER_EMAIL, + GENERAL_USER_PASSWORD, + MOD_DISABLED_USER_EMAIL, + MOD_DISABLED_USER_PASSWORD, + UNCONFIRMED_USER_EMAIL, + UNCONFIRMED_USER_PASSWORD, +) def login_user(client): - user = User.query.filter_by(id=1).first() - form = LoginForm(email=user.email, password="dog", remember_me=True) + user = User.query.filter_by(email=GENERAL_USER_EMAIL).first() + form = LoginForm(email=user.email, password=GENERAL_USER_PASSWORD, remember_me=True) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=False) - return rv + return rv, user def login_unconfirmed_user(client): - user = User.query.filter_by(confirmed=False).first() - form = LoginForm(email=user.email, password="dog", remember_me=True) + user = User.query.filter_by(email=UNCONFIRMED_USER_EMAIL).first() + form = LoginForm( + email=user.email, password=UNCONFIRMED_USER_PASSWORD, remember_me=True + ) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=False) assert b"Invalid username or password" not in rv.data - return rv + return rv, user def login_disabled_user(client): - form = LoginForm(email="may@example.org", password="yam", remember_me=True) + user = User.query.filter_by(email=DISABLED_USER_EMAIL).first() + form = LoginForm( + email=user.email, password=DISABLED_USER_PASSWORD, remember_me=True + ) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=True) - return rv + return rv, user def login_modified_disabled_user(client): - form = LoginForm(email="sam@example.org", password="the yam", remember_me=True) + user = User.query.filter_by(email=MOD_DISABLED_USER_EMAIL).first() + form = LoginForm( + email=user.email, password=MOD_DISABLED_USER_PASSWORD, remember_me=True + ) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=True) - return rv + return rv, user def login_admin(client): - user = User.query.filter_by(is_administrator=True).first() - form = LoginForm(email=user.email, password=ADMIN_PASSWORD, remember_me=True) + user = User.query.filter_by(email=ADMIN_USER_EMAIL).first() + form = LoginForm(email=user.email, password=ADMIN_USER_PASSWORD, remember_me=True) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=False) - return rv + return rv, user def login_ac(client): - user = User.query.filter_by(ac_department_id=AC_DEPT).first() - form = LoginForm(email=user.email, password="horse", remember_me=True) + user = User.query.filter_by(email=AC_USER_EMAIL).first() + form = LoginForm(email=user.email, password=AC_USER_PASSWORD, remember_me=True) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=False) - return rv + return rv, user def process_form_data(form_dict): diff --git a/OpenOversight/tests/routes/test_auth.py b/OpenOversight/tests/routes/test_auth.py index 9950ac40a..3191d2f4f 100644 --- a/OpenOversight/tests/routes/test_auth.py +++ b/OpenOversight/tests/routes/test_auth.py @@ -17,6 +17,11 @@ from OpenOversight.app.models.database import User from OpenOversight.app.utils.constants import KEY_OO_MAIL_SUBJECT_PREFIX from OpenOversight.tests.conftest import AC_DEPT +from OpenOversight.tests.constants import ( + GENERAL_USER_EMAIL, + MOD_DISABLED_USER_EMAIL, + UNCONFIRMED_USER_EMAIL, +) from OpenOversight.tests.routes.route_helpers import ( login_disabled_user, login_modified_disabled_user, @@ -58,7 +63,7 @@ def test_route_login_required(route, client, mockdata): def test_valid_user_can_login(mockdata, client, session): with current_app.test_request_context(): - rv = login_user(client) + rv, _ = login_user(client) assert rv.status_code == HTTPStatus.FOUND assert urlparse(rv.location).path == "/index" @@ -74,7 +79,7 @@ def test_valid_user_can_login_with_email_differently_cased(mockdata, client, ses def test_invalid_user_cannot_login(mockdata, client, session): with current_app.test_request_context(): form = LoginForm( - email="freddy@example.org", password="bruteforce", remember_me=True + email=UNCONFIRMED_USER_EMAIL, password="bruteforce", remember_me=True ) rv = client.post(url_for("auth.login"), data=form.data) assert b"Invalid username or password." in rv.data @@ -428,7 +433,7 @@ def test_unconfirmed_user_redirected_to_confirm_account(mockdata, client, sessio def test_disabled_user_cannot_login(mockdata, client, session): with current_app.test_request_context(): - rv = login_disabled_user(client) + rv, _ = login_disabled_user(client) assert b"User has been disabled" in rv.data @@ -438,11 +443,11 @@ def test_disabled_user_cannot_visit_pages_requiring_auth(mockdata, client, sessi # you'll get unexpected results if both tests run simultaneously. with current_app.test_request_context(): # Temporarily enable account for login - user = User.query.filter_by(email="sam@example.org").one() + user = User.query.filter_by(email=MOD_DISABLED_USER_EMAIL).one() user.is_disabled = False session.add(user) - rv = login_modified_disabled_user(client) + rv, _ = login_modified_disabled_user(client) assert b"/user/sam" in rv.data # Disable account again and check that login_required redirects user correctly @@ -477,5 +482,5 @@ def test_user_can_change_dept_pref(mockdata, client, session): assert b"Updated!" in rv.data - user = User.query.filter_by(email="jen@example.org").one() + user = User.query.filter_by(email=GENERAL_USER_EMAIL).one() assert user.dept_pref == AC_DEPT diff --git a/OpenOversight/tests/routes/test_other.py b/OpenOversight/tests/routes/test_other.py index c05c9268e..a8b613b97 100644 --- a/OpenOversight/tests/routes/test_other.py +++ b/OpenOversight/tests/routes/test_other.py @@ -5,6 +5,7 @@ from flask import current_app, url_for from OpenOversight.app.utils.constants import ENCODING_UTF_8, KEY_TIMEZONE +from OpenOversight.tests.constants import GENERAL_USER_USERNAME from OpenOversight.tests.routes.route_helpers import login_user @@ -32,9 +33,10 @@ def test_user_can_access_profile(mockdata, client, session): login_user(client) rv = client.get( - url_for("main.profile", username="test_user"), follow_redirects=True + url_for("main.profile", username=GENERAL_USER_USERNAME), + follow_redirects=True, ) - assert "test_user" in rv.data.decode(ENCODING_UTF_8) + assert GENERAL_USER_USERNAME in rv.data.decode(ENCODING_UTF_8) # User email should not appear assert "User Email" not in rv.data.decode(ENCODING_UTF_8) # Toggle button should not appear for this non-admin user @@ -48,7 +50,7 @@ def test_user_can_access_profile_differently_cased(mockdata, client, session): rv = client.get( url_for("main.profile", username="TEST_USER"), follow_redirects=True ) - assert "test_user" in rv.data.decode(ENCODING_UTF_8) + assert GENERAL_USER_USERNAME in rv.data.decode(ENCODING_UTF_8) assert "User Email" not in rv.data.decode(ENCODING_UTF_8) assert "Edit User" not in rv.data.decode(ENCODING_UTF_8) diff --git a/OpenOversight/tests/routes/test_user_api.py b/OpenOversight/tests/routes/test_user_api.py index e591e61c2..715c021d6 100644 --- a/OpenOversight/tests/routes/test_user_api.py +++ b/OpenOversight/tests/routes/test_user_api.py @@ -4,10 +4,14 @@ from flask import current_app, url_for from OpenOversight.app.auth.forms import EditUserForm, LoginForm, RegistrationForm -from OpenOversight.app.email_client import EmailClient from OpenOversight.app.models.database import User, db from OpenOversight.app.utils.constants import ENCODING_UTF_8 from OpenOversight.tests.conftest import AC_DEPT +from OpenOversight.tests.constants import ( + ADMIN_USER_EMAIL, + GENERAL_USER_EMAIL, + UNCONFIRMED_USER_EMAIL, +) from OpenOversight.tests.routes.route_helpers import login_ac, login_admin, login_user @@ -77,7 +81,7 @@ def test_admin_cannot_update_to_ac_without_department(mockdata, client, session) with current_app.test_request_context(): login_admin(client) - user = User.query.except_(User.query.filter_by(is_administrator=True)).first() + user = User.query.except_(User.query.filter_by(email=ADMIN_USER_EMAIL)).first() form = EditUserForm(is_area_coordinator=True, submit=True) @@ -95,7 +99,7 @@ def test_admin_can_update_users_to_admin(mockdata, client, session): with current_app.test_request_context(): login_admin(client) - user = User.query.except_(User.query.filter_by(is_administrator=True)).first() + user = User.query.except_(User.query.filter_by(email=ADMIN_USER_EMAIL)).first() form = EditUserForm( is_area_coordinator=False, is_administrator=True, submit=True @@ -115,7 +119,7 @@ def test_admin_can_delete_user(mockdata, client, session): with current_app.test_request_context(): login_admin(client) - user = User.query.first() + user = User.query.filter_by(email=GENERAL_USER_EMAIL).one() rv = client.get( url_for("auth.delete_user", user_id=user.id), @@ -177,9 +181,7 @@ def test_admin_can_disable_user(mockdata, client, session): def test_admin_cannot_disable_self(mockdata, client, session): with current_app.test_request_context(): - login_admin(client) - - user = User.query.filter_by(is_administrator=True).first() + _, user = login_admin(client) assert not user.is_disabled @@ -204,7 +206,7 @@ def test_admin_can_enable_user(mockdata, client, session): with current_app.test_request_context(): login_admin(client) - user = User.query.filter_by(is_administrator=False).first() + user = User.query.filter_by(email=GENERAL_USER_EMAIL).one() user.is_disabled = True db.session.commit() @@ -232,7 +234,7 @@ def test_admin_can_resend_user_confirmation_email(mockdata, client, session): with current_app.test_request_context(): login_admin(client) - user = User.query.filter_by(confirmed=False).first() + user = User.query.filter_by(email=UNCONFIRMED_USER_EMAIL).first() form = EditUserForm( resend=True, @@ -252,11 +254,11 @@ def test_admin_can_resend_user_confirmation_email(mockdata, client, session): def test_register_user_approval_required(mockdata, client, session): current_app.config["APPROVE_REGISTRATIONS"] = True - EmailClient(testing=True) with current_app.test_request_context(): diceware_password = "operative hamster persevere verbalize curling" + new_user_email = "jen@example.com" form = RegistrationForm( - email="jen@example.com", + email=new_user_email, username="redshiftzero", password=diceware_password, password2=diceware_password, @@ -272,7 +274,7 @@ def test_register_user_approval_required(mockdata, client, session): ) form = LoginForm( - email="jen@example.com", password=diceware_password, remember_me=True + email=new_user_email, password=diceware_password, remember_me=True ) rv = client.post(url_for("auth.login"), data=form.data, follow_redirects=False) @@ -287,7 +289,7 @@ def test_admin_can_approve_user(mockdata, client, session): with current_app.test_request_context(): login_admin(client) - user = User.query.filter_by(is_administrator=False).first() + user = User.query.filter_by(email=GENERAL_USER_EMAIL).first() user.approved = False db.session.commit() @@ -336,7 +338,6 @@ def test_admin_approval_sends_confirmation_email( session, ): current_app.config["APPROVE_REGISTRATIONS"] = approve_registration_config - EmailClient(testing=True) with current_app.test_request_context(): login_admin(client) diff --git a/OpenOversight/tests/test_cache.py b/OpenOversight/tests/test_cache.py index 92a9c1a54..57d3a4dc3 100644 --- a/OpenOversight/tests/test_cache.py +++ b/OpenOversight/tests/test_cache.py @@ -12,7 +12,7 @@ LinkForm, LocationForm, ) -from OpenOversight.app.models.database import Department, Incident, Job, Officer, User +from OpenOversight.app.models.database import Department, Incident, Job, Officer from OpenOversight.app.models.database_cache import ( DB_CACHE, has_database_cache_entry, @@ -87,12 +87,11 @@ def test_total_documented_assignments(mockdata, client, faker): def test_total_documented_incidents(mockdata, client, faker): with current_app.test_request_context(): - login_admin(client) + _, user = login_admin(client) department = Department.query.first() department.total_documented_assignments() department.total_documented_incidents() department.total_documented_officers() - user = User.query.first() assert has_database_cache_entry(department, KEY_DEPT_TOTAL_ASSIGNMENTS) is True assert has_database_cache_entry(department, KEY_DEPT_TOTAL_INCIDENTS) is True @@ -141,12 +140,11 @@ def test_total_documented_incidents(mockdata, client, faker): def test_total_documented_officers(mockdata, client, faker): with current_app.test_request_context(): - login_admin(client) + _, user = login_admin(client) department = Department.query.first() department.total_documented_assignments() department.total_documented_incidents() department.total_documented_officers() - user = User.query.filter_by(is_administrator=True).first() assert has_database_cache_entry(department, KEY_DEPT_TOTAL_ASSIGNMENTS) is True assert has_database_cache_entry(department, KEY_DEPT_TOTAL_INCIDENTS) is True diff --git a/OpenOversight/tests/test_functional.py b/OpenOversight/tests/test_functional.py index aa93483a8..6fa856220 100644 --- a/OpenOversight/tests/test_functional.py +++ b/OpenOversight/tests/test_functional.py @@ -12,6 +12,8 @@ from OpenOversight.app.models.database import Department, Incident, Officer, Unit, db from OpenOversight.app.utils.constants import KEY_OFFICERS_PER_PAGE +from OpenOversight.tests.conftest import AC_DEPT +from OpenOversight.tests.constants import ADMIN_USER_EMAIL DESCRIPTION_CUTOFF = 700 @@ -29,7 +31,7 @@ def login_admin(browser, server_port): with wait_for_page_load(browser): elem = browser.find_element_by_id("email") elem.clear() - elem.send_keys("test@example.org") + elem.send_keys(ADMIN_USER_EMAIL) elem = browser.find_element_by_id("password") elem.clear() elem.send_keys("testtest") @@ -109,11 +111,10 @@ def test_user_can_get_to_complaint(mockdata, browser, server_port): def test_officer_browse_pagination(mockdata, browser, server_port): - dept_id = 1 - total = Officer.query.filter_by(department_id=dept_id).count() + total = Officer.query.filter_by(department_id=AC_DEPT).count() # first page of results - browser.get(f"http://localhost:{server_port}/department/{dept_id}?page=1") + browser.get(f"http://localhost:{server_port}/department/{AC_DEPT}?page=1") wait_for_element(browser, By.TAG_NAME, "body") page_text = browser.find_element_by_tag_name("body").text expected = f"Showing 1-{current_app.config['OFFICERS_PER_PAGE']} of {total}" @@ -122,7 +123,7 @@ def test_officer_browse_pagination(mockdata, browser, server_port): # last page of results last_page_index = (total // current_app.config[KEY_OFFICERS_PER_PAGE]) + 1 browser.get( - f"http://localhost:{server_port}/department/{dept_id}?page={last_page_index}" + f"http://localhost:{server_port}/department/{AC_DEPT}?page={last_page_index}" ) wait_for_element(browser, By.TAG_NAME, "body") page_text = browser.find_element_by_tag_name("body").text diff --git a/OpenOversight/tests/test_models.py b/OpenOversight/tests/test_models.py index b7e357b82..acb32ccdf 100644 --- a/OpenOversight/tests/test_models.py +++ b/OpenOversight/tests/test_models.py @@ -9,6 +9,7 @@ Face, Image, Incident, + Job, LicensePlate, Link, Location, @@ -101,6 +102,11 @@ def test_assignment_repr(mockdata): ) +def test_job_repr(mockdata): + job = Job.query.first() + assert repr(job) == f"" + + def test_image_repr(mockdata): image = Image.query.first() assert repr(image) == f""