def test_update_cached_sync_token(): test_sync_token = "syncToken1=val1;sn=6" header = {"Sync-Token": test_sync_token} request = HttpRequest("GET", "https://bing.com/") response = HttpResponse(request, None) response.headers = header pipeline_response = PipelineResponse(request, response, None) sync_token_policy = SyncTokenPolicy() sync_token_policy.on_response(None, pipeline_response) sync_token = sync_token_policy._sync_tokens['syncToken1'] assert sync_token.token_id == 'syncToken1' assert sync_token.value == 'val1' assert sync_token.sequence_number == 6 test_new_sync_token = "syncToken1=val2;sn=10" header["Sync-Token"] = test_new_sync_token response.headers = header pipeline_response = PipelineResponse(request, response, None) sync_token_policy.on_response(None, pipeline_response) sync_token = sync_token_policy._sync_tokens['syncToken1'] assert sync_token.token_id == 'syncToken1' assert sync_token.value == 'val2' assert sync_token.sequence_number == 10
async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: """Runs the network request through the client's chained policies. :param http_request: The network request you want to make. Required. :type http_request: ~azure.core.pipeline.transport.HttpRequest :keyword bool stream: Whether the response payload will be streamed. Defaults to True. :return: The response of your network call. Does not do error handling on your response. :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse """ path_format_arguments = { 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), } http_request.url = self._client.format_url(http_request.url, **path_format_arguments) stream = kwargs.pop("stream", True) pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) return pipeline_response.http_response
async def test_example_async_pipeline_client(): url = "https://bing.com" # [START build_async_pipeline_client] from azure.core import AsyncPipelineClient from azure.core.configuration import Configuration from azure.core.pipeline.policies import AsyncRedirectPolicy, UserAgentPolicy from azure.core.pipeline.transport import HttpRequest # example configuration with some policies request = HttpRequest("GET", url) config = Configuration() config.user_agent_policy = UserAgentPolicy("myuseragent") config.redirect_policy = AsyncRedirectPolicy() async with AsyncPipelineClient(base_url=url, config=config) as client: response = await client._pipeline.run(request) # [END build_async_pipeline_client] assert client._pipeline._transport.session is None assert response.http_response.status_code == 200
def _get_auth_code_request(self, scopes, code, redirect_uri, client_secret=None): # type: (Iterable[str], str, str, Optional[str]) -> HttpRequest data = { "client_id": self._client_id, "code": code, "grant_type": "authorization_code", "redirect_uri": redirect_uri, "scope": " ".join(scopes), } if client_secret: data["client_secret"] = client_secret request = HttpRequest( "POST", self._token_endpoint, headers={"Content-Type": "application/x-www-form-urlencoded"}, data=data) return request
async def test_example_async_pipeline_client(): url = "https://bing.com" # [START build_async_pipeline_client] from azure.core import AsyncPipelineClient from azure.core.pipeline.policies import AsyncRedirectPolicy, UserAgentPolicy from azure.core.pipeline.transport import HttpRequest # example policies request = HttpRequest("GET", url) policies = [ UserAgentPolicy("myuseragent"), AsyncRedirectPolicy(), ] async with AsyncPipelineClient(base_url=url, policies=policies) as client: response = await client._pipeline.run(request) # [END build_async_pipeline_client] assert client._pipeline._transport.session is None assert isinstance(response.http_response.status_code, int)
def test_multipart_send_with_context(): transport = mock.MagicMock(spec=HttpTransport) header_policy = HeadersPolicy({ 'x-ms-date': 'Thu, 14 Jun 2018 16:46:54 GMT' }) req0 = HttpRequest("DELETE", "/container0/blob0") req1 = HttpRequest("DELETE", "/container1/blob1") request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed( req0, req1, policies=[header_policy], boundary="batch_357de4f7-6d0b-4e02-8cd2-6361411a9525", # Fix it so test are deterministic headers={'Accept': 'application/json'} ) with Pipeline(transport) as pipeline: pipeline.run(request) assert request.body == ( 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: 0\r\n' b'\r\n' b'DELETE /container0/blob0 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'Accept: application/json\r\n' b'\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: 1\r\n' b'\r\n' b'DELETE /container1/blob1 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'Accept: application/json\r\n' b'\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n' )
def update_key(self, name, version, key_ops=None, attributes=None, tags=None, **kwargs): # type: (str, str, Optional[List[str]], Mapping[str, str], Mapping[str, str], Any) -> Key url = "/".join([self.vault_url, "keys", name, version]) headers = {"Content-Type": "application/json; charset=utf-8", "x-ms-client-request-id": str(uuid.uuid1())} update_params = KeyUpdateParameters(key_ops=key_ops, key_attributes=attributes, tags=tags) body = self._serialize.body(update_params, "KeyUpdateParameters") request = HttpRequest("PATCH", url, headers=headers) request.set_json_body(body) request.format_parameters({"api-version": self.API_VERSION}) response = self._pipeline.run(request, **kwargs).http_response if response.status_code != 200: raise HttpResponseError("Request failed with code {}: '{}'".format(response.status_code, response.text())) key = self._deserialize("Key", response) return key
def post( self, url, # type: str data=None, # type: Optional[Mapping[str, str]] headers=None, # type: Optional[Mapping[str, str]] params=None, # type: Optional[Dict[str, str]] timeout=None, # type: float verify=None, # type: bool **kwargs # type: Any ): # type: (...) -> MsalTransportResponse request = HttpRequest("POST", url, headers=headers) if params: request.format_parameters(params) if data: request.headers["Content-Type"] = "application/x-www-form-urlencoded" request.set_formdata_body(data) response = self._pipeline.run( request, stream=False, connection_timeout=timeout, connection_verify=verify, **kwargs ) return MsalTransportResponse(response)
async def test_preserves_options_and_headers(): """After a challenge, the original request should be sent with its options and headers preserved. If a policy mutates the options or headers of the challenge (unauthorized) request, the options of the service request should be present when it is sent with authorization. """ url = get_random_url() token = "**" async def get_token(*_, **__): return AccessToken(token, 0) credential = Mock(get_token=Mock(wraps=get_token)) transport = async_validating_transport( requests=[Request()] * 2 + [Request(required_headers={"Authorization": "Bearer " + token})], responses=[ mock_response( status_code=401, headers={ "WWW-Authenticate": 'Bearer authorization="{}", resource=foo'.format(url) }) ] + [mock_response()] * 2, ) challenge_policy = AsyncChallengeAuthPolicy(credential=credential) policies = get_policies_for_request_mutation_test(challenge_policy) pipeline = AsyncPipeline(policies=policies, transport=transport) response = await pipeline.run(HttpRequest("GET", url)) # ensure the mock sans I/O policies were used for policy in policies: if hasattr(policy, "on_request"): assert policy.on_request.called, "mock policy wasn't invoked"
def test_retry_on_429(): 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): # type: (PipelineRequest, Any) -> PipelineResponse self._count += 1 response = HttpResponse(request, None) response.status_code = 429 return response http_request = HttpRequest('GET', 'http://127.0.0.1/') http_retry = RetryPolicy(retry_total = 1) transport = MockTransport() pipeline = Pipeline(transport, [http_retry]) pipeline.run(http_request) assert transport._count == 2
async def test_bearer_policy_send(): """The bearer token policy should invoke the next policy's send method and return the result""" expected_request = HttpRequest("GET", "https://spam.eggs") expected_response = Mock(spec=PipelineResponse) async def verify_request(request): assert request.http_request is expected_request return expected_response async def get_token(_): return "" fake_credential = Mock(get_token=get_token) policies = [ AsyncBearerTokenCredentialPolicy(fake_credential, "scope"), Mock(spec=HTTPPolicy, send=verify_request), ] pipeline = AsyncPipeline(transport=Mock(spec=AsyncHttpTransport), policies=policies) response = await pipeline.run(expected_request) assert response is expected_response
def test_response_deserialization(): # Method + Url request = HttpRequest("DELETE", "/container0/blob0") body = ( b'HTTP/1.1 202 Accepted\r\n' b'x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n' b'x-ms-version: 2018-11-09\r\n' ) response = _deserialize_response(body, request) assert response.status_code == 202 assert response.reason == "Accepted" assert response.headers == { 'x-ms-request-id': '778fdc83-801e-0000-62ff-0334671e284f', 'x-ms-version': '2018-11-09' } # Method + Url + Headers + Body request = HttpRequest( "DELETE", "/container0/blob0", headers={ "x-ms-date": "Thu, 14 Jun 2018 16:46:54 GMT", }, ) request.set_bytes_body(b"I am groot") body = ( b'HTTP/1.1 200 OK\r\n' b'x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n' b'x-ms-version: 2018-11-09\r\n' b'\r\n' b'I am groot' ) response = _deserialize_response(body, request) assert isinstance(response.status_code, int) assert response.reason == "OK" assert response.headers == { 'x-ms-request-id': '778fdc83-801e-0000-62ff-0334671e284f', 'x-ms-version': '2018-11-09' } assert response.text() == "I am groot"
async def test_multipart_send(): transport = MockAsyncHttpTransport() class RequestPolicy(object): async def on_request(self, request): # type: (PipelineRequest) -> None request.http_request.headers[ 'x-ms-date'] = 'Thu, 14 Jun 2018 16:46:54 GMT' req0 = HttpRequest("DELETE", "/container0/blob0") req1 = HttpRequest("DELETE", "/container1/blob1") request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed( req0, req1, policies=[RequestPolicy()], boundary= "batch_357de4f7-6d0b-4e02-8cd2-6361411a9525" # Fix it so test are deterministic ) async with AsyncPipeline(transport) as pipeline: await pipeline.run(request) assert request.body == ( 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: 0\r\n' b'\r\n' b'DELETE /container0/blob0 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'\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: 1\r\n' b'\r\n' b'DELETE /container1/blob1 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n')
def test_distributed_tracing_policy_attributes(): """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 = HttpRequest("GET", "http://127.0.0.1/temp?query=query") pipeline_request = PipelineRequest(request, PipelineContext(None)) policy.on_request(pipeline_request) response = HttpResponse(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 __init__(self, arguments): super().__init__(arguments) token = AccessToken("**", int(time.time() + 3600)) self.request = HttpRequest("GET", "https://localhost") credential = Mock(get_token=Mock(return_value=token)) self.pipeline = Pipeline( transport=Mock(), policies=[BearerTokenCredentialPolicy(credential=credential)]) completed_future = asyncio.Future() completed_future.set_result(token) async_credential = Mock(get_token=Mock(return_value=completed_future)) # returning a token is okay because the policy does nothing with the transport's response async_transport = Mock(send=Mock(return_value=completed_future)) self.async_pipeline = AsyncPipeline( async_transport, policies=[ AsyncBearerTokenCredentialPolicy(credential=async_credential) ])
async def test_bearer_policy_adds_header(): """The bearer token policy should add a header containing a token from its credential""" expected_token = AccessToken("expected_token", 0) async def verify_authorization_header(request): assert request.http_request.headers[ "Authorization"] == "Bearer {}".format(expected_token.token) get_token_calls = 0 async def get_token(_): nonlocal get_token_calls get_token_calls += 1 return expected_token fake_credential = Mock(get_token=get_token) policies = [ AsyncBearerTokenCredentialPolicy(fake_credential, "scope"), Mock(send=verify_authorization_header) ] pipeline = AsyncPipeline(transport=Mock(), policies=policies) await pipeline.run(HttpRequest("GET", "https://spam.eggs"), context=None) assert get_token_calls == 1
def __init__(self, arguments): super().__init__(arguments) token = AccessToken("**", int(time.time() + 3600)) self.request = HttpRequest("GET", "https://localhost") credential = Mock(get_token=Mock(return_value=token)) self.pipeline = Pipeline( transport=Mock(), policies=[BearerTokenCredentialPolicy(credential=credential)]) get_token_future = asyncio.Future() get_token_future.set_result(token) async_credential = Mock(get_token=Mock(return_value=get_token_future)) send_future = asyncio.Future() send_future.set_result(Mock()) async_transport = Mock(send=Mock(return_value=send_future)) self.async_pipeline = AsyncPipeline( async_transport, policies=[ AsyncBearerTokenCredentialPolicy(credential=async_credential) ])
def _set_body(content: ContentType, data: dict, files: Any, json_body: Any, internal_request: _PipelineTransportHttpRequest) -> None: if data is not None and not isinstance(data, dict): content = data data = None if content is not None: _set_content_body(content, internal_request) elif json_body is not None: internal_request.set_json_body(json_body) _set_content_type_header("application/json", internal_request) elif files is not None: internal_request.set_formdata_body(files) # if you don't supply your content type, we'll create a boundary for you with multipart/form-data boundary = binascii.hexlify(os.urandom(16)).decode( "ascii") # got logic from httpx, thanks httpx! # _set_content_type_header("multipart/form-data; boundary={}".format(boundary), internal_request) elif data: _set_content_type_header("application/x-www-form-urlencoded", internal_request) internal_request.set_formdata_body(data) # need to set twice because Content-Type is being popped in set_formdata_body # don't want to risk changing pipeline.transport, so doing twice here _set_content_type_header("application/x-www-form-urlencoded", internal_request)
def test_bearer_policy_optionally_enforces_https(): """HTTPS enforcement should be controlled by a keyword argument, and enabled by default""" def assert_option_popped(request, **kwargs): assert "enforce_https" not in kwargs, "BearerTokenCredentialPolicy didn't pop the 'enforce_https' option" credential = Mock(get_token=lambda *_, **__: AccessToken("***", 42)) pipeline = Pipeline( transport=Mock(send=assert_option_popped), policies=[BearerTokenCredentialPolicy(credential, "scope")] ) # by default and when enforce_https=True, the policy should raise when given an insecure request with pytest.raises(ServiceRequestError): pipeline.run(HttpRequest("GET", "http://not.secure")) with pytest.raises(ServiceRequestError): pipeline.run(HttpRequest("GET", "http://not.secure"), enforce_https=True) # when enforce_https=False, an insecure request should pass pipeline.run(HttpRequest("GET", "http://not.secure"), enforce_https=False) # https requests should always pass pipeline.run(HttpRequest("GET", "https://secure"), enforce_https=False) pipeline.run(HttpRequest("GET", "https://secure"), enforce_https=True) pipeline.run(HttpRequest("GET", "https://secure"))
async def test_recursive_multipart_receive(): req0 = HttpRequest("DELETE", "/container0/blob0") internal_req0 = HttpRequest("DELETE", "/container0/blob0") req0.set_multipart_mixed(internal_req0) request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed(req0) class MockResponse(AsyncHttpResponse): def __init__(self, request, body, content_type): super(MockResponse, self).__init__(request, None) self._body = body self.content_type = content_type def body(self): return self._body internal_body_as_str = ( "--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\r\n" "Content-Type: application/http\r\n" "Content-ID: 0\r\n" "\r\n" "HTTP/1.1 400 Accepted\r\n" "x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n" "x-ms-version: 2018-11-09\r\n" "\r\n" "--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed--") body_as_str = ( "--batchresponse_8d5f5bcd-2cb5-44bb-91b5-e9a722e68cb6\r\n" "Content-Type: application/http\r\n" "Content-ID: 0\r\n" "\r\n" "HTTP/1.1 202 Accepted\r\n" "Content-Type: multipart/mixed; boundary=batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\r\n" "\r\n" "{}" "--batchresponse_8d5f5bcd-2cb5-44bb-91b5-e9a722e68cb6--" ).format(internal_body_as_str) response = MockResponse( request, body_as_str.encode('ascii'), "multipart/mixed; boundary=batchresponse_8d5f5bcd-2cb5-44bb-91b5-e9a722e68cb6" ) parts = [] async for part in response.parts(): parts.append(part) assert len(parts) == 1 res0 = parts[0] assert res0.status_code == 202 internal_parts = [] async for part in res0.parts(): internal_parts.append(part) assert len(internal_parts) == 1 internal_response0 = internal_parts[0] assert internal_response0.status_code == 400
async def test_multipart_receive(): class MockResponse(AsyncHttpResponse): def __init__(self, request, body, content_type): super(MockResponse, self).__init__(request, None) self._body = body self.content_type = content_type def body(self): return self._body 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 = HttpRequest("DELETE", "/container0/blob0") req1 = HttpRequest("DELETE", "/container1/blob1") request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed( req0, req1, policies=[ResponsePolicy(), AsyncResponsePolicy()]) body_as_str = ( "--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\r\n" "Content-Type: application/http\r\n" "Content-ID: 0\r\n" "\r\n" "HTTP/1.1 202 Accepted\r\n" "x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n" "x-ms-version: 2018-11-09\r\n" "\r\n" "--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\r\n" "Content-Type: application/http\r\n" "Content-ID: 2\r\n" "\r\n" "HTTP/1.1 404 The specified blob does not exist.\r\n" "x-ms-error-code: BlobNotFound\r\n" "x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e2852\r\n" "x-ms-version: 2018-11-09\r\n" "Content-Length: 216\r\n" "Content-Type: application/xml\r\n" "\r\n" '<?xml version="1.0" encoding="utf-8"?>\r\n' "<Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.\r\n" "RequestId:778fdc83-801e-0000-62ff-0334671e2852\r\n" "Time:2018-06-14T16:46:54.6040685Z</Message></Error>\r\n" "--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed--") response = MockResponse( request, body_as_str.encode('ascii'), "multipart/mixed; boundary=batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed" ) parts = [] async for part in response.parts(): parts.append(part) assert len(parts) == 2 res0 = parts[0] assert res0.status_code == 202 assert res0.headers['x-ms-fun'] == 'true' assert res0.headers['x-ms-async-fun'] == 'true' res1 = parts[1] assert res1.status_code == 404 assert res1.headers['x-ms-fun'] == 'true' assert res1.headers['x-ms-async-fun'] == 'true'
async def do(): request = HttpRequest("GET", "https://bing.com/") policies = [UserAgentPolicy("myusergant"), AsyncRedirectPolicy()] async with AsyncPipeline(TrioRequestsTransport(), policies=policies) as pipeline: return await pipeline.run(request)
async def test_multipart_send(): # transport = mock.MagicMock(spec=AsyncHttpTransport) # MagicMock support async cxt manager only after 3.8 # https://github.com/python/cpython/pull/9296 class MockAsyncHttpTransport(AsyncHttpTransport): async def __aenter__(self): return self async def __aexit__(self, *args): pass async def open(self): pass async def close(self): pass async def send(self, request, **kwargs): pass transport = MockAsyncHttpTransport() class RequestPolicy(object): async def on_request(self, request): # type: (PipelineRequest) -> None request.http_request.headers[ 'x-ms-date'] = 'Thu, 14 Jun 2018 16:46:54 GMT' req0 = HttpRequest("DELETE", "/container0/blob0") req1 = HttpRequest("DELETE", "/container1/blob1") request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed( req0, req1, policies=[RequestPolicy()], boundary= "batch_357de4f7-6d0b-4e02-8cd2-6361411a9525" # Fix it so test are deterministic ) async with AsyncPipeline(transport) as pipeline: await pipeline.run(request) assert request.body == ( 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: 0\r\n' b'\r\n' b'DELETE /container0/blob0 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'\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: 1\r\n' b'\r\n' b'DELETE /container1/blob1 HTTP/1.1\r\n' b'x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT\r\n' b'\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n')
def test_request_url_with_params_with_none(self): request = HttpRequest("GET", "/") request.url = "a/b/c?t=y" with pytest.raises(ValueError): request.format_parameters({"g": None})
async def test_multipart_receive_with_combination_changeset_last(): changeset = HttpRequest(None, None) changeset.set_multipart_mixed(HttpRequest("DELETE", "/container1/blob1"), HttpRequest("DELETE", "/container2/blob2")) request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed(HttpRequest("DELETE", "/container0/blob0"), changeset) body_as_bytes = ( b'--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\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'HTTP/1.1 200\r\n' b'x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n' b'x-ms-version: 2018-11-09\r\n' b'\r\n' b'\r\n' b'--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed\r\n' b'Content-Type: multipart/mixed; boundary="changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525"\r\n' b'\r\n' b'--changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'Content-Type: application/http\r\n' b'Content-Transfer-Encoding: binary\r\n' b'Content-ID: 0\r\n' b'\r\n' b'HTTP/1.1 202\r\n' b'x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n' b'x-ms-version: 2018-11-09\r\n' b'\r\n' b'\r\n' b'--changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'Content-Type: application/http\r\n' b'Content-Transfer-Encoding: binary\r\n' b'Content-ID: 1\r\n' b'\r\n' b'HTTP/1.1 404\r\n' b'x-ms-request-id: 778fdc83-801e-0000-62ff-0334671e284f\r\n' b'x-ms-version: 2018-11-09\r\n' b'\r\n' b'\r\n' b'--changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525--\r\n' b'\r\n' b'--batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed--\r\n') response = MockResponse( request, body_as_bytes, "multipart/mixed; boundary=batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed" ) parts = [] async for part in response.parts(): parts.append(part) assert len(parts) == 3 assert parts[0].status_code == 200 assert parts[1].status_code == 202 assert parts[2].status_code == 404
async def test_multipart_send_with_combination_changeset_middle(): transport = MockAsyncHttpTransport() changeset = HttpRequest(None, None) changeset.set_multipart_mixed( HttpRequest("DELETE", "/container1/blob1"), boundary="changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525") request = HttpRequest("POST", "http://account.blob.core.windows.net/?comp=batch") request.set_multipart_mixed( HttpRequest("DELETE", "/container0/blob0"), changeset, HttpRequest("DELETE", "/container2/blob2"), boundary="batch_357de4f7-6d0b-4e02-8cd2-6361411a9525") async with AsyncPipeline(transport) as pipeline: await pipeline.run(request) assert request.body == ( 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: 0\r\n' b'\r\n' b'DELETE /container0/blob0 HTTP/1.1\r\n' b'\r\n' b'\r\n' b'--batch_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'Content-Type: multipart/mixed; boundary=changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'\r\n' b'--changeset_357de4f7-6d0b-4e02-8cd2-6361411a9525\r\n' b'Content-Type: application/http\r\n' b'Content-Transfer-Encoding: binary\r\n' b'Content-ID: 1\r\n' b'\r\n' b'DELETE /container1/blob1 HTTP/1.1\r\n' b'\r\n' b'\r\n' 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')
def test_repr(self): request = HttpRequest("GET", "hello.com") assert repr(request) == "<HttpRequest [GET], url: 'hello.com'>"
async def _batch_send( self, entities, # type: List[TableEntity] *reqs: "HttpRequest", **kwargs ): """Given a series of request, do a Storage batch call.""" # Pop it here, so requests doesn't feel bad about additional kwarg raise_on_any_failure = kwargs.pop("raise_on_any_failure", True) policies = [StorageHeadersPolicy()] changeset = HttpRequest("POST", None) changeset.set_multipart_mixed( *reqs, policies=policies, boundary="changeset_{}".format(uuid4()) ) request = self._client._client.post( # pylint: disable=protected-access url="https://{}/$batch".format(self._primary_hostname), headers={ "x-ms-version": self.api_version, "DataServiceVersion": "3.0", "MaxDataServiceVersion": "3.0;NetFx", }, ) request.set_multipart_mixed( changeset, policies=policies, enforce_https=False, boundary="batch_{}".format(uuid4()), ) pipeline_response = await self._pipeline.run(request, **kwargs) response = pipeline_response.http_response if response.status_code == 403: raise ClientAuthenticationError( message="There was an error authenticating with the service", response=response, ) if response.status_code == 404: raise ResourceNotFoundError( message="The resource could not be found", response=response ) if response.status_code != 202: raise BatchErrorException( message="There is a failure in the batch operation.", response=response, parts=None, ) parts_iter = response.parts() parts = [] async for p in parts_iter: parts.append(p) transaction_result = BatchTransactionResult(reqs, parts, entities) if raise_on_any_failure: if any(p for p in parts if not 200 <= p.status_code < 300): if any(p for p in parts if p.status_code == 404): raise ResourceNotFoundError( message="The resource could not be found", response=response ) raise BatchErrorException( message="There is a failure in the batch operation.", response=response, parts=parts, ) return transaction_result
def test_request_xml(self): request = HttpRequest("GET", "/") data = ET.Element("root") request.set_xml_body(data) assert request.data == b"<?xml version='1.0' encoding='utf8'?>\n<root />"
# HttpXTransport does not support stream data: # File "lib\site-packages\httpx\_content_streams.py", line 404, in encode # raise TypeError(f"Unexpected type for 'data', {type(data)!r}") # TypeError: Unexpected type for 'data', <class '__main__.LargeStream'> # # start = time.perf_counter() # req = HttpRequest("PUT", url, data=LargeStream(size), headers=headers) # resp = pipelinex.run(req) # stop = time.perf_counter() # duration = stop - start # mbps = ((size / duration) * 8) / (1024 * 1024) # print(f'[PipelineX, stream] Put {size:,} bytes in {duration:.2f} seconds ({mbps:.2f} Mbps), Response={resp.http_response.status_code}') start = time.perf_counter() req = HttpRequest("PUT", url, data=array, headers=headers) resp = pipelinex.run(req) stop = time.perf_counter() duration = stop - start mbps = ((size / duration) * 8) / (1024 * 1024) print( f'[PipelineX, array] Put {size:,} bytes in {duration:.2f} seconds ({mbps:.2f} Mbps), Response={resp.http_response.status_code}' ) start = time.perf_counter() req = HttpRequest("PUT", url, data=LargeStream(size), headers=headers) resp = pipeline.run(req) stop = time.perf_counter() duration = stop - start mbps = ((size / duration) * 8) / (1024 * 1024) print(