示例#1
0
 async def test_stop_exposure_no_expose_running(self):
     """Test that stop_exposure does nothing if there is no active
     `expose` command.
     """
     spec = AvsFiberSpectrograph()
     spec.stop_exposure()
     self.patch.return_value.AVS_StopMeasure.assert_not_called()
示例#2
0
 def test_disconnect_bad_handle(self):
     """Do not attempt to disconnect if the device handle is bad."""
     spec = AvsFiberSpectrograph()
     spec.handle = AvsReturnCode.invalidHandle.value
     spec.disconnect()
     self.patch.return_value.AVS_Deactivate.assert_not_called()
     self.patch.return_value.AVS_Done.assert_called_once_with()
示例#3
0
 def test_get_status_getAnalogIn_fails(self):
     spec = AvsFiberSpectrograph()
     self.patch.return_value.AVS_GetAnalogIn.side_effect = None
     self.patch.return_value.AVS_GetAnalogIn.return_value = (
         AvsReturnCode.ERR_TIMEOUT.value)
     with pytest.raises(AvsReturnError, match="GetAnalogIn.*ERR_TIMEOUT"):
         spec.get_status()
示例#4
0
    async def test_disconnect_stop_exposure_exception(self):
        """Test that `disconnect` does not raise if `stop_exposure` raises, but
        does log an error message, and continues with deactivating the device.
        """
        duration = 5  # seconds
        spec = AvsFiberSpectrograph()
        self.patch.return_value.AVS_StopMeasure.return_value = (
            AvsReturnCode.ERR_INVALID_PARAMETER.value)

        t0 = time.monotonic()
        task = asyncio.create_task(spec.expose(duration))
        await asyncio.sleep(0.1)  # give the event loop time to start
        try:
            with self.assertLogs(spec.log, "ERROR"):
                spec.disconnect()
        except AvsReturnError:
            self.fail(
                "disconnect() should not raise an exception, even if `stop_exposure` does."
            )
        with pytest.raises(asyncio.CancelledError):
            await task
        t1 = time.monotonic()

        # cancelling the task should make it end much sooner than the duration
        assert t1 - t0 < 1
        self.patch.return_value.AVS_StopMeasure.assert_called_with(self.handle)
        self.patch.return_value.AVS_Deactivate.assert_called_once_with(
            self.handle)
        self.patch.return_value.AVS_Done.assert_called_once_with()
        assert spec.handle is None
示例#5
0
 def test_disconnect(self):
     """Test a successful USB disconnect command."""
     spec = AvsFiberSpectrograph()
     spec.disconnect()
     self.patch.return_value.AVS_Deactivate.assert_called_once_with(
         self.handle)
     self.patch.return_value.AVS_Done.assert_called_once_with()
     assert spec.handle is None
示例#6
0
 def test_get_status_getParameter_fails(self):
     spec = AvsFiberSpectrograph()
     self.patch.return_value.AVS_GetParameter.side_effect = None
     self.patch.return_value.AVS_GetParameter.return_value = (
         AvsReturnCode.ERR_INVALID_DEVICE_ID.value)
     with pytest.raises(AvsReturnError,
                        match="GetParameter.*ERR_INVALID_DEVICE_ID"):
         spec.get_status()
示例#7
0
 def test_get_status_getVersionInfo_fails(self):
     spec = AvsFiberSpectrograph()
     self.patch.return_value.AVS_GetVersionInfo.side_effect = None
     self.patch.return_value.AVS_GetVersionInfo.return_value = (
         AvsReturnCode.ERR_DEVICE_NOT_FOUND.value)
     with pytest.raises(AvsReturnError,
                        match="GetVersionInfo.*ERR_DEVICE_NOT_FOUND"):
         spec.get_status()
示例#8
0
 def test_disconnect_fails_logged(self):
     """Test that a "failed" Deactivate emits an error."""
     self.patch.return_value.AVS_Deactivate.return_value = False
     spec = AvsFiberSpectrograph()
     with self.assertLogs(spec.log, "ERROR"):
         spec.disconnect()
     self.patch.return_value.AVS_Deactivate.assert_called_once_with(
         self.handle)
     self.patch.return_value.AVS_Done.assert_called_once_with()
示例#9
0
 def test_disconnect_no_handle(self):
     """Test that we do not attempt to disconnect if there is no device
     handle.
     """
     spec = AvsFiberSpectrograph()
     spec.handle = None
     spec.disconnect()
     self.patch.return_value.AVS_Deactivate.assert_not_called()
     self.patch.return_value.AVS_Done.assert_called_once_with()
