async def test_cancel_tasks(loop):
    """
    Test that an execution manager cancels all un-protected
    running asyncio Tasks when cancel is called
    """
    async def fake_task():
        while True:
            await asyncio.sleep(1)

    exec_mgr = ExecutionManager(loop=loop)

    cancellable_task = loop.create_task(fake_task())
    exec_mgr.register_cancellable_task(cancellable_task)

    other_task = loop.create_task(fake_task())

    # current, cancellable, and other
    assert len(asyncio.all_tasks(loop)) == 3
    assert len([t for t in asyncio.all_tasks(loop) if t.cancelled()]) == 0

    await exec_mgr.cancel()
    await asyncio.sleep(0.1)

    all_tasks = asyncio.all_tasks(loop)
    assert len(all_tasks) == 2  # current and other
    assert other_task in all_tasks
    assert cancellable_task not in all_tasks
async def test_state_machine(loop):
    """
    Test that an execution manager's state is RUNNING on init
    and PAUSE when it when pause is called, unless CANCELLED
    """
    exec_mgr = ExecutionManager(loop=loop)
    assert await exec_mgr.get_state() == ExecutionState.RUNNING

    # passes through on wait_for_is_running if state is RUNNING
    await asyncio.wait_for(exec_mgr.wait_for_is_running(), timeout=0.2)

    await exec_mgr.pause()
    assert await exec_mgr.get_state() == ExecutionState.PAUSED

    with pytest.raises(asyncio.TimeoutError):
        # should stall on wait_for_is_running when state is PAUSED
        await asyncio.wait_for(exec_mgr.wait_for_is_running(), timeout=0.2)

    await exec_mgr.resume()
    assert await exec_mgr.get_state() == ExecutionState.RUNNING

    await exec_mgr.cancel()
    assert await exec_mgr.get_state() == ExecutionState.CANCELLED

    with pytest.raises(ExecutionCancelledError):
        # attempting to pause when CANCELLED should raise
        await exec_mgr.pause()

    with pytest.raises(ExecutionCancelledError):
        # should raise on wait_for_is_running when state is CANCELLED
        await asyncio.wait_for(exec_mgr.wait_for_is_running(), timeout=0.2)

    await exec_mgr.reset()
    assert await exec_mgr.get_state() == ExecutionState.RUNNING
async def test_get_modules(async_server, loop, async_client, monkeypatch):
    hw = async_server['com.opentrons.hardware']
    magdeck = await hw._backend.build_module(
        port='/dev/ot_module_magdeck1',
        model='magdeck',
        interrupt_callback=lambda x: None,
        execution_manager=ExecutionManager(loop=loop),
        loop=loop)
    monkeypatch.setattr(API, 'attached_modules', [magdeck])
    keys = sorted([
        'name', 'port', 'serial', 'model', 'fwVersion', 'status', 'data',
        'hasAvailableUpdate', 'revision', 'moduleModel', 'displayName'
    ])
    resp = await async_client.get('/modules')
    body = await resp.json()
    assert resp.status == 200
    assert 'modules' in body
    assert len(body['modules']) == 1
    assert sorted(body['modules'][0].keys()) == keys
    assert 'engaged' in body['modules'][0]['data']
    tempdeck = await hw._backend.build_module(
        port='/dev/ot_module_tempdeck1',
        model='tempdeck',
        interrupt_callback=lambda x: None,
        execution_manager=ExecutionManager(loop=loop),
        loop=loop)
    monkeypatch.setattr(API, 'attached_modules', [tempdeck])
    for model in ('temp_deck_v1', 'temp_deck_v1.1', 'temp_deck_v2'):
        tempdeck._device_info['model'] = model
        resp = await async_client.get('/modules')
        body = await resp.json()
        assert resp.status == 200
        assert len(body['modules']) == 1
        assert not body['modules'][0]['hasAvailableUpdate']
Exemple #4
0
async def test_sim_initialization(loop):
    mag = await modules.build(port='/dev/ot_module_sim_magdeck0',
                              which='magdeck',
                              simulating=True,
                              interrupt_callback=lambda x: None,
                              loop=loop,
                              execution_manager=ExecutionManager(loop=loop))
    assert isinstance(mag, modules.AbstractModule)
Exemple #5
0
def magdeck():
    m = asyncio.get_event_loop().run_until_complete(
        utils.build(
            port='/dev/ot_module_magdeck1',
            which='magdeck',
            simulating=True,
            interrupt_callback=lambda x: None,
            execution_manager=ExecutionManager(loop=asyncio.get_event_loop()),
            loop=asyncio.get_event_loop()))
    yield m
