test_spoolbuddy_spool_colours_3033.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. """The kiosk paints a scanned spool with its extra colours and effect (#3033).
  2. The tag-matched broadcast is the only place the kiosk learns about a scanned
  3. spool, and it carried `rgba` alone, so a dual-colour or marble spool arrived as
  4. one flat colour however the frontend drew it.
  5. """
  6. from unittest.mock import AsyncMock, MagicMock, patch
  7. import pytest
  8. from httpx import AsyncClient
  9. from sqlalchemy.ext.asyncio import AsyncSession
  10. from backend.app.models.settings import Settings
  11. SPOOLBUDDY_API = "/api/v1/spoolbuddy"
  12. @pytest.fixture
  13. async def spoolman_enabled(db_session: AsyncSession):
  14. db_session.add(Settings(key="spoolman_enabled", value="true"))
  15. db_session.add(Settings(key="spoolman_url", value="http://spoolman.local:7912"))
  16. await db_session.commit()
  17. @pytest.fixture
  18. async def spoolman_disabled(db_session: AsyncSession):
  19. db_session.add(Settings(key="spoolman_enabled", value="false"))
  20. await db_session.commit()
  21. async def _scan(async_client: AsyncClient) -> dict:
  22. with patch("backend.app.api.routes.spoolbuddy.ws_manager") as mock_ws:
  23. mock_ws.broadcast = AsyncMock()
  24. resp = await async_client.post(
  25. f"{SPOOLBUDDY_API}/nfc/tag-scanned",
  26. json={"device_id": "sb-test", "tag_uid": "AABB1122334455FF", "tray_uuid": None},
  27. )
  28. assert resp.status_code == 200
  29. mock_ws.broadcast.assert_called_once()
  30. return mock_ws.broadcast.call_args[0][0]
  31. class TestTheScanBroadcastCarriesTheSpoolsColours:
  32. @pytest.mark.asyncio
  33. @pytest.mark.integration
  34. async def test_a_local_dual_colour_spool(self, async_client: AsyncClient, spoolman_disabled):
  35. """The reporter's spool #23, Inland PLA Silk Blue-Yellow."""
  36. spool = MagicMock()
  37. spool.id = 23
  38. spool.material = "PLA"
  39. spool.subtype = "Silk"
  40. spool.color_name = "Blue-Yellow"
  41. spool.rgba = "044482FF"
  42. spool.extra_colors = "044482,f8d008"
  43. spool.effect_type = "dual-color"
  44. spool.brand = "Inland"
  45. spool.label_weight = 1000
  46. spool.core_weight = 250
  47. spool.weight_used = 0
  48. with patch("backend.app.api.routes.spoolbuddy.get_spool_by_tag", new_callable=AsyncMock, return_value=spool):
  49. msg = await _scan(async_client)
  50. assert msg["type"] == "spoolbuddy_tag_matched"
  51. assert msg["spool"]["extra_colors"] == "044482,f8d008"
  52. assert msg["spool"]["effect_type"] == "dual-color"
  53. @pytest.mark.asyncio
  54. @pytest.mark.integration
  55. async def test_a_spoolman_spool_sends_its_stops_and_no_effect(self, async_client: AsyncClient, spoolman_enabled):
  56. """Spoolman keeps the stops in `multi_color_hexes` and has no effect
  57. field, so the effect stays None rather than being guessed."""
  58. sm_spool = {
  59. "id": 23,
  60. "filament": {
  61. "material": "PLA",
  62. "name": "PLA Silk",
  63. "color_hex": "044482",
  64. "multi_color_hexes": "044482,F8D008",
  65. "weight": 1000.0,
  66. "vendor": {"name": "Inland"},
  67. },
  68. "used_weight": 0.0,
  69. "archived": False,
  70. "registered": "2024-01-01T00:00:00Z",
  71. }
  72. client = MagicMock()
  73. client.base_url = "http://spoolman.local:7912"
  74. client.get_spools = AsyncMock(return_value=[sm_spool])
  75. client.find_spool_by_tag = AsyncMock(return_value=sm_spool)
  76. client.merge_spool_extra = AsyncMock(return_value={})
  77. with (
  78. patch("backend.app.services.spoolman.get_spoolman_client", AsyncMock(return_value=client)),
  79. patch("backend.app.services.spoolman.init_spoolman_client", AsyncMock(return_value=client)),
  80. ):
  81. msg = await _scan(async_client)
  82. assert msg["type"] == "spoolbuddy_tag_matched"
  83. assert msg["spool"]["extra_colors"] == "044482,F8D008"
  84. assert msg["spool"]["effect_type"] is None