csv_lease_file4_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright (C) 2014-2016 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. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/duid.h>
  9. #include <dhcpsrv/csv_lease_file4.h>
  10. #include <dhcpsrv/lease.h>
  11. #include <dhcpsrv/tests/lease_file_io.h>
  12. #include <gtest/gtest.h>
  13. #include <sstream>
  14. using namespace isc;
  15. using namespace isc::asiolink;
  16. using namespace isc::dhcp;
  17. using namespace isc::dhcp::test;
  18. using namespace isc::util;
  19. namespace {
  20. // HWADDR values used by unit tests.
  21. const uint8_t HWADDR0[] = { 0, 1, 2, 3, 4, 5 };
  22. const uint8_t HWADDR1[] = { 0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf };
  23. const uint8_t CLIENTID[] = { 1, 2, 3, 4 };
  24. /// @brief Test fixture class for @c CSVLeaseFile4 validation.
  25. class CSVLeaseFile4Test : public ::testing::Test {
  26. public:
  27. /// @brief Constructor.
  28. ///
  29. /// Initializes IO for lease file used by unit tests.
  30. CSVLeaseFile4Test();
  31. /// @brief Prepends the absolute path to the file specified
  32. /// as an argument.
  33. ///
  34. /// @param filename Name of the file.
  35. /// @return Absolute path to the test file.
  36. static std::string absolutePath(const std::string& filename);
  37. /// @brief Creates the lease file to be parsed by unit tests.
  38. void writeSampleFile() const;
  39. /// @brief Checks the stats for the file
  40. ///
  41. /// This method is passed a leasefile and the values for the statistics it
  42. /// should have for comparison.
  43. ///
  44. /// @param lease_file A reference to the file we are using
  45. /// @param reads the number of attempted reads
  46. /// @param read_leases the number of valid leases read
  47. /// @param read_errs the number of errors while reading leases
  48. /// @param writes the number of attempted writes
  49. /// @param write_leases the number of leases successfully written
  50. /// @param write_errs the number of errors while writing
  51. void checkStats(CSVLeaseFile4& lease_file,
  52. uint32_t reads, uint32_t read_leases,
  53. uint32_t read_errs, uint32_t writes,
  54. uint32_t write_leases, uint32_t write_errs) const {
  55. EXPECT_EQ(reads, lease_file.getReads());
  56. EXPECT_EQ(read_leases, lease_file.getReadLeases());
  57. EXPECT_EQ(read_errs, lease_file.getReadErrs());
  58. EXPECT_EQ(writes, lease_file.getWrites());
  59. EXPECT_EQ(write_leases, lease_file.getWriteLeases());
  60. EXPECT_EQ(write_errs, lease_file.getWriteErrs());
  61. }
  62. /// @brief Name of the test lease file.
  63. std::string filename_;
  64. /// @brief Object providing access to lease file IO.
  65. LeaseFileIO io_;
  66. /// @brief hardware address 0 (corresponds to HWADDR0 const)
  67. HWAddrPtr hwaddr0_;
  68. /// @brief hardware address 1 (corresponds to HWADDR1 const)
  69. HWAddrPtr hwaddr1_;
  70. };
  71. CSVLeaseFile4Test::CSVLeaseFile4Test()
  72. : filename_(absolutePath("leases4.csv")), io_(filename_) {
  73. hwaddr0_.reset(new HWAddr(HWADDR0, sizeof(HWADDR0), HTYPE_ETHER));
  74. hwaddr1_.reset(new HWAddr(HWADDR1, sizeof(HWADDR1), HTYPE_ETHER));
  75. }
  76. std::string
  77. CSVLeaseFile4Test::absolutePath(const std::string& filename) {
  78. std::ostringstream s;
  79. s << DHCP_DATA_DIR << "/" << filename;
  80. return (s.str());
  81. }
  82. void
  83. CSVLeaseFile4Test::writeSampleFile() const {
  84. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  85. "fqdn_fwd,fqdn_rev,hostname,state\n"
  86. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
  87. "host.example.com,0\n"
  88. "192.0.2.1,,a:11:01:04,200,200,8,1,1,host.example.com,1\n"
  89. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
  90. "0,0,,1\n");
  91. }
  92. // This test checks the capability to read and parse leases from the file.
  93. TEST_F(CSVLeaseFile4Test, parse) {
  94. // Create a file to be parsed.
  95. writeSampleFile();
  96. // Open the lease file.
  97. CSVLeaseFile4 lf(filename_);
  98. ASSERT_NO_THROW(lf.open());
  99. // Verify the counters are cleared
  100. {
  101. SCOPED_TRACE("Check stats are empty");
  102. checkStats(lf, 0, 0, 0, 0, 0, 0);
  103. }
  104. Lease4Ptr lease;
  105. // Reading first read should be successful.
  106. {
  107. SCOPED_TRACE("First lease valid");
  108. EXPECT_TRUE(lf.next(lease));
  109. ASSERT_TRUE(lease);
  110. checkStats(lf, 1, 1, 0, 0, 0, 0);
  111. // Verify that the lease attributes are correct.
  112. EXPECT_EQ("192.0.2.1", lease->addr_.toText());
  113. HWAddr hwaddr1(*lease->hwaddr_);
  114. EXPECT_EQ("06:07:08:09:0a:bc", hwaddr1.toText(false));
  115. EXPECT_FALSE(lease->client_id_);
  116. EXPECT_EQ(200, lease->valid_lft_);
  117. EXPECT_EQ(0, lease->cltt_);
  118. EXPECT_EQ(8, lease->subnet_id_);
  119. EXPECT_TRUE(lease->fqdn_fwd_);
  120. EXPECT_TRUE(lease->fqdn_rev_);
  121. EXPECT_EQ("host.example.com", lease->hostname_);
  122. EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
  123. }
  124. // Second lease is malformed - HW address is empty.
  125. {
  126. SCOPED_TRACE("Second lease malformed");
  127. EXPECT_FALSE(lf.next(lease));
  128. checkStats(lf, 2, 1, 1, 0, 0, 0);
  129. }
  130. // Even though parsing previous lease failed, reading the next lease should be
  131. // successful.
  132. {
  133. SCOPED_TRACE("Third lease valid");
  134. EXPECT_TRUE(lf.next(lease));
  135. ASSERT_TRUE(lease);
  136. checkStats(lf, 3, 2, 1, 0, 0, 0);
  137. // Verify that the third lease is correct.
  138. EXPECT_EQ("192.0.3.15", lease->addr_.toText());
  139. HWAddr hwaddr3(*lease->hwaddr_);
  140. EXPECT_EQ("dd:de:ba:0d:1b:2e:3e:4f", hwaddr3.toText(false));
  141. ASSERT_TRUE(lease->client_id_);
  142. EXPECT_EQ("0a:00:01:04", lease->client_id_->toText());
  143. EXPECT_EQ(100, lease->valid_lft_);
  144. EXPECT_EQ(0, lease->cltt_);
  145. EXPECT_EQ(7, lease->subnet_id_);
  146. EXPECT_FALSE(lease->fqdn_fwd_);
  147. EXPECT_FALSE(lease->fqdn_rev_);
  148. EXPECT_TRUE(lease->hostname_.empty());
  149. EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
  150. }
  151. // There are no more leases. Reading should cause no error, but the returned
  152. // lease pointer should be NULL.
  153. {
  154. SCOPED_TRACE("Fifth read empty");
  155. EXPECT_TRUE(lf.next(lease));
  156. EXPECT_FALSE(lease);
  157. checkStats(lf, 4, 2, 1, 0, 0, 0);
  158. }
  159. // We should be able to do it again.
  160. {
  161. SCOPED_TRACE("Sixth read empty");
  162. EXPECT_TRUE(lf.next(lease));
  163. EXPECT_FALSE(lease);
  164. checkStats(lf, 5, 2, 1, 0, 0, 0);
  165. }
  166. }
  167. // This test checks creation of the lease file and writing leases.
  168. TEST_F(CSVLeaseFile4Test, recreate) {
  169. CSVLeaseFile4 lf(filename_);
  170. ASSERT_NO_THROW(lf.recreate());
  171. ASSERT_TRUE(io_.exists());
  172. // Verify the counters are cleared
  173. checkStats(lf, 0, 0, 0, 0, 0, 0);
  174. // Create first lease, with NULL client id.
  175. Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
  176. hwaddr0_,
  177. NULL, 0,
  178. 200, 50, 80, 0, 8, true, true,
  179. "host.example.com"));
  180. lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
  181. {
  182. SCOPED_TRACE("First write");
  183. ASSERT_NO_THROW(lf.append(*lease));
  184. checkStats(lf, 0, 0, 0, 1, 1, 0);
  185. }
  186. // Create second lease, with non-NULL client id.
  187. lease.reset(new Lease4(IOAddress("192.0.3.10"),
  188. hwaddr1_,
  189. CLIENTID, sizeof(CLIENTID),
  190. 100, 60, 90, 0, 7));
  191. {
  192. SCOPED_TRACE("Second write");
  193. ASSERT_NO_THROW(lf.append(*lease));
  194. checkStats(lf, 0, 0, 0, 2, 2, 0);
  195. }
  196. // Close the lease file.
  197. lf.close();
  198. // Check that the contents of the csv file are correct.
  199. EXPECT_EQ("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  200. "fqdn_fwd,fqdn_rev,hostname,state\n"
  201. "192.0.3.2,00:01:02:03:04:05,,200,200,8,1,1,host.example.com,2\n"
  202. "192.0.3.10,0d:0e:0a:0d:0b:0e:0e:0f,01:02:03:04,100,100,7,0,"
  203. "0,,0\n",
  204. io_.readFile());
  205. }
  206. // Verifies that a schema 1.0 file with records from
  207. // schema 1.0 and 2.0 loads correctly.
  208. TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
  209. // Create mixed schema file
  210. io_.writeFile(
  211. // schema 1.0 header
  212. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  213. "fqdn_fwd,fqdn_rev,hostname\n"
  214. // schema 1.0 record
  215. "192.0.2.1,06:07:08:09:1a:bc,,200,200,8,1,1,"
  216. "one.example.com\n"
  217. // schema 2.0 record - has state
  218. "192.0.2.2,06:07:08:09:2a:bc,,200,200,8,1,1,"
  219. "two.example.com,1\n"
  220. // schema 2.0 record - has state
  221. "192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
  222. "three.example.com,2\n"
  223. );
  224. // Open the lease file.
  225. CSVLeaseFile4 lf(filename_);
  226. ASSERT_NO_THROW(lf.open());
  227. Lease4Ptr lease;
  228. // Reading first read should be successful.
  229. {
  230. SCOPED_TRACE("First lease valid");
  231. EXPECT_TRUE(lf.next(lease));
  232. ASSERT_TRUE(lease);
  233. // Verify that the lease attributes are correct.
  234. EXPECT_EQ("192.0.2.1", lease->addr_.toText());
  235. HWAddr hwaddr1(*lease->hwaddr_);
  236. EXPECT_EQ("06:07:08:09:1a:bc", hwaddr1.toText(false));
  237. EXPECT_FALSE(lease->client_id_);
  238. EXPECT_EQ(200, lease->valid_lft_);
  239. EXPECT_EQ(0, lease->cltt_);
  240. EXPECT_EQ(8, lease->subnet_id_);
  241. EXPECT_TRUE(lease->fqdn_fwd_);
  242. EXPECT_TRUE(lease->fqdn_rev_);
  243. EXPECT_EQ("one.example.com", lease->hostname_);
  244. // Verify that added state is DEFAULT
  245. EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
  246. }
  247. {
  248. SCOPED_TRACE("Second lease valid");
  249. EXPECT_TRUE(lf.next(lease));
  250. ASSERT_TRUE(lease);
  251. // Verify that the lease attributes are correct.
  252. EXPECT_EQ("192.0.2.2", lease->addr_.toText());
  253. HWAddr hwaddr1(*lease->hwaddr_);
  254. EXPECT_EQ("06:07:08:09:2a:bc", hwaddr1.toText(false));
  255. EXPECT_FALSE(lease->client_id_);
  256. EXPECT_EQ(200, lease->valid_lft_);
  257. EXPECT_EQ(0, lease->cltt_);
  258. EXPECT_EQ(8, lease->subnet_id_);
  259. EXPECT_TRUE(lease->fqdn_fwd_);
  260. EXPECT_TRUE(lease->fqdn_rev_);
  261. EXPECT_EQ("two.example.com", lease->hostname_);
  262. EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
  263. }
  264. {
  265. SCOPED_TRACE("Third lease valid");
  266. EXPECT_TRUE(lf.next(lease));
  267. ASSERT_TRUE(lease);
  268. // Verify that the third lease is correct.
  269. EXPECT_EQ("192.0.2.3", lease->addr_.toText());
  270. HWAddr hwaddr1(*lease->hwaddr_);
  271. EXPECT_EQ("06:07:08:09:3a:bc", hwaddr1.toText(false));
  272. EXPECT_FALSE(lease->client_id_);
  273. EXPECT_EQ(200, lease->valid_lft_);
  274. EXPECT_EQ(0, lease->cltt_);
  275. EXPECT_EQ(8, lease->subnet_id_);
  276. EXPECT_TRUE(lease->fqdn_fwd_);
  277. EXPECT_TRUE(lease->fqdn_rev_);
  278. EXPECT_EQ("three.example.com", lease->hostname_);
  279. EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
  280. }
  281. }
  282. // Verifies that a lease file with fewer header columns than the
  283. // minimum allowed will not open.
  284. TEST_F(CSVLeaseFile4Test, tooFewHeaderColumns) {
  285. // Create 1.0 file
  286. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  287. "fqdn_fwd,fqdn_rev\n");
  288. // Open the lease file.
  289. CSVLeaseFile4 lf(filename_);
  290. ASSERT_THROW(lf.open(), CSVFileError);
  291. }
  292. // Verifies that a lease file with an unrecognized column header
  293. // will not open.
  294. TEST_F(CSVLeaseFile4Test, invalidHeaderColumn) {
  295. // Create 1.0 file
  296. io_.writeFile("address,hwaddr,BOGUS,valid_lifetime,expire,subnet_id,"
  297. "fqdn_fwd,fqdn_rev,hostname,state\n");
  298. // Open the lease file.
  299. CSVLeaseFile4 lf(filename_);
  300. ASSERT_THROW(lf.open(), CSVFileError);
  301. }
  302. // Verifies that a lease file with more header columns than defined
  303. // columns will downgrade.
  304. TEST_F(CSVLeaseFile4Test, downGrade) {
  305. // Create 2.0 PLUS a column file
  306. io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  307. "fqdn_fwd,fqdn_rev,hostname,state,FUTURE_COL\n"
  308. "192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
  309. "three.example.com,2,BOGUS\n");
  310. // Lease file should open and report as needing downgrade.
  311. CSVLeaseFile4 lf(filename_);
  312. ASSERT_NO_THROW(lf.open());
  313. EXPECT_TRUE(lf.needsConversion());
  314. EXPECT_EQ(util::VersionedCSVFile::NEEDS_DOWNGRADE,
  315. lf.getInputSchemaState());
  316. Lease4Ptr lease;
  317. {
  318. SCOPED_TRACE("First lease valid");
  319. EXPECT_TRUE(lf.next(lease));
  320. ASSERT_TRUE(lease);
  321. // Verify that the third lease is correct.
  322. EXPECT_EQ("192.0.2.3", lease->addr_.toText());
  323. HWAddr hwaddr1(*lease->hwaddr_);
  324. EXPECT_EQ("06:07:08:09:3a:bc", hwaddr1.toText(false));
  325. EXPECT_FALSE(lease->client_id_);
  326. EXPECT_EQ(200, lease->valid_lft_);
  327. EXPECT_EQ(0, lease->cltt_);
  328. EXPECT_EQ(8, lease->subnet_id_);
  329. EXPECT_TRUE(lease->fqdn_fwd_);
  330. EXPECT_TRUE(lease->fqdn_rev_);
  331. EXPECT_EQ("three.example.com", lease->hostname_);
  332. EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
  333. }
  334. }
  335. /// @todo Currently we don't check invalid lease attributes, such as invalid
  336. /// lease type, invalid preferred lifetime vs valid lifetime etc. The Lease6
  337. /// should be extended with the function that validates lease attributes. Once
  338. /// this is implemented we should provide more tests for malformed leases
  339. /// in the CSV file. See http://kea.isc.org/ticket/2405.
  340. } // end of anonymous namespace