2025-11-01 02:43:26 +00:00
|
|
|
import asyncio
|
|
|
|
|
|
|
|
|
|
import aiosqlite
|
|
|
|
|
|
|
|
|
|
import db
|
|
|
|
|
from tests.test_data import create_test_data
|
|
|
|
|
from scripts.migration_to_households import run_migration
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def table_has_column(conn: aiosqlite.Connection, table: str, col: str) -> bool:
|
|
|
|
|
async with conn.execute(f"PRAGMA table_info({table});") as c:
|
|
|
|
|
async for row in c:
|
|
|
|
|
if row[1] == col:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_migration_adds_tables_and_columns_and_ports_data(tmp_path):
|
|
|
|
|
async def _run():
|
|
|
|
|
db_path = tmp_path / "test.sqlite"
|
|
|
|
|
conn = await db.connect(str(db_path))
|
|
|
|
|
# Bootstrap v1 schema
|
|
|
|
|
await db.create(conn)
|
|
|
|
|
await conn.commit()
|
|
|
|
|
|
|
|
|
|
# Seed some v1 data (persons, products, recipes, meals)
|
|
|
|
|
await create_test_data(conn)
|
|
|
|
|
await conn.commit()
|
|
|
|
|
|
|
|
|
|
# Run migration
|
|
|
|
|
await run_migration(conn)
|
|
|
|
|
|
|
|
|
|
# Verify new tables exist
|
2025-11-01 04:34:01 +00:00
|
|
|
for tbl in [
|
|
|
|
|
"User",
|
|
|
|
|
"LocalCredentials",
|
|
|
|
|
"OAuthCredentials",
|
|
|
|
|
"Household",
|
|
|
|
|
"HouseholdMember",
|
|
|
|
|
"HouseholdInvitation",
|
|
|
|
|
]:
|
2025-11-01 02:43:26 +00:00
|
|
|
async with conn.execute(
|
|
|
|
|
"SELECT name FROM sqlite_master WHERE type='table' AND name=?;", (tbl,)
|
|
|
|
|
) as c:
|
|
|
|
|
assert await c.fetchone() is not None, f"Missing table {tbl}"
|
|
|
|
|
|
|
|
|
|
# Verify household_id column exists on tenant tables
|
|
|
|
|
tenant_tables = [
|
|
|
|
|
"Recipe",
|
|
|
|
|
"Ingredient",
|
|
|
|
|
"Meal",
|
|
|
|
|
"MealParticipant",
|
|
|
|
|
"MealRecipe",
|
|
|
|
|
"ShoppingList",
|
|
|
|
|
"ShoppingListItem",
|
|
|
|
|
]
|
|
|
|
|
for tbl in tenant_tables:
|
|
|
|
|
assert await table_has_column(conn, tbl, "household_id"), f"{tbl} lacks household_id"
|
|
|
|
|
|
|
|
|
|
# Default household exists
|
2025-11-01 04:34:01 +00:00
|
|
|
async with conn.execute(
|
|
|
|
|
"SELECT id, slug FROM Household WHERE slug='default' LIMIT 1;"
|
|
|
|
|
) as c:
|
2025-11-01 02:43:26 +00:00
|
|
|
row = await c.fetchone()
|
|
|
|
|
assert row is not None
|
|
|
|
|
|
|
|
|
|
# Persons were ported to Users and memberships created
|
|
|
|
|
async with conn.execute("SELECT COUNT(1) FROM Person;") as c:
|
|
|
|
|
row = await c.fetchone()
|
|
|
|
|
assert row is not None
|
|
|
|
|
person_count = int(row[0])
|
|
|
|
|
async with conn.execute("SELECT COUNT(1) FROM User;") as c:
|
|
|
|
|
row = await c.fetchone()
|
|
|
|
|
assert row is not None
|
|
|
|
|
user_count = int(row[0])
|
|
|
|
|
assert user_count == person_count
|
|
|
|
|
|
|
|
|
|
async with conn.execute("SELECT COUNT(1) FROM HouseholdMember;") as c:
|
|
|
|
|
row = await c.fetchone()
|
|
|
|
|
assert row is not None
|
|
|
|
|
member_count = int(row[0])
|
|
|
|
|
assert member_count == person_count
|
|
|
|
|
|
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
|
|
asyncio.run(_run())
|