test_log_error_detection.py 10 KB

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