]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#964,!577] Added unit tests
authorThomas Markwalder <tmark@isc.org>
Mon, 28 Oct 2019 17:50:10 +0000 (13:50 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 5 Nov 2019 16:23:48 +0000 (11:23 -0500)
src/lib/dhcp/tests/iface_mgr_unittest.cc
    Modified tests to verify that external socket callbacks receive
    the correct socket descriptor when invoked by IfaceMgr.

src/lib/http/tests/server_client_unittests.cc
    TEST_F(HttpClientTest, closeIfOutOfBandwidth) - new test to
    verifies HttpClient::closeIfOutOfBandwidth()

src/lib/dhcp/tests/iface_mgr_unittest.cc
src/lib/http/tests/server_client_unittests.cc

index bcb3552248d98f4ce79e72362c56136d3cf79bcd..b542a2e055546556a3d2f6b99ea9e9218204d210 100644 (file)
@@ -695,14 +695,18 @@ public:
         int pipefd[2];
         EXPECT_TRUE(pipe(pipefd) == 0);
         EXPECT_NO_THROW(ifacemgr->addExternalSocket(pipefd[0],
-                        [&callback_ok](int /* fd */){ callback_ok = true; }));
+                        [&callback_ok, &pipefd](int fd) {
+                            callback_ok = (pipefd[0] == fd);
+                        }));
 
 
         // Let's create a second pipe and register it as well
         int secondpipe[2];
         EXPECT_TRUE(pipe(secondpipe) == 0);
         EXPECT_NO_THROW(ifacemgr->addExternalSocket(secondpipe[0],
-                        [&callback2_ok](int /* fd */){ callback2_ok = true; }));
+                        [&callback2_ok, &secondpipe](int fd) {
+                            callback2_ok = (secondpipe[0] == fd);
+                        }));
 
         // Verify a call with no data and normal external sockets works ok.
         Pkt4Ptr pkt4;
@@ -778,14 +782,18 @@ public:
         int pipefd[2];
         EXPECT_TRUE(pipe(pipefd) == 0);
         EXPECT_NO_THROW(ifacemgr->addExternalSocket(pipefd[0],
-                        [&callback_ok](int /* fd*/){ callback_ok = true; }));
+                        [&callback_ok, &pipefd](int fd) {
+                            callback_ok = (pipefd[0] == fd);
+                        }));
 
 
         // Let's create a second pipe and register it as well
         int secondpipe[2];
         EXPECT_TRUE(pipe(secondpipe) == 0);
         EXPECT_NO_THROW(ifacemgr->addExternalSocket(secondpipe[0],
-                        [&callback2_ok](int /*fd */){ callback2_ok = true; }));
+                        [&callback2_ok, &secondpipe](int fd) {
+                            callback2_ok = (secondpipe[0] == fd);
+                        }));
 
         // Verify a call with no data and normal external sockets works ok.
         Pkt6Ptr pkt6;
index dd846eb131f959b9aa61d3f2e81e9f0b27ca5f35..7db256f2ea39bc5fef08b813e2ec83b149a805ce 100644 (file)
@@ -1402,6 +1402,7 @@ public:
             if (++resp_num > 1) {
                 io_service_.stop();
             }
+
             EXPECT_FALSE(ec);
         },
             HttpClient::RequestTimeout(10000),
@@ -1458,6 +1459,140 @@ public:
         EXPECT_EQ(-1, monitor.registered_fd_);
     }
 
