diff --git a/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc b/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc index 22a045db72..35b4cfbb9c 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc @@ -59,30 +59,6 @@ public: " exception type"; } } - - /// @brief Replace a pattern in a configuration. - /// - /// @param config Configuration to patch. - /// @param from String to replace. - /// @param repl String which replaces all occurrences of from. - /// @result A copy of config where all occurrences of from were replaced - /// by repl. - std::string replaceInConfig(const std::string& config, - const std::string& from, - const std::string& repl) { - std::string result(config); - if (from.empty()) { - return (result); - } - for (;;) { - size_t where = result.find(from); - if (where == std::string::npos) { - return (result); - } - result.replace(where, from.size(), repl); - } - return (result); - } }; // Verifies that load balancing configuration is parsed correctly. @@ -1356,6 +1332,7 @@ TEST_F(HAConfigTest, tlsParameterInheritance) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"my-server\"," @@ -1403,6 +1380,7 @@ TEST_F(HAConfigTest, tlsParameterInheritance) { expected = TEST_CA_DIR; expected += "/kea-client.key"; EXPECT_EQ(expected, impl->getConfig()->getKeyFile().get()); + EXPECT_FALSE(impl->getConfig()->getRequireClientCerts()); // Check the first peer parameters: it inherits them from the global level. HAConfig::PeerConfigPtr cfg = impl->getConfig()->getThisServerConfig(); @@ -1448,6 +1426,7 @@ TEST_F(HAConfigTest, missingTrustAnchor) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," @@ -1483,6 +1462,7 @@ TEST_F(HAConfigTest, missingCertFile) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," @@ -1518,6 +1498,7 @@ TEST_F(HAConfigTest, missingKeyFile) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," @@ -1553,6 +1534,7 @@ TEST_F(HAConfigTest, badTrustAnchor) { " \"trust-anchor\": \"/this-file-does-not-exist\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," @@ -1592,6 +1574,7 @@ TEST_F(HAConfigTest, badCertFile) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"/this-file-does-not-exist\"," " \"key-file\": \"!CA!/kea-client.key\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," @@ -1631,6 +1614,7 @@ TEST_F(HAConfigTest, badKeyFile) { " \"trust-anchor\": \"!CA!/kea-ca.crt\"," " \"cert-file\": \"!CA!/kea-client.crt\"," " \"key-file\": \"/this-file-does-not-exist\"," + " \"require-client-certs\": false," " \"peers\": [" " {" " \"name\": \"server1\"," diff --git a/src/hooks/dhcp/high_availability/tests/ha_mt_unittest.cc b/src/hooks/dhcp/high_availability/tests/ha_mt_unittest.cc index 51ee2c2b52..3c3f32d541 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_mt_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_mt_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2021-2022 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 @@ -260,6 +260,124 @@ TEST_F(HAMtServiceTest, multiThreadingBasics) { } } +// Verifies multiThreadingBasics can be extended to use HTTPS/TLS> +TEST_F(HAMtServiceTest, multiThreadingTls) { + + // Build the HA JSON configuration. + std::stringstream ss; + ss << + "[" + " {" + " \"this-server-name\": \"server1\"," + " \"mode\": \"passive-backup\"," + " \"wait-backup-ack\": true," + " \"require-client-certs\": false," + " \"peers\": [" + " {" + " \"name\": \"server1\"," + " \"url\": \"https://127.0.0.1:8080/\"," + " \"role\": \"primary\"," + " \"trust-anchor\": \"!CA!/kea-ca.crt\"," + " \"cert-file\": \"!CA!/kea-server.crt\"," + " \"key-file\": \"!CA!/kea-server.key\"" + " }," + " {" + " \"name\": \"server2\"," + " \"url\": \"https://127.0.0.1:8081/\"," + " \"role\": \"backup\"," + " \"trust-anchor\": \"!CA!/kea-ca.crt\"," + " \"cert-file\": \"!CA!/kea-client.crt\"," + " \"key-file\": \"!CA!/kea-client.key\"" + " }" + " ]"; + + // Enable MT, listener, and 3 threads for both client and listener. + ss << "," << makeHAMtJson(true, true, 3, 3) << "}]"; + ConstElementPtr config_json; + const std::string& patched = replaceInConfig(ss.str(), "!CA!", + TEST_CA_DIR); + ASSERT_NO_THROW_LOG(config_json = Element::fromJSON(patched)); + + // Enable DHCP multi-threading configuration in CfgMgr with 3 threads. + setDHCPMultiThreadingConfig(true, 3); + + // Create the HA configuration + HAConfigPtr ha_config(new HAConfig()); + HAConfigParser parser; + ASSERT_NO_THROW_LOG(parser.parse(ha_config, config_json)); + + // Instantiate the service. + TestHAServicePtr service; + ASSERT_NO_THROW_LOG(service.reset(new TestHAService(io_service_, network_state_, + ha_config))); + // Multi-threading should be enabled. + ASSERT_TRUE(ha_config->getEnableMultiThreading()); + + // Now we'll start, pause, resume and stop a few times. + for (int i = 0; i < 3; ++i) { + // Verify we're stopped. + // Client should exist but be stopped. + ASSERT_TRUE(service->client_); + ASSERT_TRUE(service->client_->isStopped()); + if (i == 0) { + EXPECT_FALSE(service->client_->getThreadIOService()->stopped()); + } else { + EXPECT_TRUE(service->client_->getThreadIOService()->stopped()); + } + + // Listener should exist but be stopped. + ASSERT_TRUE(service->listener_); + ASSERT_TRUE(service->listener_->isStopped()); + EXPECT_FALSE(service->listener_->getThreadIOService()); + + // Start client and listener. + ASSERT_NO_THROW_LOG(service->startClientAndListener()); + + // Verify we've started. + // Client should be running. + ASSERT_TRUE(service->client_->isRunning()); + ASSERT_TRUE(service->client_->getThreadIOService()); + EXPECT_FALSE(service->client_->getThreadIOService()->stopped()); + EXPECT_EQ(service->client_->getThreadPoolSize(), 3); + EXPECT_EQ(service->client_->getThreadCount(), 3); + + // Listener should be running. + ASSERT_TRUE(service->listener_->isRunning()); + ASSERT_TRUE(service->listener_->getThreadIOService()); + EXPECT_FALSE(service->listener_->getThreadIOService()->stopped()); + EXPECT_EQ(service->listener_->getThreadPoolSize(), 3); + EXPECT_EQ(service->listener_->getThreadCount(), 3); + + { + // Entering a critical section should pause both client + // and listener. + MultiThreadingCriticalSection cs; + + // Client should be paused. + ASSERT_TRUE(service->client_->isPaused()); + EXPECT_TRUE(service->client_->getThreadIOService()->stopped()); + + // Listener should be paused. + ASSERT_TRUE(service->listener_->isPaused()); + EXPECT_TRUE(service->listener_->getThreadIOService()->stopped()); + } + + // Exiting critical section should resume both client + // and listener. + + // Client should be running. + ASSERT_TRUE(service->client_->isRunning()); + EXPECT_FALSE(service->client_->getThreadIOService()->stopped()); + + // Listener should be running. + ASSERT_TRUE(service->listener_->isRunning()); + EXPECT_FALSE(service->listener_->getThreadIOService()->stopped()); + + // Stop should succeed. + ASSERT_NO_THROW_LOG(service->stopClientAndListener()); + } +} + // Verifies permutations of HA+MT configuration and start-up. TEST_F(HAMtServiceTest, multiThreadingConfigStartup) { diff --git a/src/hooks/dhcp/high_availability/tests/ha_test.h b/src/hooks/dhcp/high_availability/tests/ha_test.h index ae2dde7590..a98646727e 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_test.h +++ b/src/hooks/dhcp/high_availability/tests/ha_test.h @@ -1,4 +1,4 @@ -// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2017-2022 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 @@ -235,6 +235,30 @@ public: uint32_t thread_pool_size = 0, uint32_t queue_size = 16); + /// @brief Replace a pattern in a configuration. + /// + /// @param config Configuration to patch. + /// @param from String to replace. + /// @param repl String which replaces all occurrences of from. + /// @result A copy of config where all occurrences of from were replaced + /// by repl. + std::string replaceInConfig(const std::string& config, + const std::string& from, + const std::string& repl) { + std::string result(config); + if (from.empty()) { + return (result); + } + for (;;) { + size_t where = result.find(from); + if (where == std::string::npos) { + return (result); + } + result.replace(where, from.size(), repl); + } + return (result); + } + /// @brief Constructs JSON string for HA "multi-threading" element. /// /// Constructs a JSON string with the following content: