def test_span_namer(http_request, http_response):
    settings.tracing_implementation.set_value(FakeSpan)
    with FakeSpan(name="parent") as root_span:

        request = http_request("GET", "http://localhost/temp?query=query")
        pipeline_request = PipelineRequest(request, PipelineContext(None))

        def fixed_namer(http_request):
            assert http_request is request
            return "overridenname"

        policy = DistributedTracingPolicy(network_span_namer=fixed_namer)

        policy.on_request(pipeline_request)

        response = create_http_response(http_response, request, None)
        response.headers = request.headers
        response.status_code = 202

        policy.on_response(
            pipeline_request,
            PipelineResponse(request, response, PipelineContext(None)))

        def operation_namer(http_request):
            assert http_request is request
            return "operation level name"

        pipeline_request.context.options[
            'network_span_namer'] = operation_namer

        policy.on_request(pipeline_request)

        response = create_http_response(http_response, request, None)
        response.headers = request.headers
        response.status_code = 202

        policy.on_response(
            pipeline_request,
            PipelineResponse(request, response, PipelineContext(None)))

    # Check init kwargs
    network_span = root_span.children[0]
    assert network_span.name == "overridenname"

    # Check operation kwargs
    network_span = root_span.children[1]
    assert network_span.name == "operation level name"
 def send(self, request,
          **kwargs):  # type: (PipelineRequest, Any) -> PipelineResponse
     self._count += 1
     response = create_http_response(http_response, request, None)
     response.status_code = 201
     headers = {"Retry-After": "1"}
     response.headers = headers
     return response
Exemple #3
0
def test_error_map(http_request, http_response):
    request = http_request("GET", "")
    response = create_http_response(http_response, request, None)
    error_map = {
        404: ResourceNotFoundError
    }
    with pytest.raises(ResourceNotFoundError):
        map_error(404, response, error_map)
Exemple #4
0
def test_error_map_with_default(http_request, http_response):
    request = http_request("GET", "")
    response = create_http_response(http_response, request, None)
    error_map = ErrorMap({
        404: ResourceNotFoundError
    }, default_error=ResourceExistsError)
    with pytest.raises(ResourceExistsError):
        map_error(401, response, error_map)
def test_distributed_tracing_policy_solo(http_request, http_response):
    """Test policy with no other policy and happy path"""
    settings.tracing_implementation.set_value(FakeSpan)
    with FakeSpan(name="parent") as root_span:
        policy = DistributedTracingPolicy()

        request = http_request("GET", "http://localhost/temp?query=query")
        request.headers["x-ms-client-request-id"] = "some client request id"

        pipeline_request = PipelineRequest(request, PipelineContext(None))
        policy.on_request(pipeline_request)

        response = create_http_response(http_response, request, None)
        response.headers = request.headers
        response.status_code = 202
        response.headers["x-ms-request-id"] = "some request id"

        assert request.headers.get("traceparent") == '123456789'

        policy.on_response(
            pipeline_request,
            PipelineResponse(request, response, PipelineContext(None)))
        time.sleep(0.001)
        policy.on_request(pipeline_request)
        try:
            raise ValueError("Transport trouble")
        except:
            policy.on_exception(pipeline_request)

    # Check on_response
    network_span = root_span.children[0]
    assert network_span.name == "/temp"
    assert network_span.attributes.get("http.method") == "GET"
    assert network_span.attributes.get("component") == "http"
    assert network_span.attributes.get(
        "http.url") == "http://localhost/temp?query=query"
    assert network_span.attributes.get("http.user_agent") is None
    assert network_span.attributes.get("x-ms-request-id") == "some request id"
    assert network_span.attributes.get(
        "x-ms-client-request-id") == "some client request id"
    assert network_span.attributes.get("http.status_code") == 202

    # Check on_exception
    network_span = root_span.children[1]
    assert network_span.name == "/temp"
    assert network_span.attributes.get("http.method") == "GET"
    assert network_span.attributes.get("component") == "http"
    assert network_span.attributes.get(
        "http.url") == "http://localhost/temp?query=query"
    assert network_span.attributes.get(
        "x-ms-client-request-id") == "some client request id"
    assert network_span.attributes.get("http.user_agent") is None
    assert network_span.attributes.get("x-ms-request-id") == None
    assert network_span.attributes.get("http.status_code") == 504
 def send(self, request,
          **kwargs):  # type: (PipelineRequest, Any) -> PipelineResponse
     if self._first:
         self._first = False
         request.body.seek(0, 2)
         raise AzureError('fail on first')
     position = request.body.tell()
     assert position == 0
     response = create_http_response(http_response, request, None)
     response.status_code = 400
     return response
