ClientRetryTest.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /***************************************************************************
  2. *
  3. * Project _____ __ ____ _ _
  4. * ( _ ) /__\ (_ _)_| |_ _| |_
  5. * )(_)( /(__)\ )( (_ _)(_ _)
  6. * (_____)(__)(__)(__) |_| |_|
  7. *
  8. *
  9. * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. *
  23. ***************************************************************************/
  24. #include "ClientRetryTest.hpp"
  25. #include "oatpp/web/app/Client.hpp"
  26. #include "oatpp/web/app/ControllerWithInterceptors.hpp"
  27. #include "oatpp/web/app/Controller.hpp"
  28. #include "oatpp/web/app/BasicAuthorizationController.hpp"
  29. #include "oatpp/web/app/BearerAuthorizationController.hpp"
  30. #include "oatpp/web/client/HttpRequestExecutor.hpp"
  31. #include "oatpp/web/server/HttpConnectionHandler.hpp"
  32. #include "oatpp/web/server/HttpRouter.hpp"
  33. #include "oatpp/parser/json/mapping/ObjectMapper.hpp"
  34. #include "oatpp/network/tcp/server/ConnectionProvider.hpp"
  35. #include "oatpp/network/tcp/client/ConnectionProvider.hpp"
  36. #include "oatpp/network/virtual_/client/ConnectionProvider.hpp"
  37. #include "oatpp/network/virtual_/server/ConnectionProvider.hpp"
  38. #include "oatpp/network/virtual_/Interface.hpp"
  39. #include "oatpp/network/ConnectionPool.hpp"
  40. #include "oatpp/core/macro/component.hpp"
  41. #include "oatpp-test/web/ClientServerTestRunner.hpp"
  42. #include "oatpp-test/Checker.hpp"
  43. namespace oatpp { namespace test { namespace web {
  44. namespace {
  45. typedef oatpp::web::server::api::ApiController ApiController;
  46. class TestServerComponent {
  47. private:
  48. v_uint16 m_port;
  49. public:
  50. TestServerComponent(v_uint16 port)
  51. : m_port(port)
  52. {}
  53. OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([this] {
  54. if(m_port == 0) { // Use oatpp virtual interface
  55. auto _interface = oatpp::network::virtual_::Interface::obtainShared("virtualhost");
  56. return std::static_pointer_cast<oatpp::network::ServerConnectionProvider>(
  57. oatpp::network::virtual_::server::ConnectionProvider::createShared(_interface)
  58. );
  59. }
  60. return std::static_pointer_cast<oatpp::network::ServerConnectionProvider>(
  61. oatpp::network::tcp::server::ConnectionProvider::createShared({"localhost", m_port})
  62. );
  63. }());
  64. OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
  65. return oatpp::web::server::HttpRouter::createShared();
  66. }());
  67. OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {
  68. OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
  69. return oatpp::web::server::HttpConnectionHandler::createShared(router);
  70. }());
  71. OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, objectMapper)([] {
  72. return oatpp::parser::json::mapping::ObjectMapper::createShared();
  73. }());
  74. };
  75. class TestClientComponent {
  76. private:
  77. v_uint16 m_port;
  78. public:
  79. TestClientComponent(v_uint16 port)
  80. : m_port(port)
  81. {}
  82. OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, clientConnectionProvider)([this] {
  83. if(m_port == 0) {
  84. auto _interface = oatpp::network::virtual_::Interface::obtainShared("virtualhost");
  85. return std::static_pointer_cast<oatpp::network::ClientConnectionProvider>(
  86. oatpp::network::virtual_::client::ConnectionProvider::createShared(_interface)
  87. );
  88. }
  89. return std::static_pointer_cast<oatpp::network::ClientConnectionProvider>(
  90. oatpp::network::tcp::client::ConnectionProvider::createShared({"localhost", m_port})
  91. );
  92. }());
  93. };
  94. void runServer(v_uint16 port, v_int32 delaySeconds, v_int32 iterations, bool stable, const std::shared_ptr<app::Controller>& controller) {
  95. TestServerComponent component(port);
  96. oatpp::test::web::ClientServerTestRunner runner;
  97. runner.addController(controller);
  98. runner.run([&runner, delaySeconds, iterations, stable, controller] {
  99. for(v_int32 i = 0; i < iterations; i ++) {
  100. std::this_thread::sleep_for(std::chrono::seconds(delaySeconds));
  101. if(!stable) {
  102. controller->available = !controller->available;
  103. OATPP_LOGI("Server", "Available=%d", (v_int32)controller->available.load());
  104. }
  105. }
  106. }, std::chrono::minutes(10));
  107. std::this_thread::sleep_for(std::chrono::seconds(1));
  108. }
  109. }
  110. void ClientRetryTest::onRun() {
  111. TestClientComponent component(m_port);
  112. auto objectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared();
  113. auto controller = app::Controller::createShared(objectMapper);
  114. OATPP_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, connectionProvider);
  115. {
  116. OATPP_LOGI(TAG, "Test: no server available");
  117. oatpp::test::PerformanceChecker checker("test: no server available");
  118. auto retryPolicy = std::make_shared<oatpp::web::client::SimpleRetryPolicy>(2, std::chrono::seconds(1));
  119. auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(connectionProvider, retryPolicy);
  120. auto client = app::Client::createShared(requestExecutor, objectMapper);
  121. auto response = client->getRoot();
  122. auto ticks = checker.getElapsedTicks();
  123. OATPP_LOGD(TAG, "ticks=%d", ticks);
  124. if(m_port == 0) {
  125. OATPP_ASSERT(response.get() == nullptr);
  126. OATPP_ASSERT(ticks >= 2 * 1000 * 1000 /* 2s */);
  127. OATPP_ASSERT(ticks < 3 * 1000 * 1000 /* 3s */);
  128. } else {
  129. // TODO - investigate why it takes more than 2 seconds on windows to try to connect to unavailable host
  130. #if !defined(WIN32) && !defined(_WIN32)
  131. OATPP_ASSERT(response.get() == nullptr);
  132. OATPP_ASSERT(ticks >= 2 * 1000 * 1000 /* 2s */);
  133. OATPP_ASSERT(ticks < 3 * 1000 * 1000 /* 3s */);
  134. #endif
  135. }
  136. }
  137. {
  138. OATPP_LOGI(TAG, "Test: server pops up");
  139. oatpp::test::PerformanceChecker checker("test: server pops up");
  140. auto retryPolicy = std::make_shared<oatpp::web::client::SimpleRetryPolicy>(10 * 10, std::chrono::milliseconds(100));
  141. auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(connectionProvider, retryPolicy);
  142. auto client = app::Client::createShared(requestExecutor, objectMapper);
  143. std::list<std::thread> threads;
  144. for(v_int32 i = 0; i < 100; i ++) {
  145. threads.push_back(std::thread([client]{
  146. auto response = client->getRoot();
  147. OATPP_ASSERT(response && "Test: server pops up");
  148. OATPP_ASSERT(response->getStatusCode() == 200);
  149. auto data = response->readBodyToString();
  150. OATPP_ASSERT(data == "Hello World!!!");
  151. }));
  152. }
  153. OATPP_LOGD(TAG, "Waiting for server to start...");
  154. std::this_thread::sleep_for(std::chrono::seconds(3));
  155. runServer(m_port, 2, 2, true, controller);
  156. for(std::thread& thread : threads) {
  157. thread.join();
  158. }
  159. auto ticks = checker.getElapsedTicks();
  160. OATPP_ASSERT(ticks < 10 * 1000 * 1000 /* 10s */);
  161. }
  162. {
  163. OATPP_LOGI(TAG, "Test: unstable server!");
  164. auto retryPolicy = std::make_shared<oatpp::web::client::SimpleRetryPolicy>(-1, std::chrono::seconds(1));
  165. auto connectionPool = oatpp::network::ClientConnectionPool::createShared(connectionProvider, 10, std::chrono::seconds(1));
  166. auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(connectionPool, retryPolicy);
  167. auto client = app::Client::createShared(requestExecutor, objectMapper);
  168. std::list<std::thread> threads;
  169. std::thread clientThread([client]{
  170. v_int64 counter = 0;
  171. v_int64 tick0 = oatpp::base::Environment::getMicroTickCount();
  172. while(oatpp::base::Environment::getMicroTickCount() - tick0 < 10 * 1000 * 1000) {
  173. auto response = client->getAvailability();
  174. OATPP_ASSERT(response && "Test: unstable server!");
  175. OATPP_ASSERT(response->getStatusCode() == 200);
  176. auto data = response->readBodyToString();
  177. OATPP_ASSERT(data == "Hello World!!!");
  178. counter ++;
  179. if(counter % 1000 == 0) {
  180. OATPP_LOGD("client", "requests=%d", counter);
  181. }
  182. }
  183. });
  184. runServer(m_port, 2, 6, false, controller);
  185. clientThread.join();
  186. connectionPool->stop();
  187. }
  188. std::this_thread::sleep_for(std::chrono::seconds(2)); // wait connection pool.
  189. }
  190. }}}