# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # -------------------------------------------------------------------------- import pytest from azure.core.exceptions import ( ResourceNotFoundError, ResourceExistsError, map_error, ErrorMap, ) from utils import request_and_responses_product, create_http_response, HTTP_RESPONSES @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(HTTP_RESPONSES)) 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) @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(HTTP_RESPONSES)) def test_error_map_no_default(http_request, http_response): request = http_request("GET", "") response = create_http_response(http_response, request, None) error_map = ErrorMap({ 404: ResourceNotFoundError
assert serialized == expected @pytest.mark.parametrize("http_request", HTTP_REQUESTS) def test_url_join(http_request): assert _urljoin('devstoreaccount1', '') == 'devstoreaccount1/' assert _urljoin('devstoreaccount1', 'testdir/') == 'devstoreaccount1/testdir/' assert _urljoin('devstoreaccount1/', '') == 'devstoreaccount1/' assert _urljoin('devstoreaccount1/', 'testdir/') == 'devstoreaccount1/testdir/' @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(HTTP_CLIENT_TRANSPORT_RESPONSES)) def test_http_client_response(port, http_request, http_response): # Create a core request request = http_request("GET", "http://localhost:{}".format(port)) # Fake a transport based on http.client conn = HTTPConnection("localhost", port) conn.request("GET", "/get") r1 = conn.getresponse() response = create_transport_response(http_response, request, r1) if is_rest(http_response): response.read() # Don't assume too much in those assert, since we reach a real server assert response.internal_response is r1
"""Tests for the HttpLoggingPolicy.""" import logging import types import pytest import sys from unittest.mock import Mock from azure.core.pipeline import (PipelineResponse, PipelineRequest, PipelineContext) from azure.core.pipeline.policies import ( HttpLoggingPolicy, ) from utils import HTTP_RESPONSES, request_and_responses_product, create_http_response @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(HTTP_RESPONSES)) 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")
import requests from azure.core.pipeline.transport import ( AsyncHttpTransport, AsyncioRequestsTransportResponse, AioHttpTransport, ) from azure.core.pipeline import AsyncPipeline, PipelineResponse from azure.core.pipeline.transport._aiohttp import AioHttpStreamDownloadGenerator from unittest import mock import pytest from utils import request_and_responses_product, ASYNC_HTTP_RESPONSES, create_http_response @pytest.mark.asyncio @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(ASYNC_HTTP_RESPONSES)) 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):
class TestBasePolling(object): convert = re.compile('([a-z0-9])([A-Z])') @staticmethod def mock_send(http_request, http_response, method, status, headers=None, body=RESPONSE_BODY): if headers is None: headers = {} response = Response() response._content_consumed = True response._content = json.dumps(body).encode( 'ascii') if body is not None else None response.request = Request() response.request.method = method response.request.url = RESOURCE_URL response.request.headers = { 'x-ms-client-request-id': '67f4dd4e-6262-45e1-8bed-5c45cf23b6d9' } response.status_code = status response.headers = headers response.headers.update( {"content-type": "application/json; charset=utf8"}) response.reason = "OK" if is_rest(http_request): request = http_request( response.request.method, response.request.url, headers=response.request.headers, content=body, ) else: request = CLIENT._request( response.request.method, response.request.url, None, # params response.request.headers, body, None, # form_content None # stream_content ) response = create_transport_response( http_response, request, response, ) return PipelineResponse( request, response, None # context ) @staticmethod def mock_update(http_request, http_response, url, headers=None): response = Response() response._content_consumed = True response.request = mock.create_autospec(Request) response.request.method = 'GET' response.headers = headers or {} response.headers.update( {"content-type": "application/json; charset=utf8"}) response.reason = "OK" if url == ASYNC_URL: response.request.url = url response.status_code = POLLING_STATUS response._content = ASYNC_BODY.encode('ascii') response.randomFieldFromPollAsyncOpHeader = None elif url == LOCATION_URL: response.request.url = url response.status_code = POLLING_STATUS response._content = LOCATION_BODY.encode('ascii') response.randomFieldFromPollLocationHeader = None elif url == ERROR: raise BadEndpointError("boom") elif url == RESOURCE_URL: response.request.url = url response.status_code = POLLING_STATUS response._content = RESOURCE_BODY.encode('ascii') else: raise Exception('URL does not match') request = http_request( response.request.method, response.request.url, ) response = create_transport_response( http_response, request, response, ) return PipelineResponse( request, response, None # context ) @staticmethod def mock_outputs(pipeline_response): response = pipeline_response.http_response try: body = json.loads(response.text()) except ValueError: raise DecodeError("Impossible to deserialize") body = { TestBasePolling.convert.sub(r'\1_\2', k).lower(): v for k, v in body.items() } properties = body.setdefault('properties', {}) if 'name' in body: properties['name'] = body['name'] if properties: properties = { TestBasePolling.convert.sub(r'\1_\2', k).lower(): v for k, v in properties.items() } del body['properties'] body.update(properties) resource = SimpleResource(**body) else: raise DecodeError("Impossible to deserialize") resource = SimpleResource(**body) return resource @staticmethod def mock_deserialization_no_body(pipeline_response): """Use this mock when you don't expect a return (last body irrelevant) """ return None @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_long_running_put(self, http_request, http_response): #TODO: Test custom header field # Test throw on non LRO related status code response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 1000, {}) CLIENT.http_request_type = http_request CLIENT.http_response_type = http_response with pytest.raises(HttpResponseError): LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() # Test with no polling necessary response_body = { 'properties': { 'provisioningState': 'Succeeded' }, 'name': TEST_NAME } response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {}, response_body) def no_update_allowed(url, headers=None): raise ValueError("Should not try to update") poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert not hasattr(poll._polling_method._pipeline_response, 'randomFieldFromPollAsyncOpHeader') # Test polling from operation-location header response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {'operation-location': ASYNC_URL}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert not hasattr(poll._polling_method._pipeline_response, 'randomFieldFromPollAsyncOpHeader') # Test polling location header response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {'location': LOCATION_URL}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollLocationHeader is None # Test polling initial payload invalid (SQLDb) response_body = {} # Empty will raise response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {'location': LOCATION_URL}, response_body) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollLocationHeader is None # Test fail to poll from operation-location header response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {'operation-location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() # Test fail to poll from location header response = TestBasePolling.mock_send(http_request, http_response, 'PUT', 201, {'location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_long_running_patch(self, http_request, http_response): CLIENT.http_request_type = http_request CLIENT.http_response_type = http_response # Test polling from location header response = TestBasePolling.mock_send( http_request, http_response, 'PATCH', 202, {'location': LOCATION_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollLocationHeader is None # Test polling from operation-location header response = TestBasePolling.mock_send( http_request, http_response, 'PATCH', 202, {'operation-location': ASYNC_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert not hasattr(poll._polling_method._pipeline_response, 'randomFieldFromPollAsyncOpHeader') # Test polling from location header response = TestBasePolling.mock_send( http_request, http_response, 'PATCH', 200, {'location': LOCATION_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollLocationHeader is None # Test polling from operation-location header response = TestBasePolling.mock_send( http_request, http_response, 'PATCH', 200, {'operation-location': ASYNC_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert not hasattr(poll._polling_method._pipeline_response, 'randomFieldFromPollAsyncOpHeader') # Test fail to poll from operation-location header response = TestBasePolling.mock_send(http_request, http_response, 'PATCH', 202, {'operation-location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() # Test fail to poll from location header response = TestBasePolling.mock_send(http_request, http_response, 'PATCH', 202, {'location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_long_running_delete(self, http_request, http_response): # Test polling from operation-location header response = TestBasePolling.mock_send(http_request, http_response, 'DELETE', 202, {'operation-location': ASYNC_URL}, body="") CLIENT.http_request_type = http_request CLIENT.http_response_type = http_response poll = LROPoller(CLIENT, response, TestBasePolling.mock_deserialization_no_body, LROBasePolling(0)) poll.wait() assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollAsyncOpHeader is None @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_long_running_post_legacy(self, http_request, http_response): # Former oooooold tests to refactor one day to something more readble # Test polling from operation-location header response = TestBasePolling.mock_send( http_request, http_response, 'POST', 201, {'operation-location': ASYNC_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) CLIENT.http_request_type = http_request CLIENT.http_response_type = http_response poll = LROPoller(CLIENT, response, TestBasePolling.mock_deserialization_no_body, LROBasePolling(0)) poll.wait() assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollAsyncOpHeader is None # Test polling from operation-location header response = TestBasePolling.mock_send( http_request, http_response, 'POST', 202, {'operation-location': ASYNC_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_deserialization_no_body, LROBasePolling(0)) poll.wait() assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollAsyncOpHeader is None # Test polling from location header response = TestBasePolling.mock_send( http_request, http_response, 'POST', 202, {'location': LOCATION_URL}, body={'properties': { 'provisioningState': 'Succeeded' }}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) assert poll.result().name == TEST_NAME assert poll._polling_method._pipeline_response.http_response.internal_response.randomFieldFromPollLocationHeader is None # Test fail to poll from operation-location header response = TestBasePolling.mock_send(http_request, http_response, 'POST', 202, {'operation-location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() # Test fail to poll from location header response = TestBasePolling.mock_send(http_request, http_response, 'POST', 202, {'location': ERROR}) with pytest.raises(BadEndpointError): poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)).result() @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_long_running_negative(self, http_request, http_response): global LOCATION_BODY global POLLING_STATUS CLIENT.http_request_type = http_request CLIENT.http_response_type = http_response # Test LRO PUT throws for invalid json LOCATION_BODY = '{' response = TestBasePolling.mock_send(http_request, http_response, 'POST', 202, {'location': LOCATION_URL}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) with pytest.raises(DecodeError): poll.result() LOCATION_BODY = '{\'"}' response = TestBasePolling.mock_send(http_request, http_response, 'POST', 202, {'location': LOCATION_URL}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) with pytest.raises(DecodeError): poll.result() LOCATION_BODY = '{' POLLING_STATUS = 203 response = TestBasePolling.mock_send(http_request, http_response, 'POST', 202, {'location': LOCATION_URL}) poll = LROPoller(CLIENT, response, TestBasePolling.mock_outputs, LROBasePolling(0)) with pytest.raises( HttpResponseError ) as error: # TODO: Node.js raises on deserialization poll.result() assert error.value.continuation_token == base64.b64encode( pickle.dumps(response)).decode('ascii') LOCATION_BODY = json.dumps({'name': TEST_NAME}) POLLING_STATUS = 200
18, 12, 8, tzinfo=_FixedOffset(-5 * 60)) with mock.patch('datetime.datetime') as mock_datetime: mock_datetime.now.return_value = now_mock_datetime mock_datetime.side_effect = lambda *args, **kw: basedatetime( *args, **kw) assert polling._extract_delay() == 60 * 60 # one hour in seconds assert str(mock_datetime.now.call_args[0][0]) == "<FixedOffset -5.0>" @pytest.mark.parametrize( "http_request,http_response", request_and_responses_product(REQUESTS_TRANSPORT_RESPONSES)) def test_post(pipeline_client_builder, deserialization_cb, http_request, http_response): # Test POST LRO with both Location and Operation-Location # The initial response contains both Location and Operation-Location, a 202 and no Body initial_response = TestBasePolling.mock_send( http_request, http_response, 'POST', 202, { 'location': 'http://example.org/location', 'operation-location': 'http://example.org/async_monitor', }, '') def send(request, **kwargs): assert request.method == 'GET'
polling, _ = polling_response continuation_token = polling.get_continuation_token() assert isinstance(continuation_token, str) polling_args = AsyncLROBasePolling.from_continuation_token( continuation_token, deserialization_callback="deserialization_callback", client=client, ) new_polling = AsyncLROBasePolling() new_polling.initialize(*polling_args) @pytest.mark.asyncio @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(ASYNCIO_REQUESTS_TRANSPORT_RESPONSES)) async def test_post(async_pipeline_client_builder, deserialization_cb, http_request, http_response): # Test POST LRO with both Location and Operation-Location # The initial response contains both Location and Operation-Location, a 202 and no Body initial_response = TestBasePolling.mock_send( http_request, http_response, 'POST', 202, { 'location': 'http://example.org/location', 'operation-location': 'http://example.org/async_monitor', }, ''
b'--changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'Content-Type: application/http\r\n' b'Content-Transfer-Encoding: binary\r\n' b'Content-ID: 2\r\n' b'\r\n' b'DELETE /container2/blob2 HTTP/1.1\r\n' b'\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n') @pytest.mark.asyncio @pytest.mark.parametrize("http_request,mock_response", request_and_responses_product(MOCK_RESPONSES)) async def test_multipart_receive(http_request, mock_response): class ResponsePolicy(object): def on_response(self, request, response): # type: (PipelineRequest, PipelineResponse) -> None response.http_response.headers['x-ms-fun'] = 'true' class AsyncResponsePolicy(object): async def on_response(self, request, response): # type: (PipelineRequest, PipelineResponse) -> None response.http_response.headers['x-ms-async-fun'] = 'true' req0 = http_request("DELETE", "/container0/blob0") req1 = http_request("DELETE", "/container1/blob1") request = http_request("POST",