def test_connection_error_response(http_request, http_response):
    class MockTransport(HttpTransport):
        def __init__(self):
            self._count = 0

        def __exit__(self, exc_type, exc_val, exc_tb):
            pass
        def close(self):
            pass
        def open(self):
            pass

        def send(self, request, **kwargs):
            request = http_request('GET', 'http://localhost/')
            response = create_http_response(http_response, request, None)
            response.status_code = 200
            return response

        def next(self):
            self.__next__()

        def __next__(self):
            if self._count == 0:
                self._count += 1
                raise requests.exceptions.ConnectionError

        def stream(self, chunk_size, decode_content=False):
            if self._count == 0:
                self._count += 1
                raise requests.exceptions.ConnectionError
            while True:
                yield b"test"

    class MockInternalResponse():
        def __init__(self):
            self.raw = MockTransport()

        def close(self):
            pass

    http_request = http_request('GET', 'http://localhost/')
    pipeline = Pipeline(MockTransport())
    http_response = create_http_response(http_response, http_request, None)
    http_response.internal_response = MockInternalResponse()
    stream = StreamDownloadGenerator(pipeline, http_response, decompress=False)
    with mock.patch('time.sleep', return_value=None):
        with pytest.raises(requests.exceptions.ConnectionError):
            stream.__next__()
def test_x_ms_retry_after(retry_after_input, http_request, http_response):
    retry_policy = RetryPolicy()
    request = http_request("GET", "http://localhost")
    response = create_http_response(http_response, request, None)
    response.headers["x-ms-retry-after-ms"] = retry_after_input
    pipeline_response = PipelineResponse(request, response, None)
    retry_after = retry_policy.get_retry_after(pipeline_response)
    seconds = float(retry_after_input)
    assert retry_after == seconds / 1000.0
    response.headers.pop("x-ms-retry-after-ms")
    response.headers["Retry-After"] = retry_after_input
    retry_after = retry_policy.get_retry_after(pipeline_response)
    assert retry_after == float(retry_after_input)
    response.headers["x-ms-retry-after-ms"] = 500
    retry_after = retry_policy.get_retry_after(pipeline_response)
    assert retry_after == float(retry_after_input)
Exemple #9
0
def test_http_logger_with_generator_body(http_request, http_response):
    class MockHandler(logging.Handler):
        def __init__(self):
            super(MockHandler, self).__init__()
            self.messages = []

        def reset(self):
            self.messages = []

        def emit(self, record):
            self.messages.append(record)

    mock_handler = MockHandler()

    logger = logging.getLogger("testlogger")
    logger.addHandler(mock_handler)
    logger.setLevel(logging.DEBUG)

    policy = HttpLoggingPolicy(logger=logger)

    universal_request = http_request('GET', 'http://localhost/')
    mock = Mock()
    mock.__class__ = types.AsyncGeneratorType
    universal_request.body = mock
    http_response = create_http_response(http_response, universal_request,
                                         None)
    http_response.status_code = 202
    request = PipelineRequest(universal_request, PipelineContext(None))

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 2
    messages_request = mock_handler.messages[0].message.split("\n")
    messages_response = mock_handler.messages[1].message.split("\n")
    assert messages_request[0] == "Request URL: 'http://localhost/'"
    assert messages_request[1] == "Request method: 'GET'"
    assert messages_request[2] == 'Request headers:'
    assert messages_request[3] == 'File upload'
    assert messages_response[0] == 'Response status: 202'
    assert messages_response[1] == 'Response headers:'

    mock_handler.reset()
 def send(self, request,
          **kwargs):  # type: (PipelineRequest, Any) -> PipelineResponse
     if self._first:
         self._first = False
         for value in request.files.values():
             name, body = value[0], value[1]
             if name and body and hasattr(body, 'read'):
                 body.seek(0, 2)
                 raise AzureError('fail on first')
     for value in request.files.values():
         name, body = value[0], value[1]
         if name and body and hasattr(body, 'read'):
             position = body.tell()
             assert not position
             response = create_http_response(http_response, request,
                                             None)
             response.status_code = 400
             return response
