| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- """Cloud preset lookups belong to the cloud account they were read with."""
- from __future__ import annotations
- from types import SimpleNamespace
- from unittest.mock import AsyncMock, patch
- import pytest
- from httpx import AsyncClient
- from backend.tests.integration.test_printer_scope_1727 import _admin_token, _auth, _group, _user
- pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
- @pytest.fixture(autouse=True)
- def _empty_cache():
- from backend.app.api.routes import cloud
- cloud.forget_all_cloud_presets()
- yield
- cloud.forget_all_cloud_presets()
- def _cloud(presets: dict[str, str]):
- details = {
- f"S{i}": {"filament_id": fid, "name": f"{name} @Bambu Lab X1C"} for i, (fid, name) in enumerate(presets.items())
- }
- return SimpleNamespace(
- is_authenticated=True,
- get_slicer_settings=AsyncMock(return_value={"filament": {"private": [{"setting_id": s} for s in details]}}),
- get_setting_detail=AsyncMock(side_effect=lambda setting_id: details[setting_id]),
- close=AsyncMock(),
- )
- async def test_each_caller_gets_the_map_of_their_own_cloud_account(async_client: AsyncClient):
- token = await _admin_token(async_client)
- group = await _group(async_client, token, "readers", permissions=["filaments:read"])
- anna, anna_id = await _user(async_client, token, "anna", [group])
- ben, _ = await _user(async_client, token, "ben", [group])
- cara, cara_id = await _user(async_client, token, "cara", [group])
- accounts = {anna_id: {"P1": "Anna Private PLA"}, cara_id: {"P2": "Cara Silk"}}
- async def build(db, user):
- return _cloud(accounts[user.id]) if user is not None and user.id in accounts else None
- with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
- maps = {
- name: (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(jwt))).json()
- for name, jwt in (("anna", anna), ("ben", ben), ("cara", cara), ("anna again", anna))
- }
- assert maps == {
- "anna": {"P1": "Anna Private PLA"},
- "ben": {},
- "cara": {"P2": "Cara Silk"},
- "anna again": {"P1": "Anna Private PLA"},
- }
- async def test_signing_out_of_the_cloud_drops_the_account_map(async_client: AsyncClient):
- token = await _admin_token(async_client)
- group = await _group(async_client, token, "readers", permissions=["filaments:read", "cloud:auth"])
- anna, _ = await _user(async_client, token, "anna", [group])
- signed_in = {"yes": True}
- async def build(db, user):
- return _cloud({"P1": "Anna Private PLA"}) if signed_in["yes"] else None
- with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
- before = (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(anna))).json()
- signed_in["yes"] = False
- logout = await async_client.post("/api/v1/cloud/logout", headers=_auth(anna))
- after = (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(anna))).json()
- assert logout.status_code == 200, logout.text
- assert (before, after) == ({"P1": "Anna Private PLA"}, {})
- async def test_signing_in_again_drops_the_account_map(db_session):
- from backend.app.api.routes import cloud
- cloud._filament_id_name_cache[None] = (0.0, {"P1": "Old account"})
- cloud._filament_id_name_cache[7] = (0.0, {"P9": "Someone else"})
- cloud._filament_cache[(None, "P1")] = {"name": "Old account", "k": None}
- cloud._filament_cache[(7, "P9")] = {"name": "Someone else", "k": None}
- await cloud.store_token(db_session, "new-token", "a@example.com", "global", None)
- assert list(cloud._filament_id_name_cache) == [7]
- assert list(cloud._filament_cache) == [(7, "P9")]
- async def test_a_preset_one_account_resolved_is_not_served_to_another(async_client: AsyncClient):
- token = await _admin_token(async_client)
- group = await _group(async_client, token, "readers", permissions=["filaments:read"])
- anna, anna_id = await _user(async_client, token, "anna", [group])
- ben, _ = await _user(async_client, token, "ben", [group])
- preset = {"name": "Anna Private PLA @Bambu Lab X1C", "setting": {"pressure_advance": "0.031"}}
- async def build(db, user):
- if user is None or user.id != anna_id:
- return None
- return SimpleNamespace(
- is_authenticated=True, get_setting_detail=AsyncMock(return_value=preset), close=AsyncMock()
- )
- with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
- for_anna = (
- await async_client.post("/api/v1/cloud/filament-info", headers=_auth(anna), json=["P5a1b2c3"])
- ).json()
- for_ben = (await async_client.post("/api/v1/cloud/filament-info", headers=_auth(ben), json=["P5a1b2c3"])).json()
- assert for_anna["P5a1b2c3"]["name"] == "Anna Private PLA @Bambu Lab X1C"
- assert for_ben["P5a1b2c3"]["name"] != for_anna["P5a1b2c3"]["name"]
- assert for_ben["P5a1b2c3"]["k"] is None
- async def test_a_filament_id_inside_the_preset_json_is_read_too(async_client: AsyncClient):
- """Same fallback as the slicer filament resolver: the preset JSON under
- ``setting`` can carry the id when the envelope does not."""
- token = await _admin_token(async_client)
- group = await _group(async_client, token, "readers", permissions=["filaments:read"])
- anna, _ = await _user(async_client, token, "anna", [group])
- cloud = SimpleNamespace(
- is_authenticated=True,
- get_slicer_settings=AsyncMock(return_value={"filament": {"private": [{"setting_id": "S0"}]}}),
- get_setting_detail=AsyncMock(
- return_value={"filament_id": None, "name": "Nested PLA @Bambu Lab X1C", "setting": {"filament_id": "P9"}}
- ),
- close=AsyncMock(),
- )
- async def build(db, user):
- return cloud
- with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
- body = (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(anna))).json()
- assert body == {"P9": "Nested PLA"}
|