test_print_cost_estimate.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. from types import SimpleNamespace
  2. from unittest.mock import AsyncMock
  3. import pytest
  4. from backend.app.services import print_cost_estimate
  5. @pytest.fixture
  6. def library_file(tmp_path):
  7. path = tmp_path / "queued.gcode.3mf"
  8. path.write_bytes(b"stub")
  9. return SimpleNamespace(file_path=str(path), file_metadata={})
  10. @pytest.mark.asyncio
  11. async def test_archive_without_stored_cost_uses_server_default(monkeypatch):
  12. archive = SimpleNamespace(
  13. id=7,
  14. file_path="missing.gcode.3mf",
  15. plate_id=None,
  16. filament_used_grams=100.0,
  17. cost=None,
  18. )
  19. monkeypatch.setattr(print_cost_estimate, "_default_cost_per_kg", AsyncMock(return_value=20.0))
  20. cost = await print_cost_estimate.estimate_queue_source_cost(SimpleNamespace(), archive=archive)
  21. assert cost == 2.0
  22. @pytest.mark.asyncio
  23. async def test_library_estimate_uses_server_default_cost(monkeypatch, library_file):
  24. monkeypatch.setattr(
  25. print_cost_estimate.threemf_tools,
  26. "extract_plate_metadata_from_3mf",
  27. lambda *_args: SimpleNamespace(
  28. filament_usage=[
  29. {"slot_id": 1, "used_g": 100.0},
  30. {"slot_id": 2, "used_g": 50.0},
  31. ]
  32. ),
  33. )
  34. monkeypatch.setattr(print_cost_estimate, "_default_cost_per_kg", AsyncMock(return_value=20.0))
  35. cost = await print_cost_estimate.estimate_queue_source_cost(
  36. SimpleNamespace(),
  37. library_file=library_file,
  38. plate_id=1,
  39. )
  40. assert cost == 3.0
  41. @pytest.mark.asyncio
  42. async def test_library_estimate_uses_server_spool_assignment_costs(monkeypatch, library_file):
  43. monkeypatch.setattr(
  44. print_cost_estimate.threemf_tools,
  45. "extract_plate_metadata_from_3mf",
  46. lambda *_args: SimpleNamespace(
  47. filament_usage=[
  48. {"slot_id": 1, "used_g": 100.0},
  49. {"slot_id": 2, "used_g": 50.0},
  50. ]
  51. ),
  52. )
  53. monkeypatch.setattr(print_cost_estimate, "_default_cost_per_kg", AsyncMock(return_value=20.0))
  54. assignments = [
  55. SimpleNamespace(ams_id=0, tray_id=0, spool=SimpleNamespace(cost_per_kg=10.0)),
  56. SimpleNamespace(ams_id=0, tray_id=1, spool=SimpleNamespace(cost_per_kg=30.0)),
  57. ]
  58. result = SimpleNamespace(scalars=lambda: SimpleNamespace(all=lambda: assignments))
  59. db = SimpleNamespace(execute=AsyncMock(return_value=result))
  60. cost = await print_cost_estimate.estimate_queue_source_cost(
  61. db,
  62. library_file=library_file,
  63. plate_id=1,
  64. ams_mapping=[0, 1],
  65. printer_id=7,
  66. )
  67. assert cost == 2.5
  68. @pytest.mark.asyncio
  69. async def test_missing_server_metadata_does_not_fall_back_to_client_hint(monkeypatch, library_file):
  70. monkeypatch.setattr(
  71. print_cost_estimate.threemf_tools,
  72. "extract_plate_metadata_from_3mf",
  73. lambda *_args: SimpleNamespace(filament_usage=[]),
  74. )
  75. cost = await print_cost_estimate.estimate_queue_source_cost(
  76. SimpleNamespace(),
  77. library_file=library_file,
  78. plate_id=1,
  79. )
  80. assert cost is None