lease_file_loader_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <asiolink/io_address.h>
  16. #include <dhcpsrv/csv_lease_file4.h>
  17. #include <dhcpsrv/csv_lease_file6.h>
  18. #include <dhcpsrv/memfile_lease_storage.h>
  19. #include <dhcpsrv/lease_file_loader.h>
  20. #include <dhcpsrv/tests/lease_file_io.h>
  21. #include <boost/scoped_ptr.hpp>
  22. #include <gtest/gtest.h>
  23. #include <sstream>
  24. #include <string>
  25. using namespace isc;
  26. using namespace isc::asiolink;
  27. using namespace isc::dhcp;
  28. using namespace isc::dhcp::test;
  29. namespace {
  30. /// @brief Test fixture class for @c LeaseFileLoader class.
  31. class LeaseFileLoaderTest : public ::testing::Test {
  32. public:
  33. /// @brief Constructor.
  34. ///
  35. /// Initializes filename used for unit tests and creates an
  36. /// IO object to be used to write to this file.
  37. LeaseFileLoaderTest();
  38. /// @brief Prepends the absolute path to the file specified
  39. /// as an argument.
  40. ///
  41. /// @param filename Name of the file.
  42. /// @return Absolute path to the test file.
  43. static std::string absolutePath(const std::string& filename);
  44. /// @brief Retrieves the lease from the storage using an IP address.
  45. ///
  46. /// This method returns the pointer to the @c Lease4 or @c Lease6
  47. /// object representing the lease in the container. This is used to
  48. /// check if the lease was parsed in the lease file and added to the
  49. /// container by the @c LeaseFileLoader::load method.
  50. ///
  51. /// @param address A string representation of the leased address.
  52. /// @param storage A reference to the container in which the lease
  53. /// is to be searched.
  54. /// @tparam LeasePtrType Type of the returned object: @c Lease4Ptr
  55. /// @c Lease6Ptr.
  56. /// @tparam LeaseStorage Type of the container: @c Lease4Container
  57. /// @c Lease6Container.
  58. ///
  59. /// @return A pointer to the lease or NULL if no lease found.
  60. template<typename LeasePtrType, typename LeaseStorage>
  61. static LeasePtrType getLease(const std::string& address, const LeaseStorage& storage) {
  62. typedef typename LeaseStorage::template nth_index<0>::type SearchIndex;
  63. // Both Lease4Storage and Lease6Storage use index 0 to retrieve the
  64. // lease using an IP address.
  65. const SearchIndex& idx = storage.template get<0>();
  66. typename SearchIndex::iterator lease = idx.find(IOAddress(address));
  67. // Lease found. Return it.
  68. if (lease != idx.end()) {
  69. return (*lease);
  70. }
  71. // No lease found.
  72. return (LeasePtrType());
  73. }
  74. /// @brief Tests the write function.
  75. ///
  76. /// This method writes the leases from the storage container to the lease file
  77. /// then compares the output to the string provided in the arguments to verify
  78. /// the write was correct. The order of the leases in the output will depend
  79. /// on the order in which the container provides the leases.
  80. ///
  81. /// @param storage A reference to the container to be written to the file
  82. /// @param compare The string to compare to what was read from the file
  83. ///
  84. /// @tparam LeaseStorage Type of the container: @c Lease4Container
  85. /// @c Lease6Container.
  86. ///
  87. template<typename LeaseObjectType, typename LeaseFileType,
  88. typename StorageType>
  89. void writeLeases(LeaseFileType& lease_file,
  90. const StorageType& storage,
  91. const std::string& compare) {
  92. // Prepare for a new file, close and remove the old
  93. lease_file.close();
  94. io_.removeFile();
  95. // Write the current leases to the file
  96. LeaseFileLoader::write<LeaseObjectType, LeaseFileType, StorageType>
  97. (lease_file, storage);
  98. // Compare to see if we got what we exepcted.
  99. EXPECT_EQ(compare, io_.readFile());
  100. }
  101. /// @brief Name of the test lease file.
  102. std::string filename_;
  103. /// @brief Object providing access to lease file IO.
  104. LeaseFileIO io_;
  105. };
  106. LeaseFileLoaderTest::LeaseFileLoaderTest()
  107. : filename_("leases4.csv"), io_(absolutePath(filename_)) {
  108. }
  109. std::string
  110. LeaseFileLoaderTest::absolutePath(const std::string& filename) {
  111. std::ostringstream s;
  112. s << DHCP_DATA_DIR << "/" << filename;
  113. return (s.str());
  114. }
  115. // This test verifies that the DHCPv4 leases can be loaded from the lease
  116. // file and that only the most recent entry for each lease is loaded and
  117. // the previous entries are discarded.
  118. //
  119. // It also tests the write function by writing the storage to a file
  120. // and comparing that with the expected value.
  121. TEST_F(LeaseFileLoaderTest, loadWrite4) {
  122. // Create lease file with leases for 192.0.2.1, 192.0.3.15. The lease
  123. // entry for the 192.0.2.3 is invalid (lacks HW address) and should
  124. // be discarded.
  125. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  126. "fqdn_fwd,fqdn_rev,hostname\n"
  127. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
  128. "host.example.com\n"
  129. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
  130. "0,0,\n"
  131. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  132. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7,"
  133. "0,0,\n"
  134. "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1,"
  135. "host.example.com\n");
  136. boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
  137. ASSERT_NO_THROW(lf->open());
  138. // Load leases from the file.
  139. Lease4Storage storage;
  140. ASSERT_NO_THROW(LeaseFileLoader::load<Lease4>(*lf, storage, 10));
  141. // There are two unique leases.
  142. ASSERT_EQ(2, storage.size());
  143. // The lease for 192.0.2.1 should exist and the cltt should be
  144. // set to the expire-valid_lifetime for the second entry for
  145. // this lease, i.e. 500 - 200 = 300.
  146. Lease4Ptr lease = getLease<Lease4Ptr>("192.0.2.1", storage);
  147. ASSERT_TRUE(lease);
  148. EXPECT_EQ(300, lease->cltt_);
  149. // The invalid entry should not be loaded.
  150. lease = getLease<Lease4Ptr>("192.0.2.3", storage);
  151. ASSERT_FALSE(lease);
  152. // The other lease should be present and the cltt time should
  153. // be set according to the values in the second entry for this
  154. // lease.
  155. lease = getLease<Lease4Ptr>("192.0.3.15", storage);
  156. ASSERT_TRUE(lease);
  157. EXPECT_EQ(35, lease->cltt_);
  158. writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
  159. (*lf, storage,
  160. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  161. "fqdn_fwd,fqdn_rev,hostname\n"
  162. "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1,"
  163. "host.example.com\n"
  164. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7,"
  165. "0,0,\n");
  166. }
  167. // This test verifies that the lease with a valid lifetime of 0
  168. // is removed from the storage. The valid lifetime of 0 is set
  169. // for the released leases.
  170. //
  171. // It also tests the write function by writing the storage to a file
  172. // and comparing that with the expected value.
  173. TEST_F(LeaseFileLoaderTest, loadWrite4LeaseRemove) {
  174. // Create lease file in which one of the entries for 192.0.2.1
  175. // has a valid_lifetime of 0 and results in the deletion of the
  176. // lease.
  177. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  178. "fqdn_fwd,fqdn_rev,hostname\n"
  179. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
  180. "host.example.com\n"
  181. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
  182. "0,0,\n"
  183. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7,"
  184. "0,0,\n"
  185. "192.0.2.1,06:07:08:09:0a:bc,,0,500,8,1,1,"
  186. "host.example.com\n");
  187. boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
  188. ASSERT_NO_THROW(lf->open());
  189. Lease4Storage storage;
  190. ASSERT_NO_THROW(LeaseFileLoader::load<Lease4>(*lf, storage, 10));
  191. // There should only be one lease. The one with the valid_lifetime
  192. // of 0 should be removed.
  193. ASSERT_EQ(1, storage.size());
  194. Lease4Ptr lease = getLease<Lease4Ptr>("192.0.3.15", storage);
  195. ASSERT_TRUE(lease);
  196. EXPECT_EQ(35, lease->cltt_);
  197. writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
  198. (*lf, storage,
  199. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  200. "fqdn_fwd,fqdn_rev,hostname\n"
  201. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7,"
  202. "0,0,\n");
  203. }
  204. // This test verifies that the DHCPv6 leases can be loaded from the lease
  205. // file and that only the most recent entry for each lease is loaded and
  206. // the previous entries are discarded.
  207. //
  208. // It also tests the write function by writing the storage to a file
  209. // and comparing that with the expected value.
  210. TEST_F(LeaseFileLoaderTest, loadWrite6) {
  211. // Create a lease file with three valid leases: 2001:db8:1::1,
  212. // 3000:1:: and 2001:db8:2::10.
  213. io_.writeFile("address,duid,valid_lifetime,expire,subnet_id,"
  214. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  215. "fqdn_rev,hostname,hwaddr\n"
  216. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  217. "200,200,8,100,0,7,0,1,1,host.example.com,\n"
  218. "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,\n"
  219. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,300,6,150,"
  220. "0,8,0,0,0,,\n"
  221. "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2,"
  222. "16,64,0,0,,\n"
  223. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150,"
  224. "0,8,0,0,0,,\n"
  225. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  226. "200,400,8,100,0,7,0,1,1,host.example.com,\n");
  227. boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
  228. ASSERT_NO_THROW(lf->open());
  229. // Load leases from the lease file.
  230. Lease6Storage storage;
  231. ASSERT_NO_THROW(LeaseFileLoader::load<Lease6>(*lf, storage, 10));
  232. // There should be 3 unique leases.
  233. ASSERT_EQ(3, storage.size());
  234. // The 2001:db8:1::1 should be present and its cltt should be
  235. // calculated according to the expiration time and the valid
  236. // lifetime from the last entry for this lease: 400 - 200 = 200.
  237. Lease6Ptr lease = getLease<Lease6Ptr>("2001:db8:1::1", storage);
  238. ASSERT_TRUE(lease);
  239. EXPECT_EQ(200, lease->cltt_);
  240. // The 3000:1:: lease should be present.
  241. lease = getLease<Lease6Ptr>("3000:1::", storage);
  242. ASSERT_TRUE(lease);
  243. EXPECT_EQ(100, lease->cltt_);
  244. // The 2001:db8:2::10 should be present and the cltt should be
  245. // calculated according to the last entry in the lease file.
  246. lease = getLease<Lease6Ptr>("2001:db8:2::10", storage);
  247. ASSERT_TRUE(lease);
  248. EXPECT_EQ(500, lease->cltt_);
  249. writeLeases<Lease6, CSVLeaseFile6, Lease6Storage>
  250. (*lf, storage,
  251. "address,duid,valid_lifetime,expire,subnet_id,"
  252. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  253. "fqdn_rev,hostname,hwaddr\n"
  254. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  255. "200,400,8,100,0,7,0,1,1,host.example.com,\n"
  256. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150,"
  257. "0,8,0,0,0,,\n"
  258. "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2,"
  259. "16,64,0,0,,\n");
  260. }
  261. // This test verifies that the lease with a valid lifetime of 0
  262. // is removed from the storage. The valid lifetime of 0 set set
  263. // for the released leases.
  264. //
  265. // It also tests the write function by writing the storage to a file
  266. // and comparing that with the expected value.
  267. TEST_F(LeaseFileLoaderTest, loadWrite6LeaseRemove) {
  268. // Create lease file in which one of the entries for the 2001:db8:1::1
  269. // has valid lifetime set to 0, in which case the lease should be
  270. // deleted.
  271. io_.writeFile("address,duid,valid_lifetime,expire,subnet_id,"
  272. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  273. "fqdn_rev,hostname,hwaddr\n"
  274. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  275. "200,200,8,100,0,7,0,1,1,host.example.com,\n"
  276. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,300,6,150,"
  277. "0,8,0,0,0,,\n"
  278. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150,"
  279. "0,8,0,0,0,,\n"
  280. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  281. "0,400,8,100,0,7,0,1,1,host.example.com,\n");
  282. boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
  283. ASSERT_NO_THROW(lf->open());
  284. // Loaded leases.
  285. Lease6Storage storage;
  286. ASSERT_NO_THROW(LeaseFileLoader::load<Lease6>(*lf, storage, 10));
  287. // There should be only one lease for 2001:db8:2::10. The other one
  288. // should have been deleted (or rather not loaded).
  289. ASSERT_EQ(1, storage.size());
  290. Lease6Ptr lease = getLease<Lease6Ptr>("2001:db8:2::10", storage);
  291. ASSERT_TRUE(lease);
  292. EXPECT_EQ(500, lease->cltt_);
  293. writeLeases<Lease6, CSVLeaseFile6, Lease6Storage>
  294. (*lf, storage,
  295. "address,duid,valid_lifetime,expire,subnet_id,"
  296. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  297. "fqdn_rev,hostname,hwaddr\n"
  298. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150,"
  299. "0,8,0,0,0,,\n");
  300. }
  301. // This test verifies that the exception is thrown when the specific
  302. // number of errors in the test data occur during reading of the lease
  303. // file.
  304. TEST_F(LeaseFileLoaderTest, loadMaxErrors) {
  305. // Create a lease file for which there is a number of invalid
  306. // entries.
  307. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  308. "fqdn_fwd,fqdn_rev,hostname\n"
  309. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
  310. "host.example.com\n"
  311. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  312. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  313. "192.0.2.10,01:02:03:04:05:06,,200,300,8,1,1,,\n"
  314. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  315. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  316. "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1,"
  317. "host.example.com\n");
  318. boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
  319. ASSERT_NO_THROW(lf->open());
  320. // Load leases and set the maximum number of errors to 3. This
  321. // should result in an exception because there are 4 invalid entries.
  322. Lease4Storage storage;
  323. ASSERT_THROW(LeaseFileLoader::load<Lease4>(*lf, storage, 3),
  324. util::CSVFileError);
  325. lf->close();
  326. ASSERT_NO_THROW(lf->open());
  327. // Repeat the test, but this time allow for 4 invalid entries. It
  328. // should load just fine.
  329. storage.clear();
  330. ASSERT_NO_THROW(LeaseFileLoader::load<Lease4>(*lf, storage, 4));
  331. ASSERT_EQ(2, storage.size());
  332. Lease4Ptr lease = getLease<Lease4Ptr>("192.0.2.1", storage);
  333. ASSERT_TRUE(lease);
  334. EXPECT_EQ(300, lease->cltt_);
  335. lease = getLease<Lease4Ptr>("192.0.2.10", storage);
  336. ASSERT_TRUE(lease);
  337. EXPECT_EQ(100, lease->cltt_);
  338. }
  339. // This test verifies that the lease with a valid lifetime set to 0 is
  340. // not loaded if there are no previous entries for this lease in the
  341. // lease file.
  342. //
  343. // It also tests the write function by writing the storage to a file
  344. // and comparing that with the expected value.
  345. TEST_F(LeaseFileLoaderTest, loadWriteLeaseWithZeroLifetime) {
  346. // Create lease file. The second lease has a valid lifetime of 0.
  347. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  348. "fqdn_fwd,fqdn_rev,hostname\n"
  349. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,,\n"
  350. "192.0.2.3,06:07:08:09:0a:bd,,0,200,8,1,1,,\n");
  351. boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
  352. ASSERT_NO_THROW(lf->open());
  353. // Set the error count to 0 to make sure that lease with a zero
  354. // lifetime doesn't cause an error.
  355. Lease4Storage storage;
  356. ASSERT_NO_THROW(LeaseFileLoader::load<Lease4>(*lf, storage, 0));
  357. // The first lease should be present.
  358. Lease4Ptr lease = getLease<Lease4Ptr>("192.0.2.1", storage);
  359. ASSERT_TRUE(lease);
  360. EXPECT_EQ(0, lease->cltt_);
  361. // The lease with a valid lifetime of 0 should not be loaded.
  362. EXPECT_FALSE(getLease<Lease4Ptr>("192.0.2.3", storage));
  363. writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
  364. (*lf, storage,
  365. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  366. "fqdn_fwd,fqdn_rev,hostname\n"
  367. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,\n");
  368. }
  369. } // end of anonymous namespace