Public Access
feat: planner orchestrator - load, filter, score, select, persist
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.requires_postgres
|
||||
|
||||
|
||||
def test_generate_meal_plan_against_seeded_data():
|
||||
"""Smoke test: with the seeded 30 recipes and a seeded grocery scrape,
|
||||
generate produces a MealPlan with up to 3 items.
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from app.database import SessionLocal
|
||||
from app.models import (
|
||||
FamilyProfile,
|
||||
GroceryItem,
|
||||
Ingredient,
|
||||
IngredientGroceryMatch,
|
||||
IngredientMatchSource,
|
||||
MealPlan,
|
||||
MealPlanItem,
|
||||
)
|
||||
from app.services.matcher import run_match_job
|
||||
from app.services.planner.generate import generate_meal_plan
|
||||
|
||||
setup = SessionLocal()
|
||||
try:
|
||||
family = FamilyProfile(
|
||||
id=uuid4(),
|
||||
name="Generate Smoke Family",
|
||||
household_size=4,
|
||||
adult_count=2,
|
||||
child_count=2,
|
||||
calorie_target=500,
|
||||
)
|
||||
setup.add(family)
|
||||
setup.commit()
|
||||
family_id = family.id
|
||||
|
||||
# Seed at least one grocery_item per ingredient that the recipes use
|
||||
# so cost matching can find prices. Pick a handful to keep runtime low.
|
||||
for ing in setup.query(Ingredient).limit(20).all():
|
||||
setup.add(
|
||||
GroceryItem(
|
||||
id=uuid4(),
|
||||
name=ing.name,
|
||||
source="lucky_california",
|
||||
external_id=f"ext-test-{ing.id}",
|
||||
current_price=Decimal("3.99"),
|
||||
regular_price=Decimal("4.99"),
|
||||
is_on_sale=True,
|
||||
scraped_at=datetime.now(timezone.utc),
|
||||
)
|
||||
)
|
||||
setup.commit()
|
||||
finally:
|
||||
setup.close()
|
||||
|
||||
work = SessionLocal()
|
||||
try:
|
||||
run_match_job(work)
|
||||
result = generate_meal_plan(work, family_id=family_id, week_start_date=date(2026, 5, 11))
|
||||
assert result.meal_plan_id is not None
|
||||
assert 1 <= len(result.selected) <= 3 # at least 1, at most 3
|
||||
plan = work.query(MealPlan).filter(MealPlan.id == result.meal_plan_id).first()
|
||||
assert plan is not None
|
||||
items = work.query(MealPlanItem).filter(MealPlanItem.meal_plan_id == plan.id).all()
|
||||
assert len(items) == len(result.selected)
|
||||
finally:
|
||||
cleanup = SessionLocal()
|
||||
try:
|
||||
cleanup.query(MealPlanItem).filter(
|
||||
MealPlanItem.meal_plan_id.in_(
|
||||
[r[0] for r in cleanup.query(MealPlan.id).filter(MealPlan.family_profile_id == family_id).all()]
|
||||
)
|
||||
).delete(synchronize_session=False)
|
||||
cleanup.query(MealPlan).filter(MealPlan.family_profile_id == family_id).delete(synchronize_session=False)
|
||||
cleanup.query(FamilyProfile).filter(FamilyProfile.id == family_id).delete(synchronize_session=False)
|
||||
cleanup.query(GroceryItem).filter(GroceryItem.external_id.like("ext-test-%")).delete(synchronize_session=False)
|
||||
cleanup.query(IngredientGroceryMatch).filter(
|
||||
IngredientGroceryMatch.source == IngredientMatchSource.AUTO
|
||||
).delete(synchronize_session=False)
|
||||
cleanup.commit()
|
||||
finally:
|
||||
cleanup.close()
|
||||
work.close()
|
||||
Reference in New Issue
Block a user