+    /// @brief Tests detection and handling out-of-bandwidth socket events
+    ///
+    /// It initiates a transacation and verifies that a mid-transacation call
+    /// to HttpClient::closeIfOutOfBandwidth() has no affect on the connection.
+    /// After succesful completion of the transaction, a second call is made
+    /// HttpClient::closeIfOutOfBandwidth().  This should result in the connection
+    /// being closed.
+    /// This step is repeated to verify that after an OOB closure, transactions
+    /// to the same destination can be processed.
+    ///
+    /// Lastly, we verify that HttpClient::stop() closes the connection correctly.
+    ///
+    /// @param version HTTP version to be used.
+    void testCloseIfOutOfBandwidth(const HttpVersion& version) {
+        // Start the server.
+        ASSERT_NO_THROW(listener_.start());
+
+        // Create a client and specify the URL on which the server can be reached.
+        HttpClient client(io_service_);
+        Url url("http://127.0.0.1:18123");
+
+        // Initiate request to the server.
+        PostHttpRequestJsonPtr request1 = createRequest("sequence", 1, version);
+        HttpResponseJsonPtr response1(new HttpResponseJson());
+        unsigned resp_num = 0;
+        ExternalMonitor monitor;
+
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request1, response1,
+            [this, &client, &resp_num, &monitor](const boost::system::error_code& ec,
+                              const HttpResponsePtr&,
+                              const std::string&) {
+            if (++resp_num == 1) {
+                io_service_.stop();
+            }
+
+            EXPECT_EQ(1, monitor.connect_cnt_);      // We should have 1 connect.
+            EXPECT_EQ(0, monitor.close_cnt_);        // We should have 0 closes
+            ASSERT_GT(monitor.registered_fd_, -1);   // We should have a valid fd.
+            int orig_fd = monitor.registered_fd_;
+
+            // Test our socket for OOBness.
+            client.closeIfOutOfBandwidth(monitor.registered_fd_);
+
+            // Since we're in a transaction, we should have no closes and
+            // the same valid fd.
+            EXPECT_EQ(0, monitor.close_cnt_);
+            ASSERT_EQ(monitor.registered_fd_, orig_fd);
+
+            EXPECT_FALSE(ec);
+        },
+            HttpClient::RequestTimeout(10000),
+            boost::bind(&ExternalMonitor::connectHandler, &monitor, _1, _2),
+            boost::bind(&ExternalMonitor::closeHandler, &monitor, _1)
+        ));
+
+        // Actually trigger the requests. The requests should be handlded by the
+        // server one after another. While the first request is being processed
+        // the server should queue another one.
+        ASSERT_NO_THROW(runIOService());
+
+        // Make sure that we received a response.
+        ASSERT_TRUE(response1);
+        ConstElementPtr sequence1 = response1->getJsonElement("sequence");
+        ASSERT_TRUE(sequence1);
+        EXPECT_EQ(1, sequence1->intValue());
+
+        // We should have had 1 connect invocations, no closes
+        // and a valid registered fd
+        EXPECT_EQ(1, monitor.connect_cnt_);
+        EXPECT_EQ(0, monitor.close_cnt_);
+        EXPECT_GT(monitor.registered_fd_, -1);
+
+        // Test our socket for OOBness.
+        client.closeIfOutOfBandwidth(monitor.registered_fd_);
+
+        // Since we're in a transaction, we should have no closes and
+        // the same valid fd.
+        EXPECT_EQ(1, monitor.close_cnt_);
+        EXPECT_EQ(-1, monitor.registered_fd_);
+
+        // Now let's do another request to the destination to verify that
+        // we'll reopen the connection without issue.
+        PostHttpRequestJsonPtr request2 = createRequest("sequence", 2, version);
+        HttpResponseJsonPtr response2(new HttpResponseJson());
+        resp_num = 0;
+        ASSERT_NO_THROW(client.asyncSendRequest(url, request2, response2,
+            [this, &client, &resp_num, &monitor](const boost::system::error_code& ec,
+                              const HttpResponsePtr&,
+                              const std::string&) {
+            if (++resp_num == 1) {
+                io_service_.stop();
+            }
+
+            EXPECT_EQ(2, monitor.connect_cnt_);      // We should have 1 connect.
+            EXPECT_EQ(1, monitor.close_cnt_);        // We should have 0 closes
+            ASSERT_GT(monitor.registered_fd_, -1);   // We should have a valid fd.
+            int orig_fd = monitor.registered_fd_;
+
+            // Test our socket for OOBness.
+            client.closeIfOutOfBandwidth(monitor.registered_fd_);
+
+            // Since we're in a transaction, we should have no closes and
+            // the same valid fd.
+            EXPECT_EQ(1, monitor.close_cnt_);
+            ASSERT_EQ(monitor.registered_fd_, orig_fd);
+
+            EXPECT_FALSE(ec);
+        },
+            HttpClient::RequestTimeout(10000),
+            boost::bind(&ExternalMonitor::connectHandler, &monitor, _1, _2),
+            boost::bind(&ExternalMonitor::closeHandler, &monitor, _1)
+        ));
+
+        // Actually trigger the requests. The requests should be handlded by the
+        // server one after another. While the first request is being processed
+        // the server should queue another one.
+        ASSERT_NO_THROW(runIOService());
+
+        // Make sure that we received the second response.
+        ASSERT_TRUE(response2);
+        ConstElementPtr sequence2 = response2->getJsonElement("sequence");
+        ASSERT_TRUE(sequence2);
+        EXPECT_EQ(2, sequence2->intValue());
+
+        // Stopping the client the close the connection.
+        client.stop();
+
+        // We should have had 2 connect invocations, 2 closes
+        // and an invalid registered fd
+        EXPECT_EQ(2, monitor.connect_cnt_);
+        EXPECT_EQ(2, monitor.close_cnt_);
+        EXPECT_EQ(-1, monitor.registered_fd_);
+    }
+
     /// @brief Simulates external registery of Connection TCP sockets
     ///
     /// Provides methods compatible with Connection callbacks for connnect
@@ -1827,4 +1962,9 @@ TEST_F(HttpClientTest, connectCloseCallbacks) {
     ASSERT_NO_FATAL_FAILURE(testConnectCloseCallbacks(HttpVersion(1, 1)));
 }
 
+/// Tests that HttpClient::closeIfOutOfBandwidth works correctly.
+TEST_F(HttpClientTest, closeIfOutOfBandwidth) {
+    ASSERT_NO_FATAL_FAILURE(testCloseIfOutOfBandwidth(HttpVersion(1, 1)));
+}
+
 }