test_cloud_filament_id_map_accounts.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. """Cloud preset lookups belong to the cloud account they were read with."""
  2. from __future__ import annotations
  3. from types import SimpleNamespace
  4. from unittest.mock import AsyncMock, patch
  5. import pytest
  6. from httpx import AsyncClient
  7. from backend.tests.integration.test_printer_scope_1727 import _admin_token, _auth, _group, _user
  8. pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
  9. @pytest.fixture(autouse=True)
  10. def _empty_cache():
  11. from backend.app.api.routes import cloud
  12. cloud.forget_all_cloud_presets()
  13. yield
  14. cloud.forget_all_cloud_presets()
  15. def _cloud(presets: dict[str, str]):
  16. details = {
  17. f"S{i}": {"filament_id": fid, "name": f"{name} @Bambu Lab X1C"} for i, (fid, name) in enumerate(presets.items())
  18. }
  19. return SimpleNamespace(
  20. is_authenticated=True,
  21. get_slicer_settings=AsyncMock(return_value={"filament": {"private": [{"setting_id": s} for s in details]}}),
  22. get_setting_detail=AsyncMock(side_effect=lambda setting_id: details[setting_id]),
  23. close=AsyncMock(),
  24. )
  25. async def test_each_caller_gets_the_map_of_their_own_cloud_account(async_client: AsyncClient):
  26. token = await _admin_token(async_client)
  27. group = await _group(async_client, token, "readers", permissions=["filaments:read"])
  28. anna, anna_id = await _user(async_client, token, "anna", [group])
  29. ben, _ = await _user(async_client, token, "ben", [group])
  30. cara, cara_id = await _user(async_client, token, "cara", [group])
  31. accounts = {anna_id: {"P1": "Anna Private PLA"}, cara_id: {"P2": "Cara Silk"}}
  32. async def build(db, user):
  33. return _cloud(accounts[user.id]) if user is not None and user.id in accounts else None
  34. with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
  35. maps = {
  36. name: (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(jwt))).json()
  37. for name, jwt in (("anna", anna), ("ben", ben), ("cara", cara), ("anna again", anna))
  38. }
  39. assert maps == {
  40. "anna": {"P1": "Anna Private PLA"},
  41. "ben": {},
  42. "cara": {"P2": "Cara Silk"},
  43. "anna again": {"P1": "Anna Private PLA"},
  44. }
  45. async def test_signing_out_of_the_cloud_drops_the_account_map(async_client: AsyncClient):
  46. token = await _admin_token(async_client)
  47. group = await _group(async_client, token, "readers", permissions=["filaments:read", "cloud:auth"])
  48. anna, _ = await _user(async_client, token, "anna", [group])
  49. signed_in = {"yes": True}
  50. async def build(db, user):
  51. return _cloud({"P1": "Anna Private PLA"}) if signed_in["yes"] else None
  52. with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
  53. before = (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(anna))).json()
  54. signed_in["yes"] = False
  55. logout = await async_client.post("/api/v1/cloud/logout", headers=_auth(anna))
  56. after = (await async_client.get("/api/v1/cloud/filament-id-map", headers=_auth(anna))).json()
  57. assert logout.status_code == 200, logout.text
  58. assert (before, after) == ({"P1": "Anna Private PLA"}, {})
  59. async def test_signing_in_again_drops_the_account_map(db_session):
  60. from backend.app.api.routes import cloud
  61. cloud._filament_id_name_cache[None] = (0.0, {"P1": "Old account"})
  62. cloud._filament_id_name_cache[7] = (0.0, {"P9": "Someone else"})
  63. cloud._filament_cache[(None, "P1")] = {"name": "Old account", "k": None}
  64. cloud._filament_cache[(7, "P9")] = {"name": "Someone else", "k": None}
  65. await cloud.store_token(db_session, "new-token", "a@example.com", "global", None)
  66. assert list(cloud._filament_id_name_cache) == [7]
  67. assert list(cloud._filament_cache) == [(7, "P9")]
  68. async def test_a_preset_one_account_resolved_is_not_served_to_another(async_client: AsyncClient):
  69. token = await _admin_token(async_client)
  70. group = await _group(async_client, token, "readers", permissions=["filaments:read"])
  71. anna, anna_id = await _user(async_client, token, "anna", [group])
  72. ben, _ = await _user(async_client, token, "ben", [group])
  73. preset = {"name": "Anna Private PLA @Bambu Lab X1C", "setting": {"pressure_advance": "0.031"}}
  74. async def build(db, user):
  75. if user is None or user.id != anna_id:
  76. return None
  77. return SimpleNamespace(
  78. is_authenticated=True, get_setting_detail=AsyncMock(return_value=preset), close=AsyncMock()
  79. )
  80. with patch("backend.app.api.routes.cloud.build_authenticated_cloud", new=build):
  81. for_anna = (
  82. await async_client.post("/api/v1/cloud/filament-info", headers=_auth(anna), json=["P5a1b2c3"])
  83. ).json()
  84. for_ben = (await async_client.post("/api/v1/cloud/filament-info", headers=_auth(ben), json=["P5a1b2c3"])).json()
  85. assert for_anna["P5a1b2c3"]["name"] == "Anna Private PLA @Bambu Lab X1C"
  86. assert for_ben["P5a1b2c3"]["name"] != for_anna["P5a1b2c3"]["name"]
  87. assert for_ben["P5a1b2c3"]["k"] is None