diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/bootstrap/test_new_instance.py | 90 | ||||
-rw-r--r-- | tests/conftest.py | 1 | ||||
-rw-r--r-- | tests/integration/test_browse.py | 90 | ||||
-rw-r--r-- | tests/playwright/conftest.py | 11 | ||||
-rw-r--r-- | tests/playwright/test_basic.py | 27 | ||||
-rw-r--r-- | tests/playwright/test_profiles.py | 2 | ||||
-rw-r--r-- | tests/playwright/test_share.py | 3 | ||||
-rw-r--r-- | tests/playwright/test_tileproxy.py | 4 |
8 files changed, 192 insertions, 36 deletions
diff --git a/tests/bootstrap/test_new_instance.py b/tests/bootstrap/test_new_instance.py index dc3076e..05076f4 100644 --- a/tests/bootstrap/test_new_instance.py +++ b/tests/bootstrap/test_new_instance.py @@ -2,6 +2,7 @@ script, as described in the documentation. """ +import configparser import contextlib import logging import os @@ -10,6 +11,8 @@ import subprocess import venv from pathlib import Path +import sqlalchemy + LOGGER = logging.getLogger(__name__) REPO_BASE = Path(__file__).parent.parent.parent @@ -51,31 +54,66 @@ def create_config(config_name: Path): Path("data").mkdir() +def cleanup_database(config_name: Path): + """Connects to the database and ensures everything is reset. + + :param config_name: Path to the config file. + """ + if not config_name.exists(): + return + + parser = configparser.ConfigParser() + parser["DEFAULT"]["here"] = str(config_name.parent) + parser.read(config_name) + + db_url = parser["app:main"]["sqlalchemy.url"] + engine = sqlalchemy.create_engine(db_url) + + match engine.name: + case "sqlite": + pass + case "postgresql": + with engine.connect() as connection: + connection.execute(sqlalchemy.text("DROP SCHEMA public CASCADE;")) + connection.execute(sqlalchemy.text("CREATE SCHEMA public;")) + connection.commit() + + def test_setup_via_fietsupdate(tmpdir): with chdir(tmpdir): - # We create a new temporary virtual environment with a fresh install, just - # to be sure there's as little interference as possible. - LOGGER.info("Installing Fietsboek into clean env") - binaries_path = install_fietsboek(tmpdir / "venv") - - LOGGER.info("Creating a test configuration") - create_config(Path("testing.ini")) - - # Try to run the migrations - subprocess.check_call( - [binaries_path / "fietsupdate", "update", "-c", "testing.ini", "-f"] - ) - - # Also try to add an administrator - subprocess.check_call([ - binaries_path / "fietsctl", - "user", - "add", - "-c", "testing.ini", - "--email", "foobar@example.com", - "--name", "Foo Bar", - "--password", "raboof", - "--admin", - ]) - - assert True + try: + # We create a new temporary virtual environment with a fresh install, just + # to be sure there's as little interference as possible. + LOGGER.info("Installing Fietsboek into clean env") + binaries_path = install_fietsboek(tmpdir / "venv") + + LOGGER.info("Installing additional SQL engines") + subprocess.check_call( + [binaries_path / "pip", "install", "psycopg2"] + ) + + LOGGER.info("Creating a test configuration") + create_config(Path("testing.ini")) + + # Try to run the migrations + subprocess.check_call( + [binaries_path / "fietsupdate", "update", "-c", "testing.ini", "-f"] + ) + + # Also try to add an administrator + subprocess.check_call([ + binaries_path / "fietsctl", + "user", + "add", + "-c", "testing.ini", + "--email", "foobar@example.com", + "--name", "Foo Bar", + "--password", "raboof", + "--admin", + ]) + + assert True + finally: + # Clean up the database. This is important with anything but SQLite, as + # the tables would otherwise persist and interfere with the other tests. + cleanup_database(Path("testing.ini")) diff --git a/tests/conftest.py b/tests/conftest.py index cd74b0b..652d443 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -52,6 +52,7 @@ def dbengine(app_settings, ini_file): yield engine + engine.dispose() Base.metadata.drop_all(bind=engine) alembic.command.stamp(alembic_cfg, None, purge=True) diff --git a/tests/integration/test_browse.py b/tests/integration/test_browse.py index 875821d..83218cc 100644 --- a/tests/integration/test_browse.py +++ b/tests/integration/test_browse.py @@ -22,6 +22,7 @@ def added_tracks(tm, dbsession, owner, data_manager): tm.abort() tracks = [] + track_ids = [] with tm: track = models.Track( owner=owner, @@ -37,6 +38,7 @@ def added_tracks(tm, dbsession, owner, data_manager): dbsession.flush() data_manager.initialize(track.id).compress_gpx(load_gpx_asset("MyTourbook_1.gpx.gz")) tracks.append(track) + track_ids.append(track.id) track = models.Track( owner=owner, @@ -52,12 +54,62 @@ def added_tracks(tm, dbsession, owner, data_manager): dbsession.flush() data_manager.initialize(track.id).compress_gpx(load_gpx_asset("Teasi_1.gpx.gz")) tracks.append(track) + track_ids.append(track.id) tm.begin() tm.doom() try: - yield tracks + yield track_ids + finally: + tm.abort() + with tm: + for track in tracks: + dbsession.delete(track) + tm.begin() + tm.doom() + + +@contextmanager +def a_lot_of_tracks(tm, dbsession, owner, data_manager): + """Adds some tracks to the database session. + + This function should be used as a context manager and it ensures that the + added tracks are deleted again after the test, to make a clean slate for + the next test. + """ + # The normal transaction is "doomed", so we need to abort it, start a fresh + # one, and then explicitely commit it, otherwise we will not persist the + # objects to the database. + tm.abort() + + gpx_data = load_gpx_asset("MyTourbook_1.gpx.gz") + + tracks = [] + track_ids = [] + with tm: + for index in range(50): + track = models.Track( + owner=owner, + title=f"Traxi {index}", + visibility=Visibility.PUBLIC, + description="One of many", + badges=[], + link_secret="foobar", + tagged_people=[], + ) + track.date = datetime(2022 - index, 3, 14, 9, 26, 59) + dbsession.add(track) + dbsession.flush() + data_manager.initialize(track.id).compress_gpx(gpx_data) + tracks.append(track) + track_ids.append(track.id) + + tm.begin() + tm.doom() + + try: + yield track_ids finally: tm.abort() with tm: @@ -78,15 +130,43 @@ def test_browse(testapp, dbsession, route_path, logged_in, tm, data_manager): assert "Barfoo" in browse.text +def test_browse_paged(testapp, dbsession, route_path, logged_in, tm, data_manager): + # pylint: disable=too-many-positional-arguments + with a_lot_of_tracks(tm, dbsession, logged_in, data_manager): + page_1 = testapp.get(route_path("browse", _query=[("page", 1)])) + assert "Traxi 0" in page_1.text + assert "Traxi 10" in page_1.text + assert "Traxi 20" not in page_1.text + assert "Traxi 30" not in page_1.text + assert "Traxi 40" not in page_1.text + + page_2 = testapp.get(route_path("browse", _query=[("page", 2)])) + assert "Traxi 0" not in page_2.text + assert "Traxi 10" not in page_2.text + assert "Traxi 20" in page_2.text + assert "Traxi 30" in page_2.text + assert "Traxi 40" not in page_2.text + + page_3 = testapp.get(route_path("browse", _query=[("page", 3)])) + assert "Traxi 0" not in page_3.text + assert "Traxi 10" not in page_3.text + assert "Traxi 20" not in page_3.text + assert "Traxi 30" not in page_3.text + assert "Traxi 40" in page_3.text + + def test_archive(testapp, dbsession, route_path, logged_in, tm, data_manager): # pylint: disable=too-many-positional-arguments - with added_tracks(tm, dbsession, logged_in, data_manager): + with added_tracks(tm, dbsession, logged_in, data_manager) as tracks: archive = testapp.get( - route_path('track-archive', _query=[("track_id[]", "1"), ("track_id[]", "2")]) + route_path( + 'track-archive', + _query=[("track_id[]", tracks[0]), ("track_id[]", tracks[1])], + ) ) result = io.BytesIO(archive.body) with zipfile.ZipFile(result, 'r') as zipped: assert len(zipped.namelist()) == 2 - assert "track_1.gpx" in zipped.namelist() - assert "track_2.gpx" in zipped.namelist() + assert f"track_{tracks[0]}.gpx" in zipped.namelist() + assert f"track_{tracks[1]}.gpx" in zipped.namelist() diff --git a/tests/playwright/conftest.py b/tests/playwright/conftest.py index 4e7f5a4..adf5ef3 100644 --- a/tests/playwright/conftest.py +++ b/tests/playwright/conftest.py @@ -7,10 +7,12 @@ from wsgiref import simple_server from pyramid.authentication import AuthTktCookieHelper from pyramid.testing import DummyRequest +import fietsboek.config from testutils import load_gpx_asset from fietsboek import models, util, actions from fietsboek.models.track import Visibility, TrackType from fietsboek.config import Config +from fietsboek.views.tileproxy import TileRequester import pytest @@ -55,7 +57,11 @@ def dbaccess(app): through and the running WSGI app cannot read them. """ session_factory = app.registry["dbsession_factory"] - return session_factory() + factory = session_factory() + + yield factory + + factory.close() class Helper: @@ -112,11 +118,14 @@ class Helper: """ if user is None: user = self.john_doe() + config = fietsboek.config.parse(self.app_settings) with self.dbaccess: user = self.dbaccess.merge(user) track = actions.add_track( self.dbaccess, self.data_manager, + TileRequester(None), + config.public_tile_layers()[0], owner=user, title="Another awesome track", visibility=Visibility.PRIVATE, diff --git a/tests/playwright/test_basic.py b/tests/playwright/test_basic.py index 231962e..3ae0f58 100644 --- a/tests/playwright/test_basic.py +++ b/tests/playwright/test_basic.py @@ -101,6 +101,33 @@ def test_edit(page: Page, playwright_helper, dbaccess): assert track.description == "Not so descriptive anymore" +def test_edit_change_gpx(page: Page, playwright_helper, tmp_path, dbaccess): + playwright_helper.login() + track_id = playwright_helper.add_track().id + + track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one() + old_cache = track.cache.length, track.cache.uphill, track.cache.downhill + + page.goto(f"/track/{track_id}") + page.locator(".btn", has_text="Edit").click() + + gpx_data = load_gpx_asset("Synthetic_BRouter_1.gpx.gz") + gpx_path = tmp_path / "NewGPX.gpx" + with open(gpx_path, "wb") as gpx_fobj: + gpx_fobj.write(gpx_data) + + page.get_by_label("New file for this track").set_input_files(gpx_path) + page.locator(".btn", has_text="Save").click() + + track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one() + new_cache = track.cache + dbaccess.refresh(new_cache) + + assert old_cache[0] != new_cache.length + assert old_cache[1] != new_cache.uphill + assert old_cache[2] != new_cache.downhill + + def test_browse(page: Page, playwright_helper, dbaccess): playwright_helper.login() track = playwright_helper.add_track() diff --git a/tests/playwright/test_profiles.py b/tests/playwright/test_profiles.py index 7e5fb3c..ffbaab0 100644 --- a/tests/playwright/test_profiles.py +++ b/tests/playwright/test_profiles.py @@ -5,7 +5,7 @@ def test_forbidden(page: Page, playwright_helper): john = playwright_helper.john_doe() with page.expect_response(lambda resp: resp.status == 403): - page.goto(f"/user/{john.id}") + page.goto(f"/user/{john.id}/") def test_profile(page: Page, playwright_helper): diff --git a/tests/playwright/test_share.py b/tests/playwright/test_share.py index de288a0..dcba899 100644 --- a/tests/playwright/test_share.py +++ b/tests/playwright/test_share.py @@ -29,7 +29,8 @@ def test_view_wrong_link(page: Page, playwright_helper, dbaccess): with page.expect_response(lambda resp: resp.status == 403): page.goto(f"/track/{track.id}?secret=foobar") - assert "Forbidden" in page.content() + assert "No entry" in page.content() + assert "not allowed to access" in page.content() def test_change_link(page: Page, playwright_helper, dbaccess): diff --git a/tests/playwright/test_tileproxy.py b/tests/playwright/test_tileproxy.py index d4d3389..2a2bdc0 100644 --- a/tests/playwright/test_tileproxy.py +++ b/tests/playwright/test_tileproxy.py @@ -14,7 +14,7 @@ def test_tileproxy(page: Page, playwright_helper, caplog): # If we're too fast, the log entry might not be there yet, wait 2 more # seconds - if "Skipping tile proxy request for testing URL" not in caplog.messages: + if "Skipping tile request for testing URL" not in caplog.messages: time.sleep(2) - assert "Skipping tile proxy request for testing URL" in caplog.messages + assert "Skipping tile request for testing URL" in caplog.messages |