def magdeck():
    m = asyncio.get_event_loop().run_until_complete(
        utils.build(
            port='/dev/ot_module_magdeck1',
            which='magdeck',
            simulating=True,
            interrupt_callback=lambda x: None,
            execution_manager=ExecutionManager(loop=asyncio.get_event_loop()),
            loop=asyncio.get_event_loop()))
    MagDeck.current_height = PropertyMock(return_value=321)

    yield m
Exemple #7
0
async def test_set_temperature(monkeypatch, loop):
    hw_tc = await modules.build(port='/dev/ot_module_sim_thermocycler0',
                                which='thermocycler',
                                simulating=True,
                                interrupt_callback=lambda x: None,
                                loop=loop,
                                execution_manager=ExecutionManager(loop=loop))

    def async_return(result):
        f = asyncio.Future()
        f.set_result(result)
        return f
    set_temp_driver_mock = mock.Mock(return_value=async_return(''))
    monkeypatch.setattr(
        hw_tc._driver, 'set_temperature', set_temp_driver_mock)

    # Test volume param
    await hw_tc.set_temperature(30, hold_time_seconds=20,
                                hold_time_minutes=1, volume=35)
    set_temp_driver_mock.assert_called_once_with(temp=30,
                                                 hold_time=80,
                                                 volume=35,
                                                 ramp_rate=None)
    set_temp_driver_mock.reset_mock()

    # Test just seconds hold

    await hw_tc.set_temperature(20, hold_time_seconds=30)
    set_temp_driver_mock.assert_called_once_with(temp=20,
                                                 hold_time=30,
                                                 volume=None,
                                                 ramp_rate=None)
    set_temp_driver_mock.reset_mock()

    # Test just minutes hold

    await hw_tc.set_temperature(40, hold_time_minutes=5.5)
    set_temp_driver_mock.assert_called_once_with(temp=40,
                                                 hold_time=330,
                                                 volume=None,
                                                 ramp_rate=None)
    set_temp_driver_mock.reset_mock()

    # Test hold_time < HOLD_TIME_FUZZY_SECONDS
    start = time.time()
    await hw_tc.set_temperature(40, hold_time_seconds=2)
    time_taken = time.time() - start
    assert 1.9 < time_taken < 2.1
    set_temp_driver_mock.assert_called_once_with(temp=40,
                                                 hold_time=2,
                                                 volume=None,
                                                 ramp_rate=None)
    set_temp_driver_mock.reset_mock()
Exemple #8
0
async def test_sim_state_update(loop):
    mag = await modules.build(port='/dev/ot_module_sim_magdeck0',
                              which='magdeck',
                              simulating=True,
                              interrupt_callback=lambda x: None,
                              loop=loop,
                              execution_manager=ExecutionManager(loop=loop))
    await mag.calibrate()
    assert mag.status == 'disengaged'
    await mag.engage(2)
    assert mag.status == 'engaged'
    await mag.deactivate()
    assert mag.status == 'disengaged'
Exemple #9
0
async def test_revision_model_parsing(loop):
    mag = await modules.build('',
                              'magdeck',
                              True,
                              lambda x: None,
                              loop=loop,
                              execution_manager=ExecutionManager(loop=loop))
    mag._device_info['model'] = 'mag_deck_v1.1'
    assert mag.model() == 'magneticModuleV1'
    mag._device_info['model'] = 'mag_deck_v20'
    assert mag.model() == 'magneticModuleV2'
    del mag._device_info['model']
    assert mag.model() == 'magneticModuleV1'
Exemple #10
0
def tempdeck():
    t = asyncio.get_event_loop().run_until_complete(
        utils.build(
            port='/dev/ot_module_tempdeck1',
            which='tempdeck',
            simulating=True,
            interrupt_callback=lambda x: None,
            execution_manager=ExecutionManager(loop=asyncio.get_event_loop()),
            loop=asyncio.get_event_loop()))
    yield t

    # Have to stop the poller
    t._poller.join()
Exemple #11
0
async def test_sim_data(loop):
    mag = await modules.build(port='/dev/ot_module_sim_magdeck0',
                              which='magdeck',
                              simulating=True,
                              interrupt_callback=lambda x: None,
                              loop=loop,
                              execution_manager=ExecutionManager(loop=loop))
    assert mag.status == 'disengaged'
    assert mag.device_info['serial'] == 'dummySerialMD'
    # return v1 when sim_model is not passed
    assert mag.device_info['model'] == 'mag_deck_v1.1'
    assert mag.device_info['version'] == 'dummyVersionMD'
    assert mag.live_data['status'] == mag.status
    assert 'data' in mag.live_data
