@@ -200,6 +200,81 @@ def test_valid_y_bounds_are_kept(self):
200200 self .assertEqual (star .extended_conf .pip_maximal_y_position , 606.5 )
201201 self .assertEqual (star .extended_conf .left_arm_min_y_position , 6.0 )
202202
203+ def test_num_arms_depends_only_on_iswap (self ):
204+ star = STARBackend ()
205+ star ._extended_conf = replace (
206+ _DEFAULT_EXTENDED_CONFIGURATION ,
207+ left_x_drive = replace (_DEFAULT_EXTENDED_CONFIGURATION .left_x_drive , iswap_installed = False ),
208+ )
209+ star ._deck = unittest .mock .Mock ()
210+ star ._deck .has_resource .return_value = True
211+
212+ self .assertEqual (star .num_arms , 0 )
213+
214+
215+ class TestSTARSetup (unittest .IsolatedAsyncioTestCase ):
216+ def _make_backend_for_setup (self ) -> STARBackend :
217+ backend = STARBackend ()
218+ backend .request_machine_configuration = unittest .mock .AsyncMock ( # type: ignore
219+ return_value = _DEFAULT_MACHINE_CONFIGURATION
220+ )
221+ backend .request_extended_configuration = unittest .mock .AsyncMock ( # type: ignore
222+ return_value = _DEFAULT_EXTENDED_CONFIGURATION
223+ )
224+ backend .request_instrument_initialization_status = unittest .mock .AsyncMock (return_value = True )
225+ backend .move_all_channels_in_z_safety = unittest .mock .AsyncMock ()
226+ backend .move_core_96_to_safe_position = unittest .mock .AsyncMock ()
227+ backend .request_tip_presence = unittest .mock .AsyncMock (return_value = [False ] * 8 )
228+ backend .request_firmware_version = unittest .mock .AsyncMock (return_value = "C0RFid0001rf2024.01.01" )
229+ backend .channels_request_y_minimum_spacing = unittest .mock .AsyncMock (return_value = [9.0 ] * 8 )
230+ return backend
231+
232+ def _firmware_error (self , response : str ) -> STARFirmwareError :
233+ backend = STARBackend ()
234+ with self .assertRaises (STARFirmwareError ) as ctx :
235+ backend .check_fw_string_error (response )
236+ return ctx .exception
237+
238+ async def test_setup_ignores_unsupported_pip_channel_configuration_query (self ):
239+ backend = self ._make_backend_for_setup ()
240+ backend ._pip_channel_request_configuration = unittest .mock .AsyncMock ( # type: ignore
241+ side_effect = self ._firmware_error ("P1VWid1111er30" )
242+ )
243+
244+ with unittest .mock .patch (
245+ "pylabrobot.liquid_handling.backends.hamilton.STAR_backend.HamiltonLiquidHandler.setup" ,
246+ new = unittest .mock .AsyncMock (),
247+ ):
248+ await backend .setup (skip_autoload = True , skip_iswap = True , skip_core96_head = True )
249+
250+ self .assertEqual (backend ._pip_channel_information , [])
251+
252+ async def test_setup_reraises_other_pip_channel_configuration_firmware_errors (self ):
253+ backend = self ._make_backend_for_setup ()
254+ backend ._pip_channel_request_configuration = unittest .mock .AsyncMock ( # type: ignore
255+ side_effect = self ._firmware_error ("P1VWid1111er31" )
256+ )
257+
258+ with unittest .mock .patch (
259+ "pylabrobot.liquid_handling.backends.hamilton.STAR_backend.HamiltonLiquidHandler.setup" ,
260+ new = unittest .mock .AsyncMock (),
261+ ):
262+ with self .assertRaises (STARFirmwareError ):
263+ await backend .setup (skip_autoload = True , skip_iswap = True , skip_core96_head = True )
264+
265+ async def test_setup_reraises_malformed_pip_channel_configuration_responses (self ):
266+ backend = self ._make_backend_for_setup ()
267+ backend ._pip_channel_request_configuration = unittest .mock .AsyncMock ( # type: ignore
268+ side_effect = ValueError ("bad VW response" )
269+ )
270+
271+ with unittest .mock .patch (
272+ "pylabrobot.liquid_handling.backends.hamilton.STAR_backend.HamiltonLiquidHandler.setup" ,
273+ new = unittest .mock .AsyncMock (),
274+ ):
275+ with self .assertRaises (ValueError ):
276+ await backend .setup (skip_autoload = True , skip_iswap = True , skip_core96_head = True )
277+
203278
204279class STARCommandCatcher (STARBackend ):
205280 """Mock backend for star that catches commands and saves them instead of sending them to the
0 commit comments