]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1239] addressed comments
authorRazvan Becheriu <razvan@isc.org>
Mon, 18 May 2020 16:45:29 +0000 (19:45 +0300)
committerRazvan Becheriu <razvan@isc.org>
Mon, 18 May 2020 17:59:29 +0000 (20:59 +0300)
src/lib/http/client.cc
src/lib/http/tests/server_client_unittests.cc

index 686031e0b8fd641ff432db4b2ad5534774ddef86..bde27af3c2f64d65cfd9767850c71bb57740809c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
index 540f1b73565a7510ac744ac47f1726dfc72462c4..9eaeb8f9f98a21783b20f46deea368f430d8ad4b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -245,8 +245,6 @@ protected:
                                         request_timeout_, idle_timeout_));
         return (conn);
     }
-
-
 };
 
 /// @brief Derivation of the @c HttpListener used in tests.
@@ -335,7 +333,6 @@ public:
         // with this and adjust the data length.
         HttpConnection::socketWriteCallback(transaction, ec, length + 1);
     }
-
 };
 
 /// @brief Implementation of the @c HttpConnection which replaces
@@ -343,7 +340,6 @@ public:
 class HttpConnectionTransactionChange : public HttpConnection {
 public:
 
-
     /// @brief Constructor.
     ///
     /// @param io_service IO service to be used by the connection.
@@ -1200,11 +1196,11 @@ public:
 
     /// @brief Destructor.
     ~HttpClientTest() {
-        MultiThreadingMgr::instance().setMode(false);
         listener_.stop();
         listener2_.stop();
         listener3_.stop();
         io_service_.poll();
+        MultiThreadingMgr::instance().setMode(false);
     }
 
     /// @brief Creates HTTP request with JSON body.
@@ -1291,6 +1287,280 @@ public:
         EXPECT_NE(sequence1->intValue(), sequence2->intValue());
     }
 