def test_distributed_tracing_policy_attributes(http_request, http_response):
    """Test policy with no other policy and happy path"""
    settings.tracing_implementation.set_value(FakeSpan)
    with FakeSpan(name="parent") as root_span:
        policy = DistributedTracingPolicy(
            tracing_attributes={'myattr': 'myvalue'})

        request = http_request("GET", "http://localhost/temp?query=query")

        pipeline_request = PipelineRequest(request, PipelineContext(None))
        policy.on_request(pipeline_request)

        response = create_http_response(http_response, request, None)
        response.headers = request.headers
        response.status_code = 202

        policy.on_response(
            pipeline_request,
            PipelineResponse(request, response, PipelineContext(None)))

    # Check on_response
    network_span = root_span.children[0]
    assert network_span.attributes.get("myattr") == "myvalue"
def test_distributed_tracing_policy_badurl(caplog, http_request,
                                           http_response):
    """Test policy with a bad url that will throw, and be sure policy ignores it"""
    settings.tracing_implementation.set_value(FakeSpan)
    with FakeSpan(name="parent") as root_span:
        policy = DistributedTracingPolicy()

        request = http_request("GET", "http://[[[")
        request.headers["x-ms-client-request-id"] = "some client request id"

        pipeline_request = PipelineRequest(request, PipelineContext(None))
        with caplog.at_level(
                logging.WARNING,
                logger="azure.core.pipeline.policies.distributed_tracing"):
            policy.on_request(pipeline_request)
        assert "Unable to start network span" in caplog.text

        response = create_http_response(http_response, request, None)
        response.headers = request.headers
        response.status_code = 202
        response.headers["x-ms-request-id"] = "some request id"

        assert request.headers.get(
            "traceparent") is None  # Got not network trace

        policy.on_response(
            pipeline_request,
            PipelineResponse(request, response, PipelineContext(None)))
        time.sleep(0.001)

        policy.on_request(pipeline_request)
        try:
            raise ValueError("Transport trouble")
        except:
            policy.on_exception(pipeline_request)

    assert len(root_span.children) == 0
Exemple #13
0
def test_no_log(mock_http_logger, http_request, http_response):
    universal_request = http_request('GET', 'http://localhost/')
    request = PipelineRequest(universal_request, PipelineContext(None))
    http_logger = NetworkTraceLoggingPolicy()
    response = PipelineResponse(
        request, create_http_response(http_response, universal_request, None),
        request.context)

    # By default, no log handler for HTTP
    http_logger.on_request(request)
    mock_http_logger.debug.assert_not_called()
    http_logger.on_response(request, response)
    mock_http_logger.debug.assert_not_called()
    mock_http_logger.reset_mock()

    # I can enable it per request
    request.context.options['logging_enable'] = True
    http_logger.on_request(request)
    assert mock_http_logger.debug.call_count >= 1
    mock_http_logger.reset_mock()
    request.context.options['logging_enable'] = True
    http_logger.on_response(request, response)
    assert mock_http_logger.debug.call_count >= 1
    mock_http_logger.reset_mock()

    # I can enable it per request (bool value should be honored)
    request.context.options['logging_enable'] = False
    http_logger.on_request(request)
    mock_http_logger.debug.assert_not_called()
    request.context.options['logging_enable'] = False
    http_logger.on_response(request, response)
    mock_http_logger.debug.assert_not_called()
    mock_http_logger.reset_mock()

    # I can enable it globally
    request.context.options = {}
    http_logger.enable_http_logger = True
    http_logger.on_request(request)
    assert mock_http_logger.debug.call_count >= 1
    http_logger.on_response(request, response)
    assert mock_http_logger.debug.call_count >= 1
    mock_http_logger.reset_mock()

    # I can enable it globally and override it locally
    http_logger.enable_http_logger = True
    request.context.options['logging_enable'] = False
    http_logger.on_request(request)
    mock_http_logger.debug.assert_not_called()
    response.context['logging_enable'] = False
    http_logger.on_response(request, response)
    mock_http_logger.debug.assert_not_called()
    mock_http_logger.reset_mock()

    # Let's make this request a failure, retried twice
    request.context.options['logging_enable'] = True
    http_logger.on_request(request)
    http_logger.on_response(request, response)

    first_count = mock_http_logger.debug.call_count
    assert first_count >= 1

    http_logger.on_request(request)
    http_logger.on_response(request, response)

    second_count = mock_http_logger.debug.call_count
    assert second_count == first_count * 2
