112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, timedelta
|
|
from unittest.mock import patch
|
|
from uuid import uuid4
|
|
|
|
from innercontext.api.auth_deps import get_current_user
|
|
from innercontext.auth import CurrentUser, IdentityData, TokenClaims
|
|
from innercontext.models import Role
|
|
from main import app
|
|
|
|
|
|
def _user(subject: str, *, role: Role = Role.MEMBER) -> CurrentUser:
|
|
claims = TokenClaims(
|
|
issuer="https://auth.test",
|
|
subject=subject,
|
|
audience=("innercontext-web",),
|
|
expires_at=datetime.now(UTC) + timedelta(hours=1),
|
|
raw_claims={"iss": "https://auth.test", "sub": subject},
|
|
)
|
|
return CurrentUser(
|
|
user_id=uuid4(),
|
|
role=role,
|
|
identity=IdentityData.from_claims(claims),
|
|
claims=claims,
|
|
)
|
|
|
|
|
|
def _set_current_user(user: CurrentUser) -> None:
|
|
app.dependency_overrides[get_current_user] = lambda: user
|
|
|
|
|
|
def test_suggest_uses_current_user_profile_and_visible_products_only(client):
|
|
owner = _user("owner")
|
|
other = _user("other")
|
|
|
|
_set_current_user(owner)
|
|
owner_profile = client.patch(
|
|
"/profile", json={"birth_date": "1991-01-15", "sex_at_birth": "male"}
|
|
)
|
|
owner_product = client.post(
|
|
"/products",
|
|
json={
|
|
"name": "Owner Serum",
|
|
"brand": "Test",
|
|
"category": "serum",
|
|
"recommended_time": "both",
|
|
"leave_on": True,
|
|
},
|
|
)
|
|
assert owner_profile.status_code == 200
|
|
assert owner_product.status_code == 201
|
|
|
|
_set_current_user(other)
|
|
other_profile = client.patch(
|
|
"/profile", json={"birth_date": "1975-06-20", "sex_at_birth": "female"}
|
|
)
|
|
other_product = client.post(
|
|
"/products",
|
|
json={
|
|
"name": "Other Serum",
|
|
"brand": "Test",
|
|
"category": "serum",
|
|
"recommended_time": "both",
|
|
"leave_on": True,
|
|
},
|
|
)
|
|
assert other_profile.status_code == 200
|
|
assert other_product.status_code == 201
|
|
|
|
_set_current_user(owner)
|
|
|
|
with patch(
|
|
"innercontext.api.routines.call_gemini_with_function_tools"
|
|
) as mock_gemini:
|
|
mock_response = type(
|
|
"Response",
|
|
(),
|
|
{
|
|
"text": '{"steps": [{"product_id": null, "action_type": "shaving_razor"}], "reasoning": "ok", "summary": {"primary_goal": "safe", "constraints_applied": [], "confidence": 0.7}}'
|
|
},
|
|
)
|
|
mock_gemini.return_value = (mock_response, None)
|
|
|
|
response = client.post(
|
|
"/routines/suggest",
|
|
json={
|
|
"routine_date": "2026-03-05",
|
|
"part_of_day": "am",
|
|
"include_minoxidil_beard": False,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
kwargs = mock_gemini.call_args.kwargs
|
|
prompt = kwargs["contents"]
|
|
assert "Birth date: 1991-01-15" in prompt
|
|
assert "Birth date: 1975-06-20" not in prompt
|
|
assert "Owner Serum" in prompt
|
|
assert "Other Serum" not in prompt
|
|
|
|
handler = kwargs["function_handlers"]["get_product_details"]
|
|
payload = handler(
|
|
{
|
|
"product_ids": [
|
|
owner_product.json()["id"],
|
|
other_product.json()["id"],
|
|
]
|
|
}
|
|
)
|
|
assert len(payload["products"]) == 1
|
|
assert payload["products"][0]["name"] == "Owner Serum"
|