Example #1
0
    async def on_event_message(self, topic: str, raw: dict):
        try:
            evt = HistoryEvent(**raw)
            victoria.fget(self.app).write_soon(evt)
            LOGGER.debug(f'MQTT: {evt.key} = {str(evt.data)[:30]}...')

        except ValidationError as ex:
            LOGGER.error(f'Invalid history event: {topic} {strex(ex)}')
async def test_metrics(app, client):
    vic = victoria.fget(app)
    args = TimeSeriesMetricsQuery(fields=['service/f1', 'service/f2'])
    await vic.end()  # We don't want to actually write values

    # No values cached yet
    assert await vic.metrics(args) == []

    # Don't return invalid values
    vic.write_soon(HistoryEvent(key='service', data={
        'f1': 1,
        'f2': 'invalid'
    }))
    assert await vic.metrics(args) == [
        {
            'metric': 'service/f1',
            'value': 1,
            'timestamp': ANY,
        },
    ]

    # Only update new values
    vic.write_soon(HistoryEvent(key='service', data={'f2': 2}))
    assert await vic.metrics(args) == [{
        'metric': 'service/f1',
        'value': 1,
        'timestamp': ANY,
    }, {
        'metric': 'service/f2',
        'value': 2,
        'timestamp': ANY,
    }]
async def test_fields(app, client, aresponses: ResponsesMockServer):
    vic = victoria.fget(app)

    aresponses.add(path_pattern='/victoria/api/v1/series',
                   method_pattern='POST',
                   response={
                       'status':
                       'success',
                       'data': [
                           {
                               '__name__':
                               'spock/setpoint-sensor-pair-2/setting[degC]'
                           },
                           {
                               '__name__': 'spock/actuator-1/value'
                           },
                           {
                               '__name__': 'sparkey/HERMS MT PID/integralReset'
                           },
                           {
                               '__name__':
                               'sparkey/HERMS HLT PID/inputValue[degC]'
                           },
                       ]
                   })

    args = TimeSeriesFieldsQuery(duration='1d')
    assert await vic.fields(args) == [
        'sparkey/HERMS HLT PID/inputValue[degC]',
        'sparkey/HERMS MT PID/integralReset',
        'spock/actuator-1/value',
        'spock/setpoint-sensor-pair-2/setting[degC]',
    ]
async def test_ranges(app, client, aresponses: ResponsesMockServer):
    vic = victoria.fget(app)

    result = {
        'metric': {
            '__name__': 'sparkey/sensor'
        },
        'values': [
            [1626367339.856, '1'],
            [1626367349.856, '2'],
            [1626367359.856, '3'],
        ],
    }

    aresponses.add(
        path_pattern='/victoria/api/v1/query_range',
        method_pattern='POST',
        repeat=3,
        response={
            'status': 'success',
            'data': {
                'resultType': 'matrix',
                'result': [result],
            },
        },
    )

    args = TimeSeriesRangesQuery(fields=['f1', 'f2', 'f3'])
    retv = await vic.ranges(args)
    assert retv == [TimeSeriesRange(**result)] * 3
async def test_ping(app, client, aresponses: ResponsesMockServer):
    vic = victoria.fget(app)

    aresponses.add(path_pattern='/victoria/health',
                   method_pattern='GET',
                   response='OK')
    await vic.ping()

    aresponses.add(path_pattern='/victoria/health',
                   method_pattern='GET',
                   response='NOK')
    with pytest.raises(ConnectionError):
        await vic.ping()
async def test_csv(app, client, aresponses: ResponsesMockServer):
    vic = victoria.fget(app)

    aresponses.add(
        path_pattern='/victoria/api/v1/export',
        method_pattern='POST',
        response='\n'.join([
            '{"metric":{"__name__":"sparkey/HERMS BK PWM/setting"},' +
            '"values":[0,0,0,0,0,0,0],' +
            '"timestamps":[1626368070381,1626368075435,1626368080487,1626368085534,'
            + '1626368090630,1626368095687,1626368100749]}',
            '{"metric":{"__name__":"sparkey/HERMS BK PWM/setting"},' +
            '"values":[0,0,0,0],' +
            '"timestamps":[1626368105840,1626368110891,1626368115940,1626368121034]}',
            '{"metric":{"__name__":"spock/actuator-1/value"},' +
            '"values":[40,40,40,40,40,40,40,40,40,40,40],' +
            '"timestamps":[1626368070380,1626368078080,1626368083130,1626368088178,'
            +
            '1626368093272,1626368098328,1626368103383,1626368108480,1626368113533,1626368118579,1626368123669]}',
            '{"metric":{"__name__":"spock/pin-actuator-1/state"},' +
            '"values":[0,0,0,0,0,0,0,0,0,0,0],' +
            '"timestamps":[1626368070380,1626368078080,1626368083130,1626368088178,'
            +
            '1626368093272,1626368098328,1626368103383,1626368108480,1626368113533,1626368118579,1626368123669]}',
        ]))
    args = TimeSeriesCsvQuery(
        fields=[
            'sparkey/HERMS BK PWM/setting', 'spock/pin-actuator-1/state',
            'spock/actuator-1/value'
        ],
        precision='ISO8601',
    )

    result = []
    async for line in vic.csv(args):
        result.append(line)
    assert len(result) == 23  # headers, 11 from sparkey, 11 from spock
    assert result[0] == ','.join(['time'] + args.fields)

    # line 1: values from spock
    line = result[1].split(',')
    assert ciso8601.parse_datetime(line[0])
    assert line[1:] == ['', '0', '40']

    # line 2: values from sparkey
    line = result[2].split(',')
    assert ciso8601.parse_datetime(line[0])
    assert line[1:] == ['0', '', '']
async def test_write_soon(app, mocker, m_write_interval, client,
                          aresponses: ResponsesMockServer):
    ns_time = int(1e9)
    mocker.patch(TESTED + '.time.time_ns').return_value = ns_time
    vic = victoria.fget(app)

    written = []

    async def handler(request):
        written.append(await request.text())
        return web.Response()

    aresponses.add(
        path_pattern='/victoria/write',
        method_pattern='GET',
        repeat=aresponses.INFINITY,
        response=handler,
    )

    vic.write_soon(HistoryEvent(key='service', data={
        'f1': 1,
        'f2': 'invalid'
    }))
    vic.write_soon(HistoryEvent(key='service', data={}))

    await asyncio.sleep(0.1)
    assert written == [f'service f1=1.0 {ns_time}']

    args = TimeSeriesMetricsQuery(fields=['service/f1'])
    assert await vic.metrics(args) == [
        TimeSeriesMetric(
            metric='service/f1',
            value=1.0,
            timestamp=1000,
        ),
    ]

    vic.write_soon(HistoryEvent(key='service', data={'f1': 2, 'f2': 3}))
    await asyncio.sleep(0.1)
    assert written == [
        f'service f1=1.0 {ns_time}',
        f'service f1=2.0,f2=3.0 {ns_time}',
    ]
async def test_write_error(app, mocker, m_write_interval, client,
                           aresponses: ResponsesMockServer):
    vic = victoria.fget(app)

    aresponses.add(
        path_pattern='/victoria/write',
        method_pattern='GET',
        repeat=aresponses.INFINITY,
        response=web.Response(status=400),
    )

    vic.write_soon(HistoryEvent(key='service', data={
        'f1': 1,
        'f2': 'invalid'
    }))
    vic.write_soon(HistoryEvent(key='service', data={
        'f1': 2,
        'f2': 'invalid'
    }))
    vic.write_soon(HistoryEvent(key='service', data={
        'f1': 3,
        'f2': 'invalid'
    }))
    vic.write_soon(HistoryEvent(key='service', data={}))

    await asyncio.sleep(0.1)

    args = TimeSeriesMetricsQuery(fields=['service/f1'])
    result = await vic.metrics(args)
    assert [v.dict() for v in result] == [{
        'metric': 'service/f1',
        'value': 3.0,
        'timestamp': ANY,
    }]

    assert len(vic._pending_lines) == 3

    mocker.patch(TESTED + '.MAX_PENDING_LINES', 3)
    await asyncio.sleep(0.1)
    assert len(vic._pending_lines) == 2
Example #9
0
 def __init__(self, request: web.Request) -> None:
     super().__init__(request)
     self.victoria = victoria.fget(request.app)
async def m_write_interval(app):
    victoria.fget(app)._write_interval = timedelta(seconds=0.001)