test_cloud_filament_id_map_single_flight.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. """The cloud filament-ID map is built once per account at a time, without a
  2. request holding a database connection (RC-C11).
  3. When the 5-minute cache expired, every K-profile view asked at once and each
  4. ran the full 1 + N Bambu Cloud fetch while its request held a database
  5. connection idle in transaction.
  6. """
  7. import asyncio
  8. from contextlib import asynccontextmanager
  9. from types import SimpleNamespace
  10. from unittest.mock import AsyncMock, patch
  11. import pytest
  12. from backend.app.api.routes import cloud
  13. pytestmark = pytest.mark.asyncio
  14. @pytest.fixture(autouse=True)
  15. def _empty():
  16. cloud.forget_all_cloud_presets()
  17. yield
  18. cloud.forget_all_cloud_presets()
  19. def _slow_cloud(release: asyncio.Event):
  20. async def settings():
  21. await release.wait()
  22. return {"filament": {"private": [{"setting_id": "S1"}]}}
  23. return SimpleNamespace(
  24. is_authenticated=True,
  25. get_slicer_settings=AsyncMock(side_effect=settings),
  26. get_setting_detail=AsyncMock(return_value={"filament_id": "P1", "name": "Mine @Bambu Lab X1C"}),
  27. close=AsyncMock(),
  28. )
  29. @asynccontextmanager
  30. async def _own_session():
  31. yield "own session"
  32. async def test_views_arriving_together_share_one_build():
  33. release = asyncio.Event()
  34. built: list = []
  35. async def build(db, user):
  36. # A real token read awaits the database.
  37. await asyncio.sleep(0.001)
  38. built.append(db)
  39. return _slow_cloud(release)
  40. user = SimpleNamespace(id=7)
  41. with (
  42. patch.object(cloud, "build_authenticated_cloud", new=build),
  43. patch("backend.app.core.database.async_session", new=_own_session),
  44. ):
  45. calls = [asyncio.create_task(cloud.get_filament_id_map(current_user=user)) for _ in range(3)]
  46. await asyncio.sleep(0.05)
  47. release.set()
  48. results = await asyncio.gather(*calls)
  49. assert results == [{"P1": "Mine"}] * 3
  50. assert built == ["own session"], "every view built the map itself, or in its request's session"
  51. async def test_a_build_running_when_the_account_signs_out_is_not_cached():
  52. release = asyncio.Event()
  53. async def build(db, user):
  54. return _slow_cloud(release)
  55. with (
  56. patch.object(cloud, "build_authenticated_cloud", new=build),
  57. patch("backend.app.core.database.async_session", new=_own_session),
  58. ):
  59. call = asyncio.create_task(cloud.get_filament_id_map(current_user=SimpleNamespace(id=7)))
  60. await asyncio.sleep(0.05)
  61. cloud._forget_account_presets(7)
  62. release.set()
  63. await call
  64. assert 7 not in cloud._filament_id_name_cache