async def test_sim_update(loop):
    temp = await modules.build(port='/dev/ot_module_sim_tempdeck0',
                               which='tempdeck',
                               simulating=True,
                               interrupt_callback=lambda x: None,
                               loop=loop,
                               execution_manager=ExecutionManager(loop=loop))
    await asyncio.wait_for(temp.set_temperature(10), 0.2)
    assert temp.temperature == 10
    assert temp.target == 10
    assert temp.status == 'holding at target'
    await temp.deactivate()
    assert temp.temperature == 0
    assert temp.target is None
    assert temp.status == 'idle'
async def test_poller(monkeypatch, loop):
    temp = modules.tempdeck.TempDeck(
        port='/dev/ot_module_sim_tempdeck0',
        execution_manager=ExecutionManager(loop=loop),
        simulating=True,
        loop=loop)
    hit = False

    def update_called():
        nonlocal hit
        hit = True

    monkeypatch.setattr(temp._driver, 'update_temperature', update_called)
    await temp._connect()
    assert temp._poller.is_alive()
    await asyncio.sleep(tempdeck.TEMP_POLL_INTERVAL_SECS * 1.1)
    assert hit
def tempdeck():
    t = asyncio.get_event_loop().run_until_complete(
        utils.build(
            port='/dev/ot_module_tempdeck1',
            which='tempdeck',
            simulating=True,
            interrupt_callback=lambda x: None,
            execution_manager=ExecutionManager(loop=asyncio.get_event_loop()),
            loop=asyncio.get_event_loop()))
    TempDeck.temperature = PropertyMock(return_value=123.0)
    TempDeck.target = PropertyMock(return_value=321.0)

    yield t

    # Have to stop the poller
    t._poller.stop()
    t._poller.join()
async def test_execute_module_command(virtual_smoothie_env, loop, async_server,
                                      async_client, monkeypatch):
    hw = async_server['com.opentrons.hardware']

    magdeck = await hw._backend.build_module(
        port='/dev/ot_module_magdeck1',
        model='magdeck',
        interrupt_callback=lambda x: None,
        execution_manager=ExecutionManager(loop=loop),
        loop=loop)
    monkeypatch.setattr(API, 'attached_modules', [magdeck])

    resp = await async_client.post('/modules/dummySerialMD',
                                   json={'command_type': 'deactivate'})
    body = await resp.json()
    assert resp.status == 200
    assert 'message' in body
    assert body['message'] == 'Success'
async def test_sim_state(loop):
    temp = await modules.build(port='/dev/ot_module_sim_tempdeck0',
                               which='tempdeck',
                               simulating=True,
                               interrupt_callback=lambda x: None,
                               loop=loop,
                               execution_manager=ExecutionManager(loop=loop))
    assert temp.temperature == 0
    assert temp.target is None
    assert temp.status == 'idle'
    assert temp.live_data['status'] == temp.status
    assert temp.live_data['data']['currentTemp'] == temp.temperature
    assert temp.live_data['data']['targetTemp'] == temp.target
    status = temp.device_info
    assert status['serial'] == 'dummySerialTD'
    # return v1 if sim_model is not passed
    assert status['model'] == 'temp_deck_v1.1'
    assert status['version'] == 'dummyVersionTD'
Exemple #17
0
async def test_sim_state(loop):
    therm = await modules.build(port='/dev/ot_module_sim_thermocycler0',
                                which='thermocycler',
                                simulating=True,
                                interrupt_callback=lambda x: None,
                                loop=loop,
                                execution_manager=ExecutionManager(loop=loop))

    assert therm.temperature is None
    assert therm.target is None
    assert therm.status == 'idle'
    assert therm.live_data['status'] == therm.status
    assert therm.live_data['data']['currentTemp'] == therm.temperature
    assert therm.live_data['data']['targetTemp'] == therm.target
    status = therm.device_info
    assert status['serial'] == 'dummySerialTC'
    assert status['model'] == 'dummyModelTC'
    assert status['version'] == 'dummyVersionTC'
