generic_host_data_source_unittest.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. // Copyright (C) 2015-2017 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. #ifndef GENERIC_HOST_DATA_SOURCE_UNITTEST_H
  7. #define GENERIC_HOST_DATA_SOURCE_UNITTEST_H
  8. #include <asiolink/io_address.h>
  9. #include <dhcpsrv/base_host_data_source.h>
  10. #include <dhcpsrv/host.h>
  11. #include <dhcp/classify.h>
  12. #include <dhcp/option.h>
  13. #include <boost/algorithm/string/join.hpp>
  14. #include <boost/shared_ptr.hpp>
  15. #include <gtest/gtest.h>
  16. #include <sstream>
  17. #include <vector>
  18. namespace isc {
  19. namespace dhcp {
  20. namespace test {
  21. /// @brief Test Fixture class with utility functions for HostDataSource backends
  22. ///
  23. /// It contains utility functions for test purposes.
  24. /// All concrete HostDataSource test classes should be derived from it.
  25. class GenericHostDataSourceTest : public ::testing::Test {
  26. public:
  27. /// @brief Universe (V4 or V6).
  28. enum Universe {
  29. V4,
  30. V6
  31. };
  32. /// @brief Options to be inserted into a host.
  33. ///
  34. /// Parameter of this type is passed to the @ref addTestOptions to
  35. /// control which option types should be inserted into a host.
  36. enum AddedOptions {
  37. DHCP4_ONLY,
  38. DHCP6_ONLY,
  39. DHCP4_AND_DHCP6
  40. };
  41. /// @brief Default constructor.
  42. GenericHostDataSourceTest();
  43. /// @brief Virtual destructor.
  44. virtual ~GenericHostDataSourceTest();
  45. /// @brief Creates a host reservation for specified IPv4 address.
  46. ///
  47. /// @param address IPv4 address to be set
  48. /// @param id Identifier type.
  49. ///
  50. /// @return generated Host object
  51. HostPtr initializeHost4(const std::string& address,
  52. const Host::IdentifierType& id);
  53. /// @brief Creates a host reservation for specified IPv6 address.
  54. ///
  55. /// @param address IPv6 address to be reserved
  56. /// @param id type of identifier (IDENT_DUID or IDENT_HWADDR are supported)
  57. /// @param prefix reservation type (true = prefix, false = address)
  58. /// @param new_identifier Boolean value indicating if new host
  59. /// identifier should be generated or the same as previously.
  60. ///
  61. /// @return generated Host object
  62. HostPtr initializeHost6(std::string address, Host::IdentifierType id,
  63. bool prefix, bool new_identifier = true);
  64. /// @brief Generates a hardware address in text version.
  65. ///
  66. /// @param increase A boolean value indicating if new address (increased)
  67. /// must be generated or the same address as previously.
  68. /// @return HW address in textual form acceptable by Host constructor
  69. std::vector<uint8_t> generateHWAddr(const bool new_identifier = true);
  70. /// @brief Generates a host identifier in a textual form..
  71. ///
  72. /// @param increase A boolean value indicating if new identifier (increased)
  73. /// must be generated or the same identifier as previously.
  74. /// @return Identifier in textual form acceptable by Host constructor
  75. std::vector<uint8_t> generateIdentifier(const bool new_identifier = true);
  76. /// @brief Compares hardware addresses of the two hosts.
  77. ///
  78. /// This method compares two hardware address and uses gtest
  79. /// macros to signal unexpected (mismatch if expect_match is true;
  80. /// match if expect_match is false) values.
  81. ///
  82. /// @param host1 first host to be compared
  83. /// @param host2 second host to be compared
  84. /// @param expect_match true = HW addresses expected to be the same,
  85. /// false = HW addresses expected to be different
  86. void
  87. compareHwaddrs(const ConstHostPtr& host1, const ConstHostPtr& host2,
  88. bool expect_match);
  89. /// @brief Compares DUIDs of the two hosts.
  90. ///
  91. /// This method compares two DUIDs (client-ids) and uses gtest
  92. /// macros to signal unexpected (mismatch if expect_match is true;
  93. /// match if expect_match is false) values.
  94. ///
  95. /// @param host1 first host to be compared
  96. /// @param host2 second host to be compared
  97. /// @param expect_match true = DUIDs expected to be the same,
  98. /// false = DUIDs expected to be different
  99. void
  100. compareDuids(const ConstHostPtr& host1, const ConstHostPtr& host2,
  101. bool expect_match);
  102. /// @brief Compares two hosts
  103. ///
  104. /// This method uses gtest macros to signal errors.
  105. ///
  106. /// @param host1 first host to compare
  107. /// @param host2 second host to compare
  108. void compareHosts(const ConstHostPtr& host1, const ConstHostPtr& host2);
  109. /// @brief Compares two IPv6 reservation lists.
  110. ///
  111. /// This method uses gtest macros to signal errors.
  112. ///
  113. /// @param resv1 first IPv6 reservations list
  114. /// @param resv2 second IPv6 reservations list
  115. void compareReservations6(IPv6ResrvRange resv1, IPv6ResrvRange resv2);
  116. /// @brief Compares two client classes
  117. ///
  118. /// This method uses gtest macros to signal errors.
  119. ///
  120. /// @param classes1 first list of client classes
  121. /// @param classes2 second list of client classes
  122. void compareClientClasses(const ClientClasses& classes1,
  123. const ClientClasses& classes2);
  124. /// @brief Compares options within two configurations.
  125. ///
  126. /// This method uses gtest macros to signal errors.
  127. ///
  128. /// @param cfg1 First configuration.
  129. /// @param cfg2 Second configuration.
  130. void compareOptions(const ConstCfgOptionPtr& cfg1,
  131. const ConstCfgOptionPtr& cfg2) const;
  132. /// @brief Creates an opton descriptor holding an empty option.
  133. ///
  134. /// @param universe V4 or V6.
  135. /// @param option_type Option type.
  136. /// @param persist A boolean flag indicating if the option is always
  137. /// returned to the client or only when requested.
  138. ///
  139. /// @return Descriptor holding an empty option.
  140. OptionDescriptor createEmptyOption(const Option::Universe& universe,
  141. const uint16_t option_type,
  142. const bool persist) const;
  143. /// @brief Creates an instance of the option for which it is possible to
  144. /// specify universe, option type, persistence flag and value in
  145. /// the constructor.
  146. ///
  147. /// Examples of options that can be created using this function are:
  148. /// - @ref OptionString
  149. /// - different variants of @ref OptionInt.
  150. ///
  151. /// @param universe V4 or V6.
  152. /// @param option_type Option type.
  153. /// @param persist A boolean flag indicating if the option is always
  154. /// returned to the client or only when requested.
  155. /// @param formatted A boolean value selecting if the formatted option
  156. /// value should be used (if true), or binary value (if false).
  157. /// @param value Option value to be assigned to the option.
  158. /// @tparam OptionType Class encapsulating the option.
  159. /// @tparam DataType Option value data type.
  160. ///
  161. /// @return Descriptor holding an instance of the option created.
  162. template<typename OptionType, typename DataType>
  163. OptionDescriptor createOption(const Option::Universe& universe,
  164. const uint16_t option_type,
  165. const bool persist,
  166. const bool formatted,
  167. const DataType& value) const {
  168. boost::shared_ptr<OptionType> option(new OptionType(universe, option_type,
  169. value));
  170. std::ostringstream s;
  171. if (formatted) {
  172. // Using formatted option value. Convert option value to a
  173. // textual format.
  174. s << value;
  175. }
  176. OptionDescriptor desc(option, persist, s.str());
  177. return (desc);
  178. }
  179. /// @brief Creates an instance of the option for which it is possible to
  180. /// specify option type, persistence flag and value in the constructor.
  181. ///
  182. /// Examples of options that can be created using this function are:
  183. /// - @ref Option4AddrLst
  184. /// - @ref Option6AddrLst
  185. ///
  186. /// @param option_type Option type.
  187. /// @param persist A boolean flag indicating if the option is always
  188. /// returned to the client or only when requested.
  189. /// @param formatted A boolean value selecting if the formatted option
  190. /// value should be used (if true), or binary value (if false).
  191. /// @param value Option value to be assigned to the option.
  192. /// @tparam OptionType Class encapsulating the option.
  193. /// @tparam DataType Option value data type.
  194. ///
  195. /// @return Descriptor holding an instance of the option created.
  196. template<typename OptionType, typename DataType>
  197. OptionDescriptor createOption(const uint16_t option_type,
  198. const bool persist,
  199. const bool formatted,
  200. const DataType& value) const {
  201. boost::shared_ptr<OptionType> option(new OptionType(option_type, value));
  202. std::ostringstream s;
  203. if (formatted) {
  204. // Using formatted option value. Convert option value to a
  205. // textual format.
  206. s << value;
  207. }
  208. OptionDescriptor desc(option, persist, s.str());
  209. return (desc);
  210. }
  211. /// @brief Creates an instance of the option holding list of IP addresses.
  212. ///
  213. /// @param option_type Option type.
  214. /// @param persist A boolean flag indicating if the option is always
  215. /// returned to the client or only when requested.
  216. /// @param formatted A boolean value selecting if the formatted option
  217. /// value should be used (if true), or binary value (if false).
  218. /// @param address1 First address to be included. If address is empty, it is
  219. /// not included.
  220. /// @param address2 Second address to be included. If address is empty, it
  221. /// is not included.
  222. /// @param address3 Third address to be included. If address is empty, it
  223. /// is not included.
  224. /// @tparam OptionType Class encapsulating the option.
  225. ///
  226. /// @return Descriptor holding an instance of the option created.
  227. template<typename OptionType>
  228. OptionDescriptor
  229. createAddressOption(const uint16_t option_type,
  230. const bool persist,
  231. const bool formatted,
  232. const std::string& address1 = "",
  233. const std::string& address2 = "",
  234. const std::string& address3 = "") const {
  235. std::ostringstream s;
  236. // First address.
  237. typename OptionType::AddressContainer addresses;
  238. if (!address1.empty()) {
  239. addresses.push_back(asiolink::IOAddress(address1));
  240. if (formatted) {
  241. s << address1;
  242. }
  243. }
  244. // Second address.
  245. if (!address2.empty()) {
  246. addresses.push_back(asiolink::IOAddress(address2));
  247. if (formatted) {
  248. if (s.tellp() != std::streampos(0)) {
  249. s << ",";
  250. }
  251. s << address2;
  252. }
  253. }
  254. // Third address.
  255. if (!address3.empty()) {
  256. addresses.push_back(asiolink::IOAddress(address3));
  257. if (formatted) {
  258. if (s.tellp() != std::streampos(0)) {
  259. s << ",";
  260. }
  261. s << address3;
  262. }
  263. }
  264. boost::shared_ptr<OptionType> option(new OptionType(option_type,
  265. addresses));
  266. OptionDescriptor desc(option, persist, s.str());
  267. return (desc);
  268. }
  269. /// @brief Returns number of entries in the v4 options table.
  270. ///
  271. /// This utility method is expected to be implemented by specific backends.
  272. /// The code here is just a boilerplate for backends that do not store
  273. /// host options in a table.
  274. ///
  275. /// @param number of existing entries in options table
  276. virtual int countDBOptions4() {
  277. return (-1);
  278. }
  279. /// @brief Returns number of entries in the v6 options table.
  280. ///
  281. /// This utility method is expected to be implemented by specific backends.
  282. /// The code here is just a boilerplate for backends that do not store
  283. /// host options in a table.
  284. ///
  285. /// @param number of existing entries in options table
  286. virtual int countDBOptions6() {
  287. return (-1);
  288. }
  289. /// @brief Returns number of entries in the v6 reservations table.
  290. ///
  291. /// This utility method is expected to be implemented by specific backends.
  292. /// The code here is just a boilerplate for backends that do not store
  293. /// v6 reservations in a table.
  294. ///
  295. /// @param number of existing entries in v6_reservations table
  296. virtual int countDBReservations6() {
  297. return (-1);
  298. }
  299. /// @brief Creates an instance of the vendor option.
  300. ///
  301. /// @param universe V4 or V6.
  302. /// @param persist A boolean flag indicating if the option is always
  303. /// returned to the client or only when requested.
  304. /// @param formatted A boolean value selecting if the formatted option
  305. /// value should be used (if true), or binary value (if false).
  306. /// @param vendor_id Vendor identifier.
  307. ///
  308. /// @return Descriptor holding an instance of the option created.
  309. OptionDescriptor createVendorOption(const Option::Universe& universe,
  310. const bool persist,
  311. const bool formatted,
  312. const uint32_t vendor_id) const;
  313. /// @brief Adds multiple options into the host.
  314. ///
  315. /// This method creates the following options into the host object:
  316. /// - DHCPv4 boot file name option,
  317. /// - DHCPv4 default ip ttl option,
  318. /// - DHCPv4 option 1 within vendor-encapsulated-options space,
  319. /// - DHCPv4 option 254 with a single IPv4 address,
  320. /// - DHCPv4 option 1 within isc option space,
  321. /// - DHCPv6 boot file url option,
  322. /// - DHCPv6 information refresh time option,
  323. /// - DHCPv6 vendor option with vendor id 2495,
  324. /// - DHCPv6 option 1024, with a sigle IPv6 address,
  325. /// - DHCPv6 empty option 1, within isc2 option space,
  326. /// - DHCPv6 option 2, within isc2 option space with 3 IPv6 addresses,
  327. ///
  328. /// This method also creates option definitions for the non-standard
  329. /// options and registers them in the LibDHCP as runtime option
  330. /// definitions.
  331. ///
  332. /// @param host Host object into which options should be added.
  333. /// @param formatted A boolean value selecting if the formatted option
  334. /// value should be used (if true), or binary value (if false).
  335. /// @param added_options Controls which options should be inserted into
  336. /// a host: DHCPv4, DHCPv6 options or both.
  337. void addTestOptions(const HostPtr& host, const bool formatted,
  338. const AddedOptions& added_options) const;
  339. /// @brief Pointer to the host data source
  340. HostDataSourcePtr hdsptr_;
  341. /// @brief Test that backend can be started in read-only mode.
  342. ///
  343. /// Some backends can operate when the database is read only, e.g.
  344. /// host reservation tables are read only, or the database user has
  345. /// read only privileges on the entire database. In such cases, the
  346. /// Kea server administrator can specify in the backend configuration
  347. /// that the database should be opened in read only mode, i.e.
  348. /// INSERT, UPDATE, DELETE statements can't be issued. If any of the
  349. /// functions updating the database is called for the backend, the
  350. /// error is reported. The database running in read only mode can
  351. /// be merely used to retrieve existing host reservations from the
  352. /// database. This test verifies that this is the case.
  353. ///
  354. /// @param valid_db_type Parameter specifying type of backend to
  355. /// be used, e.g. type=mysql.
  356. void testReadOnlyDatabase(const char* valid_db_type);
  357. /// @brief Test that checks that simple host with IPv4 reservation
  358. /// can be inserted and later retrieved.
  359. ///
  360. /// Uses gtest macros to report failures.
  361. /// @param id Identifier type.
  362. void testBasic4(const Host::IdentifierType& id);
  363. /// @brief Test inserts several hosts with unique IPv4 address and
  364. /// checks that they can be retrieved properly.
  365. ///
  366. /// Uses gtest macros to report failures.
  367. /// @param id Identifier type.
  368. void testGetByIPv4(const Host::IdentifierType& id);
  369. /// @brief Test that hosts can be retrieved by host identifier.
  370. ///
  371. /// Uses gtest macros to report failures.
  372. void testGet4ByIdentifier(const Host::IdentifierType& identifier_type);
  373. /// @brief Test that clients with stored HW address can't be retrieved
  374. /// by DUID with the same value.
  375. ///
  376. /// Test procedure: add host reservation with hardware address X, try to retrieve
  377. /// host by client-identifier X, verify that the reservation is not returned.
  378. ///
  379. /// Uses gtest macros to report failures.
  380. void testHWAddrNotClientId();
  381. /// @brief Test that clients with stored DUID can't be retrieved
  382. /// by HW address of the same value.
  383. ///
  384. /// Test procedure: add host reservation with client identifier X, try to
  385. /// retrieve host by hardware address X, verify that the reservation is not
  386. /// returned.
  387. ///
  388. /// Uses gtest macros to report failures.
  389. void testClientIdNotHWAddr();
  390. /// @brief Test adds specified number of hosts with unique hostnames, then
  391. /// retrieves them and checks that the hostnames are set properly.
  392. ///
  393. /// Uses gtest macros to report failures.
  394. ///
  395. /// @param name hostname to be used (if n>1, numbers will be appended)
  396. /// @param num number of hostnames to be added.
  397. void testHostname(std::string name, int num);
  398. /// @brief Test inserts multiple reservations for the same host for different
  399. /// subnets and check that they can be retrieved properly.
  400. ///
  401. /// Uses gtest macros to report failures.
  402. ///
  403. /// @param subnets number of subnets to test
  404. /// @param id Host identifier type.
  405. void testMultipleSubnets(int subnets, const Host::IdentifierType& id);
  406. /// @brief Test inserts several hosts with unique IPv6 addresses and
  407. /// checks that they can be retrieved properly.
  408. ///
  409. /// Uses gtest macros to report failures.
  410. /// @param id type of the identifier to be used (IDENT_HWADDR or IDENT_DUID)
  411. /// @param prefix true - reserve IPv6 prefix, false - reserve IPv6 address
  412. void testGetByIPv6(Host::IdentifierType id, bool prefix);
  413. /// @brief Test inserts several hosts with unique prefixes and checks
  414. /// that the can be retrieved by subnet id and prefix value.
  415. void testGetBySubnetIPv6();
  416. /// @brief Test that hosts can be retrieved by hardware address.
  417. ///
  418. /// Uses gtest macros to report failures.
  419. void testGet6ByHWAddr();
  420. /// @brief Test that hosts can be retrieved by client-id
  421. ///
  422. /// Uses gtest macros to report failures.
  423. void testGet6ByClientId();
  424. /// @brief Test verifies if a host reservation can be stored with both
  425. /// IPv6 address and prefix.
  426. /// Uses gtest macros to report failures.
  427. void testAddr6AndPrefix();
  428. /// @brief Tests if host with multiple IPv6 reservations can be added and then
  429. /// retrieved correctly.
  430. void testMultipleReservations();
  431. /// @brief Tests if compareIPv6Reservations() method treats same pool of
  432. /// reservations but added in different order as equal.
  433. void testMultipleReservationsDifferentOrder();
  434. /// @brief Test if host reservations made for different IPv6 subnets
  435. /// are handled correctly.
  436. ///
  437. /// Uses gtest macros to report failures.
  438. ///
  439. /// @param subnets number of subnets to test
  440. /// @param id identifier type (IDENT_HWADDR or IDENT_DUID)
  441. void testSubnetId6(int subnets, Host::IdentifierType id);
  442. /// @brief Test if the duplicate host with same DUID can't be inserted.
  443. ///
  444. /// Uses gtest macros to report failures.
  445. void testAddDuplicate6WithSameDUID();
  446. /// @brief Test if the duplicate host with same HWAddr can't be inserted.
  447. ///
  448. /// Uses gtest macros to report failures.
  449. void testAddDuplicate6WithSameHWAddr();
  450. /// @brief Test if the duplicate IPv4 host with can't be inserted.
  451. ///
  452. /// Uses gtest macros to report failures.
  453. void testAddDuplicate4();
  454. /// @brief Test that DHCPv4 options can be inserted and retrieved from
  455. /// the database.
  456. ///
  457. /// Uses gtest macros to report failures.
  458. ///
  459. /// @param formatted Boolean value indicating if the option values
  460. /// should be stored in the textual format in the database.
  461. void testOptionsReservations4(const bool formatted);
  462. /// @brief Test that DHCPv6 options can be inserted and retrieved from
  463. /// the database.
  464. ///
  465. /// Uses gtest macros to report failures.
  466. ///
  467. /// @param formatted Boolean value indicating if the option values
  468. /// should be stored in the textual format in the database.
  469. void testOptionsReservations6(const bool formatted);
  470. /// @brief Test that DHCPv4 and DHCPv6 options can be inserted and retrieved
  471. /// with a single query to the database.
  472. ///
  473. /// Uses gtest macros to report failures.
  474. ///
  475. /// @param formatted Boolean value indicating if the option values
  476. /// should be stored in the textual format in the database.
  477. void testOptionsReservations46(const bool formatted);
  478. /// @brief Test that multiple client classes for IPv4 can be inserted and
  479. /// retrieved for a given host reservation.
  480. ///
  481. /// Uses gtest macros to report failures.
  482. ///
  483. void testMultipleClientClasses4();
  484. /// @brief Test that multiple client classes for IPv6 can be inserted and
  485. /// retrieved for a given host reservation.
  486. ///
  487. /// Uses gtest macros to report failures.
  488. ///
  489. void testMultipleClientClasses6();
  490. /// @brief Test that multiple client classes for both IPv4 and IPv6 can
  491. /// be inserted and retrieved for a given host reservation.
  492. ///
  493. /// Uses gtest macros to report failures.
  494. ///
  495. void testMultipleClientClassesBoth();
  496. /// @brief Test that siaddr, sname, file fields can be retrieved
  497. /// from a database for a host.
  498. ///
  499. /// Uses gtest macros to report failures.
  500. void testMessageFields4();
  501. /// @brief Tests that delete(subnet-id, addr4) call works.
  502. ///
  503. /// Uses gtest macros to report failures.
  504. void testDeleteByAddr4();
  505. /// @brief Tests that delete(subnet4-id, identifier-type, identifier) works.
  506. ///
  507. /// Uses gtest macros to report failures.
  508. void testDeleteById4();
  509. /// @brief Tests that delete(subnet4-id, id-type, id) also deletes options.
  510. void testDeleteById4Options();
  511. /// @brief Tests that delete(subnet6-id, identifier-type, identifier) works.
  512. ///
  513. /// Uses gtest macros to report failures.
  514. void testDeleteById6();
  515. /// @brief Tests that delete(subnet6-id, id-type, id) also deletes options.
  516. ///
  517. /// Uses gtest macros to report failures.
  518. void testDeleteById6Options();
  519. /// @brief Returns DUID with identical content as specified HW address
  520. ///
  521. /// This method does not have any sense in real life and is only useful
  522. /// in testing corner cases in the database backends (e.g. whether the DB
  523. /// is able to tell the difference between hwaddr and duid)
  524. ///
  525. /// @param hwaddr hardware address to be copied
  526. /// @return duid with the same value as specified HW address
  527. DuidPtr HWAddrToDuid(const HWAddrPtr& hwaddr);
  528. /// @brief Returns HW address with identical content as specified DUID
  529. ///
  530. /// This method does not have any sense in real life and is only useful
  531. /// in testing corner cases in the database backends (e.g. whether the DB
  532. /// is able to tell the difference between hwaddr and duid)
  533. ///
  534. /// @param duid DUID to be copied
  535. /// @return HW address with the same value as specified DUID
  536. HWAddrPtr DuidToHWAddr(const DuidPtr& duid);
  537. };
  538. }; // namespace test
  539. }; // namespace dhcp
  540. }; // namespace isc
  541. #endif