test_log_error_detection.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. """
  2. Tests that verify no errors are logged during normal operations.
  3. These tests use the capture_logs fixture to detect runtime errors
  4. that might not cause test failures but indicate problems.
  5. """
  6. class TestMQTTMessageProcessingNoErrors:
  7. """Verify MQTT message processing doesn't log errors."""
  8. def test_process_print_status_message(self, capture_logs):
  9. """Test processing a typical print status message."""
  10. from backend.app.services.bambu_mqtt import BambuMQTTClient
  11. client = BambuMQTTClient(
  12. ip_address="192.168.1.100",
  13. serial_number="TEST123",
  14. access_code="12345678",
  15. )
  16. # Process a realistic status message
  17. message = {
  18. "print": {
  19. "gcode_state": "RUNNING",
  20. "gcode_file": "/data/Metadata/test.gcode",
  21. "subtask_name": "Test Print",
  22. "mc_percent": 50,
  23. "mc_remaining_time": 1800,
  24. "layer_num": 100,
  25. "total_layer_num": 200,
  26. "nozzle_temper": 220.0,
  27. "bed_temper": 60.0,
  28. }
  29. }
  30. client._process_message(message)
  31. assert not capture_logs.has_errors(), f"Errors during message processing: {capture_logs.format_errors()}"
  32. def test_process_xcam_data(self, capture_logs):
  33. """Test processing xcam (camera/AI) data."""
  34. from backend.app.services.bambu_mqtt import BambuMQTTClient
  35. client = BambuMQTTClient(
  36. ip_address="192.168.1.100",
  37. serial_number="TEST123",
  38. access_code="12345678",
  39. )
  40. message = {
  41. "print": {
  42. "gcode_state": "RUNNING",
  43. "xcam": {
  44. "timelapse": "enable",
  45. "printing_monitor": True,
  46. "spaghetti_detector": True,
  47. "first_layer_inspector": False,
  48. },
  49. }
  50. }
  51. client._process_message(message)
  52. assert not capture_logs.has_errors(), f"Errors during xcam processing: {capture_logs.format_errors()}"
  53. def test_process_ams_data(self, capture_logs):
  54. """Test processing AMS (Automatic Material System) data."""
  55. from backend.app.services.bambu_mqtt import BambuMQTTClient
  56. client = BambuMQTTClient(
  57. ip_address="192.168.1.100",
  58. serial_number="TEST123",
  59. access_code="12345678",
  60. )
  61. message = {
  62. "print": {
  63. "ams": {
  64. "ams": [
  65. {
  66. "id": "0",
  67. "humidity": "3",
  68. "temp": "25.0",
  69. "tray": [
  70. {
  71. "id": "0",
  72. "tray_type": "PLA",
  73. "tray_color": "FF0000",
  74. "remain": 80,
  75. }
  76. ],
  77. }
  78. ]
  79. }
  80. }
  81. }
  82. client._process_message(message)
  83. assert not capture_logs.has_errors(), f"Errors during AMS processing: {capture_logs.format_errors()}"
  84. def test_process_hms_errors(self, capture_logs):
  85. """Test processing HMS (Health Management System) errors."""
  86. from backend.app.services.bambu_mqtt import BambuMQTTClient
  87. client = BambuMQTTClient(
  88. ip_address="192.168.1.100",
  89. serial_number="TEST123",
  90. access_code="12345678",
  91. )
  92. message = {
  93. "print": {
  94. "hms": [
  95. {
  96. "attr": 0,
  97. "code": 117506052,
  98. }
  99. ]
  100. }
  101. }
  102. client._process_message(message)
  103. assert not capture_logs.has_errors(), f"Errors during HMS processing: {capture_logs.format_errors()}"
  104. class TestPrintLifecycleNoErrors:
  105. """Verify print lifecycle doesn't log errors."""
  106. def test_print_start_to_complete(self, capture_logs):
  107. """Test full print lifecycle from start to completion."""
  108. from backend.app.services.bambu_mqtt import BambuMQTTClient
  109. client = BambuMQTTClient(
  110. ip_address="192.168.1.100",
  111. serial_number="TEST123",
  112. access_code="12345678",
  113. )
  114. client.on_print_start = lambda data: None
  115. client.on_print_complete = lambda data: None
  116. # Start print
  117. client._process_message(
  118. {
  119. "print": {
  120. "gcode_state": "RUNNING",
  121. "gcode_file": "/data/Metadata/test.gcode",
  122. "subtask_name": "Test",
  123. "mc_percent": 0,
  124. }
  125. }
  126. )
  127. # Progress updates
  128. for percent in [25, 50, 75]:
  129. client._process_message(
  130. {
  131. "print": {
  132. "gcode_state": "RUNNING",
  133. "gcode_file": "/data/Metadata/test.gcode",
  134. "mc_percent": percent,
  135. }
  136. }
  137. )
  138. # Complete
  139. client._process_message(
  140. {
  141. "print": {
  142. "gcode_state": "FINISH",
  143. "gcode_file": "/data/Metadata/test.gcode",
  144. "subtask_name": "Test",
  145. }
  146. }
  147. )
  148. assert not capture_logs.has_errors(), f"Errors during print lifecycle: {capture_logs.format_errors()}"
  149. def test_print_failure_handling(self, capture_logs):
  150. """Test print failure is handled without errors."""
  151. from backend.app.services.bambu_mqtt import BambuMQTTClient
  152. client = BambuMQTTClient(
  153. ip_address="192.168.1.100",
  154. serial_number="TEST123",
  155. access_code="12345678",
  156. )
  157. client.on_print_start = lambda data: None
  158. client.on_print_complete = lambda data: None
  159. # Start print
  160. client._process_message(
  161. {
  162. "print": {
  163. "gcode_state": "RUNNING",
  164. "gcode_file": "/data/Metadata/test.gcode",
  165. "subtask_name": "Test",
  166. }
  167. }
  168. )
  169. # Fail
  170. client._process_message(
  171. {
  172. "print": {
  173. "gcode_state": "FAILED",
  174. "gcode_file": "/data/Metadata/test.gcode",
  175. "subtask_name": "Test",
  176. "print_error": 117506052,
  177. }
  178. }
  179. )
  180. assert not capture_logs.has_errors(), f"Errors during print failure: {capture_logs.format_errors()}"
  181. class TestServiceImports:
  182. """Verify service imports don't have issues."""
  183. def test_archive_service_import(self, capture_logs):
  184. """Verify ArchiveService can be imported without errors."""
  185. from backend.app.services.archive import ArchiveService
  186. assert ArchiveService is not None
  187. assert not capture_logs.has_errors()
  188. def test_notification_service_import(self, capture_logs):
  189. """Verify NotificationService can be imported without errors."""
  190. from backend.app.services.notification_service import notification_service
  191. assert notification_service is not None
  192. assert not capture_logs.has_errors()
  193. def test_printer_manager_import(self, capture_logs):
  194. """Verify PrinterManager can be imported without errors."""
  195. from backend.app.services.printer_manager import printer_manager
  196. assert printer_manager is not None
  197. assert not capture_logs.has_errors()
  198. def test_main_module_import(self, capture_logs):
  199. """Verify main module imports cleanly."""
  200. # This will fail if there are import shadowing issues
  201. from backend.app import main
  202. assert main is not None
  203. # Verify key functions exist
  204. assert hasattr(main, "on_print_start")
  205. assert hasattr(main, "on_print_complete")
  206. assert not capture_logs.has_errors()
  207. class TestEdgeCases:
  208. """Test edge cases that might cause errors."""
  209. def test_empty_message(self, capture_logs):
  210. """Test handling of empty message."""
  211. from backend.app.services.bambu_mqtt import BambuMQTTClient
  212. client = BambuMQTTClient(
  213. ip_address="192.168.1.100",
  214. serial_number="TEST123",
  215. access_code="12345678",
  216. )
  217. client._process_message({})
  218. assert not capture_logs.has_errors(), f"Errors with empty message: {capture_logs.format_errors()}"
  219. def test_message_with_unknown_fields(self, capture_logs):
  220. """Test handling of message with unknown fields."""
  221. from backend.app.services.bambu_mqtt import BambuMQTTClient
  222. client = BambuMQTTClient(
  223. ip_address="192.168.1.100",
  224. serial_number="TEST123",
  225. access_code="12345678",
  226. )
  227. client._process_message(
  228. {
  229. "print": {
  230. "gcode_state": "RUNNING",
  231. "unknown_field_1": "value1",
  232. "unknown_field_2": 12345,
  233. "unknown_nested": {"a": 1, "b": 2},
  234. }
  235. }
  236. )
  237. assert not capture_logs.has_errors(), f"Errors with unknown fields: {capture_logs.format_errors()}"
  238. def test_message_with_null_values(self, capture_logs):
  239. """Test handling of message with null values for optional fields."""
  240. from backend.app.services.bambu_mqtt import BambuMQTTClient
  241. client = BambuMQTTClient(
  242. ip_address="192.168.1.100",
  243. serial_number="TEST123",
  244. access_code="12345678",
  245. )
  246. # Only test null values for fields that should handle them gracefully
  247. # mc_percent is expected to be a number when present
  248. client._process_message(
  249. {
  250. "print": {
  251. "gcode_state": "IDLE",
  252. "gcode_file": None,
  253. "subtask_name": None,
  254. "bed_temper": 0.0, # Use 0 instead of None
  255. }
  256. }
  257. )
  258. assert not capture_logs.has_errors(), f"Errors with null values: {capture_logs.format_errors()}"