Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip #111

Merged
Merged

wip #111

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
..
This file is part of pytest-invenio.
Copyright (C) 2018-2024 CERN.
Copyright (C) 2024 Graz University of Technology.
pytest-invenio is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.

Changes
=======

Version 3.0.0 (released 2024-12-02)

- setup: remove pytest pin
- global: add compatibility to sqlalchemy >= 2.0
- fixtures: apply new sqlalchemy session rollback handling

Version 2.2.1 (released 2024-06-27)

- installation: pin importlib-metadata ``<8.0.0``
Expand Down
3 changes: 2 additions & 1 deletion pytest_invenio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# This file is part of pytest-invenio.
# Copyright (C) 2017-2024 CERN.
# Copyright (C) 2024 Graz University of Technology.
#
# pytest-invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -499,6 +500,6 @@ def test_browser(live_server, browser):
"""


__version__ = "2.2.1"
__version__ = "3.0.0"

__all__ = ("__version__",)
43 changes: 27 additions & 16 deletions pytest_invenio/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# This file is part of pytest-invenio.
# Copyright (C) 2017-2024 CERN.
# Copyright (C) 2018 Esteban J. G. Garbancho.
# Copyright (C) 2024 Graz University of Technology.
#
# pytest-invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -284,6 +285,7 @@ def test_acase(base_app):
"""
# Use create_app from the module if defined, otherwise use default
# create_app fixture.

create_app = getattr(request.module, "create_app", create_app)
app_ = create_app(**app_config)

Expand Down Expand Up @@ -482,8 +484,8 @@ def database(appctx):
from invenio_db import db as db_
from sqlalchemy_utils.functions import create_database, database_exists

if not database_exists(str(db_.engine.url)):
create_database(str(db_.engine.url))
if not database_exists(str(db_.engine.url.render_as_string(hide_password=False))):
create_database(str(db_.engine.url.render_as_string(hide_password=False)))

