68 lines
3.3 KiB
Python
68 lines
3.3 KiB
Python
"""Exercise Qt and backend shutdown with no device transport in the UI."""
|
|
import sys
|
|
import os
|
|
import time
|
|
from station import runtime_client as runtime
|
|
runtime.start(offline=True)
|
|
import station.operator_app as ui
|
|
app=ui.QApplication.instance();app.setFont(ui.QFont('Noto Sans SC',11));app.setStyleSheet(ui._STYLE)
|
|
window=ui.StationApp();window.resize(1440,900);window.show()
|
|
window._apply_theme('dark',persist=False)
|
|
assert app.property('darkTheme') is True
|
|
assert window._theme_selector.currentData()=='dark'
|
|
window._apply_theme('light',persist=False)
|
|
assert app.property('darkTheme') is False
|
|
assert window._theme_selector.currentData()=='light'
|
|
assert 'rclpy' not in sys.modules
|
|
assert 'serial' not in sys.modules
|
|
assert 'station.operator_console' not in sys.modules
|
|
assert set(window._pages) == {'main','calibration','settings','ros_monitor'}
|
|
# A photo must preserve the current RGB frame; no capture/device operation is needed.
|
|
import tempfile
|
|
from unittest.mock import patch
|
|
sample=bytes([12,84,192])*(32*18)
|
|
selected=next(cam for _page,cam,_label in window._camera_labels if cam.get('arm')==window._arm)
|
|
with tempfile.TemporaryDirectory() as pictures:
|
|
with patch.object(ui.Path,'home',return_value=ui.Path(pictures)), patch.object(ui.camera_view,'previews',return_value={selected['id']+'_color':(sample,32,18)}):
|
|
window._take_photo()
|
|
photos=list(ui.Path(pictures).rglob('*.png'))
|
|
assert len(photos)==1
|
|
image=ui.QImage(str(photos[0]))
|
|
assert (image.width(),image.height())==(32,18)
|
|
assert image.pixelColor(0,0).getRgb()[:3]==(12,84,192)
|
|
window._open_camera(selected['id'])
|
|
assert selected['id'] in window._camera_windows
|
|
window._camera_windows[selected['id']].close()
|
|
assert not window._camera_windows
|
|
errors=[];ticks=[]
|
|
duration=float(os.environ.get("ORISYS_GUI_TEST_SECONDS","2.2"))
|
|
started=time.monotonic()
|
|
frames=[bytes([v,40,80])*(320*180) for v in (30,70,120)]
|
|
def tick():
|
|
ticks.append(time.monotonic())
|
|
if duration>10:
|
|
if len(ticks)%100==0:
|
|
window._show_page(("main","calibration")[(len(ticks)//100)%2])
|
|
for key in ui.camera_view._PREVIEW_WANT:
|
|
ui.camera_view._PREVIEW[key]=(frames[len(ticks)%3],320,180)
|
|
ui.camera_view._META[key]=(320,180,20.)
|
|
original=sys.excepthook
|
|
def fail(*args): errors.append(str(args[1]));original(*args)
|
|
sys.excepthook=fail
|
|
beat=ui.QTimer();beat.timeout.connect(tick);beat.start(50)
|
|
ui.QTimer.singleShot(200,lambda:window._start(lambda:(time.sleep(.7),{'ok':True,'message':'test'})[1],'test'))
|
|
ui.QTimer.singleShot(500,lambda:window._show_page('calibration'))
|
|
ui.QTimer.singleShot(1000,lambda:window._show_page('calibration'))
|
|
ui.QTimer.singleShot(1500,lambda:window._show_page('ros_monitor'))
|
|
ui.QTimer.singleShot(1900,lambda:window._show_page('main'))
|
|
ui.QTimer.singleShot(round(duration*1000),window.close)
|
|
ui.QTimer.singleShot(round((duration+15)*1000),app.quit)
|
|
app.exec()
|
|
assert len(ticks)>20,len(ticks)
|
|
assert not errors,errors
|
|
assert runtime._runtime is None
|
|
assert not any(job.isRunning() for job in window._jobs.values())
|
|
print('Qt responsive, no device modules, async task and graceful shutdown PASS',
|
|
{'seconds':round(time.monotonic()-started,2),'ticks':len(ticks),
|
|
'max_gap':round(max((b-a for a,b in zip(ticks,ticks[1:])),default=0),3),'errors':errors},flush=True)
|