maka transport adapter base class for any transport to add its own implementation (#928)
This commit is contained in:
parent
71457f89d8
commit
eb509cebb8
@ -21,6 +21,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if(BUILD_TRANSPORT_CURL)
|
||||
SET(CURL_OPTIONS_TESTS curl_options.cpp)
|
||||
SET(CURL_TRANSPORT_TESTS transport_adapter_curl.cpp)
|
||||
endif()
|
||||
|
||||
include(GoogleTest)
|
||||
@ -39,8 +40,8 @@ add_executable (
|
||||
simplified_header.cpp
|
||||
string.cpp
|
||||
telemetry_policy.cpp
|
||||
transport_adapter.cpp
|
||||
transport_adapter_file_upload.cpp
|
||||
transport_adapter_base.cpp
|
||||
${CURL_TRANSPORT_TESTS}
|
||||
url.cpp
|
||||
uuid.cpp
|
||||
)
|
||||
|
||||
@ -1,508 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "transport_adapter.hpp"
|
||||
#include <azure/core/context.hpp>
|
||||
#include <azure/core/response.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace Azure { namespace Core { namespace Test {
|
||||
|
||||
static std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> CreatePolicies()
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> p;
|
||||
Azure::Core::Http::RetryOptions opt;
|
||||
opt.RetryDelay = std::chrono::milliseconds(10);
|
||||
|
||||
// Retry policy will help to prevent server-occasionally-errors
|
||||
p.push_back(std::make_unique<Azure::Core::Http::RetryPolicy>(opt));
|
||||
p.push_back(std::make_unique<Azure::Core::Http::TransportPolicy>());
|
||||
return p;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> TransportAdapter::policies
|
||||
= CreatePolicies();
|
||||
|
||||
Azure::Core::Http::HttpPipeline TransportAdapter::pipeline(policies);
|
||||
Azure::Core::Context TransportAdapter::context = Azure::Core::GetApplicationContext();
|
||||
|
||||
// Connection pool feature is curl-implementation only. No other transport adapter would have the
|
||||
// connection pool
|
||||
#ifdef BUILD_CURL_HTTP_TRANSPORT_ADAPTER
|
||||
// connectionPoolTest requires `ConnectionsOnPool` hook which is only available when building
|
||||
// BUILD_TESTING. This test is only built when that case is true.
|
||||
TEST_F(TransportAdapter, connectionPoolTest)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
Azure::Core::Http::CurlConnectionPool::ClearIndex();
|
||||
|
||||
auto threadRoutine = [host]() {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
};
|
||||
|
||||
std::thread t1(threadRoutine);
|
||||
std::thread t2(threadRoutine);
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
// 2 connections must be available at this point
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 2);
|
||||
|
||||
std::thread t3(threadRoutine);
|
||||
std::thread t4(threadRoutine);
|
||||
std::thread t5(threadRoutine);
|
||||
t3.join();
|
||||
t4.join();
|
||||
t5.join();
|
||||
|
||||
// Two connections re-used plus one connection created
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 3);
|
||||
|
||||
#ifdef RUN_LONG_UNIT_TESTS
|
||||
{
|
||||
// Test pool clean routine
|
||||
std::cout << "Running Connection Pool Cleaner Test. This test takes more than 3 minutes to "
|
||||
"complete."
|
||||
<< std::endl
|
||||
<< "Add compiler option -DRUN_LONG_UNIT_TESTS=OFF when building if you want to "
|
||||
"skip this "
|
||||
"test."
|
||||
<< std::endl;
|
||||
|
||||
// Wait for 180 secs to make sure any previous connection is removed by the cleaner
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 180));
|
||||
|
||||
std::cout << "First wait time done. Validating state." << std::endl;
|
||||
|
||||
// index is not affected by cleaner. It does not remove index
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsIndexOnPool(), 1);
|
||||
// cleaner should have removed connections
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 0);
|
||||
|
||||
std::thread t1(threadRoutine);
|
||||
std::thread t2(threadRoutine);
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
// wait for connection to be moved back to pool
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
||||
// 2 connections must be available at this point and one index
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsIndexOnPool(), 1);
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(TransportAdapter, get)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
|
||||
// Need to init request again, since retry would be on after it is sent
|
||||
request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
// Add a header and send again. RawResponse should return that header in the body
|
||||
request.AddHeader("123", "456");
|
||||
response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
// header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,`
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize + 6 + 13);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, get204)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://mt3.google.com/generate_204");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode(), Azure::Core::Http::HttpStatusCode::NoContent);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, getLoop)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// loop sending request
|
||||
for (auto i = 0; i < 50; i++)
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, head)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
auto expectedResponseBodySize = 0;
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
|
||||
// Check content-length header to be greater than 0
|
||||
int64_t contentLengthHeader = std::stoull(response->GetHeaders().at("content-length"));
|
||||
EXPECT_TRUE(contentLengthHeader > 0);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, put)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1K
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, deleteRequest)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/delete");
|
||||
|
||||
// Delete with 1k payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, patch)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/patch");
|
||||
|
||||
// Patch with 1kb payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, getChunk)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://anglesharp.azurewebsites.net/Chunked");
|
||||
auto expectedResponseBodySize = -1; // chunked will return unknown body length
|
||||
auto expectedChunkResponse = std::string(
|
||||
"<!DOCTYPE html>\r\n<html lang=en>\r\n<head>\r\n<meta charset='utf-8'>\r\n<title>Chunked "
|
||||
"transfer encoding test</title>\r\n</head>\r\n<body><h1>Chunked transfer encoding "
|
||||
"test</h1><h5>This is a chunked response after 100 ms.</h5><h5>This is a chunked "
|
||||
"response after 1 second. The server should not close the stream before all chunks are "
|
||||
"sent to a client.</h5></body></html>");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = pipeline.Send(context, request);
|
||||
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize, expectedChunkResponse);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, putErrorResponse)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
// Try to make a PUT to a GET url. This will return an error code from server.
|
||||
// This test makes sure that the connection is not re-used (because it gets closed by server)
|
||||
// and next request is not hang
|
||||
for (auto i = 0; i < 10; i++)
|
||||
{
|
||||
auto requestBodyVector = std::vector<uint8_t>(10, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
auto response = pipeline.Send(context, request);
|
||||
}
|
||||
}
|
||||
|
||||
// **********************
|
||||
// ***Same tests but getting stream to pull from socket, simulating the Download Op
|
||||
// **********************
|
||||
|
||||
TEST_F(TransportAdapter, getWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
|
||||
request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
// Add a header and send again. Response should return that header in the body
|
||||
request.AddHeader("123", "456");
|
||||
response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
// header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,`
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize + 6 + 13);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, getLoopWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
|
||||
// loop sending request
|
||||
for (auto i = 0; i < 50; i++)
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, headWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
auto expectedResponseBodySize = 0;
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
|
||||
// Check content-length header to be greater than 0
|
||||
int64_t contentLengthHeader = std::stoull(response->GetHeaders().at("content-length"));
|
||||
EXPECT_TRUE(contentLengthHeader > 0);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, putWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1k
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &bodyRequest, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, deleteRequestWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/delete");
|
||||
|
||||
// Delete with 1k payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, patchWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/patch");
|
||||
|
||||
// Patch with 1kb payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, getChunkWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://anglesharp.azurewebsites.net/Chunked");
|
||||
auto expectedResponseBodySize = -1; // chunked will return unknown body length
|
||||
auto expectedChunkResponse = std::string(
|
||||
"<!DOCTYPE html>\r\n<html lang=en>\r\n<head>\r\n<meta charset='utf-8'>\r\n<title>Chunked "
|
||||
"transfer encoding test</title>\r\n</head>\r\n<body><h1>Chunked transfer encoding "
|
||||
"test</h1><h5>This is a chunked response after 100 ms.</h5><h5>This is a chunked "
|
||||
"response after 1 second. The server should not close the stream before all chunks are "
|
||||
"sent to a client.</h5></body></html>");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize, expectedChunkResponse);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, createResponseT)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
std::string expectedType("This is the Response Type");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, false);
|
||||
auto response = pipeline.Send(context, request);
|
||||
|
||||
Azure::Core::Response<std::string> responseT(expectedType, std::move(response));
|
||||
auto& r = responseT.GetRawResponse();
|
||||
|
||||
EXPECT_TRUE(r.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok);
|
||||
auto expectedResponseBodySize = std::stoull(r.GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(r, expectedResponseBodySize);
|
||||
|
||||
// Direct access
|
||||
EXPECT_STREQ((*responseT).data(), expectedType.data());
|
||||
EXPECT_STREQ(responseT->data(), expectedType.data());
|
||||
// extracting T out of response
|
||||
auto result = responseT.ExtractValue();
|
||||
EXPECT_STREQ(result.data(), expectedType.data());
|
||||
// Test that calling getValue again will return empty
|
||||
result = responseT.ExtractValue();
|
||||
EXPECT_STREQ(result.data(), std::string("").data());
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, customSizePut)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1MB
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024 * 1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
// Make transport adapter to read all stream content for uploading instead of chunks
|
||||
request.SetUploadChunkSize(1024 * 1024);
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, putWithStreamOnFail)
|
||||
{
|
||||
// point to bad address pah to generate server MethodNotAllowed error
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
// PUT 1k
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &bodyRequest, true);
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(
|
||||
response->GetStatusCode(), Azure::Core::Http::HttpStatusCode::MethodNotAllowed);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, cancelTransferUpload)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
Azure::Core::Context cancelThis;
|
||||
|
||||
auto threadRoutine = [host, cancelThis]() {
|
||||
// Start a big upload and expect it to throw cancelation
|
||||
std::vector<uint8_t> bigBuffer(1024 * 1024 * 200, 'x'); // upload 200 Mb
|
||||
auto stream = Azure::Core::Http::MemoryBodyStream(bigBuffer);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &stream);
|
||||
|
||||
// Request will be canceled from main thread throwing the exception
|
||||
EXPECT_THROW(pipeline.Send(cancelThis, request), Azure::Core::OperationCanceledException);
|
||||
};
|
||||
|
||||
// Start request
|
||||
std::thread t1(threadRoutine);
|
||||
|
||||
// Wait 100 ms so we know upload has started
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
cancelThis.Cancel();
|
||||
t1.join();
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, cancelTransferDownload)
|
||||
{
|
||||
// public big blob (321MB)
|
||||
Azure::Core::Http::Url host("https://bigtestfiles.blob.core.windows.net/cpptestfiles/321MB");
|
||||
Azure::Core::Context cancelThis;
|
||||
|
||||
auto threadRoutine = [host, cancelThis]() {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// Request will be canceled from main thread throwing the exception
|
||||
EXPECT_THROW(pipeline.Send(cancelThis, request), Azure::Core::OperationCanceledException);
|
||||
};
|
||||
|
||||
// Start request
|
||||
std::thread t1(threadRoutine);
|
||||
|
||||
// Wait 100 ms so we know download has started
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
cancelThis.Cancel();
|
||||
t1.join();
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, requestFailedException)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://unresolvedHost.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
EXPECT_THROW(pipeline.Send(context, request), Azure::Core::RequestFailedException);
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, dynamicCast)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://unresolvedHost.org/get");
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// test dynamic cast
|
||||
try
|
||||
{
|
||||
auto result = pipeline.Send(context, request);
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException& err)
|
||||
{
|
||||
// if ref can't be cast, it throws
|
||||
EXPECT_NO_THROW(dynamic_cast<Azure::Core::Http::TransportException&>(err));
|
||||
EXPECT_NO_THROW(dynamic_cast<std::runtime_error&>(err));
|
||||
EXPECT_THROW(dynamic_cast<std::range_error&>(err), std::bad_cast);
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Core::Test
|
||||
597
sdk/core/azure-core/test/ut/transport_adapter_base.cpp
Normal file
597
sdk/core/azure-core/test/ut/transport_adapter_base.cpp
Normal file
@ -0,0 +1,597 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifdef POSIX
|
||||
#include <fcntl.h>
|
||||
#endif // Posix
|
||||
|
||||
#ifdef WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#endif // Windows
|
||||
|
||||
#include "transport_adapter_base.hpp"
|
||||
#include <azure/core/context.hpp>
|
||||
#include <azure/core/response.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace Azure { namespace Core { namespace Test {
|
||||
|
||||
namespace Datails {
|
||||
constexpr int64_t c_fileSize = 1024 * 100;
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, get)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
|
||||
// Need to init request again, since retry would be on after it is sent
|
||||
request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
// Add a header and send again. RawResponse should return that header in the body
|
||||
request.AddHeader("123", "456");
|
||||
response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
// header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,`
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize + 6 + 13);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, get204)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://mt3.google.com/generate_204");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode(), Azure::Core::Http::HttpStatusCode::NoContent);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, getLoop)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// loop sending request
|
||||
for (auto i = 0; i < 50; i++)
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, head)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
auto expectedResponseBodySize = 0;
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
|
||||
// Check content-length header to be greater than 0
|
||||
int64_t contentLengthHeader = std::stoull(response->GetHeaders().at("content-length"));
|
||||
EXPECT_TRUE(contentLengthHeader > 0);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, put)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1K
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, deleteRequest)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/delete");
|
||||
|
||||
// Delete with 1k payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, patch)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/patch");
|
||||
|
||||
// Patch with 1kb payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, getChunk)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://anglesharp.azurewebsites.net/Chunked");
|
||||
auto expectedResponseBodySize = -1; // chunked will return unknown body length
|
||||
auto expectedChunkResponse = std::string(
|
||||
"<!DOCTYPE html>\r\n<html lang=en>\r\n<head>\r\n<meta charset='utf-8'>\r\n<title>Chunked "
|
||||
"transfer encoding test</title>\r\n</head>\r\n<body><h1>Chunked transfer encoding "
|
||||
"test</h1><h5>This is a chunked response after 100 ms.</h5><h5>This is a chunked "
|
||||
"response after 1 second. The server should not close the stream before all chunks are "
|
||||
"sent to a client.</h5></body></html>");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize, expectedChunkResponse);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, putErrorResponse)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
// Try to make a PUT to a GET url. This will return an error code from server.
|
||||
// This test makes sure that the connection is not re-used (because it gets closed by server)
|
||||
// and next request is not hang
|
||||
for (auto i = 0; i < 10; i++)
|
||||
{
|
||||
auto requestBodyVector = std::vector<uint8_t>(10, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
}
|
||||
}
|
||||
|
||||
// **********************
|
||||
// ***Same tests but getting stream to pull from socket, simulating the Download Op
|
||||
// **********************
|
||||
|
||||
TEST_P(TransportAdapter, getWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
|
||||
request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
// Add a header and send again. Response should return that header in the body
|
||||
request.AddHeader("123", "456");
|
||||
response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
// header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,`
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize + 6 + 13);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, getLoopWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
|
||||
// loop sending request
|
||||
for (auto i = 0; i < 50; i++)
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, headWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
auto expectedResponseBodySize = 0;
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
|
||||
// Check content-length header to be greater than 0
|
||||
int64_t contentLengthHeader = std::stoull(response->GetHeaders().at("content-length"));
|
||||
EXPECT_TRUE(contentLengthHeader > 0);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, putWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1k
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, deleteRequestWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/delete");
|
||||
|
||||
// Delete with 1k payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, patchWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/patch");
|
||||
|
||||
// Patch with 1kb payload
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, getChunkWithStream)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://anglesharp.azurewebsites.net/Chunked");
|
||||
auto expectedResponseBodySize = -1; // chunked will return unknown body length
|
||||
auto expectedChunkResponse = std::string(
|
||||
"<!DOCTYPE html>\r\n<html lang=en>\r\n<head>\r\n<meta charset='utf-8'>\r\n<title>Chunked "
|
||||
"transfer encoding test</title>\r\n</head>\r\n<body><h1>Chunked transfer encoding "
|
||||
"test</h1><h5>This is a chunked response after 100 ms.</h5><h5>This is a chunked "
|
||||
"response after 1 second. The server should not close the stream before all chunks are "
|
||||
"sent to a client.</h5></body></html>");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize, expectedChunkResponse);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, createResponseT)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
std::string expectedType("This is the Response Type");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, false);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
|
||||
Azure::Core::Response<std::string> responseT(expectedType, std::move(response));
|
||||
auto& r = responseT.GetRawResponse();
|
||||
|
||||
EXPECT_TRUE(r.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok);
|
||||
auto expectedResponseBodySize = std::stoull(r.GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(r, expectedResponseBodySize);
|
||||
|
||||
// Direct access
|
||||
EXPECT_STREQ((*responseT).data(), expectedType.data());
|
||||
EXPECT_STREQ(responseT->data(), expectedType.data());
|
||||
// extracting T out of response
|
||||
auto result = responseT.ExtractValue();
|
||||
EXPECT_STREQ(result.data(), expectedType.data());
|
||||
// Test that calling getValue again will return empty
|
||||
result = responseT.ExtractValue();
|
||||
EXPECT_STREQ(result.data(), std::string("").data());
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, customSizePut)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
|
||||
// PUT 1MB
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024 * 1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest);
|
||||
// Make transport adapter to read all stream content for uploading instead of chunks
|
||||
request.SetUploadChunkSize(1024 * 1024);
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, putWithStreamOnFail)
|
||||
{
|
||||
// point to bad address pah to generate server MethodNotAllowed error
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
|
||||
// PUT 1k
|
||||
auto requestBodyVector = std::vector<uint8_t>(1024, 'x');
|
||||
auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector);
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest, true);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(
|
||||
response->GetStatusCode(), Azure::Core::Http::HttpStatusCode::MethodNotAllowed);
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, cancelTransferUpload)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
Azure::Core::Context cancelThis;
|
||||
|
||||
auto threadRoutine = [&]() {
|
||||
// Start a big upload and expect it to throw cancelation
|
||||
std::vector<uint8_t> bigBuffer(1024 * 1024 * 200, 'x'); // upload 200 Mb
|
||||
auto stream = Azure::Core::Http::MemoryBodyStream(bigBuffer);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &stream);
|
||||
|
||||
// Request will be canceled from main thread throwing the exception
|
||||
EXPECT_THROW(m_pipeline->Send(cancelThis, request), Azure::Core::OperationCanceledException);
|
||||
};
|
||||
|
||||
// Start request
|
||||
std::thread t1(threadRoutine);
|
||||
|
||||
// Wait 100 ms so we know upload has started
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
cancelThis.Cancel();
|
||||
t1.join();
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, cancelTransferDownload)
|
||||
{
|
||||
// public big blob (321MB)
|
||||
Azure::Core::Http::Url host("https://bigtestfiles.blob.core.windows.net/cpptestfiles/321MB");
|
||||
Azure::Core::Context cancelThis;
|
||||
|
||||
auto threadRoutine = [&]() {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// Request will be canceled from main thread throwing the exception
|
||||
EXPECT_THROW(m_pipeline->Send(cancelThis, request), Azure::Core::OperationCanceledException);
|
||||
};
|
||||
|
||||
// Start request
|
||||
std::thread t1(threadRoutine);
|
||||
|
||||
// Wait 100 ms so we know download has started
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
cancelThis.Cancel();
|
||||
t1.join();
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, requestFailedException)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://unresolvedHost.org/get");
|
||||
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
EXPECT_THROW(
|
||||
m_pipeline->Send(Azure::Core::GetApplicationContext(), request),
|
||||
Azure::Core::RequestFailedException);
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, dynamicCast)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://unresolvedHost.org/get");
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
|
||||
// test dynamic cast
|
||||
try
|
||||
{
|
||||
auto result = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException& err)
|
||||
{
|
||||
// if ref can't be cast, it throws
|
||||
EXPECT_NO_THROW(dynamic_cast<Azure::Core::Http::TransportException&>(err));
|
||||
EXPECT_NO_THROW(dynamic_cast<std::runtime_error&>(err));
|
||||
EXPECT_THROW(dynamic_cast<std::range_error&>(err), std::bad_cast);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, SizePutFromFile)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read all stream content for uploading instead of chunks
|
||||
request.SetUploadChunkSize(Azure::Core::Test::Datails::c_fileSize);
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, SizePutFromFileDefault)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read default chunk size
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TransportAdapter, SizePutFromFileBiggerPage)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read more than file size (5Mb)
|
||||
request.SetUploadChunkSize(Azure::Core::Test::Datails::c_fileSize * 5);
|
||||
{
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
/***************** Test Utils *************************/
|
||||
void TransportAdapter::checkResponseCode(
|
||||
Azure::Core::Http::HttpStatusCode code,
|
||||
Azure::Core::Http::HttpStatusCode expectedCode)
|
||||
{
|
||||
EXPECT_PRED2(
|
||||
[](Azure::Core::Http::HttpStatusCode a, Azure::Core::Http::HttpStatusCode b) {
|
||||
return a == b;
|
||||
},
|
||||
code,
|
||||
expectedCode);
|
||||
}
|
||||
|
||||
void TransportAdapter::CheckBodyFromBuffer(
|
||||
Azure::Core::Http::RawResponse& response,
|
||||
int64_t size,
|
||||
std::string expectedBody)
|
||||
{
|
||||
auto body = response.GetBodyStream();
|
||||
EXPECT_EQ(body, nullptr);
|
||||
std::vector<uint8_t> bodyVector = response.GetBody();
|
||||
int64_t bodySize = bodyVector.size();
|
||||
|
||||
if (size > 0)
|
||||
{ // only for known body size
|
||||
EXPECT_EQ(bodySize, size);
|
||||
}
|
||||
|
||||
if (expectedBody.size() > 0)
|
||||
{
|
||||
auto bodyString = std::string(bodyVector.begin(), bodyVector.end());
|
||||
EXPECT_STREQ(expectedBody.data(), bodyString.data());
|
||||
}
|
||||
}
|
||||
|
||||
void TransportAdapter::CheckBodyFromStream(
|
||||
Azure::Core::Http::RawResponse& response,
|
||||
int64_t size,
|
||||
std::string expectedBody)
|
||||
{
|
||||
auto body = response.GetBodyStream();
|
||||
EXPECT_NE(body, nullptr);
|
||||
|
||||
std::vector<uint8_t> bodyVector
|
||||
= Azure::Core::Http::BodyStream::ReadToEnd(Azure::Core::GetApplicationContext(), *body);
|
||||
int64_t bodySize = body->Length();
|
||||
EXPECT_EQ(bodySize, size);
|
||||
bodySize = bodyVector.size();
|
||||
|
||||
if (size > 0)
|
||||
{ // only for known body size
|
||||
EXPECT_EQ(bodyVector.size(), size);
|
||||
}
|
||||
|
||||
if (expectedBody.size() > 0)
|
||||
{
|
||||
auto bodyString = std::string(bodyVector.begin(), bodyVector.end());
|
||||
EXPECT_STREQ(expectedBody.data(), bodyString.data());
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Core::Test
|
||||
@ -20,11 +20,26 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Test {
|
||||
|
||||
class TransportAdapter : public ::testing::Test {
|
||||
class TransportAdapter
|
||||
: public testing::TestWithParam<Azure::Core::Http::TransportPolicyOptions> {
|
||||
protected:
|
||||
static Azure::Core::Http::HttpPipeline pipeline;
|
||||
static std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
static Azure::Core::Context context;
|
||||
std::unique_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
|
||||
|
||||
// Befor each test, create pipeline
|
||||
virtual void SetUp() override
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
Azure::Core::Http::RetryOptions opt;
|
||||
opt.RetryDelay = std::chrono::milliseconds(10);
|
||||
|
||||
// Retry policy will help to prevent server-occasionally-errors
|
||||
policies.push_back(std::make_unique<Azure::Core::Http::RetryPolicy>(opt));
|
||||
// Will get transport policy options from test param
|
||||
// auto param = GetParam();
|
||||
policies.push_back(std::make_unique<Azure::Core::Http::TransportPolicy>(GetParam()));
|
||||
|
||||
m_pipeline = std::make_unique<Azure::Core::Http::HttpPipeline>(policies);
|
||||
}
|
||||
|
||||
static void CheckBodyFromBuffer(
|
||||
Azure::Core::Http::RawResponse& response,
|
||||
115
sdk/core/azure-core/test/ut/transport_adapter_curl.cpp
Normal file
115
sdk/core/azure-core/test/ut/transport_adapter_curl.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "transport_adapter_base.hpp"
|
||||
#include <azure/core/context.hpp>
|
||||
#include <azure/core/response.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using testing::ValuesIn;
|
||||
|
||||
namespace Azure { namespace Core { namespace Test {
|
||||
|
||||
/********************** Define the parameters for the base test and a suffix ***************/
|
||||
namespace {
|
||||
static Azure::Core::Http::TransportPolicyOptions GetTransportOptions()
|
||||
{
|
||||
Azure::Core::Http::TransportPolicyOptions options;
|
||||
options.Transport = std::make_shared<Azure::Core::Http::CurlTransport>();
|
||||
return options;
|
||||
}
|
||||
|
||||
// When adding more than one parameter, this function should return a unique string.
|
||||
// But since we are only using one parameter (the libcurl transport adapter) this is fine.
|
||||
static std::string GetSuffix(const testing::TestParamInfo<TransportAdapter::ParamType>& info)
|
||||
{
|
||||
// Can't use empty spaces or underscores (_) as per google test documentation
|
||||
// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#specifying-names-for-value-parameterized-test-parameters
|
||||
(void)(info);
|
||||
std::string suffix("curlImplementation");
|
||||
return suffix;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*********************** Unique Tests for Libcurl ********************************/
|
||||
TEST_P(TransportAdapter, connectionPoolTest)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/get");
|
||||
Azure::Core::Http::CurlConnectionPool::ClearIndex();
|
||||
|
||||
auto threadRoutine = [&]() {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host);
|
||||
auto response = m_pipeline->Send(Azure::Core::GetApplicationContext(), request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
CheckBodyFromBuffer(*response, expectedResponseBodySize);
|
||||
};
|
||||
|
||||
std::thread t1(threadRoutine);
|
||||
std::thread t2(threadRoutine);
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
// 2 connections must be available at this point
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 2);
|
||||
|
||||
std::thread t3(threadRoutine);
|
||||
std::thread t4(threadRoutine);
|
||||
std::thread t5(threadRoutine);
|
||||
t3.join();
|
||||
t4.join();
|
||||
t5.join();
|
||||
|
||||
// Two connections re-used plus one connection created
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 3);
|
||||
|
||||
#ifdef RUN_LONG_UNIT_TESTS
|
||||
{
|
||||
// Test pool clean routine
|
||||
std::cout << "Running Connection Pool Cleaner Test. This test takes more than 3 minutes to "
|
||||
"complete."
|
||||
<< std::endl
|
||||
<< "Add compiler option -DRUN_LONG_UNIT_TESTS=OFF when building if you want to "
|
||||
"skip this test."
|
||||
<< std::endl;
|
||||
|
||||
// Wait for 180 secs to make sure any previous connection is removed by the cleaner
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 180));
|
||||
|
||||
std::cout << "First wait time done. Validating state." << std::endl;
|
||||
|
||||
// index is not affected by cleaner. It does not remove index
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsIndexOnPool(), 1);
|
||||
// cleaner should have removed connections
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 0);
|
||||
|
||||
std::thread t1(threadRoutine);
|
||||
std::thread t2(threadRoutine);
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
// wait for connection to be moved back to pool
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
||||
// 2 connections must be available at this point and one index
|
||||
EXPECT_EQ(Http::CurlConnectionPool::ConnectionsIndexOnPool(), 1);
|
||||
// Depending on how fast the previous requests are sent, there could be one or more
|
||||
// connections in the pool. If first request is too fast, the second request will reuse the
|
||||
// same connection.
|
||||
EXPECT_PRED1(
|
||||
[](int currentConnections) { return currentConnections > 1; },
|
||||
Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************** Base Transpoer Adapter Tests ******************************/
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TransportAdapterCurlImpl,
|
||||
TransportAdapter,
|
||||
testing::Values(GetTransportOptions()),
|
||||
GetSuffix);
|
||||
|
||||
}}} // namespace Azure::Core::Test
|
||||
@ -1,188 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifdef POSIX
|
||||
#include <fcntl.h>
|
||||
#endif // Posix
|
||||
|
||||
#ifdef WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#endif // Windows
|
||||
|
||||
#include <azure/core/http/http.hpp>
|
||||
|
||||
#include "transport_adapter.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Core { namespace Test {
|
||||
namespace Datails {
|
||||
constexpr int64_t c_fileSize = 1024 * 100;
|
||||
}
|
||||
|
||||
void TransportAdapter::checkResponseCode(
|
||||
Azure::Core::Http::HttpStatusCode code,
|
||||
Azure::Core::Http::HttpStatusCode expectedCode)
|
||||
{
|
||||
EXPECT_PRED2(
|
||||
[](Azure::Core::Http::HttpStatusCode a, Azure::Core::Http::HttpStatusCode b) {
|
||||
return a == b;
|
||||
},
|
||||
code,
|
||||
expectedCode);
|
||||
}
|
||||
|
||||
void TransportAdapter::CheckBodyFromBuffer(
|
||||
Azure::Core::Http::RawResponse& response,
|
||||
int64_t size,
|
||||
std::string expectedBody)
|
||||
{
|
||||
auto body = response.GetBodyStream();
|
||||
EXPECT_EQ(body, nullptr);
|
||||
std::vector<uint8_t> bodyVector = response.GetBody();
|
||||
int64_t bodySize = bodyVector.size();
|
||||
|
||||
if (size > 0)
|
||||
{ // only for known body size
|
||||
EXPECT_EQ(bodySize, size);
|
||||
}
|
||||
|
||||
if (expectedBody.size() > 0)
|
||||
{
|
||||
auto bodyString = std::string(bodyVector.begin(), bodyVector.end());
|
||||
EXPECT_STREQ(expectedBody.data(), bodyString.data());
|
||||
}
|
||||
}
|
||||
|
||||
void TransportAdapter::CheckBodyFromStream(
|
||||
Azure::Core::Http::RawResponse& response,
|
||||
int64_t size,
|
||||
std::string expectedBody)
|
||||
{
|
||||
auto body = response.GetBodyStream();
|
||||
EXPECT_NE(body, nullptr);
|
||||
|
||||
std::vector<uint8_t> bodyVector = Azure::Core::Http::BodyStream::ReadToEnd(context, *body);
|
||||
int64_t bodySize = body->Length();
|
||||
EXPECT_EQ(bodySize, size);
|
||||
bodySize = bodyVector.size();
|
||||
|
||||
if (size > 0)
|
||||
{ // only for known body size
|
||||
EXPECT_EQ(bodyVector.size(), size);
|
||||
}
|
||||
|
||||
if (expectedBody.size() > 0)
|
||||
{
|
||||
auto bodyString = std::string(bodyVector.begin(), bodyVector.end());
|
||||
EXPECT_STREQ(expectedBody.data(), bodyString.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, SizePutFromFile)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read all stream content for uploading instead of chunks
|
||||
request.SetUploadChunkSize(Azure::Core::Test::Datails::c_fileSize);
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, SizePutFromFileDefault)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read default chunk size
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransportAdapter, SizePutFromFileBiggerPage)
|
||||
{
|
||||
Azure::Core::Http::Url host("http://httpbin.org/put");
|
||||
std::string testDataPath(AZURE_TEST_DATA_PATH);
|
||||
|
||||
#ifdef POSIX
|
||||
testDataPath.append("/fileData");
|
||||
int f = open(testDataPath.data(), O_RDONLY);
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
testDataPath.append("\\fileData");
|
||||
HANDLE f = CreateFile(
|
||||
testDataPath.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
#endif
|
||||
auto requestBodyStream
|
||||
= Azure::Core::Http::FileBodyStream(f, 0, Azure::Core::Test::Datails::c_fileSize);
|
||||
auto request = Azure::Core::Http::Request(
|
||||
Azure::Core::Http::HttpMethod::Put, host, &requestBodyStream, true);
|
||||
// Make transport adapter to read more than file size (5Mb)
|
||||
request.SetUploadChunkSize(Azure::Core::Test::Datails::c_fileSize * 5);
|
||||
{
|
||||
auto response = pipeline.Send(context, request);
|
||||
checkResponseCode(response->GetStatusCode());
|
||||
auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length"));
|
||||
|
||||
CheckBodyFromStream(*response, expectedResponseBodySize);
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Core::Test
|
||||
Loading…
Reference in New Issue
Block a user