test_printer_kill_switch.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. from types import SimpleNamespace
  2. import pytest
  3. from backend.app import main as main_module
  4. @pytest.fixture(autouse=True)
  5. def clear_kill_switch_state():
  6. main_module._unauthorized_print_kill_sent.clear()
  7. main_module._expected_prints.clear()
  8. main_module._active_prints.clear()
  9. main_module._expected_print_registered_at.clear()
  10. yield
  11. main_module._unauthorized_print_kill_sent.clear()
  12. main_module._expected_prints.clear()
  13. main_module._active_prints.clear()
  14. main_module._expected_print_registered_at.clear()
  15. def test_gcode_3mf_status_filename_matches_registered_expected_print():
  16. state = SimpleNamespace(
  17. current_print=None,
  18. subtask_name="",
  19. gcode_file="foreign_job.gcode.3mf",
  20. )
  21. keys = main_module._build_status_print_keys(7, state)
  22. assert (7, "foreign_job.gcode.3mf") in keys
  23. assert (7, "foreign_job.gcode") in keys
  24. @pytest.mark.asyncio
  25. async def test_unauthorized_active_print_triggers_stop(monkeypatch):
  26. stop_calls: list[int] = []
  27. async def fake_status(*args, **kwargs):
  28. return None
  29. async def kill_switch_enabled(_db):
  30. return True
  31. monkeypatch.setattr(main_module.printer_manager, "get_current_print_user", lambda printer_id: None)
  32. monkeypatch.setattr(
  33. main_module.printer_manager, "stop_print", lambda printer_id: stop_calls.append(printer_id) or True
  34. )
  35. monkeypatch.setattr(main_module.printer_manager, "get_printer", lambda printer_id: None)
  36. monkeypatch.setattr(main_module.printer_manager, "get_model", lambda printer_id: None)
  37. monkeypatch.setattr(main_module, "printer_state_to_dict", lambda *args, **kwargs: {})
  38. monkeypatch.setattr(main_module.mqtt_relay, "on_printer_status", fake_status)
  39. monkeypatch.setattr(main_module.ws_manager, "send_printer_status", fake_status)
  40. monkeypatch.setattr("backend.app.services.finance_budget.is_printer_kill_switch_enabled", kill_switch_enabled)
  41. state = SimpleNamespace(
  42. connected=True,
  43. state="RUNNING",
  44. progress=0,
  45. layer_num=0,
  46. temperatures={},
  47. raw_data={},
  48. stg_cur=0,
  49. cooling_fan_speed=None,
  50. big_fan1_speed=None,
  51. big_fan2_speed=None,
  52. chamber_light=False,
  53. active_extruder=0,
  54. tray_now=255,
  55. door_open=False,
  56. ams_filament_backup=False,
  57. current_print=None,
  58. subtask_name="foreign_job",
  59. gcode_file="foreign_job.gcode",
  60. )
  61. await main_module.on_printer_status_change(7, state)
  62. assert stop_calls == [7]
  63. assert 7 in main_module._unauthorized_print_kill_sent
  64. @pytest.mark.asyncio
  65. async def test_bambuddy_authorized_print_is_not_stopped(monkeypatch):
  66. monkeypatch.setitem(main_module._expected_prints, (7, "foreign_job"), 123)
  67. stop_calls: list[int] = []
  68. async def fake_status(*args, **kwargs):
  69. return None
  70. async def kill_switch_enabled(_db):
  71. return True
  72. monkeypatch.setattr(main_module.printer_manager, "get_current_print_user", lambda printer_id: None)
  73. monkeypatch.setattr(
  74. main_module.printer_manager, "stop_print", lambda printer_id: stop_calls.append(printer_id) or True
  75. )
  76. monkeypatch.setattr(main_module.printer_manager, "get_printer", lambda printer_id: None)
  77. monkeypatch.setattr(main_module.printer_manager, "get_model", lambda printer_id: None)
  78. monkeypatch.setattr(main_module, "printer_state_to_dict", lambda *args, **kwargs: {})
  79. monkeypatch.setattr(main_module.mqtt_relay, "on_printer_status", fake_status)
  80. monkeypatch.setattr(main_module.ws_manager, "send_printer_status", fake_status)
  81. monkeypatch.setattr("backend.app.services.finance_budget.is_printer_kill_switch_enabled", kill_switch_enabled)
  82. state = SimpleNamespace(
  83. connected=True,
  84. state="RUNNING",
  85. progress=0,
  86. layer_num=0,
  87. temperatures={},
  88. raw_data={},
  89. stg_cur=0,
  90. cooling_fan_speed=None,
  91. big_fan1_speed=None,
  92. big_fan2_speed=None,
  93. chamber_light=False,
  94. active_extruder=0,
  95. tray_now=255,
  96. door_open=False,
  97. ams_filament_backup=False,
  98. current_print=None,
  99. subtask_name="foreign_job",
  100. gcode_file="foreign_job.gcode",
  101. )
  102. await main_module.on_printer_status_change(7, state)
  103. assert stop_calls == []
  104. assert 7 not in main_module._unauthorized_print_kill_sent
  105. @pytest.mark.asyncio
  106. async def test_unauthorized_print_state_is_cleared_when_print_ends(monkeypatch):
  107. stop_calls: list[int] = []
  108. async def fake_status(*args, **kwargs):
  109. return None
  110. async def kill_switch_enabled(_db):
  111. return True
  112. monkeypatch.setattr(main_module.printer_manager, "get_current_print_user", lambda printer_id: None)
  113. monkeypatch.setattr(
  114. main_module.printer_manager, "stop_print", lambda printer_id: stop_calls.append(printer_id) or True
  115. )
  116. monkeypatch.setattr(main_module.printer_manager, "get_printer", lambda printer_id: None)
  117. monkeypatch.setattr(main_module.printer_manager, "get_model", lambda printer_id: None)
  118. monkeypatch.setattr(main_module, "printer_state_to_dict", lambda *args, **kwargs: {})
  119. monkeypatch.setattr(main_module.mqtt_relay, "on_printer_status", fake_status)
  120. monkeypatch.setattr(main_module.ws_manager, "send_printer_status", fake_status)
  121. monkeypatch.setattr("backend.app.services.finance_budget.is_printer_kill_switch_enabled", kill_switch_enabled)
  122. active_state = SimpleNamespace(
  123. connected=True,
  124. state="RUNNING",
  125. progress=0,
  126. layer_num=0,
  127. temperatures={},
  128. raw_data={},
  129. stg_cur=0,
  130. cooling_fan_speed=None,
  131. big_fan1_speed=None,
  132. big_fan2_speed=None,
  133. chamber_light=False,
  134. active_extruder=0,
  135. tray_now=255,
  136. door_open=False,
  137. ams_filament_backup=False,
  138. current_print=None,
  139. subtask_name="foreign_job",
  140. gcode_file="foreign_job.gcode",
  141. )
  142. idle_state = SimpleNamespace(
  143. connected=True,
  144. state="IDLE",
  145. progress=0,
  146. layer_num=0,
  147. temperatures={},
  148. raw_data={},
  149. stg_cur=0,
  150. cooling_fan_speed=None,
  151. big_fan1_speed=None,
  152. big_fan2_speed=None,
  153. chamber_light=False,
  154. active_extruder=0,
  155. tray_now=255,
  156. door_open=False,
  157. ams_filament_backup=False,
  158. current_print=None,
  159. subtask_name="",
  160. gcode_file=None,
  161. )
  162. await main_module.on_printer_status_change(7, active_state)
  163. assert stop_calls == [7]
  164. assert 7 in main_module._unauthorized_print_kill_sent
  165. await main_module.on_printer_status_change(7, idle_state)
  166. assert 7 not in main_module._unauthorized_print_kill_sent