def test_distributed_tracing_policy_with_user_agent(http_request,
                                                    http_response):
    """Test policy working with user agent."""
    settings.tracing_implementation.set_value(FakeSpan)
    with mock.patch.dict('os.environ', {"AZURE_HTTP_USER_AGENT": "mytools"}):
        with FakeSpan(name="parent") as root_span:
            policy = DistributedTracingPolicy()

            request = http_request("GET", "http://localhost")
            request.headers[
                "x-ms-client-request-id"] = "some client request id"

            pipeline_request = PipelineRequest(request, PipelineContext(None))

            user_agent = UserAgentPolicy()
            user_agent.on_request(pipeline_request)
            policy.on_request(pipeline_request)

            response = create_http_response(http_response, request, None)
            response.headers = request.headers
            response.status_code = 202
            response.headers["x-ms-request-id"] = "some request id"
            pipeline_response = PipelineResponse(request, response,
                                                 PipelineContext(None))

            assert request.headers.get("traceparent") == '123456789'

            policy.on_response(pipeline_request, pipeline_response)

            time.sleep(0.001)
            policy.on_request(pipeline_request)
            try:
                raise ValueError("Transport trouble")
            except:
                policy.on_exception(pipeline_request)

            user_agent.on_response(pipeline_request, pipeline_response)

        network_span = root_span.children[0]
        assert network_span.name == "/"
        assert network_span.attributes.get("http.method") == "GET"
        assert network_span.attributes.get("component") == "http"
        assert network_span.attributes.get("http.url") == "http://localhost"
        assert network_span.attributes.get("http.user_agent").endswith(
            "mytools")
        assert network_span.attributes.get(
            "x-ms-request-id") == "some request id"
        assert network_span.attributes.get(
            "x-ms-client-request-id") == "some client request id"
        assert network_span.attributes.get("http.status_code") == 202

        network_span = root_span.children[1]
        assert network_span.name == "/"
        assert network_span.attributes.get("http.method") == "GET"
        assert network_span.attributes.get("component") == "http"
        assert network_span.attributes.get("http.url") == "http://localhost"
        assert network_span.attributes.get("http.user_agent").endswith(
            "mytools")
        assert network_span.attributes.get(
            "x-ms-client-request-id") == "some client request id"
        assert network_span.attributes.get("x-ms-request-id") is None
        assert network_span.attributes.get("http.status_code") == 504
        # Exception should propagate status for Opencensus
        assert network_span.status == 'Transport trouble'
