fix: v0.4.3 修复长会话越跑越卡/命令无响应——日志手工 cursor 裁剪在 PySide6 6.11 必抛异常且打断 _poll_dlpc 消费;改 setMaximumBlockCount(500) 环形裁剪+逐事件兜底;新增 selftest_log 回归;重打包
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# coding: utf-8
|
||||
"""收发日志上限与队列消费回归自检(无窗口, 离屏渲染)。
|
||||
|
||||
背景: v0.4.3 之前收发日志用 textCursor 手工裁剪, 其中 `cursor.Start` /
|
||||
`cursor.BlockUnderCursor` 是实例级枚举访问 —— PySide6 6.11 移除了该形式,
|
||||
日志一旦超过 500 行, 每次 _dlpc_log 追加后必抛 AttributeError; 且异常会
|
||||
逃出 _poll_dlpc 的 drain 循环(旧 try 只捕获 queue.Empty), 每 tick 最多
|
||||
消费到第一条 event, `_dlpc_log_q` 棘轮积压、日志裁剪与自动滚动全部失效,
|
||||
电源自检/功率检测序列还会被异常打断在启动处(之后所有命令被"序列进行中"
|
||||
拦截)。v0.4.3 改为 setMaximumBlockCount 环形裁剪 + 逐事件异常兜底。
|
||||
|
||||
本测试保证:
|
||||
1. 连续追加 600 行日志不抛异常, document().blockCount() 环形封顶 500, 末行在;
|
||||
2. 单条异常事件(模拟未来引入的坏数据)不中断 _poll_dlpc 本轮队列消费
|
||||
—— 其后的事件仍全部入日志、队列清空。
|
||||
|
||||
运行: python selftest_log.py (依赖 PySide6-Fluent-Widgets 与 pyserial ——
|
||||
串口卡构建后 txt_dlpc 才存在)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from qfluentwidgets import Theme, setTheme
|
||||
|
||||
import app_fluent
|
||||
import dlpc_rs485
|
||||
|
||||
|
||||
def check_cap(win):
|
||||
for i in range(600):
|
||||
win._dlpc_log(f"cap-line-{i}")
|
||||
blocks = win.txt_dlpc.document().blockCount()
|
||||
has_last = "cap-line-599" in win.txt_dlpc.toPlainText()
|
||||
print(f" 追加 600 行: blockCount={blocks}(封顶 500), 末行在: {has_last}")
|
||||
return blocks <= 500 and has_last
|
||||
|
||||
|
||||
def check_drain_resilience(win):
|
||||
win._timer.stop() # 排除 80ms 轮询定时器干扰
|
||||
win._dlpc_log_q.put(("pdframe", "poison-not-a-frame")) # 该条分发必抛异常
|
||||
win._dlpc_log_q.put(("event", "after-poison-1"))
|
||||
win._dlpc_log_q.put(("event", "after-poison-2"))
|
||||
win._poll_dlpc() # 单次手动驱动(不进事件循环)
|
||||
left = win._dlpc_log_q.qsize()
|
||||
text = win.txt_dlpc.toPlainText()
|
||||
drained = left == 0 and "after-poison-1" in text and "after-poison-2" in text
|
||||
print(f" 坏条目后消费不中断: 残留队列={left}, 后续事件全部写入: {drained}")
|
||||
return drained
|
||||
|
||||
|
||||
def main():
|
||||
if not dlpc_rs485.HAS_SERIAL:
|
||||
print("FAILED 缺少 pyserial: 串口卡未构建, txt_dlpc 不存在")
|
||||
return 1
|
||||
app = QApplication.instance() or QApplication(sys.argv)
|
||||
setTheme(Theme.AUTO)
|
||||
win = app_fluent.App(0)
|
||||
passed = check_cap(win)
|
||||
passed &= check_drain_resilience(win)
|
||||
win.close()
|
||||
print("ALL PASS" if passed else "FAILED")
|
||||
return 0 if passed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user