lfc_controller_unittests.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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 <lfc/lfc_controller.h>
  15. #include <gtest/gtest.h>
  16. #include <fstream>
  17. #include <cerrno>
  18. using namespace isc::lfc;
  19. using namespace std;
  20. namespace {
  21. class LFCControllerTest : public ::testing::Test {
  22. public:
  23. string pstr_; ///< String for name for pid file
  24. string xstr_; ///< String for name for previous file
  25. string istr_; ///< String for name for copy file
  26. string ostr_; ///< String for name for output file
  27. string fstr_; ///< String for name for finish file
  28. string cstr_; ///< String for name for config file
  29. /// @brief Create a file and write the filename into it.
  30. void touchFile(const std::string& filename, int);
  31. /// @brief Create a file and write the given string into it.
  32. void writeFile(const std::string& filename, const std::string& contents) const;
  33. /// @brief Read a string from a file
  34. std::string readFile(const std::string& contents) const;
  35. /// @brief check the file to see if i matches what was written to it.
  36. bool checkFile(const std::string& filename, int);
  37. protected:
  38. /// @brief Sets up the file names and Removes any old test
  39. /// files before the test
  40. virtual void SetUp() {
  41. // set up the test files we need
  42. string baseDir = TEST_DATA_BUILDDIR;
  43. pstr_ = baseDir + "/" + "lease_file." + "pid"; // pid
  44. xstr_ = baseDir + "/" + "lease_file." + "2"; // previous
  45. istr_ = baseDir + "/" + "lease_file." + "1"; // copy
  46. ostr_ = baseDir + "/" + "lease_file." + "output"; // output
  47. fstr_ = baseDir + "/" + "lease_file." + "completed"; // finish
  48. cstr_ = baseDir + "/" + "config_file"; // config
  49. // and remove any outstanding test files
  50. removeTestFile();
  51. }
  52. /// @brief Removes any remaining test files after the test
  53. virtual void TearDown() {
  54. removeTestFile();
  55. }
  56. private:
  57. /// @brief Removes any remaining test files
  58. void removeTestFile() const {
  59. remove(pstr_.c_str());
  60. remove(xstr_.c_str());
  61. remove(istr_.c_str());
  62. remove(ostr_.c_str());
  63. remove(fstr_.c_str());
  64. }
  65. };
  66. void
  67. LFCControllerTest::touchFile(const std::string& filename, int i) {
  68. std::ofstream fs;
  69. fs.open(filename, std::ofstream::out);
  70. fs << i << std::endl;
  71. fs.close();
  72. }
  73. std::string
  74. LFCControllerTest::readFile(const std::string& filename) const {
  75. std::ifstream fs;
  76. fs.open(filename, std::ifstream::in);
  77. std::string contents((std::istreambuf_iterator<char>(fs)),
  78. std::istreambuf_iterator<char>());
  79. fs.close();
  80. return (contents);
  81. }
  82. void
  83. LFCControllerTest::writeFile(const std::string& filename,
  84. const std::string& contents) const {
  85. std::ofstream fs(filename, std::ofstream::out);
  86. if (fs.is_open()) {
  87. fs << contents;
  88. fs.close();
  89. }
  90. }
  91. bool
  92. LFCControllerTest::checkFile(const std::string& filename, int i) {
  93. std::ifstream fs;
  94. int j;
  95. fs.open(filename, std::ifstream::in);
  96. fs >> j;
  97. fs.close();
  98. if (i == j)
  99. return (true);
  100. return (false);
  101. }
  102. /// @brief Verify initial state of LFC controller.
  103. /// Create an instance of the controller and see that
  104. /// all of the initial values are empty as expected.
  105. TEST_F(LFCControllerTest, initialValues) {
  106. LFCController lfc_controller;
  107. // Verify that we start with all the private variables empty
  108. EXPECT_EQ(lfc_controller.getProtocolVersion(), 0);
  109. EXPECT_TRUE(lfc_controller.getConfigFile().empty());
  110. EXPECT_TRUE(lfc_controller.getPreviousFile().empty());
  111. EXPECT_TRUE(lfc_controller.getCopyFile().empty());
  112. EXPECT_TRUE(lfc_controller.getOutputFile().empty());
  113. EXPECT_TRUE(lfc_controller.getFinishFile().empty());
  114. EXPECT_TRUE(lfc_controller.getPidFile().empty());
  115. }
  116. /// @brief Verify that parsing a full command line works.
  117. /// Parse a complete command line then verify the parsed
  118. /// and saved data matches our expectations.
  119. TEST_F(LFCControllerTest, fullCommandLine) {
  120. LFCController lfc_controller;
  121. // Verify that standard options can be parsed without error
  122. char* argv[] = { const_cast<char*>("progName"),
  123. const_cast<char*>("-4"),
  124. const_cast<char*>("-x"),
  125. const_cast<char*>("previous"),
  126. const_cast<char*>("-i"),
  127. const_cast<char*>("copy"),
  128. const_cast<char*>("-o"),
  129. const_cast<char*>("output"),
  130. const_cast<char*>("-c"),
  131. const_cast<char*>("config"),
  132. const_cast<char*>("-f"),
  133. const_cast<char*>("finish"),
  134. const_cast<char*>("-p"),
  135. const_cast<char*>("pid") };
  136. int argc = 14;
  137. ASSERT_NO_THROW(lfc_controller.parseArgs(argc, argv));
  138. // Check all the parsed data from above to the known values
  139. EXPECT_EQ(lfc_controller.getProtocolVersion(), 4);
  140. EXPECT_EQ(lfc_controller.getConfigFile(), "config");
  141. EXPECT_EQ(lfc_controller.getPreviousFile(), "previous");
  142. EXPECT_EQ(lfc_controller.getCopyFile(), "copy");
  143. EXPECT_EQ(lfc_controller.getOutputFile(), "output");
  144. EXPECT_EQ(lfc_controller.getFinishFile(), "finish");
  145. EXPECT_EQ(lfc_controller.getPidFile(), "pid");
  146. }
  147. /// @brief Verify that parsing a correct but incomplete line fails.
  148. /// Parse a command line that is correctly formatted but isn't complete
  149. /// (doesn't include some options or an some option arguments). We
  150. /// expect that the parse will fail with an InvalidUsage exception.
  151. TEST_F(LFCControllerTest, notEnoughData) {
  152. LFCController lfc_controller;
  153. // Test the results if we don't include all of the required arguments
  154. // This argument list is correct but we shall only suppy part of it
  155. // to the parse routine via the argc variable.
  156. char* argv[] = { const_cast<char*>("progName"),
  157. const_cast<char*>("-4"),
  158. const_cast<char*>("-x"),
  159. const_cast<char*>("previous"),
  160. const_cast<char*>("-i"),
  161. const_cast<char*>("copy"),
  162. const_cast<char*>("-o"),
  163. const_cast<char*>("output"),
  164. const_cast<char*>("-c"),
  165. const_cast<char*>("config"),
  166. const_cast<char*>("-f"),
  167. const_cast<char*>("finish"),
  168. const_cast<char*>("-p"),
  169. const_cast<char*>("pid") };
  170. int argc = 1;
  171. for (; argc < 14; ++argc) {
  172. EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage)
  173. << "test failed for argc = " << argc;
  174. }
  175. // Verify we can still parse the full string properly
  176. ASSERT_NO_THROW(lfc_controller.parseArgs(argc, argv));
  177. }
  178. /// @brief Verify that extra arguments cause the parse to fail.
  179. /// Parse a full command line plus some extra arguments on the end
  180. /// to verify that we don't stop parsing when we find all of the
  181. /// required arguments. We exepct the parse to fail with an
  182. /// InvalidUsage exception.
  183. TEST_F(LFCControllerTest, tooMuchData) {
  184. LFCController lfc_controller;
  185. // The standard options plus some others
  186. char* argv[] = { const_cast<char*>("progName"),
  187. const_cast<char*>("-4"),
  188. const_cast<char*>("-x"),
  189. const_cast<char*>("previous"),
  190. const_cast<char*>("-i"),
  191. const_cast<char*>("copy"),
  192. const_cast<char*>("-o"),
  193. const_cast<char*>("output"),
  194. const_cast<char*>("-c"),
  195. const_cast<char*>("config"),
  196. const_cast<char*>("-f"),
  197. const_cast<char*>("finish"),
  198. const_cast<char*>("-p"),
  199. const_cast<char*>("pid"),
  200. const_cast<char*>("some"),
  201. const_cast<char*>("other"),
  202. const_cast<char*>("args"),
  203. };
  204. int argc = 17;
  205. // We expect an error as we have arguments that aren't valid
  206. EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage);
  207. }
  208. /// @brief Verify that unknown arguments cause the parse to fail.
  209. /// Parse some unknown arguments to verify that we generate the
  210. /// proper InvalidUsage exception.
  211. TEST_F(LFCControllerTest, someBadData) {
  212. LFCController lfc_controller;
  213. // Some random arguments
  214. char* argv[] = { const_cast<char*>("progName"),
  215. const_cast<char*>("some"),
  216. const_cast<char*>("bad"),
  217. const_cast<char*>("args"),
  218. };
  219. int argc = 4;
  220. // We expect an error as the arguments aren't valid
  221. EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage);
  222. }
  223. /// @brief Verify that we do file_cleanup correctly. We create different
  224. /// files and see if we properly delete and move them.
  225. TEST_F(LFCControllerTest, fileCleanup) {
  226. LFCController lfc_controller, lfc_controller_launch;
  227. // We can use the same arguments and controller for all of the tests
  228. // as the files get redone for each subtest. We leave "-d" in the arg
  229. // list but don't pass it as we use 14 as the argument count. This
  230. // makes it easy to turn it on by simply increasing argc below to 15
  231. char* argv[] = { const_cast<char*>("progName"),
  232. const_cast<char*>("-4"),
  233. const_cast<char*>("-x"),
  234. const_cast<char*>(xstr_.c_str()),
  235. const_cast<char*>("-i"),
  236. const_cast<char*>(istr_.c_str()),
  237. const_cast<char*>("-o"),
  238. const_cast<char*>(ostr_.c_str()),
  239. const_cast<char*>("-c"),
  240. const_cast<char*>(cstr_.c_str()),
  241. const_cast<char*>("-f"),
  242. const_cast<char*>(fstr_.c_str()),
  243. const_cast<char*>("-p"),
  244. const_cast<char*>(pstr_.c_str()),
  245. const_cast<char*>("-d")
  246. };
  247. int argc = 14;
  248. lfc_controller.parseArgs(argc, argv);
  249. // Test 1: Start with no files - we expect an execption as there
  250. // is no file to copy.
  251. EXPECT_THROW(lfc_controller.fileCleanup(), RunTimeFail);
  252. // Test 2: Create a file for each of previous, copy and finish. We should
  253. // delete the previous and copy files then move finish to previous.
  254. touchFile(xstr_.c_str(), 1);
  255. touchFile(istr_.c_str(), 2);
  256. touchFile(fstr_.c_str(), 3);
  257. lfc_controller.fileCleanup();
  258. // verify finish is now previous and copy and finish are gone
  259. EXPECT_TRUE(checkFile(xstr_.c_str(), 3));
  260. EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT));
  261. EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT));
  262. remove(pstr_.c_str());
  263. // Test 3: Create a file for previous and finish but not copy.
  264. touchFile(xstr_.c_str(), 4);
  265. touchFile(fstr_.c_str(), 6);
  266. lfc_controller.fileCleanup();
  267. // verify finish is now previous and copy and finish are gone
  268. EXPECT_TRUE(checkFile(xstr_.c_str(), 6));
  269. EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT));
  270. EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT));
  271. remove(pstr_.c_str());
  272. // Test 4: Create a file for copy and finish but not previous.
  273. touchFile(istr_.c_str(), 8);
  274. touchFile(fstr_.c_str(), 9);
  275. lfc_controller.fileCleanup();
  276. // verify finish is now previous and copy and finish are gone
  277. EXPECT_TRUE(checkFile(xstr_.c_str(), 9));
  278. EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT));
  279. EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT));
  280. remove(pstr_.c_str());
  281. // Test 5: rerun test 2 but using launch instead of cleanup
  282. // as we already have a finish file we shouldn't do any extra
  283. // processing
  284. touchFile(xstr_.c_str(), 10);
  285. touchFile(istr_.c_str(), 11);
  286. touchFile(fstr_.c_str(), 12);
  287. lfc_controller_launch.launch(argc, argv);
  288. // verify finish is now previous and copy and finish are gone
  289. // as we ran launch we also check to see if the pid is gone.
  290. EXPECT_TRUE(checkFile(xstr_.c_str(), 12));
  291. EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT));
  292. EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT));
  293. EXPECT_TRUE((remove(pstr_.c_str()) != 0) && (errno == ENOENT));
  294. remove(pstr_.c_str());
  295. }
  296. /// @brief Verify that we properly combine and clean up files
  297. ///
  298. /// This is mostly a retest as we already test that the loader and
  299. /// writer functions work in their own tests but we combine it all
  300. /// here. This is the v4 version
  301. TEST_F(LFCControllerTest, programLaunch4) {
  302. LFCController lfc_controller;
  303. // We can use the same arguments and controller for all of the tests
  304. // as the files get redone for each subtest.
  305. char* argv[] = { const_cast<char*>("progName"),
  306. const_cast<char*>("-4"),
  307. const_cast<char*>("-x"),
  308. const_cast<char*>(xstr_.c_str()),
  309. const_cast<char*>("-i"),
  310. const_cast<char*>(istr_.c_str()),
  311. const_cast<char*>("-o"),
  312. const_cast<char*>(ostr_.c_str()),
  313. const_cast<char*>("-c"),
  314. const_cast<char*>(cstr_.c_str()),
  315. const_cast<char*>("-f"),
  316. const_cast<char*>(fstr_.c_str()),
  317. const_cast<char*>("-p"),
  318. const_cast<char*>(pstr_.c_str()),
  319. const_cast<char*>("-d")
  320. };
  321. int argc = 14;
  322. lfc_controller.parseArgs(argc, argv);
  323. // Create the test previous file
  324. writeFile(xstr_.c_str(),
  325. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  326. "fqdn_fwd,fqdn_rev,hostname\n"
  327. "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
  328. "host.example.com\n"
  329. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
  330. "0,0,\n"
  331. "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n"
  332. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7,"
  333. "0,0,\n"
  334. "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1,"
  335. "host.example.com\n"
  336. "192.0.2.5,06:07:08:09:0a:bc,,200,200,8,1,1,"
  337. "host.example.com\n");
  338. // Create the test copy file
  339. writeFile(istr_.c_str(),
  340. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  341. "fqdn_fwd,fqdn_rev,hostname\n"
  342. "192.0.2.1,06:07:08:09:0a:bc,,200,800,8,1,1,"
  343. "host.example.com\n"
  344. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,150,7,"
  345. "0,0,\n"
  346. "192.0.2.5,06:07:08:09:0a:bc,,200,0,8,1,1,"
  347. "host.example.com\n");
  348. // Run the cleanup
  349. lfc_controller.launch(argc, argv);
  350. // Compare the results
  351. EXPECT_EQ(readFile(xstr_.c_str()),
  352. "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
  353. "fqdn_fwd,fqdn_rev,hostname\n"
  354. "192.0.2.1,06:07:08:09:0a:bc,,200,800,8,1,1,"
  355. "host.example.com\n"
  356. "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,150,7,"
  357. "0,0,\n");
  358. }
  359. /// @brief Verify that we properly combine and clean up files
  360. ///
  361. /// This is mostly a retest as we already test that the loader and
  362. /// writer functions work in their own tests but we combine it all
  363. /// here. This is the v6 version
  364. TEST_F(LFCControllerTest, programLaunch6) {
  365. LFCController lfc_controller;
  366. // We can use the same arguments and controller for all of the tests
  367. // as the files get redone for each subtest.
  368. char* argv[] = { const_cast<char*>("progName"),
  369. const_cast<char*>("-6"),
  370. const_cast<char*>("-x"),
  371. const_cast<char*>(xstr_.c_str()),
  372. const_cast<char*>("-i"),
  373. const_cast<char*>(istr_.c_str()),
  374. const_cast<char*>("-o"),
  375. const_cast<char*>(ostr_.c_str()),
  376. const_cast<char*>("-c"),
  377. const_cast<char*>(cstr_.c_str()),
  378. const_cast<char*>("-f"),
  379. const_cast<char*>(fstr_.c_str()),
  380. const_cast<char*>("-p"),
  381. const_cast<char*>(pstr_.c_str()),
  382. const_cast<char*>("-d")
  383. };
  384. int argc = 14;
  385. lfc_controller.parseArgs(argc, argv);
  386. // Create the test previous file
  387. writeFile(xstr_.c_str(),
  388. "address,duid,valid_lifetime,expire,subnet_id,"
  389. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  390. "fqdn_rev,hostname,hwaddr\n"
  391. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  392. "200,200,8,100,0,7,0,1,1,host.example.com,\n"
  393. "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,\n"
  394. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,300,6,150,"
  395. "0,8,0,0,0,,\n"
  396. "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2,"
  397. "16,64,0,0,,\n"
  398. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150,"
  399. "0,8,0,0,0,,\n"
  400. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  401. "200,400,8,100,0,7,0,1,1,host.example.com,\n"
  402. );
  403. // Create the test copy file
  404. writeFile(istr_.c_str(),
  405. "address,duid,valid_lifetime,expire,subnet_id,"
  406. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  407. "fqdn_rev,hostname,hwaddr\n"
  408. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,1000,6,150,"
  409. "0,8,0,0,0,,\n"
  410. "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  411. "0,200,8,100,0,7,0,1,1,host.example.com,\n"
  412. "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  413. "200,600,8,100,0,7,0,1,1,host.example.com,\n"
  414. "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,400,8,0,2,"
  415. "16,64,0,0,,\n"
  416. );
  417. // Run the cleanup
  418. lfc_controller.launch(argc, argv);
  419. // Compare the results
  420. EXPECT_EQ(readFile(xstr_.c_str()),
  421. "address,duid,valid_lifetime,expire,subnet_id,"
  422. "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
  423. "fqdn_rev,hostname,hwaddr\n"
  424. "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
  425. "200,600,8,100,0,7,0,1,1,host.example.com,\n"
  426. "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,1000,6,150,"
  427. "0,8,0,0,0,,\n"
  428. "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,400,8,0,2,"
  429. "16,64,0,0,,\n"
  430. );
  431. }
  432. } // end of anonymous namespace