From 9c5707c061466844a5c0dc214a15589caa60aada Mon Sep 17 00:00:00 2001 From: James Kent Date: Fri, 8 Sep 2023 12:35:58 -0500 Subject: [PATCH] run test in ci --- .github/workflows/workflow.yml | 2 +- compose/neurosynth_compose/openapi | 2 +- .../neurosynth_compose/resources/analysis.py | 27 +++++- .../neurosynth_compose/schemas/analysis.py | 3 + .../celery_tests/test_meta_analysis_result.py | 6 +- .../tests/api/test_annotation.py | 2 +- .../neurosynth_compose/tests/api/test_crud.py | 8 +- .../tests/api/test_meta_analysis.py | 4 +- .../tests/api/test_meta_analysis_result.py | 4 +- .../tests/api/test_specification.py | 2 +- .../tests/api/test_studyset.py | 5 +- compose/neurosynth_compose/tests/conftest.py | 87 ++++++++++++++----- .../tests/schemathesis_api/test_annotation.py | 2 +- .../schemathesis_api/test_meta_analysis.py | 2 +- .../schemathesis_api/test_specification.py | 2 +- .../tests/schemathesis_api/test_studyset.py | 2 +- store/neurostore/tests/test_auth.py | 4 +- 17 files changed, 117 insertions(+), 47 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 55b47b06d..d06f5bfdc 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -254,7 +254,7 @@ jobs: -e "NEUROVAULT_ACCESS_TOKEN=${NEUROVAULT_ACCESS_TOKEN}" \ --rm -w /compose \ compose \ - bash -c "python -m pytest neurosynth_compose/tests && python -m pytest --celery neurosynth_compose/tests/api/celery_tests" + bash -c "python -m pytest neurosynth_compose/tests && python -m pytest --celery neurosynth_compose/tests/api/celery_tests && python -m pytest --auth neurosynth_compose/tests/api/test_auth.py" style_check: runs-on: ubuntu-latest diff --git a/compose/neurosynth_compose/openapi b/compose/neurosynth_compose/openapi index 198069f10..85e9c2cbb 160000 --- a/compose/neurosynth_compose/openapi +++ b/compose/neurosynth_compose/openapi @@ -1 +1 @@ -Subproject commit 198069f108eaf86ec5ff48cb27e7e944a078ca47 +Subproject commit 85e9c2cbb4ef306183306c5b651b964e35ca4171 diff --git a/compose/neurosynth_compose/resources/analysis.py b/compose/neurosynth_compose/resources/analysis.py index cc9d79c71..b4f4b779f 100644 --- a/compose/neurosynth_compose/resources/analysis.py +++ b/compose/neurosynth_compose/resources/analysis.py @@ -44,6 +44,26 @@ from .singular import singularize +def create_user(): + from auth0.v3.authentication.users import Users + auth = request.headers.get("Authorization", None) + if auth is None: + return None + token = auth.split()[1] + profile_info = Users( + current_app.config["AUTH0_BASE_URL"].removeprefix("https://") + ).userinfo(access_token=token) + + # user signed up with auth0, but has not made any queries yet... + # should have endpoint to "create user" after sign on with auth0 + current_user = User( + external_id=connexion.context["user"], + name=profile_info.get("name", "Unknown") + ) + + return current_user + + def get_current_user(): user = connexion.context.get("user") if user: @@ -81,9 +101,10 @@ def update_or_create(cls, data, id=None, commit=True): if not current_user: # user signed up with auth0, but has not made any queries yet... # should have endpoint to "create user" after sign on with auth0 - current_user = User(external_id=connexion.context["user"]) - db.session.add(current_user) - db.session.commit() + current_user = create_user() + if current_user: + db.session.add(current_user) + db.session.commit() id = id or data.get("id", None) # want to handle case of {"id": "asdfasf"} diff --git a/compose/neurosynth_compose/schemas/analysis.py b/compose/neurosynth_compose/schemas/analysis.py index 25ba8bfc1..87ae7bf79 100644 --- a/compose/neurosynth_compose/schemas/analysis.py +++ b/compose/neurosynth_compose/schemas/analysis.py @@ -119,6 +119,9 @@ class BaseSchema(Schema): created_at = fields.DateTime() updated_at = fields.DateTime(allow_none=True) user_id = fields.String(data_key="user") + username = fields.String( + attribute="user.name", dump_only=True + ) class EstimatorSchema(Schema): diff --git a/compose/neurosynth_compose/tests/api/celery_tests/test_meta_analysis_result.py b/compose/neurosynth_compose/tests/api/celery_tests/test_meta_analysis_result.py index fa8b35bfa..93173c0e5 100644 --- a/compose/neurosynth_compose/tests/api/celery_tests/test_meta_analysis_result.py +++ b/compose/neurosynth_compose/tests/api/celery_tests/test_meta_analysis_result.py @@ -14,7 +14,7 @@ @celery_test -def test_file_upload_neurovault(app, db, mock_pynv): +def test_file_upload_neurovault(session, app, db, mock_pynv): import os from pathlib import Path import shutil @@ -35,7 +35,7 @@ def test_file_upload_neurovault(app, db, mock_pynv): @celery_test def test_create_or_update_neurostore_analysis( - auth_client, app, db, mock_pynv, meta_analysis_cached_result_files + session, auth_client, app, db, mock_pynv, meta_analysis_cached_result_files ): cluster_tables = [ f for f in meta_analysis_cached_result_files["tables"] if "clust.tsv" in f.name @@ -78,7 +78,7 @@ def test_create_or_update_neurostore_analysis( @celery_test -def test_result_upload(auth_client, app, db, meta_analysis_cached_result_files): +def test_result_upload(session, auth_client, app, db, meta_analysis_cached_result_files): data = {} data["statistical_maps"] = [ (open(m, "rb"), m.name) for m in meta_analysis_cached_result_files["maps"] diff --git a/compose/neurosynth_compose/tests/api/test_annotation.py b/compose/neurosynth_compose/tests/api/test_annotation.py index 63ae6bc69..695c8ab3e 100644 --- a/compose/neurosynth_compose/tests/api/test_annotation.py +++ b/compose/neurosynth_compose/tests/api/test_annotation.py @@ -1,4 +1,4 @@ -def test_get_annotations(auth_client, user_data): +def test_get_annotations(session, auth_client, user_data): get_all = auth_client.get("/api/annotations") assert get_all.status_code == 200 id_ = get_all.json["results"][0]["id"] diff --git a/compose/neurosynth_compose/tests/api/test_crud.py b/compose/neurosynth_compose/tests/api/test_crud.py index 523240eb9..e8db2c990 100644 --- a/compose/neurosynth_compose/tests/api/test_crud.py +++ b/compose/neurosynth_compose/tests/api/test_crud.py @@ -21,7 +21,7 @@ ("projects", Project, ProjectSchema), ], ) -def test_create(auth_client, user_data, endpoint, model, schema): +def test_create(session, auth_client, user_data, endpoint, model, schema): user = User.query.filter_by(name="user1").first() examples = model.query.filter_by(user=user).all() for example in examples: @@ -42,6 +42,8 @@ def test_create(auth_client, user_data, endpoint, model, schema): del payload["neurostore_url"] if "neurostore_study" in payload: del payload["neurostore_study"] + if "username" in payload: + del payload["username"] if isinstance(example, MetaAnalysis): del payload["neurostore_analysis"] @@ -75,7 +77,7 @@ def test_create(auth_client, user_data, endpoint, model, schema): ("projects", Project, ProjectSchema), ], ) -def test_read(auth_client, user_data, endpoint, model, schema): +def test_read(session, auth_client, user_data, endpoint, model, schema): user = User.query.filter_by(name="user1").first() if hasattr(model, "public"): query = (model.user == user) | (model.public == True) # noqa E712 @@ -107,7 +109,7 @@ def test_read(auth_client, user_data, endpoint, model, schema): ("projects", Project, ProjectSchema, {"name": "my project"}), ], ) -def test_update(auth_client, db, session, user_data, endpoint, model, schema, update): +def test_update(session, auth_client, db, user_data, endpoint, model, schema, update): user = User.query.filter_by(name="user1").first() record = model.query.filter_by(user=user).first() diff --git a/compose/neurosynth_compose/tests/api/test_meta_analysis.py b/compose/neurosynth_compose/tests/api/test_meta_analysis.py index b73a70ad4..5403bb360 100644 --- a/compose/neurosynth_compose/tests/api/test_meta_analysis.py +++ b/compose/neurosynth_compose/tests/api/test_meta_analysis.py @@ -1,4 +1,4 @@ -def test_get_meta_analyses(app, auth_client, user_data): +def test_get_meta_analyses(session, app, auth_client, user_data): get_all = auth_client.get("/api/meta-analyses") assert get_all.status_code == 200 @@ -15,5 +15,5 @@ def test_get_meta_analyses(app, auth_client, user_data): assert data[key] is None or isinstance(data[key], dict) -def test_ingest_neurostore(neurostore_data): +def test_ingest_neurostore(session, neurostore_data): pass diff --git a/compose/neurosynth_compose/tests/api/test_meta_analysis_result.py b/compose/neurosynth_compose/tests/api/test_meta_analysis_result.py index bb13b066b..af46c46ad 100644 --- a/compose/neurosynth_compose/tests/api/test_meta_analysis_result.py +++ b/compose/neurosynth_compose/tests/api/test_meta_analysis_result.py @@ -1,7 +1,7 @@ from neurosynth_compose.models import MetaAnalysis -def test_create_meta_analysis_result(app, auth_client, user_data): +def test_create_meta_analysis_result(session, app, auth_client, user_data): meta_analysis = MetaAnalysis.query.first() headers = {"Compose-Upload-Key": meta_analysis.run_key} data = { @@ -20,7 +20,7 @@ def test_create_meta_analysis_result(app, auth_client, user_data): assert meta_resp.status_code == 200 -def test_create_meta_analysis_result_no_snapshots(app, db, auth_client, user_data): +def test_create_meta_analysis_result_no_snapshots(session, app, db, auth_client, user_data): meta_analysis = MetaAnalysis.query.first() meta_analysis.studyset.snapshot = None meta_analysis.annotation.snapshot = None diff --git a/compose/neurosynth_compose/tests/api/test_specification.py b/compose/neurosynth_compose/tests/api/test_specification.py index 4bdec5b79..7ef494781 100644 --- a/compose/neurosynth_compose/tests/api/test_specification.py +++ b/compose/neurosynth_compose/tests/api/test_specification.py @@ -1,3 +1,3 @@ -def test_get_specification(app, auth_client, user_data): +def test_get_specification(session, app, auth_client, user_data): get = auth_client.get("/api/specifications") assert get.status_code == 200 diff --git a/compose/neurosynth_compose/tests/api/test_studyset.py b/compose/neurosynth_compose/tests/api/test_studyset.py index 423368760..34422c299 100644 --- a/compose/neurosynth_compose/tests/api/test_studyset.py +++ b/compose/neurosynth_compose/tests/api/test_studyset.py @@ -2,17 +2,18 @@ from ...schemas import StudysetSchema -def test_get_studysets(auth_client, user_data): +def test_get_studysets(session, auth_client, user_data): get = auth_client.get("/api/studysets") assert get.status_code == 200 -def test_post_studyset_with_new_neurostore_id(auth_client, user_data): +def test_post_studyset_with_new_neurostore_id(session, auth_client, user_data): user = User.query.filter_by(name="user1").first() example = Studyset.query.filter_by(user=user).first() schema = StudysetSchema() payload = schema.dump(example) payload.pop("url") + payload.pop("username") # payload["neurostore_id"] = "" resp = auth_client.post("/api/studysets", data=payload) diff --git a/compose/neurosynth_compose/tests/conftest.py b/compose/neurosynth_compose/tests/conftest.py index 59db40b88..b21ae2647 100644 --- a/compose/neurosynth_compose/tests/conftest.py +++ b/compose/neurosynth_compose/tests/conftest.py @@ -42,6 +42,12 @@ def pytest_addoption(parser): default=False, help="Run celery tests", ) + parser.addoption( + "--auth", + action="store_true", + default=False, + help="Run authentication tests", + ) celery_test = pytest.mark.skipif( @@ -52,21 +58,56 @@ def pytest_addoption(parser): "not config.getoption('--schemathesis')", reason="Only run when --schemathesis is given", ) - +auth_test = pytest.mark.skipif( + "not config.getoption('--auth')", + reason="Only run when --auth is given", +) """ Test fixtures for bypassing authentication """ -# https://github.com/pytest-dev/pytest/issues/363#issuecomment-406536200 @pytest.fixture(scope="session") -def monkeysession(request): - from _pytest.monkeypatch import MonkeyPatch +def real_app(): + """Session-wide test `Flask` application.""" + from ..core import app as _app - mpatch = MonkeyPatch() - yield mpatch - mpatch.undo() + if "APP_SETTINGS" not in environ: + config = "neurostore.config.TestingConfig" + else: + config = environ["APP_SETTINGS"] + if not getattr(_app, "config", None): + _app = _app._app + _app.config.from_object(config) + # _app.config["SQLALCHEMY_ECHO"] = True + + # Establish an application context before running the tests. + ctx = _app.app_context() + ctx.push() + + yield _app + + ctx.pop() + + +@pytest.fixture(scope="session") +def real_db(real_app): + """Session-wide test database.""" + _db.create_all() + + yield _db + + _db.session.remove() + sa.orm.close_all_sessions() + _db.drop_all() + + +# https://github.com/pytest-dev/pytest/issues/363#issuecomment-406536200 +@pytest.fixture(scope="session", autouse=False) +def monkeysession(request): + with pytest.MonkeyPatch.context() as mp: + yield mp def mock_decode_token(token): @@ -201,7 +242,7 @@ def celery_app(app, db): return make_celery(app) -@pytest.fixture(scope="function", autouse=True) +@pytest.fixture(scope="function", autouse=False) def session(db): """Creates a new db session for a test. Changes in session are rolled back""" @@ -295,11 +336,11 @@ def mock_add_users(app, db, mock_auth): @pytest.fixture(scope="function") -def add_users(app, db): +def add_users(real_app, real_db): """Adds a test user to db""" from neurosynth_compose.resources.auth import decode_token - domain = app.config["AUTH0_BASE_URL"].split("://")[1] + domain = real_app.config["AUTH0_BASE_URL"].split("://")[1] token = GetToken(domain) users = [ @@ -318,26 +359,28 @@ def add_users(app, db): name = u["name"] passw = u["password"] payload = token.login( - client_id=app.config["AUTH0_CLIENT_ID"], - client_secret=app.config["AUTH0_CLIENT_SECRET"], + client_id=real_app.config["AUTH0_CLIENT_ID"], + client_secret=real_app.config["AUTH0_CLIENT_SECRET"], username=name + "@email.com", password=passw, realm="Username-Password-Authentication", - audience=app.config["AUTH0_API_AUDIENCE"], - scope="openid", + audience=real_app.config["AUTH0_API_AUDIENCE"], + scope="openid profile email", ) token_info = decode_token(payload["access_token"]) - user = User( - name=name, - external_id=token_info["sub"], - ) - if User.query.filter_by(name=token_info["sub"]).first() is None: - db.session.add(user) - db.session.commit() + # do not add user1 into database + if name != "user1": + user = User( + name=name, + external_id=token_info["sub"], + ) + if User.query.filter_by(external_id=token_info["sub"]).first() is None: + real_db.session.add(user) + real_db.session.commit() tokens[name] = { "token": payload["access_token"], - "id": User.query.filter_by(external_id=token_info["sub"]).first().id, + "external_id": token_info["sub"], } yield tokens diff --git a/compose/neurosynth_compose/tests/schemathesis_api/test_annotation.py b/compose/neurosynth_compose/tests/schemathesis_api/test_annotation.py index 40c82190b..f7e6bdddf 100644 --- a/compose/neurosynth_compose/tests/schemathesis_api/test_annotation.py +++ b/compose/neurosynth_compose/tests/schemathesis_api/test_annotation.py @@ -7,6 +7,6 @@ @schemathesis_test @schema.parametrize(endpoint="^/api/annotations") -def test_annotation_endpoint(case, auth_client): +def test_annotation_endpoint(case, auth_client, session): response = case.call_wsgi(headers=auth_client._get_headers()) case.validate_response(response) diff --git a/compose/neurosynth_compose/tests/schemathesis_api/test_meta_analysis.py b/compose/neurosynth_compose/tests/schemathesis_api/test_meta_analysis.py index 2f1c0471c..c0a9248fb 100644 --- a/compose/neurosynth_compose/tests/schemathesis_api/test_meta_analysis.py +++ b/compose/neurosynth_compose/tests/schemathesis_api/test_meta_analysis.py @@ -7,7 +7,7 @@ @schemathesis_test @schema.parametrize(endpoint="^/api/meta-analyses") -def test_meta_analysis_endpoint(case, auth_client): +def test_meta_analysis_endpoint(case, auth_client, session): # The `session` argument must be supplied. response = case.call_wsgi(headers=auth_client._get_headers()) case.validate_response(response) diff --git a/compose/neurosynth_compose/tests/schemathesis_api/test_specification.py b/compose/neurosynth_compose/tests/schemathesis_api/test_specification.py index 7d2f418da..1a72b2ae6 100644 --- a/compose/neurosynth_compose/tests/schemathesis_api/test_specification.py +++ b/compose/neurosynth_compose/tests/schemathesis_api/test_specification.py @@ -7,7 +7,7 @@ @schemathesis_test @schema.parametrize(endpoint="^/api/specifications") -def test_specification_endpoint(case, auth_client): +def test_specification_endpoint(case, auth_client, session): # The `session` argument must be supplied. response = case.call_wsgi(headers=auth_client._get_headers()) case.validate_response(response) diff --git a/compose/neurosynth_compose/tests/schemathesis_api/test_studyset.py b/compose/neurosynth_compose/tests/schemathesis_api/test_studyset.py index a007d3bd8..e7f3a797b 100644 --- a/compose/neurosynth_compose/tests/schemathesis_api/test_studyset.py +++ b/compose/neurosynth_compose/tests/schemathesis_api/test_studyset.py @@ -7,7 +7,7 @@ @schemathesis_test @schema.parametrize(endpoint="^/api/studysets") -def test_studyset_endpoint(case, auth_client): +def test_studyset_endpoint(case, auth_client, session): # The `session` argument must be supplied. response = case.call_wsgi(headers=auth_client._get_headers()) case.validate_response(response) diff --git a/store/neurostore/tests/test_auth.py b/store/neurostore/tests/test_auth.py index fe1010899..f0445abb0 100644 --- a/store/neurostore/tests/test_auth.py +++ b/store/neurostore/tests/test_auth.py @@ -2,7 +2,7 @@ import pytest -@auth_test +#@auth_test def test_decode_token(add_users): from ..resources.auth import decode_token, AuthError @@ -13,7 +13,7 @@ def test_decode_token(add_users): decode_token(user["token"]) -@auth_test +#@auth_test def test_creating_new_user_on_db(add_users): from .request_utils import Client