示例#10
0
 async def check_duration_fails(duration):
     spec = AvsFiberSpectrograph()
     with pytest.raises(RuntimeError,
                        match="Exposure duration not in valid range:"):
         # timeout=1s because the command should fail immediately.
         await asyncio.wait_for(spec.expose(duration), 1)
     self.patch.return_value.AVS_PrepareMeasure.assert_not_called()
     self.patch.return_value.AVS_Measure.assert_not_called()
     self.patch.return_value.AVS_PollScan.assert_not_called()
     self.patch.return_value.AVS_GetScopeData.assert_not_called()
示例#11
0
 def test_disconnect_other_exception(self):
     """Test that disconnect continues if there some other exception raised
     during disconnect.
     """
     self.patch.return_value.AVS_Deactivate.side_effect = RuntimeError
     spec = AvsFiberSpectrograph()
     with self.assertLogs(spec.log, "ERROR"):
         spec.disconnect()
     self.patch.return_value.AVS_Deactivate.assert_called_once_with(
         self.handle)
     self.patch.return_value.AVS_Done.assert_called_once_with()
示例#12
0
    def test_get_status(self):
        spec = AvsFiberSpectrograph()
        status = spec.get_status()
        assert status.fpga_version == self.fpga_version
        assert status.firmware_version == self.firmware_version
        assert status.library_version == self.library_version
        assert status.n_pixels == self.n_pixels
        assert status.temperature_setpoint == self.temperature_setpoint
        np.testing.assert_allclose(status.temperature, self.temperature)
        assert status.config is None

        # Check that full=True returns a AvsDeviceConfig instead of None
        # (we're not worried about the contents of it here)
        status = spec.get_status(full=True)
        assert status.config is not None
示例#13
0
 def test_disconnect_on_delete(self):
     """Test that the connection is closed if the object is deleted."""
     spec = AvsFiberSpectrograph()
     del spec
     self.patch.return_value.AVS_Deactivate.assert_called_once_with(
         self.handle)
     self.patch.return_value.AVS_Done.assert_called_once_with()
示例#14
0
    def test_connect_device_serial_number_already_connected(self):
        """Test that connect raises if the device requested by serial number
        claims to already be connected in its AvsIdentity field.
        """
        n_devices = 2
        serial_number = "54321"
        id1 = AvsIdentity(
            bytes(str(serial_number), "ascii"),
            b"Fake Spectrograph 2",
            AvsDeviceStatus.USB_IN_USE_BY_OTHER.value,
        )

        def mock_getList(a_listSize, a_pRequiredSize, a_pList):
            """Pretend that the desired device is already connected."""
            a_pList[:] = [self.id0, id1]
            return n_devices

        self.patch.return_value.AVS_GetList.side_effect = mock_getList
        self.patch.return_value.AVS_UpdateUSBDevices.return_value = n_devices

        with pytest.raises(RuntimeError,
                           match="Requested AVS device is already in use"):
            AvsFiberSpectrograph(serial_number=serial_number)
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_called_once()
        self.patch.return_value.AVS_Activate.assert_not_called()
示例#15
0
    def test_connect_no_serial_number_two_devices_fails(self):
        serial_number = "54321"
        n_devices = 2
        id1 = AvsIdentity(
            bytes(str(serial_number), "ascii"),
            b"Fake Spectrograph 2",
            AvsDeviceStatus.USB_AVAILABLE.value,
        )

        def mock_getList(a_listSize, a_pRequiredSize, a_pList):
            """Pretend that two devices are connected."""
            a_pList[0] = self.id0
            a_pList[1] = id1
            return n_devices

        self.patch.return_value.AVS_GetList.side_effect = mock_getList
        self.patch.return_value.AVS_UpdateUSBDevices.return_value = n_devices

        msg = (
            "Multiple devices found, but no serial number specified. Attached devices: "
        )
        with pytest.raises(RuntimeError, match=msg):
            AvsFiberSpectrograph()
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_called_once()
        self.patch.return_value.AVS_Activate.assert_not_called()
示例#16
0
 def test_create_with_logger(self):
     """Test that a passed-in logger is used for log messages."""
     log = logging.Logger("testingLogger")
     with self.assertLogs(log, logging.DEBUG):
         spec = AvsFiberSpectrograph(log=log)
     # simple check that the instance was created successfully
     assert spec.device == self.id0