Exemple #18
0
async def test_sim_update(loop):
    therm = await modules.build(port='/dev/ot_module_sim_thermocycler0',
                                which='thermocycler',
                                simulating=True,
                                interrupt_callback=lambda x: None,
                                loop=loop,
                                execution_manager=ExecutionManager(loop=loop))

    await therm.set_temperature(temperature=10,
                                hold_time_seconds=None,
                                hold_time_minutes=4.0,
                                volume=50)
    assert therm.temperature == 10
    assert therm.target == 10
    assert therm.status == 'holding at target'
    await asyncio.wait_for(therm.wait_for_temp(), timeout=0.2)
    await therm.deactivate_block()
    assert therm.temperature is None
    assert therm.target is None
    assert therm.status == 'idle'

    await therm.set_lid_temperature(temperature=80)
    assert therm.lid_temp == 80
    assert therm.lid_target == 80
    await asyncio.wait_for(therm.wait_for_lid_temp(), timeout=0.2)
    await therm.deactivate_lid()
    assert therm.lid_temp is None
    assert therm.lid_target is None

    await therm.set_temperature(temperature=10, volume=60, hold_time_seconds=2)
    await therm.set_lid_temperature(temperature=70)
    await asyncio.wait_for(therm.wait_for_temp(), timeout=0.2)
    await asyncio.wait_for(therm.wait_for_lid_temp(), timeout=0.2)
    assert therm.temperature == 10
    assert therm.target == 10
    assert therm.lid_temp == 70
    assert therm.lid_target == 70
    await therm.deactivate()
    assert therm.temperature is None
    assert therm.target is None
    assert therm.status == 'idle'
    assert therm.lid_temp is None
    assert therm.lid_target is None
def thermocycler():
    t = asyncio.get_event_loop().run_until_complete(
        utils.build(
            port='/dev/ot_module_thermocycler1',
            which='thermocycler',
            simulating=True,
            interrupt_callback=lambda x: None,
            execution_manager=ExecutionManager(loop=asyncio.get_event_loop()),
            loop=asyncio.get_event_loop()))
    Thermocycler.lid_status = PropertyMock(return_value="open")
    Thermocycler.lid_target = PropertyMock(return_value=1.2)
    Thermocycler.lid_temp = PropertyMock(return_value=22.0)
    Thermocycler.temperature = PropertyMock(return_value=100.0)
    Thermocycler.target = PropertyMock(return_value=200.0)
    Thermocycler.hold_time = PropertyMock(return_value=1)
    Thermocycler.ramp_rate = PropertyMock(return_value=3)
    Thermocycler.current_cycle_index = PropertyMock(return_value=1)
    Thermocycler.total_cycle_count = PropertyMock(return_value=3)
    Thermocycler.current_step_index = PropertyMock(return_value=5)
    Thermocycler.total_step_count = PropertyMock(return_value=2)
    return t
Exemple #20
0
async def test_lid(loop):
    therm = await modules.build(port='/dev/ot_module_sim_thermocycler0',
                                which='thermocycler',
                                simulating=True,
                                interrupt_callback=lambda x: None,
                                loop=loop,
                                execution_manager=ExecutionManager(loop=loop))

    assert therm.lid_status == 'open'

    await therm.open()
    assert therm.lid_status == 'open'

    await therm.close()
    assert therm.lid_status == 'closed'

    await therm.close()
    assert therm.lid_status == 'closed'

    await therm.open()
    assert therm.lid_status == 'open'
async def test_module_update_integration(monkeypatch, loop):
    from opentrons.hardware_control import modules

    def async_return(result):
        f = asyncio.Future()
        f.set_result(result)
        return f

    bootloader_kwargs = {
        'stdout': asyncio.subprocess.PIPE,
        'stderr': asyncio.subprocess.PIPE,
        'loop': loop,
    }

    # test temperature module update with avrdude bootloader

    tempdeck = await modules.build(
        port='/dev/ot_module_sim_tempdeck0',
        which='tempdeck',
        simulating=True,
        interrupt_callback=lambda x: None,
        loop=loop,
        execution_manager=ExecutionManager(loop=loop),
        sim_model='temperatureModuleV2')

    upload_via_avrdude_mock = mock.Mock(
        return_value=(async_return((True, 'avrdude bootloader worked'))))
    monkeypatch.setattr(modules.update, 'upload_via_avrdude',
                        upload_via_avrdude_mock)

    async def mock_find_avrdude_bootloader_port():
        return 'ot_module_avrdude_bootloader1'

    monkeypatch.setattr(modules.update, 'find_bootloader_port',
                        mock_find_avrdude_bootloader_port)

    await modules.update_firmware(tempdeck, 'fake_fw_file_path', loop)
    upload_via_avrdude_mock.assert_called_once_with(
        'ot_module_avrdude_bootloader1', 'fake_fw_file_path',
        bootloader_kwargs)
    upload_via_avrdude_mock.reset_mock()

    # test magnetic module update with avrdude bootloader

    magdeck = await modules.build(
        port='/dev/ot_module_sim_magdeck0',
        which='magdeck',
        simulating=True,
        interrupt_callback=lambda x: None,
        loop=loop,
        execution_manager=ExecutionManager(loop=loop))

    await modules.update_firmware(magdeck, 'fake_fw_file_path', loop)
    upload_via_avrdude_mock.assert_called_once_with(
        'ot_module_avrdude_bootloader1', 'fake_fw_file_path',
        bootloader_kwargs)

    # test thermocycler module update with bossa bootloader

    thermocycler = await modules.build(
        port='/dev/ot_module_sim_thermocycler0',
        which='thermocycler',
        simulating=True,
        interrupt_callback=lambda x: None,
        loop=loop,
        execution_manager=ExecutionManager(loop=loop))

    upload_via_bossa_mock = mock.Mock(
        return_value=(async_return((True, 'bossa bootloader worked'))))
    monkeypatch.setattr(modules.update, 'upload_via_bossa',
                        upload_via_bossa_mock)

    async def mock_find_bossa_bootloader_port():
        return 'ot_module_bossa_bootloader1'

    monkeypatch.setattr(modules.update, 'find_bootloader_port',
                        mock_find_bossa_bootloader_port)

    await modules.update_firmware(thermocycler, 'fake_fw_file_path', loop)
    upload_via_bossa_mock.assert_called_once_with(
        'ot_module_bossa_bootloader1', 'fake_fw_file_path', bootloader_kwargs)