Exemple #15
0
def test_http_logger(http_request, http_response):
    class MockHandler(logging.Handler):
        def __init__(self):
            super(MockHandler, self).__init__()
            self.messages = []

        def reset(self):
            self.messages = []

        def emit(self, record):
            self.messages.append(record)

    mock_handler = MockHandler()

    logger = logging.getLogger("testlogger")
    logger.addHandler(mock_handler)
    logger.setLevel(logging.DEBUG)

    policy = HttpLoggingPolicy(logger=logger)

    universal_request = http_request('GET', 'http://localhost/')
    http_response = create_http_response(http_response, universal_request,
                                         None)
    http_response.status_code = 202
    request = PipelineRequest(universal_request, PipelineContext(None))

    # Basics

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 2
    messages_request = mock_handler.messages[0].message.split("\n")
    messages_response = mock_handler.messages[1].message.split("\n")
    assert messages_request[0] == "Request URL: 'http://localhost/'"
    assert messages_request[1] == "Request method: 'GET'"
    assert messages_request[2] == 'Request headers:'
    assert messages_request[3] == 'No body was attached to the request'
    assert messages_response[0] == 'Response status: 202'
    assert messages_response[1] == 'Response headers:'

    mock_handler.reset()

    # Let's make this request a failure, retried twice

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 4
    messages_request1 = mock_handler.messages[0].message.split("\n")
    messages_response1 = mock_handler.messages[1].message.split("\n")
    messages_request2 = mock_handler.messages[2].message.split("\n")
    messages_response2 = mock_handler.messages[3].message.split("\n")
    assert messages_request1[0] == "Request URL: 'http://localhost/'"
    assert messages_request1[1] == "Request method: 'GET'"
    assert messages_request1[2] == 'Request headers:'
    assert messages_request1[3] == 'No body was attached to the request'
    assert messages_response1[0] == 'Response status: 202'
    assert messages_response1[1] == 'Response headers:'
    assert messages_request2[0] == "Request URL: 'http://localhost/'"
    assert messages_request2[1] == "Request method: 'GET'"
    assert messages_request2[2] == 'Request headers:'
    assert messages_request2[3] == 'No body was attached to the request'
    assert messages_response2[0] == 'Response status: 202'
    assert messages_response2[1] == 'Response headers:'

    mock_handler.reset()

    # Headers and query parameters

    policy.allowed_query_params = ['country']

    universal_request.headers = {
        "Accept": "Caramel",
        "Hate": "Chocolat",
    }
    http_response.headers = {
        "Content-Type": "Caramel",
        "HateToo": "Chocolat",
    }
    universal_request.url = "http://localhost/?country=france&city=aix"

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 2
    messages_request = mock_handler.messages[0].message.split("\n")
    messages_response = mock_handler.messages[1].message.split("\n")
    assert messages_request[
        0] == "Request URL: 'http://localhost/?country=france&city=REDACTED'"
    assert messages_request[1] == "Request method: 'GET'"
    assert messages_request[2] == "Request headers:"
    # Dict not ordered in Python, exact logging order doesn't matter
    assert set([messages_request[3], messages_request[4]]) == set(
        ["    'Accept': 'Caramel'", "    'Hate': 'REDACTED'"])
    assert messages_request[5] == 'No body was attached to the request'
    assert messages_response[0] == "Response status: 202"
    assert messages_response[1] == "Response headers:"
    # Dict not ordered in Python, exact logging order doesn't matter
    assert set([messages_response[2], messages_response[3]]) == set(
        ["    'Content-Type': 'Caramel'", "    'HateToo': 'REDACTED'"])

    mock_handler.reset()
