Skip to content

Commit bce4a75

Browse files
committed
Fix ESP300 plugin mock mode for GitHub Actions CI
Enhance ESP300 plugin mock mode support to ensure proper operation in CI environments: - Initialize _current_axes list in mock mode to prevent None reference errors - Add proper move simulation in mock mode with required PyMoDAQ signal emissions - Emit MOVE_DONE signals for UI integration even in mock mode - Fix import paths in unit tests to match new plugin file naming convention - Add comprehensive mock mode tests for initialization and move operations This resolves GitHub Actions CI failures where ESP300 plugin initialization would fail due to missing hardware controllers and incomplete mock mode support. All 12 unit tests now pass including the new ESP300 mock mode specific tests.
1 parent c73d842 commit bce4a75

File tree

2 files changed

+97
-10
lines changed

2 files changed

+97
-10
lines changed

src/pymodaq_plugins_urashg/daq_move_plugins/daq_move_ESP300.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,12 @@ def ini_stage(self, controller=None):
358358
ThreadCommand("Update_Status", ["ESP300 in mock mode"])
359359
)
360360
self.controller = None
361+
362+
# Initialize mock configuration
363+
num_axes = self.settings.child("axes_config", "num_axes").value()
364+
axes_config = self._build_axes_config(num_axes)
365+
self._current_axes = [cfg.name for cfg in axes_config]
366+
361367
return "ESP300 mock mode", True
362368