+    // Test that the client can communicate with two different destinations
+    // simultaneously.
+    void testMultipleDestinations() {
+        // Start two servers running on different ports.
+        ASSERT_NO_THROW(listener_.start());
+        ASSERT_NO_THROW(listener2_.start());
+
+        // Create the client. It will be communicating with the two servers.
+        HttpClient client(io_service_);
+
+        // Specify the URLs on which the servers are available.
+        Url url1("http://127.0.0.1:18123");
+        Url url2("http://[::1]:18124");
+
+        // Create a request to the first server.
+        PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
+        HttpResponseJsonPtr response1(new HttpResponseJson());
+        unsigned resp_num = 0;
+        ASSERT_NO_THROW(client.asyncSendRequest(url1, request1, response1,
+            [this, &resp_num](const boost::system::error_code& ec,
+                              const HttpResponsePtr&,
+                              const std::string&) {
+            if (++resp_num > 1) {
+                io_service_.stop();
+            }
+            EXPECT_FALSE(ec);
+        }));
+
+        // Create a request to the second server.
+        PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
+        HttpResponseJsonPtr response2(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url2, request2, response2,
+            [this, &resp_num](const boost::system::error_code& ec,
+                              const HttpResponsePtr&,
+                              const std::string&) {
+            if (++resp_num > 1) {
+                io_service_.stop();
+            }
+            EXPECT_FALSE(ec);
+        }));
+
+        // Actually trigger the requests.
+        ASSERT_NO_THROW(runIOService());
+
+        // Make sure we have received two different responses.
+        ASSERT_TRUE(response1);
+        ConstElementPtr sequence1 = response1->getJsonElement("sequence");
+        ASSERT_TRUE(sequence1);
+
+        ASSERT_TRUE(response2);
+        ConstElementPtr sequence2 = response2->getJsonElement("sequence");
+        ASSERT_TRUE(sequence2);
+
+        EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    }
+
+    // Test that idle connection can be resumed for second request.
+    void testIdleConnection() {
+        // Start the server that has short idle timeout. It closes the idle
+        // connection after 200ms.
+        ASSERT_NO_THROW(listener3_.start());
+
+        // Create the client that will communicate with this server.
+        HttpClient client(io_service_);
+
+        // Specify the URL of this server.
+        Url url("http://127.0.0.1:18125");
+
+        // Create the first request.
+        PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
+        HttpResponseJsonPtr response1(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
+            [this](const boost::system::error_code& ec, const HttpResponsePtr&,
+                   const std::string&) {
+            io_service_.stop();
+            EXPECT_FALSE(ec);
+        }));
+
+        // Run the IO service until the response is received.
+        ASSERT_NO_THROW(runIOService());
+
+        // Make sure the response has been received.
+        ASSERT_TRUE(response1);
+        ConstElementPtr sequence1 = response1->getJsonElement("sequence");
+        ASSERT_TRUE(sequence1);
+
+        // Delay the generation of the second request by 2x server idle timeout.
+        // This should be enough to cause the server to close the connection.
+        ASSERT_NO_THROW(runIOService(SHORT_IDLE_TIMEOUT * 2));
+
+        // Create another request.
+        PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
+        HttpResponseJsonPtr response2(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
+            [this](const boost::system::error_code& ec, const HttpResponsePtr&,
+                   const std::string&) {
+            io_service_.stop();
+            EXPECT_FALSE(ec);
+        }));
+
+        // Actually trigger the second request.
+        ASSERT_NO_THROW(runIOService());
+
+        // Make sire that the server has responded.
+        ASSERT_TRUE(response2);
+        ConstElementPtr sequence2 = response2->getJsonElement("sequence");
+        ASSERT_TRUE(sequence2);
+
+        // Make sure that two different responses have been received.
+        EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    }
+
+    // This test verifies that the client returns IO error code when the
+    // server is unreachable.
+    void testUnreachable () {
+        // Create the client.
+        HttpClient client(io_service_);
+
+        // Specify the URL of the server. This server is down.
+        Url url("http://127.0.0.1:18123");
+
+        // Create the request.
+        PostHttpRequestJsonPtr request = createRequest("sequence", 1);
+        HttpResponseJsonPtr response(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
+            [this](const boost::system::error_code& ec,
+                   const HttpResponsePtr&,
+                   const std::string&) {
+            io_service_.stop();
+            // The server should have returned an IO error.
+            EXPECT_TRUE(ec);
+        }));
+
+        // Actually trigger the request.
+        ASSERT_NO_THROW(runIOService());
+    }
+
+    // Test that an error is returned by the client if the server response is
+    // malformed.
+    void testMalformedResponse () {
+        // Start the server.
+        ASSERT_NO_THROW(listener_.start());
+
+        // Create the client.
+        HttpClient client(io_service_);
+
+        // Specify the URL of the server.
+        Url url("http://127.0.0.1:18123");
+
+        // The response is going to be malformed in such a way that it holds
+        // an invalid content type. We affect the content type by creating
+        // a request that holds a JSON parameter requesting a specific
+        // content type.
+        PostHttpRequestJsonPtr request = createRequest("requested-content-type", "text/html");
+        HttpResponseJsonPtr response(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
+            [this](const boost::system::error_code& ec,
+                   const HttpResponsePtr& response,
+                   const std::string& parsing_error) {
+            io_service_.stop();
+            // There should be no IO error (answer from the server is received).
+            EXPECT_FALSE(ec);
+            // The response object is NULL because it couldn't be finalized.
+            EXPECT_FALSE(response);
+            // The message parsing error should be returned.
+            EXPECT_FALSE(parsing_error.empty());
+        }));
+
+        // Actually trigger the request.
+        ASSERT_NO_THROW(runIOService());
+    }
+
+    // Test that client times out when it doesn't receive the entire response
+    // from the server within a desired time.
+    void testClientRequestTimeout() {
+        // Start the server.
+        ASSERT_NO_THROW(listener_.start());
+
+        // Create the client.
+        HttpClient client(io_service_);
+
+        // Specify the URL of the server.
+        Url url("http://127.0.0.1:18123");
+
+        unsigned cb_num = 0;
+
+        // Create the request which asks the server to generate a partial
+        // (although well formed) response. The client will be waiting for the
+        // rest of the response to be provided and will eventually time out.
+        PostHttpRequestJsonPtr request1 = createRequest("partial-response", true);
+        HttpResponseJsonPtr response1(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
+            [this, &cb_num](const boost::system::error_code& ec,
+                            const HttpResponsePtr& response,
+                            const std::string&) {
+            if (++cb_num > 1) {
+                io_service_.stop();
+            }
+            // In this particular case we know exactly the type of the
+            // IO error returned, because the client explicitly sets this
+            // error code.
+            EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
+            // There should be no response returned.
+            EXPECT_FALSE(response);
+        }, HttpClient::RequestTimeout(100)));
+
+        // Create another request after the timeout. It should be handled ok.
+        PostHttpRequestJsonPtr request2 = createRequest("sequence", 1);
+        HttpResponseJsonPtr response2(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
+                        [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
+                   const std::string&) {
+            if (++cb_num > 1) {
+                io_service_.stop();
+            }
+        }));
+
+        // Actually trigger the requests.
+        ASSERT_NO_THROW(runIOService());
+    }
+
+    // Test that client times out when connection takes too long.
+    void testClientConnectTimeout() {
+        // Start the server.
+        ASSERT_NO_THROW(listener_.start());
+
+        // Create the client.
+        HttpClient client(io_service_);
+
+        // Specify the URL of the server.
+        Url url("http://127.0.0.1:18123");
+
+        unsigned cb_num = 0;
+
+        PostHttpRequestJsonPtr request = createRequest("sequence", 1);
+        HttpResponseJsonPtr response(new HttpResponseJson());
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
+            [this, &cb_num](const boost::system::error_code& ec,
+                            const HttpResponsePtr& response,
+                            const std::string&) {
+            if (++cb_num > 1) {
+                io_service_.stop();
+            }
+            // In this particular case we know exactly the type of the
+            // IO error returned, because the client explicitly sets this
+            // error code.
+            EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
+            // There should be no response returned.
+            EXPECT_FALSE(response);
+
+        }, HttpClient::RequestTimeout(100),
+
+           // This callback is invoked upon an attempt to connect to the
+           // server. The false value indicates to the HttpClient to not
+           // try to send a request to the server. This simulates the
+           // case of connect() taking very long and should eventually
+           // cause the transaction to time out.
+           [](const boost::system::error_code& /*ec*/, int) {
+               return (false);
+        }));
+
+        // Create another request after the timeout. It should be handled ok.
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
+                        [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
+                   const std::string&) {
+            if (++cb_num > 1) {
+                io_service_.stop();
+            }
+        }));
+
+        // Actually trigger the requests.
+        ASSERT_NO_THROW(runIOService());
+    }
+
     /// @brief Tests the behavior of the HTTP client when the premature
     /// timeout occurs.
     ///
