Fix unittest IO synchronization.

This commit is contained in:
Anton Skrypnyk 2024-07-24 17:15:46 +03:00
parent 73f77ed659
commit 8178dea15a
4 changed files with 49 additions and 42 deletions

View File

@ -6,9 +6,7 @@ import collections
from dataclasses import dataclass, field from dataclasses import dataclass, field
import math import math
import os import os
import queue
import re import re
import threading
import time import time
import asyncio import asyncio
from pybambu import BambuClient, commands from pybambu import BambuClient, commands
@ -478,27 +476,6 @@ class BambuVirtualPrinter:
else: else:
return False 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): def close(self):
if self.bambu_client.connected: if self.bambu_client.connected:
self.bambu_client.disconnect() self.bambu_client.disconnect()

View File

@ -44,6 +44,7 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase):
self.input_bytes = CharCountingQueue(self._rx_buffer_size, name="RxBuffer") self.input_bytes = CharCountingQueue(self._rx_buffer_size, name="RxBuffer")
self.output_bytes = queue.Queue() self.output_bytes = queue.Queue()
self._error_detected: Exception | None = None
def _init_logger(self, log_handler): def _init_logger(self, log_handler):
log = logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter.serial") log = logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter.serial")
@ -63,7 +64,6 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase):
try: try:
data = self.input_bytes.get(block=True, timeout=0.01) data = self.input_bytes.get(block=True, timeout=0.01)
data = to_bytes(data, encoding="ascii", errors="replace") data = to_bytes(data, encoding="ascii", errors="replace")
self.input_bytes.task_done()
buffer += data buffer += data
line, buffer = self._read_next_line(buffer) line, buffer = self._read_next_line(buffer)
@ -71,8 +71,12 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase):
self._received_lines += 1 self._received_lines += 1
self._process_input_gcode_line(line) self._process_input_gcode_line(line)
line, buffer = self._read_next_line(buffer) line, buffer = self._read_next_line(buffer)
self.input_bytes.task_done()
except queue.Empty: except queue.Empty:
continue continue
except Exception as e:
self._error_detected = e
break
self._log.debug("Closing IO read loop") self._log.debug("Closing IO read loop")
@ -92,6 +96,8 @@ class PrinterSerialIO(threading.Thread, BufferedIOBase):
def flush(self): def flush(self):
self.input_bytes.join() self.input_bytes.join()
if self._error_detected is not None:
raise self._error_detected
def write(self, data: bytes) -> int: def write(self, data: bytes) -> int:
data = to_bytes(data, errors="replace") data = to_bytes(data, errors="replace")

View File

@ -80,18 +80,12 @@ class RemoteSDCardFileList:
def _get_existing_files_info(self): def _get_existing_files_info(self):
ftp = self._connect_ftps_server() 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 = [] existing_files = []
return list(self._scan_ftp_file_list(ftp, file_list, 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
def _connect_ftps_server(self): def _connect_ftps_server(self):
host = self._settings.get(["host"]) host = self._settings.get(["host"])

View File

@ -84,6 +84,8 @@ def files_info_ftp():
return { return {
"print.3mf": (1000, _f_date(datetime(2024, 5, 6))), "print.3mf": (1000, _f_date(datetime(2024, 5, 6))),
"print2.3mf": (1200, _f_date(datetime(2024, 5, 7))), "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()) all_files = list(files_info_ftp.keys())
file_registry = DictGetter( file_registry = DictGetter(
{ {
("", ".3mf"): all_files, ("", ".3mf"): list(
("cache/", ".3mf"): [f"cache/{file}" for file in all_files], 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( ftps_client_mock.list_files.side_effect = lambda folder, ext: file_registry(
@ -118,7 +124,7 @@ def ftps_session_mock(files_info_ftp):
yield yield
@fixture @fixture(scope="function")
def printer(output_test_folder, settings, profile_manager, log_test, ftps_session_mock): def printer(output_test_folder, settings, profile_manager, log_test, ftps_session_mock):
async def _mock_connection(self): async def _mock_connection(self):
pass pass
@ -145,12 +151,36 @@ def test_list_sd_card(printer: BambuVirtualPrinter):
printer.write(b"M20\n") # GCode for listing SD card printer.write(b"M20\n") # GCode for listing SD card
printer.flush() printer.flush()
result = printer.readlines() 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): def test_cannot_start_print_without_file(printer: BambuVirtualPrinter):
printer.write(b"M\n") printer.write(b"M24\n")
result = printer.readline() 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) assert isinstance(printer.current_state, PrintingState)