示例#17
0
    async def test_stop_exposure(self):
        """Test that `stop_exposure` ends the active `expose`."""
        duration = 5  # seconds
        spec = AvsFiberSpectrograph()

        t0 = time.monotonic()
        task = asyncio.create_task(spec.expose(duration))
        await asyncio.sleep(0.1)  # give the event loop time to start
        spec.stop_exposure()
        with pytest.raises(asyncio.CancelledError):
            await task
        t1 = time.monotonic()

        # cancelling the task should make it end much sooner than the duration
        assert t1 - t0 < 1
        self.patch.return_value.AVS_StopMeasure.assert_called_with(self.handle)
示例#18
0
 def test_connect(self):
     """Test connecting to the first device."""
     spec = AvsFiberSpectrograph()
     self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
     self.patch.return_value.AVS_GetList.assert_called_once()
     self.patch.return_value.AVS_Activate.assert_called_once_with(self.id0)
     self.patch.return_value.AVS_GetNumPixels.assert_called_once()
     assert spec.device == self.id0
示例#19
0
 def test_create_with_stdout_log(self):
     """Test that the ``log_to_stdout`` init option works."""
     capture = io.StringIO()
     with contextlib.redirect_stdout(capture):
         spec = AvsFiberSpectrograph(log_to_stdout=True)
     assert "Found 1 attached USB Avantes device" in capture.getvalue()
     assert "Activated connection" in capture.getvalue()
     # simple check that the instance was created successfully
     assert spec.device == self.id0
示例#20
0
    async def test_expose_raises_if_active_exposure(self):
        """Starting a new exposure while one is currently active should
        raise.
        """
        duration = 0.2  # seconds
        spec = AvsFiberSpectrograph()

        task = asyncio.create_task(spec.expose(duration))
        await asyncio.sleep(0.1)  # give the event loop time to start
        with pytest.raises(RuntimeError, match="Cannot start new exposure"):
            task2 = asyncio.create_task(spec.expose(duration))
            await task2
        await task
        # in addition to raising, should have only called these functions once
        self.patch.return_value.AVS_PrepareMeasure.assert_called_once()
        self.patch.return_value.AVS_Measure.assert_called_once_with(
            self.handle, 0, 1)
        self.patch.return_value.AVS_GetScopeData.assert_called_once()
示例#21
0
    def test_connect_no_devices(self):
        """Test that connect raises if no devices were found."""
        self.patch.return_value.AVS_UpdateUSBDevices.return_value = 0

        with pytest.raises(RuntimeError,
                           match="No attached USB Avantes devices found"):
            AvsFiberSpectrograph()
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_not_called()
        self.patch.return_value.AVS_Activate.assert_not_called()
示例#22
0
    async def test_stop_exposure_during_poll_loop(self):
        """Test that `stop_exposure` ends the active `expose` when called
        during the `PollData` loop.
        """
        duration = 0.2  # seconds
        # repeat "no data" forever, so that `stop` will trigger during polling
        self.patch.return_value.AVS_PollScan.side_effect = itertools.repeat(0)
        spec = AvsFiberSpectrograph()

        task = asyncio.create_task(spec.expose(duration))
        await asyncio.sleep(duration + 0.1
                            )  # wait until we are in the poll loop
        spec.stop_exposure()
        with pytest.raises(asyncio.CancelledError):
            await task

        self.patch.return_value.AVS_StopMeasure.assert_called_with(self.handle)
        self.patch.return_value.AVS_PollScan.assert_called_with(self.handle)
        self.patch.return_value.AVS_GetScopeData.assert_not_called()
示例#23
0
    def test_connect_Activate_fails(self):
        """Test that connect raises if the Activate command fails."""
        self.patch.return_value.AVS_Activate.return_value = (
            AvsReturnCode.ERR_DLL_INITIALISATION.value)

        with pytest.raises(AvsReturnError, match="Activate"):
            AvsFiberSpectrograph()
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_called_once()
        self.patch.return_value.AVS_Activate.assert_called_once()
示例#24
0
 def test_connect_invalid_size(self):
     """Test that connect raises if GetList returns "Invalid Size"."""
     self.patch.return_value.AVS_GetList.side_effect = None
     self.patch.return_value.AVS_GetList.return_value = (
         AvsReturnCode.ERR_INVALID_SIZE.value)
     with pytest.raises(AvsReturnError, match="Fatal Error"):
         AvsFiberSpectrograph()
     self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
     self.patch.return_value.AVS_GetList.assert_called_once()
     self.patch.return_value.AVS_Activate.assert_not_called()
