def test_request_exec():
    rest = SnowflakeRestful(host="testaccount.snowflakecomputing.com",
                            port=443)

    default_parameters = {
        "method": "POST",
        "full_url": "https://testaccount.snowflakecomputing.com/",
        "headers": {},
        "data": '{"code": 12345}',
        "token": None,
    }

    # request mock
    output_data = {"success": True, "code": 12345}
    request_mock = MagicMock()
    type(request_mock).status_code = PropertyMock(return_value=OK)
    request_mock.json.return_value = output_data

    # session mock
    session = MagicMock()
    session.request.return_value = request_mock

    # success
    ret = rest._request_exec(session=session, **default_parameters)
    assert ret == output_data, "output data"

    # retryable exceptions
    for errcode in [
            BAD_REQUEST,  # 400
            FORBIDDEN,  # 403
            INTERNAL_SERVER_ERROR,  # 500
            BAD_GATEWAY,  # 502
            SERVICE_UNAVAILABLE,  # 503
            GATEWAY_TIMEOUT,  # 504
            555,  # random 5xx error
    ]:
        type(request_mock).status_code = PropertyMock(return_value=errcode)
        try:
            rest._request_exec(session=session, **default_parameters)
            pytest.fail("should fail")
        except RetryRequest as e:
            cls = STATUS_TO_EXCEPTION.get(errcode, OtherHTTPRetryableError)
            assert isinstance(e.args[0],
                              cls), "must be internal error exception"

    # unauthorized
    type(request_mock).status_code = PropertyMock(return_value=UNAUTHORIZED)
    with pytest.raises(InterfaceError):
        rest._request_exec(session=session, **default_parameters)

    # unauthorized with catch okta unauthorized error
    # TODO: what is the difference to InterfaceError?
    type(request_mock).status_code = PropertyMock(return_value=UNAUTHORIZED)
    with pytest.raises(DatabaseError):
        rest._request_exec(session=session,
                           catch_okta_unauthorized_error=True,
                           **default_parameters)

    class IncompleteReadMock(IncompleteRead):
        def __init__(self):
            IncompleteRead.__init__(self, "")

    # handle retryable exception
    for exc in [
            requests.exceptions.ConnectTimeout,
            requests.exceptions.ReadTimeout,
            IncompleteReadMock,
            urllib3.exceptions.ProtocolError,
            requests.exceptions.ConnectionError,
            AttributeError,
    ]:
        session = MagicMock()
        session.request = Mock(side_effect=exc)

        try:
            rest._request_exec(session=session, **default_parameters)
            pytest.fail("should fail")
        except RetryRequest as e:
            cause = e.args[0]
            assert isinstance(cause, exc), "same error class"

    # handle OpenSSL errors and BadStateLine
    for exc in [
            OpenSSL.SSL.SysCallError(errno.ECONNRESET),
            OpenSSL.SSL.SysCallError(errno.ETIMEDOUT),
            OpenSSL.SSL.SysCallError(errno.EPIPE),
            OpenSSL.SSL.SysCallError(-1),  # unknown
            # TODO: should we keep this?
            # urllib3.exceptions.ReadTimeoutError(None, None, None),
            BadStatusLine("fake"),
    ]:
        session = MagicMock()
        session.request = Mock(side_effect=exc)
        try:
            rest._request_exec(session=session, **default_parameters)
            pytest.fail("should fail")
        except RetryRequest as e:
            assert e.args[0] == exc, "same error instance"
Ejemplo n.º 2
0
def test_request_exec():
    rest = SnowflakeRestful(
        host='testaccount.snowflakecomputing.com',
        port=443)

    default_parameters = {
        'method': "POST",
        'full_url': "https://testaccount.snowflakecomputing.com/",
        'headers': {},
        'data': '{"code": 12345}',
        'proxies': None,
        'token': None
    }

    # request mock
    output_data = {'success': True, 'code': 12345}
    request_mock = MagicMock()
    type(request_mock).status_code = PropertyMock(return_value=OK)
    request_mock.json.return_value = output_data

    # session mock
    session = MagicMock()
    session.request.return_value = request_mock

    # success
    ret = rest._request_exec(session=session, **default_parameters)
    assert ret == output_data, 'output data'

    # retryable exceptions
    for errcode in [
        BAD_REQUEST,  # 400
        FORBIDDEN,  # 403
        INTERNAL_SERVER_ERROR,  # 500
        BAD_GATEWAY,  # 502
        SERVICE_UNAVAILABLE,  # 503
        GATEWAY_TIMEOUT,  # 504
        555,  # random 5xx error
    ]:
        type(request_mock).status_code = PropertyMock(return_value=errcode)
        try:
            rest._request_exec(
                session=session, **default_parameters)
            pytest.fail('should fail')
        except RetryRequest as e:
            cls = STATUS_TO_EXCEPTION.get(
                errcode,
                OtherHTTPRetryableError)
            assert isinstance(
                e.args[0],
                cls), "must be internal error exception"

    # unauthorized
    type(request_mock).status_code = PropertyMock(return_value=UNAUTHORIZED)
    with pytest.raises(InterfaceError):
        rest._request_exec(
            session=session, **default_parameters)

    # unauthorized with catch okta unauthorized error
    # TODO: what is the difference to InterfaceError?
    type(request_mock).status_code = PropertyMock(return_value=UNAUTHORIZED)
    with pytest.raises(DatabaseError):
        rest._request_exec(
            session=session, catch_okta_unauthorized_error=True,
            **default_parameters)

    # handle retryable exception
    for exc in [
        ConnectTimeout,
        ReadTimeout,
        SSLError,
        ProtocolError,
        ConnectionError,
        AttributeError,
        PyAsn1Error
    ]:
        session = MagicMock()
        session.request = Mock(side_effect=exc)

        try:
            rest._request_exec(
                session=session, **default_parameters)
            pytest.fail('should fail')
        except RetryRequest as e:
            cause = e.args[0]
            assert isinstance(cause, exc), "same error class"

    # handle OpenSSL errors and BadStateLine
    for exc in [
        OpenSSL.SSL.SysCallError(errno.ECONNRESET),
        OpenSSL.SSL.SysCallError(errno.ETIMEDOUT),
        OpenSSL.SSL.SysCallError(errno.EPIPE),
        OpenSSL.SSL.SysCallError(-1),  # unknown
        ReadTimeoutError(None, None, None),
        BadStatusLine('fake')
    ]:
        session = MagicMock()
        session.request = Mock(side_effect=exc)
        try:
            rest._request_exec(
                session=session, **default_parameters)
            pytest.fail('should fail')
        except RetryRequest as e:
            assert e.args[0] == exc, "same error instance"