diff --git a/.gitignore b/.gitignore index 2b3a003e5..f426b11b3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ [Rr]eleases/ x64/ x86/ -bld/ +bld*/ [Bb]in/ [Oo]bj/ [Ll]og/ diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index 978a59def..b2ead6cd0 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -204,6 +204,7 @@ if(BUILD_TESTING) add_subdirectory(test/nlohmann-json-test) endif() add_subdirectory(test/fault-injector) + add_subdirectory(test/libcurl-stress-test) endif() if (BUILD_PERFORMANCE_TESTS) diff --git a/sdk/core/azure-core/test/libcurl-stress-test/CMakeLists.txt b/sdk/core/azure-core/test/libcurl-stress-test/CMakeLists.txt new file mode 100644 index 000000000..1ef828894 --- /dev/null +++ b/sdk/core/azure-core/test/libcurl-stress-test/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.13) + +project(azure-core-libcurl-stress-test LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +add_executable( + azure-core-libcurl-stress-test + libcurl_stress_test.cpp +) + +target_link_libraries(azure-core-libcurl-stress-test PRIVATE azure-core) + +create_map_file(azure-core-libcurl-stress-test azure-core-libcurl-stress-test.map) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Dockerfile + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + +find_program(DOCKER_EXECUTABLE docker) +#if docker is found try to build the docker image in the defined docker_build stage which should be run after build +if(DOCKER_EXECUTABLE) + add_custom_target(docker_build + COMMAND ${DOCKER_EXECUTABLE} build --build-arg targetTest=azure-core-libcurl-stress-test --build-arg build=on --tag=azuresdkforcpp/curlstress -f Dockerfile .) +endif() diff --git a/sdk/core/azure-core/test/libcurl-stress-test/Dockerfile b/sdk/core/azure-core/test/libcurl-stress-test/Dockerfile new file mode 100644 index 000000000..1373c598f --- /dev/null +++ b/sdk/core/azure-core/test/libcurl-stress-test/Dockerfile @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/mirror/docker/library/ubuntu:22.04 + +ARG targetTest +ARG build + +# copy the tagrget binary +ADD $targetTest ./$targetTest +RUN chmod +x ./$targetTest + +# install the mem check tool +RUN apt-get update -y +RUN apt-get install valgrind -y + +# execute under memcheck tool +RUN valgrind --tool=memcheck -s ./$targetTest $build diff --git a/sdk/core/azure-core/test/libcurl-stress-test/libcurl_stress_test.cpp b/sdk/core/azure-core/test/libcurl-stress-test/libcurl_stress_test.cpp new file mode 100644 index 000000000..d3d429b68 --- /dev/null +++ b/sdk/core/azure-core/test/libcurl-stress-test/libcurl_stress_test.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @brief Validates the Azure Core transport adapters with fault responses from server. + * + * @note This test requires the Http-fault-injector + * (https://github.com/Azure/azure-sdk-tools/tree/main/tools/http-fault-injector) running. Follow + * the instructions to install and run the server before running this test. + * + */ +#define REQUESTS 100 +#define WARMUP 100 +#define ROUNDS 100 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void SendRequest(std::string target) +{ + std::cout << target << std::endl; + /* The transport adapter must allow insecure SSL certs. + If both curl and winHttp are available, curl is preferred for this test.for*/ +#if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) + Azure::Core::Http::CurlTransportOptions curlOptions; + curlOptions.SslVerifyPeer = false; + auto implementationClient = std::make_shared(curlOptions); + +#elif (BUILD_TRANSPORT_WINHTTP_ADAPTER) + Azure::Core::Http::WinHttpTransportOptions winHttpOptions; + auto implementationClient = std::make_shared(winHttpOptions); +#endif + try + { + + Azure::Core::Context context; + // auto duration = std::chrono::milliseconds(1000); + // auto deadline = std::chrono::system_clock::now() + duration; + auto request + = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, Azure::Core::Url(target)); + auto response = implementationClient->Send(request, context); //.WithDeadline(deadline)); + // Make sure to pull all bytes from network. + auto body = response->ExtractBodyStream()->ReadToEnd(); + } + catch (std::exception const&) + { + } +} + +void Operation(int repetitions) +{ + std::string base = "https://xyz."; + for (int i = 0; i < repetitions; i++) + { + std::cout << i << std::endl; + SendRequest(base + std::to_string(i) + ".abc"); + } +} + +int main(int argc, char** argv) // i can have either 0 or 2 params here +{ + (void)argv; // to get rid of the unused warning + // some param was passed to the program , which happens only in build mode, not run of the docker + // file. thus we will run a quick test to make sure the executable runs. + if (argc != 1) + { + std::cout << "--------------\tBUILD TEST\t--------------" << std::endl; + Operation(5); + std::cout << "--------------\tEND BUILD TEST\t--------------" << std::endl; + return 0; + } + + std::cout << "--------------\tSTARTING TEST\t--------------" << std::endl; + std::cout << "--------------\tPRE WARMUP\t--------------" << std::endl; + Operation(WARMUP); + + std::cout << "--------------\tPOST WARMUP\t--------------" << std::endl; + + for (int i = 0; i < ROUNDS; i++) + { + std::cout << "--------------\tTEST ITERATION:" << i << "\t--------------" << std::endl; + Operation(REQUESTS); + + std::cout << "--------------\tDONE ITERATION:" << i << "\t--------------" << std::endl; + } + + return 0; +}