fix: recipe recursion false positive (#6591)

Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Co-authored-by: Michael Genson <genson.michael@gmail.com>
This commit is contained in:
gpotter@gmail.com
2025-11-28 09:28:18 -08:00
committed by GitHub
parent 3146e99b03
commit 8f1ce1a1c3
3 changed files with 147 additions and 14 deletions

View File

@@ -691,6 +691,130 @@ def test_recipe_recursion_cycle_three_level(api_client: TestClient, unique_user:
assert "cannot reference itself" in response.text.lower()
def test_recipe_recursion_valid_branched_chain(api_client: TestClient, unique_user: TestUser):
"""Test that valid branched nesting without cycles is allowed (d -> b -> a, d -> c -> a)."""
database = unique_user.repos
food = database.ingredient_foods.create(
SaveIngredientFood(
name=random_string(10),
group_id=unique_user.group_id,
)
)
# Create recipe_a
recipe_a: Recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="", food=food),
],
)
)
# Create recipe_b
recipe_b: Recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="", referenced_recipe=recipe_a),
],
)
)
# Create recipe_c
recipe_c: Recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="", referenced_recipe=recipe_a),
],
)
)
# Create recipe_d to reference recipe_b and recipe_c
recipe_d: Recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="", referenced_recipe=recipe_b),
RecipeIngredient(note="", referenced_recipe=recipe_c),
],
)
)
recipe_url = api_routes.recipes_slug(recipe_d.slug)
response = api_client.get(recipe_url, headers=unique_user.token)
assert response.status_code == 200
recipe_data = json.loads(response.text)
response = api_client.put(recipe_url, json=recipe_data, headers=unique_user.token)
assert response.status_code == 200
def test_recipe_recursion_same_recipe_twice(api_client: TestClient, unique_user: TestUser):
"""Test that referencing the same recipe multiple times in one recipe is allowed.
This tests the bug where using the same sub-recipe twice (e.g., a spice mix used
in both marinade and vegetables) incorrectly triggered a cycle detection.
"""
database = unique_user.repos
food = database.ingredient_foods.create(
SaveIngredientFood(
name=random_string(10),
group_id=unique_user.group_id,
)
)
# Create a spice mix recipe
sub_recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="", food=food),
],
)
)
# Create a main recipe that uses the spice mix twice
main_recipe = database.recipes.create(
Recipe(
name=random_string(10),
user_id=unique_user.user_id,
group_id=unique_user.group_id,
recipe_ingredient=[
RecipeIngredient(note="For marinade", referenced_recipe=sub_recipe),
RecipeIngredient(note="For vegetables", referenced_recipe=sub_recipe),
],
)
)
# Verify we can fetch and update the recipe without errors
recipe_url = api_routes.recipes_slug(main_recipe.slug)
response = api_client.get(recipe_url, headers=unique_user.token)
assert response.status_code == 200
recipe_data = json.loads(response.text)
# Verify both ingredients are present
assert len(recipe_data["recipeIngredient"]) == 2
assert recipe_data["recipeIngredient"][0]["note"] == "For marinade"
assert recipe_data["recipeIngredient"][1]["note"] == "For vegetables"
# Try to update the recipe - this should not fail with a recursion error
response = api_client.put(recipe_url, json=recipe_data, headers=unique_user.token)
assert response.status_code == 200
def test_recipe_reference_deleted(api_client: TestClient, unique_user: TestUser):
"""Test that when a referenced recipe is deleted, the parent recipe remains intact."""
database = unique_user.repos