@@ -1694,448 +1964,64 @@ TEST_F(HttpClientTest, closeBetweenRequestsMultiThreading) {
 // Test that the client can communicate with two different destinations
 // simultaneously.
 TEST_F(HttpClientTest, multipleDestinations) {
-    // Start two servers running on different ports.
-    ASSERT_NO_THROW(listener_.start());
-    ASSERT_NO_THROW(listener2_.start());
-
-    // Create the client. It will be communicating with the two servers.
-    HttpClient client(io_service_);
-
-    // Specify the URLs on which the servers are available.
-    Url url1("http://127.0.0.1:18123");
-    Url url2("http://[::1]:18124");
-
-    // Create a request to the first server.
-    PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    unsigned resp_num = 0;
-    ASSERT_NO_THROW(client.asyncSendRequest(url1, request1, response1,
-        [this, &resp_num](const boost::system::error_code& ec,
-                          const HttpResponsePtr&,
-                          const std::string&) {
-        if (++resp_num > 1) {
-            io_service_.stop();
-        }
-        EXPECT_FALSE(ec);
-    }));
-
-    // Create a request to the second server.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url2, request2, response2,
-        [this, &resp_num](const boost::system::error_code& ec,
-                          const HttpResponsePtr&,
-                          const std::string&) {
-        if (++resp_num > 1) {
-            io_service_.stop();
-        }
-        EXPECT_FALSE(ec);
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sure we have received two different responses.
-    ASSERT_TRUE(response1);
-    ConstElementPtr sequence1 = response1->getJsonElement("sequence");
-    ASSERT_TRUE(sequence1);
-
-    ASSERT_TRUE(response2);
-    ConstElementPtr sequence2 = response2->getJsonElement("sequence");
-    ASSERT_TRUE(sequence2);
-
-    EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    ASSERT_NO_FATAL_FAILURE(testMultipleDestinations());
 }
 
 // Test that the client can communicate with two different destinations
 // simultaneously.
 TEST_F(HttpClientTest, multipleDestinationsMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Start two servers running on different ports.
-    ASSERT_NO_THROW(listener_.start());
-    ASSERT_NO_THROW(listener2_.start());
-
-    // Create the client. It will be communicating with the two servers.
-    HttpClient client(io_service_);
-
-    // Specify the URLs on which the servers are available.
-    Url url1("http://127.0.0.1:18123");
-    Url url2("http://[::1]:18124");
-
-    // Create a request to the first server.
-    PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    unsigned resp_num = 0;
-    ASSERT_NO_THROW(client.asyncSendRequest(url1, request1, response1,
-        [this, &resp_num](const boost::system::error_code& ec,
-                          const HttpResponsePtr&,
-                          const std::string&) {
-        if (++resp_num > 1) {
-            io_service_.stop();
-        }
-        EXPECT_FALSE(ec);
-    }));
-
-    // Create a request to the second server.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url2, request2, response2,
-        [this, &resp_num](const boost::system::error_code& ec,
-                          const HttpResponsePtr&,
-                          const std::string&) {
-        if (++resp_num > 1) {
-            io_service_.stop();
-        }
-        EXPECT_FALSE(ec);
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sure we have received two different responses.
-    ASSERT_TRUE(response1);
-    ConstElementPtr sequence1 = response1->getJsonElement("sequence");
-    ASSERT_TRUE(sequence1);
-
-    ASSERT_TRUE(response2);
-    ConstElementPtr sequence2 = response2->getJsonElement("sequence");
-    ASSERT_TRUE(sequence2);
-
-    EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    ASSERT_NO_FATAL_FAILURE(testMultipleDestinations());
 }
 
 // Test that idle connection can be resumed for second request.
 TEST_F(HttpClientTest, idleConnection) {
-    // Start the server that has short idle timeout. It closes the idle connection
-    // after 200ms.
-    ASSERT_NO_THROW(listener3_.start());
-
-    // Create the client that will communicate with this server.
-    HttpClient client(io_service_);
-
-    // Specify the URL of this server.
-    Url url("http://127.0.0.1:18125");
-
-    // Create the first request.
-    PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
-        [this](const boost::system::error_code& ec, const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        EXPECT_FALSE(ec);
-    }));
-
-    // Run the IO service until the response is received.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sure the response has been received.
-    ASSERT_TRUE(response1);
-    ConstElementPtr sequence1 = response1->getJsonElement("sequence");
-    ASSERT_TRUE(sequence1);
-
-    // Delay the generation of the second request by 2x server idle timeout.
-    // This should be enough to cause the server to close the connection.
-    ASSERT_NO_THROW(runIOService(SHORT_IDLE_TIMEOUT * 2));
-
-    // Create another request.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
-        [this](const boost::system::error_code& ec, const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        EXPECT_FALSE(ec);
-    }));
-
-    // Actually trigger the second request.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sire that the server has responded.
-    ASSERT_TRUE(response2);
-    ConstElementPtr sequence2 = response2->getJsonElement("sequence");
-    ASSERT_TRUE(sequence2);
-
-    // Make sure that two different responses have been received.
-    EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    ASSERT_NO_FATAL_FAILURE(testIdleConnection());
 }
 
 // Test that idle connection can be resumed for second request.
 TEST_F(HttpClientTest, idleConnectionMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Start the server that has short idle timeout. It closes the idle connection
-    // after 200ms.
-    ASSERT_NO_THROW(listener3_.start());
-
-    // Create the client that will communicate with this server.
-    HttpClient client(io_service_);
-
-    // Specify the URL of this server.
-    Url url("http://127.0.0.1:18125");
-
-    // Create the first request.
-    PostHttpRequestJsonPtr request1 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
-        [this](const boost::system::error_code& ec, const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        EXPECT_FALSE(ec);
-    }));
-
-    // Run the IO service until the response is received.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sure the response has been received.
-    ASSERT_TRUE(response1);
-    ConstElementPtr sequence1 = response1->getJsonElement("sequence");
-    ASSERT_TRUE(sequence1);
-
-    // Delay the generation of the second request by 2x server idle timeout.
-    // This should be enough to cause the server to close the connection.
-    ASSERT_NO_THROW(runIOService(SHORT_IDLE_TIMEOUT * 2));
-
-    // Create another request.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 2);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
-        [this](const boost::system::error_code& ec, const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        EXPECT_FALSE(ec);
-    }));
-
-    // Actually trigger the second request.
-    ASSERT_NO_THROW(runIOService());
-
-    // Make sire that the server has responded.
-    ASSERT_TRUE(response2);
-    ConstElementPtr sequence2 = response2->getJsonElement("sequence");
-    ASSERT_TRUE(sequence2);
-
-    // Make sure that two different responses have been received.
-    EXPECT_NE(sequence1->intValue(), sequence2->intValue());
+    ASSERT_NO_FATAL_FAILURE(testIdleConnection());
 }
 
 // This test verifies that the client returns IO error code when the
 // server is unreachable.
 TEST_F(HttpClientTest, unreachable) {
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server. This server is down.
-    Url url("http://127.0.0.1:18123");
-
-    // Create the request.
-    PostHttpRequestJsonPtr request = createRequest("sequence", 1);
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this](const boost::system::error_code& ec,
-               const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        // The server should have returned an IO error.
-        EXPECT_TRUE(ec);
-    }));
-
-    // Actually trigger the request.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testUnreachable());
 }
 
 // This test verifies that the client returns IO error code when the
 // server is unreachable.
 TEST_F(HttpClientTest, unreachableMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server. This server is down.
-    Url url("http://127.0.0.1:18123");
-
-    // Create the request.
-    PostHttpRequestJsonPtr request = createRequest("sequence", 1);
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this](const boost::system::error_code& ec,
-               const HttpResponsePtr&,
-               const std::string&) {
-        io_service_.stop();
-        // The server should have returned an IO error.
-        EXPECT_TRUE(ec);
-    }));
-
-    // Actually trigger the request.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testUnreachable());
 }
 
 // Test that an error is returned by the client if the server response is
 // malformed.
 TEST_F(HttpClientTest, malformedResponse) {
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    // The response is going to be malformed in such a way that it holds
-    // an invalid content type. We affect the content type by creating
-    // a request that holds a JSON parameter requesting a specific
-    // content type.
-    PostHttpRequestJsonPtr request = createRequest("requested-content-type", "text/html");
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this](const boost::system::error_code& ec,
-               const HttpResponsePtr& response,
-               const std::string& parsing_error) {
-        io_service_.stop();
-        // There should be no IO error (answer from the server is received).
-        EXPECT_FALSE(ec);
-        // The response object is NULL because it couldn't be finalized.
-        EXPECT_FALSE(response);
-        // The message parsing error should be returned.
-        EXPECT_FALSE(parsing_error.empty());
-    }));
-
-    // Actually trigger the request.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testMalformedResponse());
 }
 
 // Test that an error is returned by the client if the server response is
 // malformed.
 TEST_F(HttpClientTest, malformedResponseMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    // The response is going to be malformed in such a way that it holds
-    // an invalid content type. We affect the content type by creating
-    // a request that holds a JSON parameter requesting a specific
-    // content type.
-    PostHttpRequestJsonPtr request = createRequest("requested-content-type", "text/html");
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this](const boost::system::error_code& ec,
-               const HttpResponsePtr& response,
-               const std::string& parsing_error) {
-        io_service_.stop();
-        // There should be no IO error (answer from the server is received).
-        EXPECT_FALSE(ec);
-        // The response object is NULL because it couldn't be finalized.
-        EXPECT_FALSE(response);
-        // The message parsing error should be returned.
-        EXPECT_FALSE(parsing_error.empty());
-    }));
-
-    // Actually trigger the request.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testMalformedResponse());
 }
 
 // Test that client times out when it doesn't receive the entire response
 // from the server within a desired time.
 TEST_F(HttpClientTest, clientRequestTimeout) {
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    unsigned cb_num = 0;
-
-    // Create the request which asks the server to generate a partial
-    // (although well formed) response. The client will be waiting for the
-    // rest of the response to be provided and will eventually time out.
-    PostHttpRequestJsonPtr request1 = createRequest("partial-response", true);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
-        [this, &cb_num](const boost::system::error_code& ec,
-                        const HttpResponsePtr& response,
-                        const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-        // In this particular case we know exactly the type of the
-        // IO error returned, because the client explicitly sets this
-        // error code.
-        EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
-        // There should be no response returned.
-        EXPECT_FALSE(response);
-    }, HttpClient::RequestTimeout(100)));
-
-    // Create another request after the timeout. It should be handled ok.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
-                    [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
-               const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testClientRequestTimeout());
 }
 
 // Test that client times out when it doesn't receive the entire response
 // from the server within a desired time.
 TEST_F(HttpClientTest, clientRequestTimeoutMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    unsigned cb_num = 0;
-
-    // Create the request which asks the server to generate a partial
-    // (although well formed) response. The client will be waiting for the
-    // rest of the response to be provided and will eventually time out.
-    PostHttpRequestJsonPtr request1 = createRequest("partial-response", true);
-    HttpResponseJsonPtr response1(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
-        [this, &cb_num](const boost::system::error_code& ec,
-                        const HttpResponsePtr& response,
-                        const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-        // In this particular case we know exactly the type of the
-        // IO error returned, because the client explicitly sets this
-        // error code.
-        EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
-        // There should be no response returned.
-        EXPECT_FALSE(response);
-    }, HttpClient::RequestTimeout(100)));
-
-    // Create another request after the timeout. It should be handled ok.
-    PostHttpRequestJsonPtr request2 = createRequest("sequence", 1);
-    HttpResponseJsonPtr response2(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
-                    [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
-               const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testClientRequestTimeout());
 }
 
 // This test verifies the behavior of the HTTP client when the premature
