test_bambu_mqtt.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. """
  2. Tests for the BambuMQTTClient service.
  3. These tests focus on timelapse tracking during prints.
  4. """
  5. import pytest
  6. from unittest.mock import MagicMock, patch
  7. class TestTimelapseTracking:
  8. """Tests for timelapse state tracking during prints."""
  9. @pytest.fixture
  10. def mqtt_client(self):
  11. """Create a BambuMQTTClient instance for testing."""
  12. from backend.app.services.bambu_mqtt import BambuMQTTClient
  13. client = BambuMQTTClient(
  14. ip_address="192.168.1.100",
  15. serial_number="TEST123",
  16. access_code="12345678",
  17. )
  18. return client
  19. def test_timelapse_flag_initializes_to_false(self, mqtt_client):
  20. """Verify _timelapse_during_print starts as False."""
  21. assert mqtt_client._timelapse_during_print is False
  22. def test_timelapse_flag_set_when_timelapse_active_during_running(self, mqtt_client):
  23. """Verify timelapse flag is set when timelapse is active while printing."""
  24. # Simulate print running
  25. mqtt_client._was_running = True
  26. mqtt_client.state.timelapse = False
  27. # Simulate xcam data showing timelapse is enabled
  28. xcam_data = {"timelapse": "enable"}
  29. mqtt_client._parse_xcam_data(xcam_data)
  30. assert mqtt_client.state.timelapse is True
  31. assert mqtt_client._timelapse_during_print is True
  32. def test_timelapse_flag_not_set_when_not_running(self, mqtt_client):
  33. """Verify timelapse flag is NOT set when printer not running."""
  34. # Printer is idle (not running)
  35. mqtt_client._was_running = False
  36. mqtt_client.state.timelapse = False
  37. # Timelapse is enabled but we're not printing
  38. xcam_data = {"timelapse": "enable"}
  39. mqtt_client._parse_xcam_data(xcam_data)
  40. assert mqtt_client.state.timelapse is True
  41. # Flag should NOT be set since we're not printing
  42. assert mqtt_client._timelapse_during_print is False
  43. def test_timelapse_flag_persists_after_timelapse_stops(self, mqtt_client):
  44. """Verify timelapse flag stays True even after recording stops."""
  45. # Simulate print running with timelapse
  46. mqtt_client._was_running = True
  47. # Enable timelapse during print
  48. xcam_data = {"timelapse": "enable"}
  49. mqtt_client._parse_xcam_data(xcam_data)
  50. assert mqtt_client._timelapse_during_print is True
  51. # Disable timelapse (recording stops at end of print)
  52. xcam_data = {"timelapse": "disable"}
  53. mqtt_client._parse_xcam_data(xcam_data)
  54. # Flag should still be True (persists until reset)
  55. assert mqtt_client.state.timelapse is False
  56. assert mqtt_client._timelapse_during_print is True
  57. def test_timelapse_flag_from_print_data(self, mqtt_client):
  58. """Verify timelapse flag is set from print data (not just xcam)."""
  59. # Simulate print running
  60. mqtt_client._was_running = True
  61. mqtt_client.state.timelapse = False
  62. mqtt_client._timelapse_during_print = False
  63. # Manually test the timelapse parsing logic from _parse_print_data
  64. # This tests the "timelapse" field in the main print data
  65. data = {"timelapse": True}
  66. mqtt_client.state.timelapse = data["timelapse"] is True
  67. if mqtt_client.state.timelapse and mqtt_client._was_running:
  68. mqtt_client._timelapse_during_print = True
  69. assert mqtt_client._timelapse_during_print is True
  70. class TestPrintCompletionWithTimelapse:
  71. """Tests for print completion including timelapse flag."""
  72. @pytest.fixture
  73. def mqtt_client(self):
  74. """Create a BambuMQTTClient instance for testing."""
  75. from backend.app.services.bambu_mqtt import BambuMQTTClient
  76. client = BambuMQTTClient(
  77. ip_address="192.168.1.100",
  78. serial_number="TEST123",
  79. access_code="12345678",
  80. )
  81. return client
  82. def test_print_complete_includes_timelapse_flag(self, mqtt_client):
  83. """Verify print complete callback includes timelapse_was_active."""
  84. # Set up completion callback
  85. callback_data = {}
  86. def on_complete(data):
  87. callback_data.update(data)
  88. mqtt_client.on_print_complete = on_complete
  89. # Simulate a print that had timelapse active
  90. mqtt_client._was_running = True
  91. mqtt_client._completion_triggered = False
  92. mqtt_client._timelapse_during_print = True
  93. mqtt_client._previous_gcode_state = "RUNNING"
  94. mqtt_client._previous_gcode_file = "test.gcode"
  95. mqtt_client.state.subtask_name = "Test Print"
  96. # Simulate print finish
  97. mqtt_client.state.state = "FINISH"
  98. # Manually trigger the completion logic (simplified)
  99. # In real code this happens in _parse_print_data
  100. should_trigger = (
  101. mqtt_client.state.state in ("FINISH", "FAILED")
  102. and not mqtt_client._completion_triggered
  103. and mqtt_client.on_print_complete
  104. and mqtt_client._previous_gcode_state == "RUNNING"
  105. )
  106. if should_trigger:
  107. status = "completed" if mqtt_client.state.state == "FINISH" else "failed"
  108. timelapse_was_active = mqtt_client._timelapse_during_print
  109. mqtt_client._completion_triggered = True
  110. mqtt_client._was_running = False
  111. mqtt_client._timelapse_during_print = False
  112. mqtt_client.on_print_complete({
  113. "status": status,
  114. "filename": mqtt_client._previous_gcode_file,
  115. "subtask_name": mqtt_client.state.subtask_name,
  116. "timelapse_was_active": timelapse_was_active,
  117. })
  118. assert "timelapse_was_active" in callback_data
  119. assert callback_data["timelapse_was_active"] is True
  120. def test_print_complete_timelapse_flag_false_when_no_timelapse(self, mqtt_client):
  121. """Verify timelapse_was_active is False when no timelapse during print."""
  122. callback_data = {}
  123. def on_complete(data):
  124. callback_data.update(data)
  125. mqtt_client.on_print_complete = on_complete
  126. # Print without timelapse
  127. mqtt_client._was_running = True
  128. mqtt_client._completion_triggered = False
  129. mqtt_client._timelapse_during_print = False # No timelapse
  130. mqtt_client._previous_gcode_state = "RUNNING"
  131. mqtt_client._previous_gcode_file = "test.gcode"
  132. mqtt_client.state.subtask_name = "Test Print"
  133. mqtt_client.state.state = "FINISH"
  134. # Trigger completion
  135. timelapse_was_active = mqtt_client._timelapse_during_print
  136. mqtt_client.on_print_complete({
  137. "status": "completed",
  138. "filename": mqtt_client._previous_gcode_file,
  139. "subtask_name": mqtt_client.state.subtask_name,
  140. "timelapse_was_active": timelapse_was_active,
  141. })
  142. assert callback_data["timelapse_was_active"] is False
  143. def test_timelapse_flag_reset_after_completion(self, mqtt_client):
  144. """Verify _timelapse_during_print is reset after print completion."""
  145. mqtt_client._timelapse_during_print = True
  146. mqtt_client._was_running = True
  147. mqtt_client._completion_triggered = False
  148. # Simulate completion reset
  149. mqtt_client._completion_triggered = True
  150. mqtt_client._was_running = False
  151. mqtt_client._timelapse_during_print = False
  152. assert mqtt_client._timelapse_during_print is False