# Use unlogged tables for PostgreSQL (see https://github.com/sqlalchemy/alembic/discussions/1108)
if db_.engine.name == "postgresql":
Expand Down Expand Up @@ -532,36 +534,39 @@ def db(database, db_session_options):
fixture will set a save point and rollback all changes performed during
the test (this is much faster than recreating the entire database).
"""
import sqlalchemy as sa
from flask_sqlalchemy.session import Session as FlaskSQLAlchemySession

class PytestInvenioSession(FlaskSQLAlchemySession):
def get_bind(self, mapper=None, clause=None, bind=None, **kwargs):
if self.bind:
return self.bind
return super().get_bind(mapper=mapper, clause=clause, bind=bind, **kwargs)

def rollback(self) -> None:
if self._transaction is None:
pass
else:
self._transaction.rollback(_to_root=False)

connection = database.engine.connect()
transaction = connection.begin()
connection.begin()

options = dict(
bind=connection,
binds={},
**db_session_options,
class_=PytestInvenioSession,
)
session = database.create_scoped_session(options=options)
session = database._make_scoped_session(options=options)

session.begin_nested()

# `session` is actually a scoped_session. For the `after_transaction_end`
# event, we need a session instance to listen for, hence the `session()`
# call.
@sa.event.listens_for(session(), "after_transaction_end")
def restart_savepoint(sess, trans):
if trans.nested and not trans._parent.nested:
session.expire_all()
session.begin_nested()

old_session = database.session
database.session = session

yield database

session.remove()
transaction.rollback()
session.rollback()
connection.close()
database.session = old_session

Expand Down Expand Up @@ -823,6 +828,12 @@ def entry_points(self):
group=group,
)

def read_text(self, *args, **kwargs):
"""Implement abstract method."""

def locate_file(self, *args, **kwargs):
"""Implement abstract method."""


@pytest.fixture(scope="module")
def entry_points(extra_entry_points):
Expand Down
26 changes: 12 additions & 14 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# This file is part of pytest-invenio.
# Copyright (C) 2017-2024 CERN.
# Copyright (C) 2022 Graz University of Technology.
# Copyright (C) 2022-2024 Graz University of Technology.
#
# pytest-invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -30,34 +30,32 @@ install_requires =
check-manifest>=0.42
coverage>=5.3,<8
docker-services-cli>=0.4.0
# See https://github.com/pytest-dev/pytest-flask/issues/167
Flask>=1.1.4,<2.3.0
pytest-cov>=3.0.0
pytest-flask>=1.2.0
pytest-github-actions-annotate-failures>=0.2.0
pytest-isort>=3.0.0
pytest-pydocstyle>=2.2.3
pytest-pycodestyle>=2.2.0
pytest>=6,<7.2.0
selenium>=3.7.0,<4
pytest>=6,<9.0.0
selenium>=3.7.0,<5
importlib-metadata>=4.4,<8.0.0
importlib-resources>=5.0

[options.extras_require]
tests =
pytest-black>=0.3.0
invenio-celery>=1.2.4,<2.0.0
invenio-db>=1.0.12,<2.0.0
invenio-files-rest>=1.3.2,<2.0.0
invenio-mail>=1.0.2,<2.0.0
invenio-search>=2.1.0,<3.0.0
pytest-black-ng>=0.4.0
invenio-celery>=2.0.0,<3.0.0
invenio-db>=2.0.0,<3.0.0
invenio-files-rest>=3.0.0,<4.0.0
invenio-mail>=1.0.2,<3.0.0
invenio-search>=3.0.0,<4.0.0
sphinx>=4.5
elasticsearch7 =
invenio-search[elasticsearch7]>=2.1.0,<3.0.0
invenio-search[elasticsearch7]>=3.0.0,<4.0.0
opensearch1 =
invenio-search[opensearch1]>=2.1.0,<3.0.0
invenio-search[opensearch1]>=3.0.0,<4.0.0
opensearch2 =
invenio-search[opensearch2]>=2.1.0,<3.0.0
invenio-search[opensearch2]>=3.0.0,<4.0.0
# Kept for backwards compatibility
docs =

Expand Down
19 changes: 9 additions & 10 deletions tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# This file is part of pytest-invenio.
# Copyright (C) 2017-2018 CERN.
# Copyright (C) 2024 Graz University of Technology.
#
# pytest-invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -337,7 +338,7 @@ def test_database(conftest_testdir):
conftest_testdir.makepyfile(
"""
def test_database(database, db_uri):
assert str(database.engine.url) == db_uri
assert str(database.engine.url.render_as_string(hide_password=False)) == db_uri
"""
)
conftest_testdir.runpytest().assert_outcomes(passed=1)
Expand All @@ -354,17 +355,15 @@ class UserA(db.Model):
username = db.Column(db.String(80), unique=True)

def test_db1(db):
assert UserA.query.count() == 0
assert db.session.query(UserA).count() == 0
db.session.add(UserA(username='alice'))
db.session.commit()
assert UserA.query.count() == 1
assert db.session.query(UserA).count() == 1

def test_db2(db):
assert UserA.query.count() == 0
assert db.session.query(UserA).count() == 0
db.session.add(UserA(username='alice'))
db.session.add(UserA(username='bob'))
db.session.commit()
assert UserA.query.count() == 2
assert db.session.query(UserA).count() == 2
"""
)
conftest_testdir.runpytest().assert_outcomes(passed=2)
Expand All @@ -381,7 +380,7 @@ class Place(db.Model):
id = db.Column(db.Integer, primary_key=True)

def test_app(app):
assert Place.query.count() == 0
assert db.session.query(Place).count() == 0
assert current_search_client.ping()
"""
)
Expand Down Expand Up @@ -564,7 +563,7 @@ def extra_entry_points():

def test_app(base_app, db):
from mock_module import Place
assert Place.query.count() == 0
assert db.session.query(Place).count() == 0

def test_extras(base_app, db):
for ep in db_entry_points():
Expand Down Expand Up @@ -627,7 +626,7 @@ def extra_entry_points():

def test_app(base_app, db):
from mock_module import Place
assert Place.query.count() == 0
assert db.session.query(Place).count() == 0

def test_extras(base_app, db):
for ep in db_entry_points():
Expand Down
Loading