Skip to content

Commit 437fc0a

Browse files
committed
fixes tests
1 parent f1bf044 commit 437fc0a

File tree

1 file changed

+135
-65
lines changed

1 file changed

+135
-65
lines changed

packages/postgres-database/tests/test_models_products_prices.py

Lines changed: 135 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import pytest
1010
import sqlalchemy as sa
11-
from asyncpg.exceptions import CheckViolationError, ForeignKeyViolationError
11+
import sqlalchemy.exc
1212
from faker import Faker
1313
from pytest_simcore.helpers.faker_factories import random_product
1414
from simcore_postgres_database.models.products import products
@@ -24,45 +24,82 @@
2424

2525
@pytest.fixture
2626
async def connection(asyncpg_engine: AsyncEngine) -> AsyncIterator[AsyncConnection]:
27-
async with asyncpg_engine.begin() as conn:
27+
async with asyncpg_engine.connect() as conn:
28+
isolation_level = await conn.get_isolation_level()
29+
assert isolation_level == "READ COMMITTED"
2830
yield conn
2931

3032

3133
@pytest.fixture
3234
async def fake_product(connection: AsyncConnection) -> Row:
3335
result = await connection.execute(
3436
products.insert()
35-
.values(random_product(group_id=None))
36-
.returning(sa.literal_column("*"))
37+
.values(random_product(name="tip", group_id=None))
38+
.returning(sa.literal_column("*")),
3739
)
40+
await connection.commit()
41+
42+
async with connection.begin():
43+
result = await connection.execute(
44+
products.insert()
45+
.values(random_product(name="s4l", group_id=None))
46+
.returning(sa.literal_column("*")),
47+
)
48+
3849
return result.one()
3950

4051

