예제 #1
0
def test_read_scheme_non_convertible_value():
    """Test that the read scheme matches the expected when the read value
    is non-convertible.

    In this case, it doesn't raise the error but log a warning.
    The error value is still processed and left for the plugin level to handle.
    """
    dev = make_metainfo_response()

    rr = api.ReadResponse(timestamp='november',
                          type='temperature',
                          value='101a')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {
        'type': 'thermistor',
        'data': {
            'temperature': {
                'value': '101a',
                'timestamp': 'november',
                'unit': {
                    'name': 'celsius',
                    'symbol': 'C'
                }
            }
        }
    }
예제 #2
0
def test_read_scheme_with_precision_rounding_2():
    """Test that the read scheme matches the expected when the read value
    must be rounded to the specified precision.
    """
    dev = make_metainfo_response()

    rr = api.ReadResponse(timestamp='november',
                          type='temperature',
                          value='10.98765432')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {
        'type': 'thermistor',
        'data': {
            'temperature': {
                'value': 10.988,
                'timestamp': 'november',
                'unit': {
                    'name': 'celsius',
                    'symbol': 'C'
                }
            }
        }
    }
예제 #3
0
def test_read_scheme_no_precision():
    """Test that the read scheme matches the expected when no precision is given
    for the device
    """
    dev = make_metainfo_response()
    dev.output[0].precision = 0

    rr = api.ReadResponse(timestamp='november',
                          type='temperature',
                          value='10.98765432')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {
        'type': 'thermistor',
        'data': {
            'temperature': {
                'value': 10.98765432,
                'timestamp': 'november',
                'unit': {
                    'name': 'celsius',
                    'symbol': 'C'
                }
            }
        }
    }
예제 #4
0
def mockread(self, rack, board, device):
    """Mock method to monkeypatch the client read method."""
    return [api.ReadResponse(
        timestamp='october',
        type='temperature',
        value='10'
    )]
예제 #5
0
def test_read_scheme_wrong_type_value():
    """Test that the read scheme matches the expected when the read value
    has the wrong type.
    """
    with pytest.raises(TypeError):
        rr = api.ReadResponse(timestamp='november',
                              type='temperature',
                              value=101)
예제 #6
0
def test_read_scheme_with_no_matching_readings():
    """Test that the read scheme matches the expected when no matching
    readings are provided.
    """
    dev = make_metainfo_response()

    rr = api.ReadResponse(timestamp='november', type='humidity', value='5')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {'type': 'thermistor', 'data': {}}
예제 #7
0
def test_read_scheme():
    """Test that the read scheme matches the expected."""
    dev = make_metainfo_response()

    rr = api.ReadResponse(timestamp='november', type='temperature', value='10')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {
        'type': 'thermistor',
        'data': {
            'temperature': {
                'value': 10.0,
                'timestamp': 'november',
                'unit': {
                    'name': 'celsius',
                    'symbol': 'C'
                }
            }
        }
    }
예제 #8
0
def test_read_scheme_no_unit():
    """Test that the read scheme matches the expected when no unit is given
    for the device
    """
    dev = make_metainfo_response()
    dev.output[0].unit.name = ''
    dev.output[0].unit.symbol = ''

    rr = api.ReadResponse(timestamp='november',
                          type='temperature',
                          value='10.98765432')

    response_scheme = ReadResponse(dev, [rr])

    assert response_scheme.data == {
        'type': 'thermistor',
        'data': {
            'temperature': {
                'value': 10.988,
                'timestamp': 'november',
                'unit': None
            }
        }
    }
예제 #9
0
def mock_read(req, timeout):
    """Mock the internal read call."""
    return [
        synse_api.ReadResponse(timestamp='october', type='test', value='10')
    ]
예제 #10
0
async def read(rack, board, device):
    """The handler for the Synse Server "read" API command.

    Args:
        rack (str): The rack which the device resides on.
        board (str): The board which the device resides on.
        device (str): The device to read.

    Returns:
        ReadResponse: The "read" response scheme model.
    """
    logger.debug(
        _('Read Command (args: {}, {}, {})').format(rack, board, device))

    # Lookup the known info for the specified device.
    plugin_name, dev = await cache.get_device_meta(rack, board, device)
    logger.debug(
        _('Device {} is managed by plugin {}').format(device, plugin_name))

    # Get the plugin context for the device's specified protocol.
    _plugin = plugin.get_plugin(plugin_name)
    logger.debug(_('Got plugin: {}').format(_plugin))
    if not _plugin:
        raise errors.PluginNotFoundError(
            _('Unable to find plugin named "{}" to read').format(plugin_name))

    read_data = []
    try:
        # Perform a gRPC read on the device's managing plugin
        read_data = _plugin.client.read(rack, board, device)
    except grpc.RpcError as ex:

        # FIXME (etd) - this isn't the nicest way of doing this check.
        # this string is returned from the SDK, and its not likely to change
        # anytime soon, so this is "safe" for now, but we should see if there
        # is a better way to check this other than comparing strings..
        if hasattr(ex, 'code') and hasattr(ex, 'details'):
            if grpc.StatusCode.NOT_FOUND == ex.code(
            ) and 'no readings found' in ex.details().lower():

                # Currently, in the SDK, there are three different behaviors for
                # devices that do not have readings. Either (a). "null" is returned,
                # (b). an empty string ("") is returned, or (c). a gRPC error is
                # returned with the NOT_FOUND status code. Cases (a) and (b) are
                # handled in the ReadResponse initialization (below). This block
                # handles case (c).
                #
                # The reason for the difference between (a) and (b) is just one
                # of implementation. The empty string is the default value for the
                # gRPC read response, but sometimes it is useful to have an explict
                # value set to make things easier to read.
                #
                # The difference between those and (c) is more distinct. (c) should
                # only happen when a configured device is not being read from at all.
                # Essentially, (c) is the fallback for when device-specific handlers
                # fail to read a configured device.
                #
                # To summarize:
                #   (a), (b)
                #       A device is configured and the plugin's device handlers
                #       can operate on the device. This indicates that the plugin
                #       is working, but the device could be failing or disconnected.
                #
                #   (c)
                #       A device is configured, but the plugin's device handler
                #       can not (or is not) able to operate on the device. This
                #       could indicate either a plugin configuration error or
                #       an error with the plugin logic itself.

                # Create empty readings for each of the device's readings.
                logger.warning(
                    _('Read for {}/{}/{} returned gRPC "no readings found". Will '
                      'apply None as reading value. Note that this response might '
                      'indicate plugin error/misconfiguration.').format(
                          rack, board, device))
                read_data = []
                for output in dev.output:
                    read_data.append(
                        api.ReadResponse(
                            timestamp=utils.rfc3339now(),
                            type=output.type,
                            value='',
                        ))
        else:
            raise errors.FailedReadCommandError(str(ex)) from ex

    return ReadResponse(device=dev, readings=read_data)