From 8178dea15a85e41b728f332e84200b95453710be Mon Sep 17 00:00:00 2001 From: Anton Skrypnyk Date: Wed, 24 Jul 2024 17:15:46 +0300 Subject: [PATCH] Fix unittest IO synchronization. --- .../printer/bambu_virtual_printer.py | 23 ---------- .../printer/printer_serial_io.py | 8 +++- .../printer/remote_sd_card_file_list.py | 16 +++---- test/test_gcode_execution.py | 44 ++++++++++++++++--- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/octoprint_bambu_printer/printer/bambu_virtual_printer.py b/octoprint_bambu_printer/printer/bambu_virtual_printer.py index 6633920..223dfb4 100644 --- a/octoprint_bambu_printer/printer/bambu_virtual_printer.py +++ b/octoprint_bambu_printer/printer/bambu_virtual_printer.py @@ -6,9 +6,7 @@ import collections from dataclasses import dataclass, field import math import os -import queue import re -import threading import time import asyncio from pybambu import BambuClient, commands @@ -478,27 +476,6 @@ class BambuVirtualPrinter: else: return False - def _writeSdFile(self, filename: str) -> None: - self.sendIO(f"Writing to file: {filename}") - - def _finishSdFile(self): - # FIXME: maybe remove or move to remote SD card - try: - self._writingToSdHandle.close() - except Exception: - pass - finally: - self._writingToSdHandle = None - self._writingToSd = False - self._selectedSdFile = None - # Most printers don't have RTC and set some ancient date - # by default. Emulate that using 2000-01-01 01:00:00 - # (taken from prusa firmware behaviour) - st = os.stat(self._writingToSdFile) - os.utime(self._writingToSdFile, (st.st_atime, 946684800)) - self._writingToSdFile = None - self.sendIO("Done saving file") - def close(self): if self.bambu_client.connected: self.bambu_client.disconnect() diff --git a/octoprint_bambu_printer/printer/printer_serial_io.py b/octoprint_bambu_printer/printer/printer_serial_io.py index 7ce55d5..36c750c 100644 --- a/octoprint_bambu_printer/printer/printer_serial_io.py +++ b/octoprint_bambu_printer/printer/printer_serial_io.py @@ -44,6 +44,7 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase): self.input_bytes = CharCountingQueue(self._rx_buffer_size, name="RxBuffer") self.output_bytes = queue.Queue() + self._error_detected: Exception | None = None def _init_logger(self, log_handler): log = logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter.serial") @@ -63,7 +64,6 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase): try: data = self.input_bytes.get(block=True, timeout=0.01) data = to_bytes(data, encoding="ascii", errors="replace") - self.input_bytes.task_done() buffer += data line, buffer = self._read_next_line(buffer) @@ -71,8 +71,12 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase): self._received_lines += 1 self._process_input_gcode_line(line) line, buffer = self._read_next_line(buffer) + self.input_bytes.task_done() except queue.Empty: continue + except Exception as e: + self._error_detected = e + break self._log.debug("Closing IO read loop") @@ -92,6 +96,8 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase): def flush(self): self.input_bytes.join() + if self._error_detected is not None: + raise self._error_detected def write(self, data: bytes) -> int: data = to_bytes(data, errors="replace") diff --git a/octoprint_bambu_printer/printer/remote_sd_card_file_list.py b/octoprint_bambu_printer/printer/remote_sd_card_file_list.py index a11d524..ab978f5 100644 --- a/octoprint_bambu_printer/printer/remote_sd_card_file_list.py +++ b/octoprint_bambu_printer/printer/remote_sd_card_file_list.py @@ -80,18 +80,12 @@ class RemoteSDCardFileList: def _get_existing_files_info(self): ftp = self._connect_ftps_server() - all_files_info: list[FileInfo] = [] + file_list = [] + file_list.extend(ftp.list_files("", ".3mf") or []) + file_list.extend(ftp.list_files("cache/", ".3mf") or []) + existing_files = [] - - filelist = ftp.list_files("", ".3mf") or [] - all_files_info.extend(self._scan_ftp_file_list(ftp, filelist, existing_files)) - - filelist_cache = ftp.list_files("cache/", ".3mf") or [] - all_files_info.extend( - self._scan_ftp_file_list(ftp, filelist_cache, existing_files) - ) - - return all_files_info + return list(self._scan_ftp_file_list(ftp, file_list, existing_files)) def _connect_ftps_server(self): host = self._settings.get(["host"]) diff --git a/test/test_gcode_execution.py b/test/test_gcode_execution.py index 9fcbbfe..bd70e0c 100644 --- a/test/test_gcode_execution.py +++ b/test/test_gcode_execution.py @@ -84,6 +84,8 @@ def files_info_ftp(): return { "print.3mf": (1000, _f_date(datetime(2024, 5, 6))), "print2.3mf": (1200, _f_date(datetime(2024, 5, 7))), + "cache/print.3mf": (1200, _f_date(datetime(2024, 5, 7))), + "cache/print2.3mf": (1200, _f_date(datetime(2024, 5, 7))), } @@ -104,8 +106,12 @@ def ftps_session_mock(files_info_ftp): all_files = list(files_info_ftp.keys()) file_registry = DictGetter( { - ("", ".3mf"): all_files, - ("cache/", ".3mf"): [f"cache/{file}" for file in all_files], + ("", ".3mf"): list( + filter(lambda f: Path(f).parent == Path("."), all_files) + ), + ("cache/", ".3mf"): list( + filter(lambda f: Path(f).parent == Path("cache/"), all_files) + ), } ) ftps_client_mock.list_files.side_effect = lambda folder, ext: file_registry( @@ -118,7 +124,7 @@ def ftps_session_mock(files_info_ftp): yield -@fixture +@fixture(scope="function") def printer(output_test_folder, settings, profile_manager, log_test, ftps_session_mock): async def _mock_connection(self): pass @@ -145,12 +151,36 @@ def test_list_sd_card(printer: BambuVirtualPrinter): printer.write(b"M20\n") # GCode for listing SD card printer.flush() result = printer.readlines() - assert result == "" # Replace with the actual expected result + assert result[0] == b"Begin file list" + assert result[1].endswith(b'"print.3mf"') + assert result[2].endswith(b'"print2.3mf"') + assert result[3] == b"End file list" + assert result[4] == b"ok" -def test_start_print(printer: BambuVirtualPrinter): - printer.write(b"M\n") - result = printer.readline() +def test_cannot_start_print_without_file(printer: BambuVirtualPrinter): + printer.write(b"M24\n") + printer.flush() + + result = printer.readlines() + assert result[0] == b"ok" + assert isinstance(printer.current_state, IdleState) + + +def test_print_started_with_selected_file(printer: BambuVirtualPrinter): + assert printer.file_system.selected_file is None + + printer.write(b"M23 print.3mf\n") + printer.flush() + + assert printer.file_system.selected_file is not None + assert printer.file_system.selected_file.file_name == "print.3mf" + + printer.write(b"M24\n") + printer.flush() + + result = printer.readlines() + assert result[0] == b"ok" assert isinstance(printer.current_state, PrintingState)