remove databases, use SQLAlechemy 2.0 instead
Among the many changes we switch to using SQLAlchemy's connection pool, which means we are no longer required to guard against multiple threads working on the database. All db funcs now receive a connection to use as their first argument, this allows the caller to control transaction & rollback behavior.
This commit is contained in:
parent
c63bee072f
commit
4981de4a04
12 changed files with 876 additions and 765 deletions
|
|
@ -17,16 +17,19 @@ def event_loop():
|
|||
|
||||
@pytest_asyncio.fixture(scope="session")
|
||||
async def shared_conn():
|
||||
c = db._shared_connection()
|
||||
await c.connect()
|
||||
"""A database connection, ready to use."""
|
||||
await db.open_connection_pool()
|
||||
|
||||
await db.apply_db_patches(c)
|
||||
yield c
|
||||
async with db.new_connection() as c:
|
||||
db._test_connection = c
|
||||
yield c
|
||||
db._test_connection = None
|
||||
|
||||
await c.disconnect()
|
||||
await db.close_connection_pool()
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def conn(shared_conn):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
async def conn(shared_conn: db.Connection):
|
||||
"""A transacted database connection, will be rolled back after use."""
|
||||
async with db.transacted(shared_conn, force_rollback=True):
|
||||
yield shared_conn
|
||||
|
|
|
|||
627
tests/test_db.py
627
tests/test_db.py
|
|
@ -4,7 +4,7 @@ import pytest
|
|||
|
||||
from unwind import db, models, web_models
|
||||
|
||||
_movie_imdb_id = 1234567
|
||||
_movie_imdb_id = 1230000
|
||||
|
||||
|
||||
def a_movie(**kwds) -> models.Movie:
|
||||
|
|
@ -21,394 +21,399 @@ def a_movie(**kwds) -> models.Movie:
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_current_patch_level(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
patch_level = "some-patch-level"
|
||||
assert patch_level != await db.current_patch_level(shared_conn)
|
||||
await db.set_current_patch_level(shared_conn, patch_level)
|
||||
assert patch_level == await db.current_patch_level(shared_conn)
|
||||
async def test_current_patch_level(conn: db.Connection):
|
||||
patch_level = "some-patch-level"
|
||||
assert patch_level != await db.current_patch_level(conn)
|
||||
await db.set_current_patch_level(conn, patch_level)
|
||||
assert patch_level == await db.current_patch_level(conn)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
async def test_get(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(m2)
|
||||
m2 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(conn, m2)
|
||||
|
||||
assert None is await db.get(models.Movie)
|
||||
assert None is await db.get(models.Movie, id="blerp")
|
||||
assert m1 == await db.get(models.Movie, id=str(m1.id))
|
||||
assert m2 == await db.get(models.Movie, release_year=m2.release_year)
|
||||
assert None is await db.get(
|
||||
models.Movie, id=str(m1.id), release_year=m2.release_year
|
||||
)
|
||||
assert m2 == await db.get(
|
||||
models.Movie, id=str(m2.id), release_year=m2.release_year
|
||||
)
|
||||
assert m1 == await db.get(
|
||||
models.Movie,
|
||||
media_type=m1.media_type,
|
||||
order_by=(models.movies.c.release_year, "asc"),
|
||||
)
|
||||
assert m2 == await db.get(
|
||||
models.Movie,
|
||||
media_type=m1.media_type,
|
||||
order_by=(models.movies.c.release_year, "desc"),
|
||||
)
|
||||
assert None is await db.get(conn, models.Movie)
|
||||
assert None is await db.get(conn, models.Movie, id="blerp")
|
||||
assert m1 == await db.get(conn, models.Movie, id=str(m1.id))
|
||||
assert m2 == await db.get(conn, models.Movie, release_year=m2.release_year)
|
||||
assert None is await db.get(
|
||||
conn, models.Movie, id=str(m1.id), release_year=m2.release_year
|
||||
)
|
||||
assert m2 == await db.get(
|
||||
conn, models.Movie, id=str(m2.id), release_year=m2.release_year
|
||||
)
|
||||
assert m1 == await db.get(
|
||||
conn,
|
||||
models.Movie,
|
||||
media_type=m1.media_type,
|
||||
order_by=(models.movies.c.release_year, "asc"),
|
||||
)
|
||||
assert m2 == await db.get(
|
||||
conn,
|
||||
models.Movie,
|
||||
media_type=m1.media_type,
|
||||
order_by=(models.movies.c.release_year, "desc"),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_all(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
async def test_get_all(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie(release_year=m1.release_year)
|
||||
await db.add(m2)
|
||||
m2 = a_movie(release_year=m1.release_year)
|
||||
await db.add(conn, m2)
|
||||
|
||||
m3 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(m3)
|
||||
m3 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(conn, m3)
|
||||
|
||||
assert [] == list(await db.get_all(models.Movie, id="blerp"))
|
||||
assert [m1] == list(await db.get_all(models.Movie, id=str(m1.id)))
|
||||
assert [m1, m2] == list(
|
||||
await db.get_all(models.Movie, release_year=m1.release_year)
|
||||
)
|
||||
assert [m1, m2, m3] == list(await db.get_all(models.Movie))
|
||||
assert [] == list(await db.get_all(conn, models.Movie, id="blerp"))
|
||||
assert [m1] == list(await db.get_all(conn, models.Movie, id=str(m1.id)))
|
||||
assert [m1, m2] == list(
|
||||
await db.get_all(conn, models.Movie, release_year=m1.release_year)
|
||||
)
|
||||
assert [m1, m2, m3] == list(await db.get_all(conn, models.Movie))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_many(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
async def test_get_many(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie(release_year=m1.release_year)
|
||||
await db.add(m2)
|
||||
m2 = a_movie(release_year=m1.release_year)
|
||||
await db.add(conn, m2)
|
||||
|
||||
m3 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(m3)
|
||||
m3 = a_movie(release_year=m1.release_year + 1)
|
||||
await db.add(conn, m3)
|
||||
|
||||
assert [] == list(await db.get_many(models.Movie)), "selected nothing"
|
||||
assert [m1] == list(await db.get_many(models.Movie, id=[str(m1.id)]))
|
||||
assert [m1] == list(await db.get_many(models.Movie, id={str(m1.id)}))
|
||||
assert [m1, m2] == list(
|
||||
await db.get_many(models.Movie, release_year=[m1.release_year])
|
||||
)
|
||||
assert [m1, m2, m3] == list(
|
||||
await db.get_many(
|
||||
models.Movie, release_year=[m1.release_year, m3.release_year]
|
||||
)
|
||||
assert [] == list(await db.get_many(conn, models.Movie)), "selected nothing"
|
||||
assert [m1] == list(await db.get_many(conn, models.Movie, id=[str(m1.id)]))
|
||||
assert [m1] == list(await db.get_many(conn, models.Movie, id={str(m1.id)}))
|
||||
assert [m1, m2] == list(
|
||||
await db.get_many(conn, models.Movie, release_year=[m1.release_year])
|
||||
)
|
||||
assert [m1, m2, m3] == list(
|
||||
await db.get_many(
|
||||
conn, models.Movie, release_year=[m1.release_year, m3.release_year]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_and_get(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
async def test_add_and_get(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie()
|
||||
await db.add(m2)
|
||||
m2 = a_movie()
|
||||
await db.add(conn, m2)
|
||||
|
||||
assert m1 == await db.get(models.Movie, id=str(m1.id))
|
||||
assert m2 == await db.get(models.Movie, id=str(m2.id))
|
||||
assert m1 == await db.get(conn, models.Movie, id=str(m1.id))
|
||||
assert m2 == await db.get(conn, models.Movie, id=str(m2.id))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m = a_movie()
|
||||
await db.add(m)
|
||||
async def test_update(conn: db.Connection):
|
||||
m = a_movie()
|
||||
await db.add(conn, m)
|
||||
|
||||
assert m == await db.get(models.Movie, id=str(m.id))
|
||||
m.title += "something else"
|
||||
assert m != await db.get(models.Movie, id=str(m.id))
|
||||
assert m == await db.get(conn, models.Movie, id=str(m.id))
|
||||
m.title += "something else"
|
||||
assert m != await db.get(conn, models.Movie, id=str(m.id))
|
||||
|
||||
await db.update(m)
|
||||
assert m == await db.get(models.Movie, id=str(m.id))
|
||||
await db.update(conn, m)
|
||||
assert m == await db.get(conn, models.Movie, id=str(m.id))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remove(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
assert m1 == await db.get(models.Movie, id=str(m1.id))
|
||||
async def test_remove(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
assert m1 == await db.get(conn, models.Movie, id=str(m1.id))
|
||||
|
||||
await db.remove(m1)
|
||||
assert None is await db.get(models.Movie, id=str(m1.id))
|
||||
await db.remove(conn, m1)
|
||||
assert None is await db.get(conn, models.Movie, id=str(m1.id))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_find_ratings(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(m1)
|
||||
async def test_find_ratings(conn: db.Connection):
|
||||
m1 = a_movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie(
|
||||
title="it's anöther Movie, Part 2",
|
||||
release_year=2015,
|
||||
genres={"genre-2"},
|
||||
)
|
||||
await db.add(m2)
|
||||
m2 = a_movie(
|
||||
title="it's anöther Movie, Part 2",
|
||||
release_year=2015,
|
||||
genres={"genre-2"},
|
||||
)
|
||||
await db.add(conn, m2)
|
||||
|
||||
m3 = a_movie(
|
||||
title="movie it's, Part 3",
|
||||
release_year=m2.release_year,
|
||||
genres=m2.genres,
|
||||
)
|
||||
await db.add(m3)
|
||||
m3 = a_movie(
|
||||
title="movie it's, Part 3",
|
||||
release_year=m2.release_year,
|
||||
genres=m2.genres,
|
||||
)
|
||||
await db.add(conn, m3)
|
||||
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(u1)
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(conn, u1)
|
||||
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(u2)
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(conn, u2)
|
||||
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(r1)
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(conn, r1)
|
||||
|
||||
r2 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u2.id,
|
||||
user=u2,
|
||||
score=77,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(r2)
|
||||
r2 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u2.id,
|
||||
user=u2,
|
||||
score=77,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(conn, r2)
|
||||
|
||||
# ---
|
||||
# ---
|
||||
|
||||
rows = await db.find_ratings(
|
||||
title=m1.title,
|
||||
media_type=m1.media_type,
|
||||
exact=True,
|
||||
ignore_tv_episodes=True,
|
||||
include_unrated=True,
|
||||
yearcomp=("=", m1.release_year),
|
||||
limit_rows=3,
|
||||
user_ids=[],
|
||||
)
|
||||
ratings = (web_models.Rating(**r) for r in rows)
|
||||
assert (web_models.RatingAggregate.from_movie(m1),) == tuple(
|
||||
web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
)
|
||||
rows = await db.find_ratings(
|
||||
conn,
|
||||
title=m1.title,
|
||||
media_type=m1.media_type,
|
||||
exact=True,
|
||||
ignore_tv_episodes=True,
|
||||
include_unrated=True,
|
||||
yearcomp=("=", m1.release_year),
|
||||
limit_rows=3,
|
||||
user_ids=[],
|
||||
)
|
||||
ratings = (web_models.Rating(**r) for r in rows)
|
||||
assert (web_models.RatingAggregate.from_movie(m1),) == tuple(
|
||||
web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
)
|
||||
|
||||
rows = await db.find_ratings(title="movie", include_unrated=False)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (
|
||||
web_models.Rating.from_movie(m2, rating=r1),
|
||||
web_models.Rating.from_movie(m2, rating=r2),
|
||||
) == ratings
|
||||
rows = await db.find_ratings(conn, title="movie", include_unrated=False)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (
|
||||
web_models.Rating.from_movie(m2, rating=r1),
|
||||
web_models.Rating.from_movie(m2, rating=r2),
|
||||
) == ratings
|
||||
|
||||
rows = await db.find_ratings(title="movie", include_unrated=True)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (
|
||||
web_models.Rating.from_movie(m1),
|
||||
web_models.Rating.from_movie(m2, rating=r1),
|
||||
web_models.Rating.from_movie(m2, rating=r2),
|
||||
web_models.Rating.from_movie(m3),
|
||||
) == ratings
|
||||
rows = await db.find_ratings(conn, title="movie", include_unrated=True)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (
|
||||
web_models.Rating.from_movie(m1),
|
||||
web_models.Rating.from_movie(m2, rating=r1),
|
||||
web_models.Rating.from_movie(m2, rating=r2),
|
||||
web_models.Rating.from_movie(m3),
|
||||
) == ratings
|
||||
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
assert tuple(
|
||||
web_models.RatingAggregate.from_movie(m) for m in [m1, m2, m3]
|
||||
) == tuple(aggr)
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
assert tuple(
|
||||
web_models.RatingAggregate.from_movie(m) for m in [m1, m2, m3]
|
||||
) == tuple(aggr)
|
||||
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[str(u1.id)])
|
||||
assert (
|
||||
web_models.RatingAggregate.from_movie(m1),
|
||||
web_models.RatingAggregate.from_movie(m2, ratings=[r1]),
|
||||
web_models.RatingAggregate.from_movie(m3),
|
||||
) == tuple(aggr)
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[str(u1.id)])
|
||||
assert (
|
||||
web_models.RatingAggregate.from_movie(m1),
|
||||
web_models.RatingAggregate.from_movie(m2, ratings=[r1]),
|
||||
web_models.RatingAggregate.from_movie(m3),
|
||||
) == tuple(aggr)
|
||||
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[str(u1.id), str(u2.id)])
|
||||
assert (
|
||||
web_models.RatingAggregate.from_movie(m1),
|
||||
web_models.RatingAggregate.from_movie(m2, ratings=[r1, r2]),
|
||||
web_models.RatingAggregate.from_movie(m3),
|
||||
) == tuple(aggr)
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[str(u1.id), str(u2.id)])
|
||||
assert (
|
||||
web_models.RatingAggregate.from_movie(m1),
|
||||
web_models.RatingAggregate.from_movie(m2, ratings=[r1, r2]),
|
||||
web_models.RatingAggregate.from_movie(m3),
|
||||
) == tuple(aggr)
|
||||
|
||||
rows = await db.find_ratings(title="movie", include_unrated=True)
|
||||
ratings = (web_models.Rating(**r) for r in rows)
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
assert tuple(
|
||||
web_models.RatingAggregate.from_movie(m) for m in [m1, m2, m3]
|
||||
) == tuple(aggr)
|
||||
rows = await db.find_ratings(conn, title="movie", include_unrated=True)
|
||||
ratings = (web_models.Rating(**r) for r in rows)
|
||||
aggr = web_models.aggregate_ratings(ratings, user_ids=[])
|
||||
assert tuple(
|
||||
web_models.RatingAggregate.from_movie(m) for m in [m1, m2, m3]
|
||||
) == tuple(aggr)
|
||||
|
||||
rows = await db.find_ratings(title="test", include_unrated=True)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (web_models.Rating.from_movie(m1),) == ratings
|
||||
rows = await db.find_ratings(conn, title="test", include_unrated=True)
|
||||
ratings = tuple(web_models.Rating(**r) for r in rows)
|
||||
assert (web_models.Rating.from_movie(m1),) == ratings
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ratings_for_movies(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie()
|
||||
await db.add(m1)
|
||||
async def test_ratings_for_movies(conn: db.Connection):
|
||||
m1 = a_movie()
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie()
|
||||
await db.add(m2)
|
||||
m2 = a_movie()
|
||||
await db.add(conn, m2)
|
||||
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(u1)
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(conn, u1)
|
||||
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(u2)
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(conn, u2)
|
||||
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(r1)
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(conn, r1)
|
||||
|
||||
# ---
|
||||
# ---
|
||||
|
||||
movie_ids = [m1.id]
|
||||
user_ids = []
|
||||
assert tuple() == tuple(
|
||||
await db.ratings_for_movies(movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
movie_ids = [m1.id]
|
||||
user_ids = []
|
||||
assert tuple() == tuple(
|
||||
await db.ratings_for_movies(conn, movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
|
||||
movie_ids = [m2.id]
|
||||
user_ids = []
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
movie_ids = [m2.id]
|
||||
user_ids = []
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(conn, movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
|
||||
movie_ids = [m2.id]
|
||||
user_ids = [u2.id]
|
||||
assert tuple() == tuple(
|
||||
await db.ratings_for_movies(movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
movie_ids = [m2.id]
|
||||
user_ids = [u2.id]
|
||||
assert tuple() == tuple(
|
||||
await db.ratings_for_movies(conn, movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
|
||||
movie_ids = [m2.id]
|
||||
user_ids = [u1.id]
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
movie_ids = [m2.id]
|
||||
user_ids = [u1.id]
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(conn, movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
|
||||
movie_ids = [m1.id, m2.id]
|
||||
user_ids = [u1.id, u2.id]
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
movie_ids = [m1.id, m2.id]
|
||||
user_ids = [u1.id, u2.id]
|
||||
assert (r1,) == tuple(
|
||||
await db.ratings_for_movies(conn, movie_ids=movie_ids, user_ids=user_ids)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_find_movies(shared_conn: db.Database):
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
m1 = a_movie(title="movie one")
|
||||
await db.add(m1)
|
||||
async def test_find_movies(conn: db.Connection):
|
||||
m1 = a_movie(title="movie one")
|
||||
await db.add(conn, m1)
|
||||
|
||||
m2 = a_movie(title="movie two", imdb_score=33, release_year=m1.release_year + 1)
|
||||
await db.add(m2)
|
||||
m2 = a_movie(title="movie two", imdb_score=33, release_year=m1.release_year + 1)
|
||||
await db.add(conn, m2)
|
||||
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(u1)
|
||||
u1 = models.User(
|
||||
imdb_id="u00001",
|
||||
name="User1",
|
||||
secret="secret1",
|
||||
)
|
||||
await db.add(conn, u1)
|
||||
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(u2)
|
||||
u2 = models.User(
|
||||
imdb_id="u00002",
|
||||
name="User2",
|
||||
secret="secret2",
|
||||
)
|
||||
await db.add(conn, u2)
|
||||
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(r1)
|
||||
r1 = models.Rating(
|
||||
movie_id=m2.id,
|
||||
movie=m2,
|
||||
user_id=u1.id,
|
||||
user=u1,
|
||||
score=66,
|
||||
rating_date=datetime.now(),
|
||||
)
|
||||
await db.add(conn, r1)
|
||||
|
||||
# ---
|
||||
# ---
|
||||
|
||||
assert () == tuple(await db.find_movies(title=m1.title, include_unrated=False))
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(title=m1.title, include_unrated=True)
|
||||
)
|
||||
assert () == tuple(
|
||||
await db.find_movies(conn, title=m1.title, include_unrated=False)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(conn, title=m1.title, include_unrated=True)
|
||||
)
|
||||
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(title="mo on", exact=False, include_unrated=True)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(title="movie one", exact=True, include_unrated=True)
|
||||
)
|
||||
assert () == tuple(
|
||||
await db.find_movies(title="mo on", exact=True, include_unrated=True)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(conn, title="mo on", exact=False, include_unrated=True)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(conn, title="movie one", exact=True, include_unrated=True)
|
||||
)
|
||||
assert () == tuple(
|
||||
await db.find_movies(conn, title="mo on", exact=True, include_unrated=True)
|
||||
)
|
||||
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(title="movie", exact=False, include_unrated=False)
|
||||
)
|
||||
assert ((m2, []), (m1, [])) == tuple(
|
||||
await db.find_movies(title="movie", exact=False, include_unrated=True)
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(conn, title="movie", exact=False, include_unrated=False)
|
||||
)
|
||||
assert ((m2, []), (m1, [])) == tuple(
|
||||
await db.find_movies(conn, title="movie", exact=False, include_unrated=True)
|
||||
)
|
||||
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, yearcomp=("=", m1.release_year))
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(
|
||||
conn, include_unrated=True, yearcomp=("=", m1.release_year)
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, yearcomp=("=", m2.release_year))
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(
|
||||
conn, include_unrated=True, yearcomp=("=", m2.release_year)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, yearcomp=("<", m2.release_year))
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(
|
||||
conn, include_unrated=True, yearcomp=("<", m2.release_year)
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, yearcomp=(">", m1.release_year))
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(
|
||||
conn, include_unrated=True, yearcomp=(">", m1.release_year)
|
||||
)
|
||||
)
|
||||
|
||||
assert ((m2, []), (m1, [])) == tuple(await db.find_movies(include_unrated=True))
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, limit_rows=1)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(include_unrated=True, skip_rows=1)
|
||||
)
|
||||
assert ((m2, []), (m1, [])) == tuple(
|
||||
await db.find_movies(conn, include_unrated=True)
|
||||
)
|
||||
assert ((m2, []),) == tuple(
|
||||
await db.find_movies(conn, include_unrated=True, limit_rows=1)
|
||||
)
|
||||
assert ((m1, []),) == tuple(
|
||||
await db.find_movies(conn, include_unrated=True, skip_rows=1)
|
||||
)
|
||||
|
||||
assert ((m2, [r1]), (m1, [])) == tuple(
|
||||
await db.find_movies(include_unrated=True, user_ids=[u1.id, u2.id])
|
||||
)
|
||||
assert ((m2, [r1]), (m1, [])) == tuple(
|
||||
await db.find_movies(conn, include_unrated=True, user_ids=[u1.id, u2.id])
|
||||
)
|
||||
|
|
|
|||
11
tests/test_models.py
Normal file
11
tests/test_models.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import pytest
|
||||
|
||||
from unwind import models
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mapper", models.mapper_registry.mappers)
|
||||
def test_fields(mapper):
|
||||
"""Test that models.fields() matches exactly all table columns."""
|
||||
dcfields = {f.name for f in models.fields(mapper.class_)}
|
||||
mfields = {c.name for c in mapper.columns}
|
||||
assert dcfields == mfields
|
||||
|
|
@ -34,7 +34,7 @@ def admin_client() -> TestClient:
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_ratings_for_group(
|
||||
shared_conn: db.Database, unauthorized_client: TestClient
|
||||
conn: db.Connection, unauthorized_client: TestClient
|
||||
):
|
||||
user = models.User(
|
||||
imdb_id="ur12345678",
|
||||
|
|
@ -48,201 +48,196 @@ async def test_get_ratings_for_group(
|
|||
)
|
||||
user.groups = [models.UserGroup(id=str(group.id), access="r")]
|
||||
path = app.url_path_for("get_ratings_for_group", group_id=str(group.id))
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
resp = unauthorized_client.get(path)
|
||||
assert resp.status_code == 404, "Group does not exist (yet)"
|
||||
|
||||
await db.add(user)
|
||||
await db.add(group)
|
||||
resp = unauthorized_client.get(path)
|
||||
assert resp.status_code == 404, "Group does not exist (yet)"
|
||||
|
||||
resp = unauthorized_client.get(path)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
await db.add(conn, user)
|
||||
await db.add(conn, group)
|
||||
|
||||
movie = models.Movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
media_type="Movie",
|
||||
imdb_id="tt12345678",
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(movie)
|
||||
resp = unauthorized_client.get(path)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
|
||||
rating = models.Rating(
|
||||
movie_id=movie.id, user_id=user.id, score=66, rating_date=datetime.now()
|
||||
)
|
||||
await db.add(rating)
|
||||
movie = models.Movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
media_type="Movie",
|
||||
imdb_id="tt12345678",
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(conn, movie)
|
||||
|
||||
rating_aggregate = {
|
||||
"canonical_title": movie.title,
|
||||
"imdb_score": movie.imdb_score,
|
||||
"imdb_votes": movie.imdb_votes,
|
||||
"link": imdb.movie_url(movie.imdb_id),
|
||||
"media_type": movie.media_type,
|
||||
"original_title": movie.original_title,
|
||||
"user_scores": [rating.score],
|
||||
"year": movie.release_year,
|
||||
}
|
||||
rating = models.Rating(
|
||||
movie_id=movie.id, user_id=user.id, score=66, rating_date=datetime.now()
|
||||
)
|
||||
await db.add(conn, rating)
|
||||
|
||||
resp = unauthorized_client.get(path)
|
||||
rating_aggregate = {
|
||||
"canonical_title": movie.title,
|
||||
"imdb_score": movie.imdb_score,
|
||||
"imdb_votes": movie.imdb_votes,
|
||||
"link": imdb.movie_url(movie.imdb_id),
|
||||
"media_type": movie.media_type,
|
||||
"original_title": movie.original_title,
|
||||
"user_scores": [rating.score],
|
||||
"year": movie.release_year,
|
||||
}
|
||||
|
||||
resp = unauthorized_client.get(path)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
|
||||
filters = {
|
||||
"imdb_id": movie.imdb_id,
|
||||
"unwind_id": str(movie.id),
|
||||
"title": movie.title,
|
||||
"media_type": movie.media_type,
|
||||
"year": movie.release_year,
|
||||
}
|
||||
for k, v in filters.items():
|
||||
resp = unauthorized_client.get(path, params={k: v})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
|
||||
filters = {
|
||||
"imdb_id": movie.imdb_id,
|
||||
"unwind_id": str(movie.id),
|
||||
"title": movie.title,
|
||||
"media_type": movie.media_type,
|
||||
"year": movie.release_year,
|
||||
}
|
||||
for k, v in filters.items():
|
||||
resp = unauthorized_client.get(path, params={k: v})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
resp = unauthorized_client.get(path, params={"title": "no such thing"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
|
||||
resp = unauthorized_client.get(path, params={"title": "no such thing"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
# Test "exact" query param.
|
||||
resp = unauthorized_client.get(
|
||||
path, params={"title": "test movie", "exact": "true"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
resp = unauthorized_client.get(path, params={"title": "te mo", "exact": "false"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
resp = unauthorized_client.get(path, params={"title": "te mo", "exact": "true"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
|
||||
# Test "exact" query param.
|
||||
resp = unauthorized_client.get(
|
||||
path, params={"title": "test movie", "exact": "true"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
resp = unauthorized_client.get(
|
||||
path, params={"title": "te mo", "exact": "false"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == [rating_aggregate]
|
||||
resp = unauthorized_client.get(path, params={"title": "te mo", "exact": "true"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
|
||||
# XXX Test "ignore_tv_episodes" query param.
|
||||
# XXX Test "include_unrated" query param.
|
||||
# XXX Test "per_page" query param.
|
||||
# XXX Test "ignore_tv_episodes" query param.
|
||||
# XXX Test "include_unrated" query param.
|
||||
# XXX Test "per_page" query param.
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_movies(
|
||||
shared_conn: db.Database,
|
||||
conn: db.Connection,
|
||||
unauthorized_client: TestClient,
|
||||
authorized_client: TestClient,
|
||||
):
|
||||
path = app.url_path_for("list_movies")
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
|
||||
m = models.Movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
media_type="Movie",
|
||||
imdb_id="tt12345678",
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(m)
|
||||
m = models.Movie(
|
||||
title="test movie",
|
||||
release_year=2013,
|
||||
media_type="Movie",
|
||||
imdb_id="tt12345678",
|
||||
genres={"genre-1"},
|
||||
)
|
||||
await db.add(conn, m)
|
||||
|
||||
response = authorized_client.get(path, params={"include_unrated": 1})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [{**models.asplain(m), "user_scores": []}]
|
||||
response = authorized_client.get(path, params={"include_unrated": 1})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [{**models.asplain(m), "user_scores": []}]
|
||||
|
||||
m_plain = {
|
||||
"canonical_title": m.title,
|
||||
"imdb_score": m.imdb_score,
|
||||
"imdb_votes": m.imdb_votes,
|
||||
"link": imdb.movie_url(m.imdb_id),
|
||||
"media_type": m.media_type,
|
||||
"original_title": m.original_title,
|
||||
"user_scores": [],
|
||||
"year": m.release_year,
|
||||
}
|
||||
m_plain = {
|
||||
"canonical_title": m.title,
|
||||
"imdb_score": m.imdb_score,
|
||||
"imdb_votes": m.imdb_votes,
|
||||
"link": imdb.movie_url(m.imdb_id),
|
||||
"media_type": m.media_type,
|
||||
"original_title": m.original_title,
|
||||
"user_scores": [],
|
||||
"year": m.release_year,
|
||||
}
|
||||
|
||||
response = authorized_client.get(path, params={"imdb_id": m.imdb_id})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
response = authorized_client.get(path, params={"imdb_id": m.imdb_id})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
|
||||
response = authorized_client.get(path, params={"unwind_id": str(m.id)})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
response = authorized_client.get(path, params={"unwind_id": str(m.id)})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_users(
|
||||
shared_conn: db.Database,
|
||||
conn: db.Connection,
|
||||
unauthorized_client: TestClient,
|
||||
authorized_client: TestClient,
|
||||
admin_client: TestClient,
|
||||
):
|
||||
path = app.url_path_for("list_users")
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
|
||||
m = models.User(
|
||||
imdb_id="ur12345678",
|
||||
name="user-1",
|
||||
secret="secret-1",
|
||||
groups=[],
|
||||
)
|
||||
await db.add(m)
|
||||
m = models.User(
|
||||
imdb_id="ur12345678",
|
||||
name="user-1",
|
||||
secret="secret-1",
|
||||
groups=[],
|
||||
)
|
||||
await db.add(conn, m)
|
||||
|
||||
m_plain = {
|
||||
"groups": m.groups,
|
||||
"id": m.id,
|
||||
"imdb_id": m.imdb_id,
|
||||
"name": m.name,
|
||||
"secret": m.secret,
|
||||
}
|
||||
m_plain = {
|
||||
"groups": m.groups,
|
||||
"id": m.id,
|
||||
"imdb_id": m.imdb_id,
|
||||
"name": m.name,
|
||||
"secret": m.secret,
|
||||
}
|
||||
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_groups(
|
||||
shared_conn: db.Database,
|
||||
conn: db.Connection,
|
||||
unauthorized_client: TestClient,
|
||||
authorized_client: TestClient,
|
||||
admin_client: TestClient,
|
||||
):
|
||||
path = app.url_path_for("list_groups")
|
||||
async with shared_conn.transaction(force_rollback=True):
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
response = unauthorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
response = authorized_client.get(path)
|
||||
assert response.status_code == 403
|
||||
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
|
||||
m = models.Group(
|
||||
name="group-1",
|
||||
users=[models.GroupUser(id="123", name="itsa-me")],
|
||||
)
|
||||
await db.add(m)
|
||||
m = models.Group(
|
||||
name="group-1",
|
||||
users=[models.GroupUser(id="123", name="itsa-me")],
|
||||
)
|
||||
await db.add(conn, m)
|
||||
|
||||
m_plain = {
|
||||
"users": m.users,
|
||||
"id": m.id,
|
||||
"name": m.name,
|
||||
}
|
||||
m_plain = {
|
||||
"users": m.users,
|
||||
"id": m.id,
|
||||
"name": m.name,
|
||||
}
|
||||
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
response = admin_client.get(path)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [m_plain]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue