def test_url_property(get_http_host):
    http_host = get_http_host()
    http_host.port = None

    security = http_logging.HttpSecurity(ssl_enable=False)
    config = http_logging.ConfigLog(security=security)

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    assert transport.url == \
        f'http://{http_host.name}/{http_host.path}'

    security.ssl_enable = True

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    assert transport.url == \
        f'https://{http_host.name}/{http_host.path}'

    http_host.port = 1234

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    assert transport.url == \
        f'https://{http_host.name}:{http_host.port}/{http_host.path}'
def test_send_success_request(
    mock_requests,
    mock_logger,
    mock_json,
    get_http_host,
):
    http_host = get_http_host()
    security = http_logging.HttpSecurity(ssl_enable=True)
    config = http_logging.ConfigLog(
        use_logging=True,
        security=security,
    )

    mock_response = mock.Mock()
    mock_response.ok = False
    mock_post = mock.Mock(return_value=mock_response)
    mock_requests.Session().post = mock_post

    mock_json.dumps().encoding.return_value = '{"foo": "bar"}'

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    events = mock.Mock()
    batches = [mock.MagicMock(), mock.MagicMock(), mock.MagicMock()]
    for batch in batches:
        batch.__len__.return_value = 10

    transport._AsyncHttpTransport__batches = mock.Mock(return_value=batches)

    transport.send(events=events)

    transport._AsyncHttpTransport__batches.assert_called_with(events)
    mock_logger.debug.assert_called()
    mock_logger.exception.assert_not_called()
    mock_requests.Session.assert_called()

    post_requests = mock_post.mock_calls

    assert len(post_requests) == 3

    for batch in batches:
        expected_request = mock.call(
            transport.url,
            headers=transport.headers,
            json=batch,
            verify=transport._ssl_verify,
            timeout=transport._timeout,
        )

        assert expected_request in post_requests
def test_headers_property(get_http_host):
    http_host = get_http_host()

    transport = AsyncHttpTransport(
        http_host=http_host,
    )

    transport.get_custom_headers = mock.Mock(return_value={})

    assert transport.headers == {'Content-Type': 'application/json'}

    transport.get_custom_headers = mock.Mock(return_value={'foo': 'bar'})

    assert transport.headers == {
        'Content-Type': 'application/json',
        'foo': 'bar',
    }
def test_send_failed_request(
    mock_requests,
    mock_logger,
    mock_json,
    get_http_host,
):
    http_host = get_http_host()
    security = http_logging.HttpSecurity(ssl_enable=True)
    config = http_logging.ConfigLog(
        use_logging=True,
        security=security,
    )

    req_exception = requests.exceptions.RequestException('HTTP Error')
    mock_response = mock.Mock()
    mock_response.ok = False  # Simulate failed request
    mock_response.raise_for_status.side_effect = req_exception
    mock_post = mock.Mock(return_value=mock_response)
    mock_requests.Session().post = mock_post

    mock_json.dumps().encoding.return_value = '{"foo": "bar"}'

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    events = mock.Mock()
    batches = [mock.MagicMock()]

    batches[0].__len__.return_value = 10

    transport._AsyncHttpTransport__batches = mock.Mock(return_value=batches)

    transport.send(events=events)

    assert len(mock_post.mock_calls) == 1

    mock_requests.Session().close.assert_called()
    mock_response.raise_for_status.assert_called()
    mock_logger.debug.assert_called()
    mock_logger.exception.assert_called_with(req_exception)
def test_custom_formatter_and_transport(http_host):
    config = http_logging.ConfigLog()
    transport = AsyncHttpTransport(http_host=http_host, config=config)
    formatter = HttpLogFormatter()

    handler = AsyncHttpHandler(
        http_host=http_host,
        support_class=http_logging.SupportClass(
            http_host=http_host,
            config=config,
            _transport=transport,
            _formatter=formatter,
        ),
    )

    handler._setup_transport()

    assert handler._transport == transport
    assert handler.formatter == formatter
def test_get_custom_headers(get_http_host):
    http_host = get_http_host()

    transport = AsyncHttpTransport(
        http_host=http_host,
    )

    assert transport.get_custom_headers() == {}

    dummy_headers = {'foo': 'bar'}
    mock_custom_headers = mock.Mock(return_value=dummy_headers)

    config = http_logging.ConfigLog(custom_headers=mock_custom_headers)

    transport = AsyncHttpTransport(
        http_host=http_host,
        config=config,
    )

    assert transport.get_custom_headers() == dummy_headers
def test_custom_path(get_http_host):
    http_host = get_http_host()

    transport = AsyncHttpTransport(http_host=http_host)

    assert transport._path == http_host.path
Exemple #8
0
def test_handler(run_localserver, localhost):
    custom_path = 'foo-bar-path'
    custom_header_dict = {'Foo': 'Bar'}

    http_host = HttpHost(
        name=localhost.host,
        port=localhost.port,
        path=custom_path,
        timeout=localhost.timeout
    )

    security = HttpSecurity(
        ssl_enable=False,
        ssl_verify=False,
    )

    config = ConfigLog(
        database_path=localhost.database_path,
        use_logging=True,
        custom_headers=lambda: custom_header_dict,
        security=security,
    )

    support_class = SupportClass(
        http_host=http_host,
        config=config,
        _transport=AsyncHttpTransport(
            http_host=http_host,
            config=config,
        ),
    )

    log_handler = AsyncHttpHandler(
        http_host=http_host,
        config=config,
        support_class=support_class,
    )

    logger = logging.getLogger('test_handler')
    logger.setLevel(logging.DEBUG)
    logger.addHandler(log_handler)

    logged_messages = {
        'debug': 'Does this help debugging?',
        'info': 'Some information...',
        'warning': 'You\'ve been warned!',
    }

    try:
        x = 1/0  # NOQA
    except Exception:
        logged_messages['error'] = traceback.format_exc()

    info_extra = {'foo': 'bar'}

    for level, message in logged_messages.items():
        if level == 'info':
            getattr(logger, level)(message, extra=info_extra)
        else:
            getattr(logger, level)(message)

    # Trigger event flushing to make sure logs are sent to localserver
    # See: https://archive.vn/B6yFt#selection-3749.0-3795.34
    print('Flushing log events...')
    log_handler.flush()

    count = 0

    while True and count <= 10:
        response = requests.post(url=localhost.last_response_url)

        data = response.json()['last_response']

        if data is None:
            time.sleep(0.5)
            count += 1
            continue

        break

    assert response.ok is True
    assert data['request']['http']['method'] == 'POST'
    assert data['request']['url']['path'] == f'/{custom_path}'

    # Verify headers
    for key, val in custom_header_dict.items():
        assert data['request']['headers'].get(key) == val

    recorded_logs = data['request']['body']
    recorded_logs_by_level = {
        log['level']['name']: log
        for log in recorded_logs
    }

    assert len(recorded_logs) == len(logged_messages)

    for level, message in logged_messages.items():
        recorded_log = recorded_logs_by_level[level.upper()]

        assert recorded_log['message'] == str(message)

        if level == 'info':
            assert 'extra' in recorded_log.keys()
            assert recorded_log['extra'] == info_extra
        else:
            assert 'extra' not in recorded_log.keys()