Exemple #16
0
def test_http_logger_operation_level(http_request, http_response):
    class MockHandler(logging.Handler):
        def __init__(self):
            super(MockHandler, self).__init__()
            self.messages = []

        def reset(self):
            self.messages = []

        def emit(self, record):
            self.messages.append(record)

    mock_handler = MockHandler()

    logger = logging.getLogger("testlogger")
    logger.addHandler(mock_handler)
    logger.setLevel(logging.DEBUG)

    policy = HttpLoggingPolicy()
    kwargs = {'logger': logger}

    universal_request = http_request('GET', 'http://localhost/')
    http_response = create_http_response(http_response, universal_request,
                                         None)
    http_response.status_code = 202
    request = PipelineRequest(universal_request,
                              PipelineContext(None, **kwargs))

    # Basics

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 2
    messages_request = mock_handler.messages[0].message.split("\n")
    messages_response = mock_handler.messages[1].message.split("\n")
    assert messages_request[0] == "Request URL: 'http://localhost/'"
    assert messages_request[1] == "Request method: 'GET'"
    assert messages_request[2] == 'Request headers:'
    assert messages_request[3] == 'No body was attached to the request'
    assert messages_response[0] == 'Response status: 202'
    assert messages_response[1] == 'Response headers:'

    mock_handler.reset()

    # Let's make this request a failure, retried twice

    request = PipelineRequest(universal_request,
                              PipelineContext(None, **kwargs))

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    policy.on_request(request)
    response = PipelineResponse(request, http_response, request.context)
    policy.on_response(request, response)

    assert all(m.levelname == 'INFO' for m in mock_handler.messages)
    assert len(mock_handler.messages) == 4
    messages_request1 = mock_handler.messages[0].message.split("\n")
    messages_response1 = mock_handler.messages[1].message.split("\n")
    messages_request2 = mock_handler.messages[2].message.split("\n")
    messages_response2 = mock_handler.messages[3].message.split("\n")
    assert messages_request1[0] == "Request URL: 'http://localhost/'"
    assert messages_request1[1] == "Request method: 'GET'"
    assert messages_request1[2] == 'Request headers:'
    assert messages_request1[3] == 'No body was attached to the request'
    assert messages_response1[0] == 'Response status: 202'
    assert messages_response1[1] == 'Response headers:'
    assert messages_request2[0] == "Request URL: 'http://localhost/'"
    assert messages_request2[1] == "Request method: 'GET'"
    assert messages_request2[2] == 'Request headers:'
    assert messages_request2[3] == 'No body was attached to the request'
    assert messages_response2[0] == 'Response status: 202'
    assert messages_response2[1] == 'Response headers:'

    mock_handler.reset()
 def send(self, request, **kwargs):
     request = http_request('GET', 'http://localhost/')
     response = create_http_response(http_response, request, None)
     response.status_code = 200
     return response
 def send(self, request,
          **kwargs):  # type: (PipelineRequest, Any) -> PipelineResponse
     self._count += 1
     response = create_http_response(http_response, request, None)
     response.status_code = 429
     return response
 def send(request, **kwargs):
     for arg in ("connection_timeout", "read_timeout"):
         assert arg not in kwargs, "policy should defer to transport configuration when not given a timeout"
     response = create_http_response(http_response, request, None)
     response.status_code = 200
     return response
Exemple #20
0
async def test_connection_error_response(http_request, http_response):
    class MockSession(object):
        def __init__(self):
            self.auto_decompress = True

        @property
        def auto_decompress(self):
            return self.auto_decompress

    class MockTransport(AsyncHttpTransport):
        def __init__(self):
            self._count = 0
            self.session = MockSession

        async def __aexit__(self, exc_type, exc_val, exc_tb):
            pass

        async def close(self):
            pass

        async def open(self):
            pass

        async def send(self, request, **kwargs):
            request = http_request('GET', 'http://localhost/')
            response = create_http_response(http_response, request, None)
            response.status_code = 200
            return response

    class MockContent():
        def __init__(self):
            self._first = True

        async def read(self, block_size):
            if self._first:
                self._first = False
                raise ConnectionError
            return None

    class MockInternalResponse():
        def __init__(self):
            self.headers = {}
            self.content = MockContent()

        async def close(self):
            pass

    class AsyncMock(mock.MagicMock):
        async def __call__(self, *args, **kwargs):
            return super(AsyncMock, self).__call__(*args, **kwargs)

    http_request = http_request('GET', 'http://localhost/')
    pipeline = AsyncPipeline(MockTransport())
    http_response = create_http_response(http_response, http_request, None)
    http_response.internal_response = MockInternalResponse()
    stream = AioHttpStreamDownloadGenerator(pipeline,
                                            http_response,
                                            decompress=False)
    with mock.patch('asyncio.sleep', new_callable=AsyncMock):
        with pytest.raises(ConnectionError):
            await stream.__anext__()