mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-05 13:35:23 +02:00
update foods and units for multitenant support
This commit is contained in:
parent
fbc17b670d
commit
9a82a172cb
11 changed files with 194 additions and 15 deletions
1
tests/fixtures/__init__.py
vendored
1
tests/fixtures/__init__.py
vendored
|
@ -1,5 +1,6 @@
|
|||
from .fixture_admin import *
|
||||
from .fixture_database import *
|
||||
from .fixture_multitenant import *
|
||||
from .fixture_recipe import *
|
||||
from .fixture_routes import *
|
||||
from .fixture_shopping_lists import *
|
||||
|
|
22
tests/fixtures/fixture_multitenant.py
vendored
Normal file
22
tests/fixtures/fixture_multitenant.py
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests import utils
|
||||
from tests.fixtures.fixture_users import build_unique_user
|
||||
from tests.utils.factories import random_string
|
||||
|
||||
|
||||
@dataclass
|
||||
class MultiTenant:
|
||||
user_one: utils.TestUser
|
||||
user_two: utils.TestUser
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def multitenants(api_client: TestClient) -> MultiTenant:
|
||||
yield MultiTenant(
|
||||
user_one=build_unique_user(random_string(12), api_client),
|
||||
user_two=build_unique_user(random_string(12), api_client),
|
||||
)
|
31
tests/fixtures/fixture_users.py
vendored
31
tests/fixtures/fixture_users.py
vendored
|
@ -6,22 +6,47 @@ from pytest import fixture
|
|||
from starlette.testclient import TestClient
|
||||
|
||||
from tests import utils
|
||||
from tests.utils.factories import random_string
|
||||
|
||||
|
||||
def build_unique_user(group: str, api_client: requests) -> utils.TestUser:
|
||||
api_routes = utils.AppRoutes()
|
||||
group = group or random_string(12)
|
||||
|
||||
registration = utils.user_registration_factory()
|
||||
response = api_client.post("/api/users/register", json=registration.dict(by_alias=True))
|
||||
assert response.status_code == 201
|
||||
|
||||
form_data = {"username": registration.username, "password": registration.password}
|
||||
|
||||
token = utils.login(form_data, api_client, api_routes)
|
||||
|
||||
user_data = api_client.get(api_routes.users_self, headers=token).json()
|
||||
assert token is not None
|
||||
|
||||
return utils.TestUser(
|
||||
_group_id=user_data.get("groupId"),
|
||||
user_id=user_data.get("id"),
|
||||
email=user_data.get("email"),
|
||||
token=token,
|
||||
)
|
||||
|
||||
|
||||
@fixture(scope="module")
|
||||
def g2_user(admin_token, api_client: requests, api_routes: utils.AppRoutes):
|
||||
def g2_user(admin_token, api_client: TestClient, api_routes: utils.AppRoutes):
|
||||
group = random_string(12)
|
||||
# Create the user
|
||||
create_data = {
|
||||
"fullName": utils.random_string(),
|
||||
"username": utils.random_string(),
|
||||
"email": utils.random_email(),
|
||||
"password": "useruser",
|
||||
"group": "New Group",
|
||||
"group": group,
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.groups, json={"name": "New Group"}, headers=admin_token)
|
||||
response = api_client.post(api_routes.groups, json={"name": group}, headers=admin_token)
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
|
79
tests/multitenant_tests/test_ingredient_food.py
Normal file
79
tests/multitenant_tests/test_ingredient_food.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.schema.recipe.recipe_ingredient import SaveIngredientFood, SaveIngredientUnit
|
||||
from tests import utils
|
||||
from tests.fixtures.fixture_multitenant import MultiTenant
|
||||
from tests.utils import routes
|
||||
|
||||
|
||||
def test_foods_are_private_by_group(
|
||||
api_client: TestClient, multitenants: MultiTenant, database: AllRepositories
|
||||
) -> None:
|
||||
user1 = multitenants.user_one
|
||||
user2 = multitenants.user_two
|
||||
|
||||
# Bootstrap foods for user1
|
||||
food_ids: set[int] = set()
|
||||
for _ in range(10):
|
||||
food = database.ingredient_foods.create(
|
||||
SaveIngredientFood(
|
||||
group_id=user1.group_id,
|
||||
name=utils.random_string(10),
|
||||
)
|
||||
)
|
||||
|
||||
food_ids.add(food.id)
|
||||
|
||||
expected_results = [
|
||||
(user1.token, food_ids),
|
||||
(user2.token, []),
|
||||
]
|
||||
|
||||
for token, expected_food_ids in expected_results:
|
||||
response = api_client.get(routes.RoutesFoods.base, headers=token)
|
||||
assert response.status_code == 200
|
||||
|
||||
data = response.json()
|
||||
|
||||
assert len(data) == len(expected_food_ids)
|
||||
|
||||
if len(data) > 0:
|
||||
for food in data:
|
||||
assert food["id"] in expected_food_ids
|
||||
|
||||
|
||||
def test_units_are_private_by_group(
|
||||
api_client: TestClient, multitenants: MultiTenant, database: AllRepositories
|
||||
) -> None:
|
||||
user1 = multitenants.user_one
|
||||
user2 = multitenants.user_two
|
||||
|
||||
# Bootstrap foods for user1
|
||||
unit_ids: set[int] = set()
|
||||
for _ in range(10):
|
||||
food = database.ingredient_units.create(
|
||||
SaveIngredientUnit(
|
||||
group_id=user1.group_id,
|
||||
name=utils.random_string(10),
|
||||
)
|
||||
)
|
||||
|
||||
unit_ids.add(food.id)
|
||||
|
||||
expected_results = [
|
||||
(user1.token, unit_ids),
|
||||
(user2.token, []),
|
||||
]
|
||||
|
||||
for token, expected_unit_ids in expected_results:
|
||||
response = api_client.get(routes.RoutesUnits.base, headers=token)
|
||||
assert response.status_code == 200
|
||||
|
||||
data = response.json()
|
||||
|
||||
assert len(data) == len(expected_unit_ids)
|
||||
|
||||
if len(data) > 0:
|
||||
for food in data:
|
||||
assert food["id"] in expected_unit_ids
|
21
tests/utils/routes.py
Normal file
21
tests/utils/routes.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from pydantic import UUID4
|
||||
|
||||
|
||||
class _RoutesBase:
|
||||
prefix = "/api"
|
||||
base = f"{prefix}/"
|
||||
|
||||
def __init__(self) -> None:
|
||||
raise Exception("This class is not meant to be instantiated.")
|
||||
|
||||
@classmethod
|
||||
def item(cls, item_id: int | str | UUID4) -> str:
|
||||
return f"{cls.base}/{item_id}"
|
||||
|
||||
|
||||
class RoutesFoods(_RoutesBase):
|
||||
base = "/api/foods"
|
||||
|
||||
|
||||
class RoutesUnits(_RoutesBase):
|
||||
base = "/api/units"
|
Loading…
Add table
Add a link
Reference in a new issue