1 // Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #include <communication_state.h> 8 #include <ha_config.h> 9 #include <ha_config_parser.h> 10 #include <asiolink/io_service.h> 11 #include <cc/data.h> 12 #include <dhcp/duid.h> 13 #include <dhcp/hwaddr.h> 14 #include <dhcp/pkt4.h> 15 #include <dhcp/pkt6.h> 16 #include <dhcpsrv/network_state.h> 17 #include <hooks/libinfo.h> 18 #include <boost/shared_ptr.hpp> 19 #include <gtest/gtest.h> 20 #include <cstdint> 21 #include <functional> 22 #include <string> 23 #include <vector> 24 #include <mutex> 25 #include <condition_variable> 26 #include <thread> 27 28 namespace isc { 29 namespace ha { 30 namespace test { 31 32 /// @brief Derivation of the @c CommunicationState class which allows 33 /// for modifications of poke time. 34 /// 35 /// @tparam @c CommunicationState4 or @c CommunicationState6. 36 template<typename StateType> 37 class NakedCommunicationState : public StateType { 38 public: 39 40 /// @brief Constructor. 41 /// 42 /// @param io_service pointer to the IO service object. NakedCommunicationState(const asiolink::IOServicePtr & io_service,const HAConfigPtr & config)43 explicit NakedCommunicationState(const asiolink::IOServicePtr& io_service, 44 const HAConfigPtr& config) 45 : StateType(io_service, config) { 46 } 47 48 /// @brief Checks if the object was poked recently. 49 /// 50 /// @return true if the object was poked less than 5 seconds ago, 51 /// false otherwise. isPoked()52 bool isPoked() const { 53 return (StateType::getDurationInMillisecs() < 5000); 54 } 55 56 using StateType::config_; 57 using StateType::timer_; 58 using StateType::clock_skew_; 59 using StateType::last_clock_skew_warn_; 60 using StateType::my_time_at_skew_; 61 using StateType::partner_time_at_skew_; 62 using StateType::unsent_update_count_; 63 }; 64 65 /// @brief Type of the NakedCommunicationState for DHCPv4. 66 typedef NakedCommunicationState<CommunicationState4> NakedCommunicationState4; 67 68 /// @brief Type of the pointer to the @c NakedCommunicationState4. 69 typedef boost::shared_ptr<NakedCommunicationState4> NakedCommunicationState4Ptr; 70 71 /// @brief Type of the NakedCommunicationState for DHCPv6. 72 typedef NakedCommunicationState<CommunicationState6> NakedCommunicationState6; 73 74 /// @brief Type of the pointer to the @c NakedCommunicationState6. 75 typedef boost::shared_ptr<NakedCommunicationState6> NakedCommunicationState6Ptr; 76 77 /// @brief General test fixture class for all HA unittests. 78 /// 79 /// It provides basic functions to load and unload HA hooks library. 80 /// All test classes should derive from this class. 81 class HATest : public ::testing::Test { 82 public: 83 84 /// @brief Constructor. 85 HATest(); 86 87 /// @brief Destructor. 88 virtual ~HATest(); 89 90 /// @brief Calls dhcp4_srv_configured callout to set IO service pointer. 91 void startHAService(); 92 93 /// @brief Runs IO service for a specified amount of time. 94 /// 95 /// @param ms number of milliseconds for which the IO service should be 96 /// run. 97 void runIOService(long ms); 98 99 /// @brief Runs IO service until timeout occurs or until provided method 100 /// returns true. 101 /// 102 /// @param ms number of milliseconds for which the IO service should be 103 /// run. 104 /// @param stop_condition pointer to the function which returns true if 105 /// when the IO service should be stopped. 106 void runIOService(long ms, std::function<bool()> stop_condition); 107 108 /// @brief Runs IO service in a thread. 109 /// 110 /// @return Shared pointer to the thread. 111 boost::shared_ptr<std::thread> runIOServiceInThread(); 112 113 /// @brief Executes commands while running IO service in a thread. 114 /// 115 /// @param commands pointer to a function to be executed while IO service 116 /// is run in thread. 117 void testSynchronousCommands(std::function<void()> commands); 118 119 protected: 120 121 /// @brief Signals that the IO service is running. 122 /// 123 /// @param running reference to the flag which is set to true when the 124 /// IO service starts running and executes this function. 125 /// @param mutex reference to the mutex used for synchronization. 126 /// @param condvar reference to condition variable used for synchronization. 127 void signalServiceRunning(bool& running, std::mutex& mutex, 128 std::condition_variable& condvar); 129 130 public: 131 132 /// @brief Handler for timeout during runIOService invocation. 133 /// 134 /// @param [out] stop_flag set to true when the handler is invoked. 135 void stopIOServiceHandler(bool& stop_flag); 136 137 /// @brief Return HA configuration with three servers in JSON format. 138 /// 139 /// @param ha_mode HA operation mode (default is load balancing). 140 /// @return Pointer to the unparsed configuration. 141 data::ConstElementPtr 142 createValidJsonConfiguration(const HAConfig::HAMode& ha_mode = 143 HAConfig::LOAD_BALANCING) const; 144 145 /// @brief Return HA configuration with one primary and two backup 146 /// servers in the JSON format. 147 /// 148 /// @return Pointer to the unparsed configuration. 149 data::ConstElementPtr 150 createValidPassiveBackupJsonConfiguration() const; 151 152 /// @brief Return HA configuration with three servers. 153 /// 154 /// @param ha_mode HA operation mode (default is load balancing). 155 /// @return Pointer to the parsed configuration. 156 HAConfigPtr createValidConfiguration(const HAConfig::HAMode& ha_mode = 157 HAConfig::LOAD_BALANCING) const; 158 159 /// @brief Return passive-backup configuration. 160 /// 161 /// @return Pointer to the parsed configuration. 162 HAConfigPtr createValidPassiveBackupConfiguration() const; 163 164 /// @brief Checks the status code and message against expected values. 165 /// 166 /// @param answer Element set containing an integer response and string 167 /// comment. 168 /// @param exp_status Status code against which to compare the status. 169 /// @param exp_txt Expected text (not checked if empty) 170 void checkAnswer(const isc::data::ConstElementPtr& answer, 171 const int exp_status, 172 const std::string& exp_txt = ""); 173 174 /// @brief Creates an identifier of arbitrary size with random values. 175 /// 176 /// This function is useful in generating random client identifiers and 177 /// HW addresses for load balancing tests. 178 /// 179 /// @param key_size Size of the generated random identifier. 180 std::vector<uint8_t> randomKey(const size_t key_size) const; 181 182 /// @brief Generates simple DHCPv4 message. 183 /// 184 /// @param msg_type DHCPv4 message type to be created. 185 /// @param hw_address_seed value from which HW address will be generated. 186 /// @param client_id_seed value from which client identifier will be 187 /// generated. 188 /// @param secs value to be stored in the "secs" field of the DHCPv4 message. 189 /// 190 /// @return Pointer to the created message. 191 dhcp::Pkt4Ptr createMessage4(const uint8_t msg_type, 192 const uint8_t hw_address_seed, 193 const uint8_t client_id_seed, 194 const uint16_t secs) const; 195 196 /// @brief Creates test DHCPv4 query instance. 197 /// 198 /// @param hw_address_text HW address to be included in the query. It is 199 /// used in load balancing. 200 /// 201 /// @return Pointer to the DHCPv4 query instance. 202 dhcp::Pkt4Ptr createQuery4(const std::string& hw_address_text) const; 203 204 /// @brief Creates test DHCPv4 query instance. 205 /// 206 /// @param hw_address HW address to be included in the query. It is used 207 /// in load balancing. 208 /// @param client_id optional client identifier. 209 dhcp::Pkt4Ptr createQuery4(const std::vector<uint8_t>& hw_address, 210 const std::vector<uint8_t>& client_id = 211 std::vector<uint8_t>()) const; 212 213 /// @brief Creates test DHCPv6 query instance. 214 /// 215 /// @param duid DUI to be included in the query. It is used in load balancing. 216 dhcp::Pkt6Ptr createQuery6(const std::vector<uint8_t>& duid) const; 217 218 /// @brief Generates simple DHCPv6 message. 219 /// 220 /// @param msg_type DHCPv6 message type to be created. 221 /// @param duid value from which DUID will be generated. 222 /// @param elapsed_time value of the Elapsed Time option. 223 /// 224 /// @return Pointer to the created message. 225 dhcp::Pkt6Ptr createMessage6(const uint8_t msg_type, 226 const uint8_t duid_seed, 227 const uint16_t elapsed_time) const; 228 229 /// @brief Sets the DHCP multi-threading configuration in staging SrvConfig. 230 /// 231 /// @param enable_multi_threading value that maps to enable-multi-threading. 232 /// @param thread_pool_size value that maps to thread-pool-size. 233 /// @param queue_size value that maps to queue-size. 234 void setDHCPMultiThreadingConfig(bool enable_multi_threading, 235 uint32_t thread_pool_size = 0, 236 uint32_t queue_size = 16); 237 238 /// @brief Constructs JSON string for HA "multi-threading" element. 239 /// 240 /// Constructs a JSON string with the following content: 241 /// 242 /// ``` 243 /// "multi-threading" { 244 /// "enable-multi-threading": <bool>, 245 /// "dedicated-http-listener": <bool>, 246 /// "http-listener-threads": <int>, 247 /// "http-client-threads": <int> 248 /// }" 249 /// ``` 250 /// 251 /// @param enable_multi_threading value for enable-multi-threading. 252 /// @param http_dedicated_listener value for dedicated-http-listener. 253 /// @param http_listener_threads value for http-listener-threads 254 /// @param http_client_threads value for http-client-threads 255 /// 256 /// @return JSON string 257 std::string makeHAMtJson(bool enable_multi_threading, 258 bool http_dedicated_listener, 259 uint32_t http_listener_threads, 260 uint32_t http_client_threads); 261 262 /// @brief Creates test DHCPv6 query instance. 263 /// 264 /// @param duid_text DUID to be included in the query. It is used in load 265 /// balancing. 266 /// 267 /// @return Pointer to the DHCPv6 query instance. 268 dhcp::Pkt6Ptr createQuery6(const std::string& duid_text) const; 269 270 /// @brief Pointer to the IO service used in the tests. 271 asiolink::IOServicePtr io_service_; 272 273 /// @brief Object holding a state of the DHCP service. 274 dhcp::NetworkStatePtr network_state_; 275 }; 276 277 } // end of namespace isc::ha::test 278 } // end of namespace isc::ha 279 } // end of namespace isc 280