4152
async def test_creating_product_prices(
42-
connection: AsyncConnection, fake_product: Row, faker: Faker
53+
asyncpg_engine: AsyncEngine,
54+
connection: AsyncConnection,
55+
fake_product: Row,
56+
faker: Faker,
4357
):
44-
4558
# a price per product
46-
result = await connection.execute(
47-
products_prices.insert()
48-
.values(
49-
product_name=fake_product.name,
50-
usd_per_credit=100,
51-
comment="PO Mr X",
52-
stripe_price_id=faker.word(),
53-
stripe_tax_rate_id=faker.word(),
59+
async with connection.begin():
60+
result = await connection.execute(
61+
products_prices.insert()
62+
.values(
63+
product_name=fake_product.name,
64+
usd_per_credit=100,
65+
comment="PO Mr X",
66+
stripe_price_id=faker.word(),
67+
stripe_tax_rate_id=faker.word(),
68+
)
69+
.returning(sa.literal_column("*")),
5470
)
55-
.returning(sa.literal_column("*"))
56-
)
57-
product_prices = result.one()
58-
assert product_prices
71+
got = result.one()
72+
assert got
73+
74+
# insert still NOT commited but can read from this connection
75+
read_query = sa.select(products_prices).where(
76+
products_prices.c.product_name == fake_product.name
77+
)
78+
result = await connection.execute(read_query)
79+
assert result.one()._asdict() == got._asdict()
80+
81+
assert connection.in_transaction() is True
82+
83+
# cannot read from other connection though
84+
async with asyncpg_engine.connect() as other_connection:
85+
result = await other_connection.execute(read_query)
86+
assert result.one_or_none() is None
87+
88+
# AFTER commit
89+
assert connection.in_transaction() is False
90+
async with asyncpg_engine.connect() as yet_another_connection:
91+
result = await yet_another_connection.execute(read_query)
92+
assert result.one()._asdict() == got._asdict()
5993

6094

6195
async def test_non_negative_price_not_allowed(
6296
connection: AsyncConnection, fake_product: Row, faker: Faker
6397
):
64-
# negative price not allowed
65-
with pytest.raises(CheckViolationError) as exc_info:
98+
99+
assert not connection.in_transaction()
100+
101+
# WRITE: negative price not allowed
102+
with pytest.raises(sqlalchemy.exc.IntegrityError) as exc_info:
66103
await connection.execute(
67104
products_prices.insert().values(
68105
product_name=fake_product.name,
@@ -74,42 +111,72 @@ async def test_non_negative_price_not_allowed(
74111
)
75112

76113
assert exc_info.value
114+
assert connection.in_transaction()
115+
await connection.rollback()
116+
assert not connection.in_transaction()
77117

78-
# zero price is allowed
79-
await connection.execute(
80-
products_prices.insert().values(
118+
# WRITE: zero price is allowed
119+
result = await connection.execute(
120+
products_prices.insert()
121+
.values(
81122
product_name=fake_product.name,
82123
usd_per_credit=0, # <----- ZERO
83124
comment="PO Mr X",
84125
stripe_price_id=faker.word(),
85126
stripe_tax_rate_id=faker.word(),
86127
)
128+
.returning("*")
87129
)
88130

131+
assert result.one()
132+
133+
assert connection.in_transaction()
134+
await connection.commit()
135+
assert not connection.in_transaction()
136+
137+
with pytest.raises(sqlalchemy.exc.ResourceClosedError):
138+
# can only get result once!
139+
assert result.one()
140+
141+
# READ
142+
result = await connection.execute(sa.select(products_prices))
143+
assert connection.in_transaction()
144+
145+
assert result.one()
146+
with pytest.raises(sqlalchemy.exc.ResourceClosedError):
147+
# can only get result once!
148+
assert result.one()
149+
89150

90151
async def test_delete_price_constraints(
91152
connection: AsyncConnection, fake_product: Row, faker: Faker
92153
):
93154
# products_prices
94-
await connection.execute(
95-
products_prices.insert().values(
96-
product_name=fake_product.name,
97-
usd_per_credit=10,
98-
comment="PO Mr X",
99-
stripe_price_id=faker.word(),
100-
stripe_tax_rate_id=faker.word(),
155+
async with connection.begin():
156+
await connection.execute(
157+
products_prices.insert().values(
158+
product_name=fake_product.name,
159+
usd_per_credit=10,
160+
comment="PO Mr X",
161+
stripe_price_id=faker.word(),
162+
stripe_tax_rate_id=faker.word(),
163+
)
101164
)
102-
)
103165

166+
# BAD DELETE:
104167
# should not be able to delete a product w/o deleting price first
105-
with pytest.raises(ForeignKeyViolationError) as exc_info:
106-
await connection.execute(products.delete())
168+
async with connection.begin():
169+
with pytest.raises(sqlalchemy.exc.IntegrityError, match="delete") as exc_info:
170+
await connection.execute(products.delete())
107171

108-
assert exc_info.match("delete")
172+
# NOTE: that asyncpg.exceptions are converted to sqlalchemy.exc
173+
# sqlalchemy.exc.IntegrityError: (sqlalchemy.dialects.postgresql.asyncpg.IntegrityError) <class 'asyncpg.exceptions.ForeignKeyViolationError'>:
174+
assert "asyncpg.exceptions.ForeignKeyViolationError" in exc_info.value.args[0]
109175

110-
# this is the correct way to delete
111-
await connection.execute(products_prices.delete())
112-
await connection.execute(products.delete())
176+
# GOOD DELETE: this is the correct way to delete
177+
async with connection.begin():
178+
await connection.execute(products_prices.delete())
179+
await connection.execute(products.delete())
113180

114181

115182
async def test_get_product_latest_price_or_none(
@@ -140,26 +207,28 @@ async def test_price_history_of_a_product(
140207
connection: AsyncConnection, fake_product: Row, faker: Faker
141208
):
142209
# initial price
143-
await connection.execute(
144-
products_prices.insert().values(
145-
product_name=fake_product.name,
146-
usd_per_credit=1,
147-
comment="PO Mr X",
148-
stripe_price_id=faker.word(),
149-
stripe_tax_rate_id=faker.word(),
210+
async with connection.begin():
211+
await connection.execute(
212+
products_prices.insert().values(
213+
product_name=fake_product.name,
214+
usd_per_credit=1,
215+
comment="PO Mr X",
216+
stripe_price_id=faker.word(),
217+
stripe_tax_rate_id=faker.word(),
218+
)
150219
)
151-
)
152220

153221
# new price
154-
await connection.execute(
155-
products_prices.insert().values(
156-
product_name=fake_product.name,
157-
usd_per_credit=2,
158-
comment="Update by Mr X",
159-
stripe_price_id=faker.word(),
160-
stripe_tax_rate_id=faker.word(),
222+
async with connection.begin():
223+
await connection.execute(
224+
products_prices.insert().values(
225+
product_name=fake_product.name,
226+
usd_per_credit=2,
227+
comment="Update by Mr X",
228+
stripe_price_id=faker.word(),
229+
stripe_tax_rate_id=faker.word(),
230+
)
161231
)
162-
)
163232

164233
# latest is 2 USD!
165234
assert await get_product_latest_price_info_or_none(
@@ -176,23 +245,24 @@ async def test_get_product_latest_stripe_info(
176245
stripe_tax_rate_id_value = faker.word()
177246

178247
# products_prices
179-
await connection.execute(
180-
products_prices.insert().values(
181-
product_name=fake_product.name,
182-
usd_per_credit=10,
183-
comment="PO Mr X",
184-
stripe_price_id=stripe_price_id_value,
185-
stripe_tax_rate_id=stripe_tax_rate_id_value,
248+
async with connection.begin():
249+
await connection.execute(
250+
products_prices.insert().values(
251+
product_name=fake_product.name,
252+
usd_per_credit=10,
253+
comment="PO Mr X",
254+
stripe_price_id=stripe_price_id_value,
255+
stripe_tax_rate_id=stripe_tax_rate_id_value,
256+
)
186257
)
187-
)
258+
259+
# undefined product
260+
with pytest.raises(ValueError, match="undefined"):
261+
await get_product_latest_stripe_info(connection, product_name="undefined")
188262

189263
# defined product
190264
product_stripe_info = await get_product_latest_stripe_info(
191265
connection, product_name=fake_product.name
192266
)
193267
assert product_stripe_info[0] == stripe_price_id_value
194268
assert product_stripe_info[1] == stripe_tax_rate_id_value
195-
196-
# undefined product
197-
with pytest.raises(ValueError, match="undefined"):
198-
await get_product_latest_stripe_info(connection, product_name="undefined")

0 commit comments

Comments
 (0)