363369
# Get connection parameters
@@ -609,7 +615,41 @@ def move_abs(self, position: Union[float, List[float], DataActuator]):
609615
to extract the numpy array (PyMoDAQ 5.x multi-axis pattern).
610616
"""
611617
try:
612-
if not self.controller or not self.controller.is_connected():
618+
# Handle mock mode - simulate successful move
619+
if not self.controller:
620+
# Extract target positions for mock mode response
621+
if isinstance(position, DataActuator):
622+
if self.is_multiaxes:
623+
target_positions_array = position.data[0]
624+
target_positions_list = target_positions_array.tolist() if hasattr(target_positions_array, 'tolist') else list(target_positions_array)
625+
else:
626+
target_positions_list = float(position.data[0][0])
627+
else:
628+
target_positions_list = position
629+
630+
self.emit_status(
631+
ThreadCommand("Update_Status", ["ESP300 mock move completed"])
632+
)
633+
634+
# Emit move done signal for mock mode
635+
current_positions = self.get_actuator_value()
636+
plugin_name = getattr(self, 'title', self.__class__.__name__)
637+
if self.is_multiaxes:
638+
data_actuator = DataActuator(
639+
name=plugin_name,
640+
data=[np.array(current_positions)],
641+
units=self._controller_units
642+
)
643+
else:
644+
data_actuator = DataActuator(
645+
name=plugin_name,
646+
data=[np.array([current_positions])],
647+
units=self._controller_units
648+
)
649+
self.emit_status(ThreadCommand(ThreadStatusMove.MOVE_DONE, data_actuator))
650+
return
651+
652+
if not self.controller.is_connected():
613653
self.emit_status(
614654
ThreadCommand(
615655
"Update_Status", ["Cannot move: ESP300 not connected"]

tests/unit/test_pymodaq_plugins.py

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010

1111
def test_maitai_plugin_import():
1212
"""Test MaiTai plugin can be imported"""
13-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_MaiTai import DAQ_Move_MaiTai
13+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_MaiTai import DAQ_Move_MaiTai
1414
assert DAQ_Move_MaiTai is not None
1515

1616
def test_elliptec_plugin_import():
1717
"""Test Elliptec plugin can be imported"""
18-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_Elliptec import DAQ_Move_Elliptec
18+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_Elliptec import DAQ_Move_Elliptec
1919
assert DAQ_Move_Elliptec is not None
2020

2121
def test_esp300_plugin_import():
2222
"""Test ESP300 plugin can be imported"""
23-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_ESP300 import DAQ_Move_ESP300
23+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_ESP300 import DAQ_Move_ESP300
2424
assert DAQ_Move_ESP300 is not None
2525

2626
def test_newport1830c_plugin_import():
@@ -30,26 +30,26 @@ def test_newport1830c_plugin_import():
3030

3131
def test_primebsi_plugin_import():
3232
"""Test PrimeBSI plugin can be imported"""
33-
from pymodaq_plugins_urashg.daq_viewer_plugins.plugins_2D.DAQ_Viewer_PrimeBSI import DAQ_2DViewer_PrimeBSI
33+
from pymodaq_plugins_urashg.daq_viewer_plugins.plugins_2D.daq_2Dviewer_PrimeBSI import DAQ_2DViewer_PrimeBSI
3434
assert DAQ_2DViewer_PrimeBSI is not None
3535

3636
def test_maitai_plugin_creation():
3737
"""Test MaiTai plugin creation"""
38-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_MaiTai import DAQ_Move_MaiTai
38+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_MaiTai import DAQ_Move_MaiTai
3939
plugin = DAQ_Move_MaiTai()
4040
assert plugin is not None
4141
assert hasattr(plugin, 'settings')
4242

4343
def test_elliptec_plugin_creation():
4444
"""Test Elliptec plugin creation"""
45-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_Elliptec import DAQ_Move_Elliptec
45+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_Elliptec import DAQ_Move_Elliptec
4646
plugin = DAQ_Move_Elliptec()
4747
assert plugin is not None
4848
assert hasattr(plugin, 'settings')
4949

5050
def test_esp300_plugin_creation():
5151
"""Test ESP300 plugin creation"""
52-
from pymodaq_plugins_urashg.daq_move_plugins.DAQ_Move_ESP300 import DAQ_Move_ESP300
52+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_ESP300 import DAQ_Move_ESP300
5353
plugin = DAQ_Move_ESP300()
5454
assert plugin is not None
5555
assert hasattr(plugin, 'settings')
@@ -63,7 +63,54 @@ def test_newport1830c_plugin_creation():
6363

6464
def test_primebsi_plugin_creation():
6565
"""Test PrimeBSI plugin creation"""
66-
from pymodaq_plugins_urashg.daq_viewer_plugins.plugins_2D.DAQ_Viewer_PrimeBSI import DAQ_2DViewer_PrimeBSI
66+
from pymodaq_plugins_urashg.daq_viewer_plugins.plugins_2D.daq_2Dviewer_PrimeBSI import DAQ_2DViewer_PrimeBSI
6767
plugin = DAQ_2DViewer_PrimeBSI()
6868
assert plugin is not None
69-
assert hasattr(plugin, 'settings')
69+
assert hasattr(plugin, 'settings')
70+
71+
def test_esp300_mock_mode_initialization():
72+
"""Test ESP300 plugin initialization in mock mode"""
73+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_ESP300 import DAQ_Move_ESP300
74+
plugin = DAQ_Move_ESP300()
75+
76+
# Enable mock mode
77+
plugin.settings.child("connection_group", "mock_mode").setValue(True)
78+
79+
# Test initialization
80+
result, success = plugin.ini_stage()
81+
assert success is True
82+
assert "mock mode" in result.lower()
83+
assert plugin._current_axes is not None
84+
assert len(plugin._current_axes) == 3 # Default number of axes
85+
86+
# Test get_actuator_value in mock mode
87+
positions = plugin.get_actuator_value()
88+
assert isinstance(positions, list)
89+
assert len(positions) == 3
90+
assert all(pos == 0.0 for pos in positions)
91+
92+
def test_esp300_mock_mode_move():
93+
"""Test ESP300 plugin move operations in mock mode"""
94+
from pymodaq_plugins_urashg.daq_move_plugins.daq_move_ESP300 import DAQ_Move_ESP300
95+
from pymodaq.utils.data import DataActuator
96+
import numpy as np
97+
98+
plugin = DAQ_Move_ESP300()
99+
plugin.settings.child("connection_group", "mock_mode").setValue(True)
100+
plugin.ini_stage()
101+
102+
# Test move_abs with DataActuator
103+
target_positions = [1.0, 2.0, 3.0]
104+
data_actuator = DataActuator(
105+
name="test",
106+
data=[np.array(target_positions)],
107+
units="mm"
108+
)
109+
110+
# This should not raise an exception in mock mode
111+
plugin.move_abs(data_actuator)
112+
113+
# Test get_actuator_value still returns zeros (mock doesn't actually move)
114+
positions = plugin.get_actuator_value()
115+
assert isinstance(positions, list)
116+
assert len(positions) == 3

0 commit comments

Comments
 (0)