test_queue_estimate_spoolman_prices.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. """The queue's cost estimate prices a library file from the Spoolman spools in
  2. its trays, as it does from built-in spools. Every slot used to be priced at
  3. the default rate in Spoolman mode."""
  4. from pathlib import Path
  5. from unittest.mock import AsyncMock, MagicMock, patch
  6. import pytest
  7. from backend.app.models.settings import Settings
  8. from backend.app.models.spoolman_slot_assignment import SpoolmanSlotAssignment
  9. from backend.app.services import print_cost_estimate as pce
  10. @pytest.mark.asyncio
  11. @pytest.mark.integration
  12. @pytest.mark.parametrize("price,expected", [(60.0, 6.0), (None, 2.5)])
  13. async def test_a_slot_is_priced_from_its_spoolman_spool(db_session, printer_factory, price, expected):
  14. """100 g from a 60/kg Spoolman spool is 6.00; an unpriced one falls back to the 25/kg default."""
  15. db_session.add(Settings(key="spoolman_enabled", value="true"))
  16. printer = await printer_factory()
  17. db_session.add(SpoolmanSlotAssignment(printer_id=printer.id, ams_id=0, tray_id=2, spoolman_spool_id=42))
  18. await db_session.commit()
  19. client = MagicMock()
  20. client.get_spool = AsyncMock(
  21. return_value={"id": 42, "price": price, "initial_weight": 1000.0, "filament": {"weight": 1000.0}}
  22. )
  23. library_file = MagicMock(file_metadata={"filament_used_grams": 100.0})
  24. with (
  25. patch(
  26. "backend.app.services.spoolman_tracking._get_spoolman_client_with_fallback",
  27. AsyncMock(return_value=client),
  28. ),
  29. patch("backend.app.services.print_cost_estimate._source_path", return_value=Path("/nonexistent.3mf")),
  30. ):
  31. cost = await pce.estimate_queue_source_cost(
  32. db_session, library_file=library_file, ams_mapping=[2], printer_id=printer.id
  33. )
  34. assert cost == expected
  35. @pytest.mark.asyncio
  36. @pytest.mark.integration
  37. async def test_only_the_spools_the_job_uses_are_asked_for(db_session, printer_factory):
  38. """Runs on queue add and at dispatch: no spool outside the mapped trays,
  39. and an unreachable Spoolman falls back to the default rate at once."""
  40. db_session.add(Settings(key="spoolman_enabled", value="true"))
  41. printer = await printer_factory()
  42. db_session.add(SpoolmanSlotAssignment(printer_id=printer.id, ams_id=0, tray_id=2, spoolman_spool_id=42))
  43. db_session.add(SpoolmanSlotAssignment(printer_id=printer.id, ams_id=0, tray_id=3, spoolman_spool_id=43))
  44. await db_session.commit()
  45. client = MagicMock()
  46. client.get_spool = AsyncMock(return_value={"id": 42, "price": 60.0, "initial_weight": 1000.0})
  47. library_file = MagicMock(file_metadata={"filament_used_grams": 100.0})
  48. with (
  49. patch(
  50. "backend.app.services.spoolman_tracking._get_spoolman_client_with_fallback",
  51. AsyncMock(return_value=client),
  52. ),
  53. patch("backend.app.services.print_cost_estimate._source_path", return_value=Path("/nonexistent.3mf")),
  54. ):
  55. await pce.estimate_queue_source_cost(
  56. db_session, library_file=library_file, ams_mapping=[2], printer_id=printer.id
  57. )
  58. client.get_spool.assert_awaited_once_with(42)
  59. with (
  60. patch(
  61. "backend.app.services.spoolman_tracking._get_spoolman_client_with_fallback", AsyncMock(return_value=None)
  62. ),
  63. patch("backend.app.services.print_cost_estimate._source_path", return_value=Path("/nonexistent.3mf")),
  64. ):
  65. cost = await pce.estimate_queue_source_cost(
  66. db_session, library_file=library_file, ams_mapping=[2], printer_id=printer.id
  67. )
  68. assert cost == 2.5