From d79d95e5b783866018270d722958a0d01fd14ac3 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Fri, 16 Oct 2020 17:39:02 -0700 Subject: [PATCH] Add prefix for Azure Core Tests - Fix CI test run (#801) * Add prefix for Azure Core Tests --- .../templates/jobs/archetype-sdk-client.yml | 2 +- .../inc/azure/core/http/curl/curl.hpp | 6 +- sdk/core/azure-core/test/ut/CMakeLists.txt | 3 +- .../azure-core/test/ut/transport_adapter.cpp | 821 +++++++++--------- sdk/core/ci.yml | 2 +- 5 files changed, 413 insertions(+), 421 deletions(-) diff --git a/eng/pipelines/templates/jobs/archetype-sdk-client.yml b/eng/pipelines/templates/jobs/archetype-sdk-client.yml index ab429b4d0..84ad38acf 100644 --- a/eng/pipelines/templates/jobs/archetype-sdk-client.yml +++ b/eng/pipelines/templates/jobs/archetype-sdk-client.yml @@ -87,7 +87,7 @@ jobs: parameters: GenerateArgs: $(CmakeArgs) - - script: ctest -V --tests-regex ${{ parameters.CtestRegex }} + - script: ctest -C Debug -V --tests-regex ${{ parameters.CtestRegex }} workingDirectory: build displayName: ctest diff --git a/sdk/core/azure-core/inc/azure/core/http/curl/curl.hpp b/sdk/core/azure-core/inc/azure/core/http/curl/curl.hpp index 2807b4e32..21f86078d 100644 --- a/sdk/core/azure-core/inc/azure/core/http/curl/curl.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/curl/curl.hpp @@ -25,8 +25,7 @@ #ifdef TESTING_BUILD // Define the class name that reads from ConnectionPool private members namespace Azure { namespace Core { namespace Test { - class TransportAdapter_ConnectionPoolCleaner_Test; - class TransportAdapter_getMultiThread_Test; + class TransportAdapter_connectionPoolTest_Test; }}} // namespace Azure::Core::Test #endif @@ -110,8 +109,7 @@ namespace Azure { namespace Core { namespace Http { { #ifdef TESTING_BUILD // Give access to private to this tests class - friend class Azure::Core::Test::TransportAdapter_getMultiThread_Test; - friend class Azure::Core::Test::TransportAdapter_ConnectionPoolCleaner_Test; + friend class Azure::Core::Test::TransportAdapter_connectionPoolTest_Test; #endif /** diff --git a/sdk/core/azure-core/test/ut/CMakeLists.txt b/sdk/core/azure-core/test/ut/CMakeLists.txt index a1059749b..4ee64796f 100644 --- a/sdk/core/azure-core/test/ut/CMakeLists.txt +++ b/sdk/core/azure-core/test/ut/CMakeLists.txt @@ -39,5 +39,6 @@ target_link_libraries(${TARGET_NAME} PRIVATE azure-core gtest) # gtest_add_tests will scan the test from azure-core-test and call add_test # for each test to ctest. This enables `ctest -r` to run specific tests directly. -gtest_add_tests(TARGET ${TARGET_NAME}) +gtest_add_tests(TARGET ${TARGET_NAME} + TEST_PREFIX azure-core.) diff --git a/sdk/core/azure-core/test/ut/transport_adapter.cpp b/sdk/core/azure-core/test/ut/transport_adapter.cpp index 78adedc7b..14bc68486 100644 --- a/sdk/core/azure-core/test/ut/transport_adapter.cpp +++ b/sdk/core/azure-core/test/ut/transport_adapter.cpp @@ -30,461 +30,454 @@ namespace Azure { namespace Core { namespace Test { Azure::Core::Http::HttpPipeline TransportAdapter::pipeline(policies); Azure::Core::Context TransportAdapter::context = Azure::Core::GetApplicationContext(); - // multiThread test requires `ConnectionsOnPool` hook which is only available when building - // TESTING_BUILD. This test is only built when that case is true. - TEST_F(TransportAdapter, getMultiThread) - { - Azure::Core::Http::Url host("http://httpbin.org/get"); - Azure::Core::Http::CurlConnectionPool::ClearIndex(); +// 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); - }; + 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(); + 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); + // 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(); + 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); - } + // Two connections re-used plus one connection created + EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 3); #ifdef RUN_LONG_UNIT_TESTS - TEST_F(TransportAdapter, ConnectionPoolCleaner) - { - Azure::Core::Http::Url host("http://httpbin.org/get"); + { + // 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 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); - }; - // 3 connections from previous test. Make sure cleaner remove them - EXPECT_EQ(Http::CurlConnectionPool::ConnectionsOnPool("httpbin.org"), 3); - - 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 remove 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 - - 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")); + // 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, 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(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(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(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( - "\r\n\r\n\r\n\r\nChunked " - "transfer encoding test\r\n\r\n

Chunked transfer encoding " - "test

This is a chunked response after 100 ms.
This is a chunked " - "response after 1 second. The server should not close the stream before all chunks are " - "sent to a client.
"); - - 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++) + TEST_F(TransportAdapter, getLoop) { - auto requestBodyVector = std::vector(10, 'x'); + 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(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); - } - } - - // ********************** - // ***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); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); - checkResponseCode(response->GetStatusCode()); - CheckBodyFromStream(*response, expectedResponseBodySize); + + CheckBodyFromBuffer(*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(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(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(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( - "\r\n\r\n\r\n\r\nChunked " - "transfer encoding test\r\n\r\n

Chunked transfer encoding " - "test

This is a chunked response after 100 ms.
This is a chunked " - "response after 1 second. The server should not close the stream before all chunks are " - "sent to a client.
"); - - 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 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(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); + TEST_F(TransportAdapter, deleteRequest) { + Azure::Core::Http::Url host("http://httpbin.org/delete"); + + // Delete with 1k payload + auto requestBodyVector = std::vector(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, putWithStreamOnFail) - { - // point to bad address pah to generate server MethodNotAllowed error - Azure::Core::Http::Url host("http://httpbin.org/get"); + TEST_F(TransportAdapter, patch) + { + Azure::Core::Http::Url host("http://httpbin.org/patch"); - // PUT 1k - auto requestBodyVector = std::vector(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")); + // Patch with 1kb payload + auto requestBodyVector = std::vector(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()); - CheckBodyFromBuffer(*response, expectedResponseBodySize); - } + 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; + 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( + "\r\n\r\n\r\n\r\nChunked " + "transfer encoding test\r\n\r\n

Chunked transfer encoding " + "test

This is a chunked response after 100 ms.
This is a chunked " + "response after 1 second. The server should not close the stream before all chunks are " + "sent to a client.
"); - auto threadRoutine = [host, cancelThis]() { - // Start a big upload and expect it to throw cancelation - std::vector 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::RequestCanceledException); - }; - - // 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); + auto response = pipeline.Send(context, request); - // Request will be canceled from main thread throwing the exception - EXPECT_THROW(pipeline.Send(cancelThis, request), Azure::Core::RequestCanceledException); - }; + checkResponseCode(response->GetStatusCode()); + CheckBodyFromBuffer(*response, expectedResponseBodySize, expectedChunkResponse); + } - // Start request - std::thread t1(threadRoutine); + TEST_F(TransportAdapter, putErrorResponse) + { + Azure::Core::Http::Url host("http://httpbin.org/get"); - // Wait 100 ms so we know download has started - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + // 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(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); + } + } - cancelThis.Cancel(); - t1.join(); - } + // ********************** + // ***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(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(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(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( + "\r\n\r\n\r\n\r\nChunked " + "transfer encoding test\r\n\r\n

Chunked transfer encoding " + "test

This is a chunked response after 100 ms.
This is a chunked " + "response after 1 second. The server should not close the stream before all chunks are " + "sent to a client.
"); + + 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 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(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(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 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::RequestCanceledException); + }; + + // 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::RequestCanceledException); + }; + + // 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(); + } }}} // namespace Azure::Core::Test diff --git a/sdk/core/ci.yml b/sdk/core/ci.yml index 7c7595fcd..23bf082c0 100644 --- a/sdk/core/ci.yml +++ b/sdk/core/ci.yml @@ -31,7 +31,7 @@ stages: - template: ../../eng/pipelines/templates/stages/archetype-sdk-client.yml parameters: ServiceDirectory: core - CtestRegex: azure-core + CtestRegex: azure-core. Artifacts: - Name: azure-core Path: azure-core