Exemple #22
0
    def load_module(
            self, module_name: str,
            location: Optional[types.DeckLocation] = None,
            configuration: str = None) -> ModuleTypes:
        """ Load a module onto the deck given its name.

        This is the function to call to use a module in your protocol, like
        :py:meth:`load_instrument` is the method to call to use an instrument
        in your protocol. It returns the created and initialized module
        context, which will be a different class depending on the kind of
        module loaded.

        A map of deck positions to loaded modules can be accessed later
        using :py:attr:`loaded_modules`.

        :param str module_name: The name or model of the module.
        :param location: The location of the module. This is usually the
                         name or number of the slot on the deck where you
                         will be placing the module. Some modules, like
                         the Thermocycler, are only valid in one deck
                         location. You do not have to specify a location
                         when loading a Thermocycler - it will always be
                         in Slot 7.
        :param configuration: Used to specify the slot configuration of
                              the Thermocycler. Only Valid in Python API
                              Version 2.4 and later. If you wish to use
                              the non-full plate configuration, you must
                              pass in the key word value `semi`
        :type location: str or int or None
        :returns ModuleContext: The loaded and initialized
                                :py:class:`ModuleContext`.
        """
        resolved_model = resolve_module_model(module_name)
        resolved_type = resolve_module_type(resolved_model)
        resolved_location = self._deck_layout.resolve_module_location(
            resolved_type, location)
        if self._api_version < APIVersion(2, 4) and configuration:
            raise APIVersionError(
                f'You have specified API {self._api_version}, but you are'
                'using thermocycler parameters only available in 2.4')

        geometry = load_module(
            resolved_model,
            self._deck_layout.position_for(
                resolved_location),
            self._api_version, configuration)

        hc_mod_instance = None
        mod_class = {
            ModuleType.MAGNETIC: MagneticModuleContext,
            ModuleType.TEMPERATURE: TemperatureModuleContext,
            ModuleType.THERMOCYCLER: ThermocyclerContext}[resolved_type]
        for mod in self._hw_manager.hardware.attached_modules:
            if models_compatible(
                    module_model_from_string(mod.model()), resolved_model):
                hc_mod_instance = SynchronousAdapter(mod)
                break

        if self.is_simulating() and hc_mod_instance is None:
            mod_type = {
                ModuleType.MAGNETIC: modules.magdeck.MagDeck,
                ModuleType.TEMPERATURE: modules.tempdeck.TempDeck,
                ModuleType.THERMOCYCLER: modules.thermocycler.Thermocycler
                }[resolved_type]
            hc_mod_instance = SynchronousAdapter(mod_type(
                    port='',
                    simulating=True,
                    loop=self._hw_manager.hardware.loop,
                    execution_manager=ExecutionManager(
                        loop=self._hw_manager.hardware.loop),
                    sim_model=resolved_model.value))
            hc_mod_instance._connect()
        if hc_mod_instance:
            mod_ctx = mod_class(self,
                                hc_mod_instance,
                                geometry,
                                self.api_version,
                                self._loop)
        else:
            raise RuntimeError(
                f'Could not find specified module: {module_name}')
        self._modules.add(mod_ctx)
        self._deck_layout[resolved_location] = geometry
        return mod_ctx