@@ -2170,109 +2056,13 @@ TEST_F(HttpClientTest, clientRequestLateStartQueueMultiThreading) {
 
 // Test that client times out when connection takes too long.
 TEST_F(HttpClientTest, clientConnectTimeout) {
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    unsigned cb_num = 0;
-
-    PostHttpRequestJsonPtr request = createRequest("sequence", 1);
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this, &cb_num](const boost::system::error_code& ec,
-                        const HttpResponsePtr& response,
-                        const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-        // In this particular case we know exactly the type of the
-        // IO error returned, because the client explicitly sets this
-        // error code.
-        EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
-        // There should be no response returned.
-        EXPECT_FALSE(response);
-
-    }, HttpClient::RequestTimeout(100),
-
-       // This callback is invoked upon an attempt to connect to the
-       // server. The false value indicates to the HttpClient to not
-       // try to send a request to the server. This simulates the
-       // case of connect() taking very long and should eventually
-       // cause the transaction to time out.
-       [](const boost::system::error_code& /*ec*/, int) {
-           return (false);
-    }));
-
-    // Create another request after the timeout. It should be handled ok.
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-                    [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
-               const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testClientConnectTimeout());
 }
 
 // Test that client times out when connection takes too long.
 TEST_F(HttpClientTest, clientConnectTimeoutMultiThreading) {
     MultiThreadingMgr::instance().setMode(true);
-    // Start the server.
-    ASSERT_NO_THROW(listener_.start());
-
-    // Create the client.
-    HttpClient client(io_service_);
-
-    // Specify the URL of the server.
-    Url url("http://127.0.0.1:18123");
-
-    unsigned cb_num = 0;
-
-    PostHttpRequestJsonPtr request = createRequest("sequence", 1);
-    HttpResponseJsonPtr response(new HttpResponseJson());
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-        [this, &cb_num](const boost::system::error_code& ec,
-                        const HttpResponsePtr& response,
-                        const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-        // In this particular case we know exactly the type of the
-        // IO error returned, because the client explicitly sets this
-        // error code.
-        EXPECT_TRUE(ec.value() == boost::asio::error::timed_out);
-        // There should be no response returned.
-        EXPECT_FALSE(response);
-
-    }, HttpClient::RequestTimeout(100),
-
-       // This callback is invoked upon an attempt to connect to the
-       // server. The false value indicates to the HttpClient to not
-       // try to send a request to the server. This simulates the
-       // case of connect() taking very long and should eventually
-       // cause the transaction to time out.
-       [](const boost::system::error_code& /*ec*/, int) {
-           return (false);
-    }));
-
-    // Create another request after the timeout. It should be handled ok.
-    ASSERT_NO_THROW(client.asyncSendRequest(url, request, response,
-                    [this, &cb_num](const boost::system::error_code& /*ec*/, const HttpResponsePtr&,
-               const std::string&) {
-        if (++cb_num > 1) {
-            io_service_.stop();
-        }
-    }));
-
-    // Actually trigger the requests.
-    ASSERT_NO_THROW(runIOService());
+    ASSERT_NO_FATAL_FAILURE(testClientConnectTimeout());
 }
 
 /// Tests that connect and close callbacks work correctly.