示例#25
0
    async def test_stop_exposure_fails(self):
        """Test `AVS_StopMeasure` returning an error: the existing exposure
        task should be cancelled, but `stop_exposure` should also raise."""
        duration = 5  # seconds
        self.patch.return_value.AVS_StopMeasure.return_value = (
            AvsReturnCode.ERR_TIMEOUT.value)
        spec = AvsFiberSpectrograph()

        t0 = time.monotonic()
        task = asyncio.create_task(spec.expose(duration))
        await asyncio.sleep(0.1)  # give the event loop time to start
        with pytest.raises(AvsReturnError, match="StopMeasure"):
            spec.stop_exposure()
        with pytest.raises(asyncio.CancelledError):
            await task
        t1 = time.monotonic()

        # cancelling the task should make it end much sooner than the duration
        assert t1 - t0 < 1
        self.patch.return_value.AVS_StopMeasure.assert_called_with(self.handle)
示例#26
0
    async def test_expose_PollScan_timeout(self):
        """Test that `expose` raises if it has to wait too long when
        polling.
        """
        duration = 0.5  # seconds
        # Have the PollScan just run forever.
        self.patch.return_value.AVS_PollScan.side_effect = itertools.repeat(0)

        spec = AvsFiberSpectrograph()
        # asyncio.TimeoutError would be raised if the `wait_for` times out,
        # but the message would not include this text.
        with pytest.raises(asyncio.TimeoutError,
                           match="Timeout polling for exposure to be ready"):
            # Use `wait_for` to keep `expose` from hanging if there is a bug.
            await asyncio.wait_for(spec.expose(duration), 2)
        self.patch.return_value.AVS_PrepareMeasure.assert_called_once()
        self.patch.return_value.AVS_Measure.assert_called_once_with(
            self.handle, 0, 1)
        # PollScan will be called a hundred times or so.
        self.patch.return_value.AVS_PollScan.assert_called()
示例#27
0
    async def test_expose_prepare_fails(self):
        duration = 0.5  # seconds
        self.patch.return_value.AVS_PrepareMeasure.side_effect = None
        self.patch.return_value.AVS_PrepareMeasure.return_value = (
            AvsReturnCode.ERR_INVALID_PARAMETER.value)

        spec = AvsFiberSpectrograph()
        with pytest.raises(AvsReturnError, match="PrepareMeasure"):
            await spec.expose(duration)
        self.patch.return_value.AVS_PrepareMeasure.assert_called_once()
        self.patch.return_value.AVS_Measure.assert_not_called()
示例#28
0
 def test_connect_other_error(self):
     """Test that connect raises with a message containing the interpreted
     code if GetList returns an error code.
     """
     self.patch.return_value.AVS_GetList.side_effect = None
     self.patch.return_value.AVS_GetList.return_value = (
         AvsReturnCode.ERR_DLL_INITIALISATION.value)
     with pytest.raises(AvsReturnError, match="ERR_DLL_INITIALISATION"):
         AvsFiberSpectrograph()
     self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
     self.patch.return_value.AVS_GetList.assert_called_once()
     self.patch.return_value.AVS_Activate.assert_not_called()
示例#29
0
    def test_connect_single_device_already_connected(self):
        """Test that connect raises if the single device claims to already
        be connected in its AvsIdentity field.
        """
        self.id0.Status = AvsDeviceStatus.USB_IN_USE_BY_APPLICATION.value

        with pytest.raises(RuntimeError,
                           match="Requested AVS device is already in use"):
            AvsFiberSpectrograph()
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_called_once()
        self.patch.return_value.AVS_Activate.assert_not_called()
示例#30
0
    def test_connect_GetNumPixels_fails(self):
        """Test that connect ."""
        self.patch.return_value.AVS_GetNumPixels.side_effect = None
        self.patch.return_value.AVS_GetNumPixels.return_value = (
            AvsReturnCode.ERR_DEVICE_NOT_FOUND.value)

        with pytest.raises(AvsReturnError, match="GetNumPixels"):
            AvsFiberSpectrograph()
        self.patch.return_value.AVS_UpdateUSBDevices.assert_called_once()
        self.patch.return_value.AVS_GetList.assert_called_once()
        self.patch.return_value.AVS_Activate.assert_called_once()
        self.patch.return_value.AVS_GetNumPixels.assert_called_once()