pgsql_lease_mgr_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // Copyright (C) 2014 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/lease_mgr_factory.h>
  17. #include <dhcpsrv/pgsql_lease_mgr.h>
  18. #include <dhcpsrv/tests/test_utils.h>
  19. #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
  20. #include <exceptions/exceptions.h>
  21. #include <gtest/gtest.h>
  22. #include <algorithm>
  23. #include <iostream>
  24. #include <sstream>
  25. #include <string>
  26. #include <utility>
  27. using namespace isc;
  28. using namespace isc::asiolink;
  29. using namespace isc::dhcp;
  30. using namespace isc::dhcp::test;
  31. using namespace std;
  32. namespace {
  33. // This holds statements to create and destroy the schema.
  34. #include "schema_pgsql_copy.h"
  35. // Connection strings.
  36. // Database: keatest
  37. // Host: localhost
  38. // Username: keatest
  39. // Password: keatest
  40. const char* VALID_TYPE = "type=postgresql";
  41. const char* INVALID_TYPE = "type=unknown";
  42. const char* VALID_NAME = "name=keatest";
  43. const char* INVALID_NAME = "name=invalidname";
  44. const char* VALID_HOST = "host=localhost";
  45. const char* INVALID_HOST = "host=invalidhost";
  46. const char* VALID_USER = "user=keatest";
  47. const char* INVALID_USER = "user=invaliduser";
  48. const char* VALID_PASSWORD = "password=keatest";
  49. const char* INVALID_PASSWORD = "password=invalid";
  50. // Given a combination of strings above, produce a connection string.
  51. string connectionString(const char* type, const char* name, const char* host,
  52. const char* user, const char* password) {
  53. const string space = " ";
  54. string result = "";
  55. if (type != NULL) {
  56. result += string(type);
  57. }
  58. if (name != NULL) {
  59. if (! result.empty()) {
  60. result += space;
  61. }
  62. result += string(name);
  63. }
  64. if (host != NULL) {
  65. if (! result.empty()) {
  66. result += space;
  67. }
  68. result += string(host);
  69. }
  70. if (user != NULL) {
  71. if (! result.empty()) {
  72. result += space;
  73. }
  74. result += string(user);
  75. }
  76. if (password != NULL) {
  77. if (! result.empty()) {
  78. result += space;
  79. }
  80. result += string(password);
  81. }
  82. return (result);
  83. }
  84. // Return valid connection string
  85. string
  86. validConnectionString() {
  87. return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST,
  88. VALID_USER, VALID_PASSWORD));
  89. }
  90. // @brief Clear everything from the database
  91. //
  92. // There is no error checking in this code: if something fails, one of the
  93. // tests will (should) fall over.
  94. void destroySchema() {
  95. // Open database
  96. PGconn * conn = 0;
  97. conn = PQconnectdb("host = 'localhost' user = 'keatest'"
  98. " password = 'keatest' dbname = 'keatest'");
  99. PGresult * r;
  100. // Get rid of everything in it.
  101. for (int i = 0; destroy_statement[i] != NULL; ++i) {
  102. r = PQexec(conn, destroy_statement[i]);
  103. PQclear(r);
  104. }
  105. PQfinish(conn);
  106. }
  107. // @brief Create the Schema
  108. //
  109. // Creates all the tables in what is assumed to be an empty database.
  110. //
  111. // There is no error checking in this code: if it fails, one of the tests
  112. // will fall over.
  113. void createSchema() {
  114. // Open database
  115. PGconn * conn = 0;
  116. conn = PQconnectdb("host = 'localhost' user = 'keatest'"
  117. " password = 'keatest' dbname = 'keatest'");
  118. PGresult * r;
  119. // Get rid of everything in it.
  120. for (int i = 0; create_statement[i] != NULL; ++i) {
  121. r = PQexec(conn, create_statement[i]);
  122. PQclear(r);
  123. }
  124. }
  125. /// @brief Test fixture class for testing PostgreSQL Lease Manager
  126. ///
  127. /// Opens the database prior to each test and closes it afterwards.
  128. /// All pending transactions are deleted prior to closure.
  129. class PgSqlLeaseMgrTest : public GenericLeaseMgrTest {
  130. public:
  131. /// @brief Constructor
  132. ///
  133. /// Deletes everything from the database and opens it.
  134. PgSqlLeaseMgrTest() {
  135. // Ensure schema is the correct one.
  136. destroySchema();
  137. createSchema();
  138. // Connect to the database
  139. try {
  140. LeaseMgrFactory::create(validConnectionString());
  141. } catch (...) {
  142. std::cerr << "*** ERROR: unable to open database. The test\n"
  143. "*** environment is broken and must be fixed before\n"
  144. "*** the PostgreSQL tests will run correctly.\n"
  145. "*** The reason for the problem is described in the\n"
  146. "*** accompanying exception output.\n";
  147. throw;
  148. }
  149. lmptr_ = &(LeaseMgrFactory::instance());
  150. }
  151. /// @brief Destructor
  152. ///
  153. /// Rolls back all pending transactions. The deletion of lmptr_ will close
  154. /// the database. Then reopen it and delete everything created by the test.
  155. virtual ~PgSqlLeaseMgrTest() {
  156. lmptr_->rollback();
  157. LeaseMgrFactory::destroy();
  158. destroySchema();
  159. }
  160. /// @brief Reopen the database
  161. ///
  162. /// Closes the database and re-open it. Anything committed should be
  163. /// visible.
  164. void reopen() {
  165. LeaseMgrFactory::destroy();
  166. LeaseMgrFactory::create(validConnectionString());
  167. lmptr_ = &(LeaseMgrFactory::instance());
  168. }
  169. };
  170. /// @brief Check that database can be opened
  171. ///
  172. /// This test checks if the PgSqlLeaseMgr can be instantiated. This happens
  173. /// only if the database can be opened. Note that this is not part of the
  174. /// PgSqlLeaseMgr test fixure set. This test checks that the database can be
  175. /// opened: the fixtures assume that and check basic operations.
  176. TEST(PgSqlOpenTest, OpenDatabase) {
  177. // Schema needs to be created for the test to work.
  178. destroySchema();
  179. createSchema();
  180. // Check that lease manager open the database opens correctly and tidy up.
  181. // If it fails, print the error message.
  182. try {
  183. LeaseMgrFactory::create(validConnectionString());
  184. EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
  185. LeaseMgrFactory::destroy();
  186. } catch (const isc::Exception& ex) {
  187. FAIL() << "*** ERROR: unable to open database, reason:\n"
  188. << " " << ex.what() << "\n"
  189. << "*** The test environment is broken and must be fixed\n"
  190. << "*** before the PostgreSQL tests will run correctly.\n";
  191. }
  192. // Check that attempting to get an instance of the lease manager when
  193. // none is set throws an exception.
  194. EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
  195. // Check that wrong specification of backend throws an exception.
  196. // (This is really a check on LeaseMgrFactory, but is convenient to
  197. // perform here.)
  198. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  199. NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
  200. InvalidParameter);
  201. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  202. INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
  203. InvalidType);
  204. // Check that invalid login data causes an exception.
  205. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  206. VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
  207. DbOpenError);
  208. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  209. VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
  210. DbOpenError);
  211. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  212. VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
  213. DbOpenError);
  214. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  215. VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
  216. DbOpenError);
  217. // Check for missing parameters
  218. EXPECT_THROW(LeaseMgrFactory::create(connectionString(
  219. VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
  220. NoDatabaseName);
  221. // Tidy up after the test
  222. destroySchema();
  223. }
  224. /// @brief Check the getType() method
  225. ///
  226. /// getType() returns a string giving the type of the backend, which should
  227. /// always be "postgresql".
  228. TEST_F(PgSqlLeaseMgrTest, getType) {
  229. EXPECT_EQ(std::string("postgresql"), lmptr_->getType());
  230. }
  231. /// @brief Check getName() returns correct database name
  232. TEST_F(PgSqlLeaseMgrTest, getName) {
  233. EXPECT_EQ(std::string("keatest"), lmptr_->getName());
  234. }
  235. /// @brief Check that getVersion() returns the expected version
  236. TEST_F(PgSqlLeaseMgrTest, checkVersion) {
  237. // Check version
  238. pair<uint32_t, uint32_t> version;
  239. ASSERT_NO_THROW(version = lmptr_->getVersion());
  240. EXPECT_EQ(PG_CURRENT_VERSION, version.first);
  241. EXPECT_EQ(PG_CURRENT_MINOR, version.second);
  242. }
  243. /// @brief Basic Lease4 Checks
  244. ///
  245. /// Checks that the addLease, getLease4 (by address) and deleteLease (with an
  246. /// IPv4 address) works.
  247. TEST_F(PgSqlLeaseMgrTest, basicLease4) {
  248. // Get the leases to be used for the test.
  249. vector<Lease4Ptr> leases = createLeases4();
  250. // Start the tests. Add three leases to the database, read them back and
  251. // check they are what we think they are.
  252. EXPECT_TRUE(lmptr_->addLease(leases[1]));
  253. EXPECT_TRUE(lmptr_->addLease(leases[2]));
  254. EXPECT_TRUE(lmptr_->addLease(leases[3]));
  255. lmptr_->commit();
  256. // Reopen the database to ensure that they actually got stored.
  257. reopen();
  258. Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]);
  259. ASSERT_TRUE(l_returned);
  260. detailCompareLease(leases[1], l_returned);
  261. l_returned = lmptr_->getLease4(ioaddress4_[2]);
  262. ASSERT_TRUE(l_returned);
  263. detailCompareLease(leases[2], l_returned);
  264. l_returned = lmptr_->getLease4(ioaddress4_[3]);
  265. ASSERT_TRUE(l_returned);
  266. detailCompareLease(leases[3], l_returned);
  267. // Check that we can't add a second lease with the same address
  268. EXPECT_FALSE(lmptr_->addLease(leases[1]));
  269. // Delete a lease, check that it's gone, and that we can't delete it
  270. // a second time.
  271. EXPECT_TRUE(lmptr_->deleteLease(ioaddress4_[1]));
  272. l_returned = lmptr_->getLease4(ioaddress4_[1]);
  273. EXPECT_FALSE(l_returned);
  274. EXPECT_FALSE(lmptr_->deleteLease(ioaddress4_[1]));
  275. // Check that the second address is still there.
  276. l_returned = lmptr_->getLease4(ioaddress4_[2]);
  277. ASSERT_TRUE(l_returned);
  278. detailCompareLease(leases[2], l_returned);
  279. }
  280. /// Checks that we are able to update an IPv4 lease in the database.
  281. TEST_F(PgSqlLeaseMgrTest, updateLease4) {
  282. testUpdateLease4();
  283. }
  284. /// @brief Basic Lease4 Checks
  285. ///
  286. /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
  287. /// updateLease4() and deleteLease (IPv4 address) can handle NULL client-id.
  288. /// (client-id is optional and may not be present)
  289. TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) {
  290. // Get the leases to be used for the test.
  291. vector<Lease4Ptr> leases = createLeases4();
  292. // Let's clear client-id pointers
  293. leases[1]->client_id_ = ClientIdPtr();
  294. leases[2]->client_id_ = ClientIdPtr();
  295. leases[3]->client_id_ = ClientIdPtr();
  296. // Start the tests. Add three leases to the database, read them back and
  297. // check they are what we think they are.
  298. EXPECT_TRUE(lmptr_->addLease(leases[1]));
  299. EXPECT_TRUE(lmptr_->addLease(leases[2]));
  300. EXPECT_TRUE(lmptr_->addLease(leases[3]));
  301. lmptr_->commit();
  302. // Reopen the database to ensure that they actually got stored.
  303. reopen();
  304. Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]);
  305. ASSERT_TRUE(l_returned);
  306. detailCompareLease(leases[1], l_returned);
  307. l_returned = lmptr_->getLease4(ioaddress4_[2]);
  308. ASSERT_TRUE(l_returned);
  309. detailCompareLease(leases[2], l_returned);
  310. l_returned = lmptr_->getLease4(ioaddress4_[3]);
  311. ASSERT_TRUE(l_returned);
  312. detailCompareLease(leases[3], l_returned);
  313. // Check that we can't add a second lease with the same address
  314. EXPECT_FALSE(lmptr_->addLease(leases[1]));
  315. // Check that we can get the lease by HWAddr
  316. HWAddr tmp(leases[2]->hwaddr_, HTYPE_ETHER);
  317. Lease4Collection returned = lmptr_->getLease4(tmp);
  318. ASSERT_EQ(1, returned.size());
  319. detailCompareLease(leases[2], *returned.begin());
  320. l_returned = lmptr_->getLease4(tmp, leases[2]->subnet_id_);
  321. ASSERT_TRUE(l_returned);
  322. detailCompareLease(leases[2], l_returned);
  323. // Check that we can update the lease
  324. // Modify some fields in lease 1 (not the address) and update it.
  325. ++leases[1]->subnet_id_;
  326. leases[1]->valid_lft_ *= 2;
  327. lmptr_->updateLease4(leases[1]);
  328. // ... and check that the lease is indeed updated
  329. l_returned = lmptr_->getLease4(ioaddress4_[1]);
  330. ASSERT_TRUE(l_returned);
  331. detailCompareLease(leases[1], l_returned);
  332. // Delete a lease, check that it's gone, and that we can't delete it
  333. // a second time.
  334. EXPECT_TRUE(lmptr_->deleteLease(ioaddress4_[1]));
  335. l_returned = lmptr_->getLease4(ioaddress4_[1]);
  336. EXPECT_FALSE(l_returned);
  337. EXPECT_FALSE(lmptr_->deleteLease(ioaddress4_[1]));
  338. // Check that the second address is still there.
  339. l_returned = lmptr_->getLease4(ioaddress4_[2]);
  340. ASSERT_TRUE(l_returned);
  341. detailCompareLease(leases[2], l_returned);
  342. }
  343. /// @brief Basic Lease6 Checks
  344. ///
  345. /// Checks that the addLease, getLease6 (by address) and deleteLease (with an
  346. /// IPv6 address) works.
  347. TEST_F(PgSqlLeaseMgrTest, basicLease6) {
  348. // Get the leases to be used for the test.
  349. vector<Lease6Ptr> leases = createLeases6();
  350. // Start the tests. Add three leases to the database, read them back and
  351. // check they are what we think they are.
  352. EXPECT_TRUE(lmptr_->addLease(leases[1]));
  353. EXPECT_TRUE(lmptr_->addLease(leases[2]));
  354. EXPECT_TRUE(lmptr_->addLease(leases[3]));
  355. lmptr_->commit();
  356. // Reopen the database to ensure that they actually got stored.
  357. reopen();
  358. Lease6Ptr l_returned = lmptr_->getLease6(leasetype6_[1], ioaddress6_[1]);
  359. ASSERT_TRUE(l_returned);
  360. detailCompareLease(leases[1], l_returned);
  361. l_returned = lmptr_->getLease6(leasetype6_[2], ioaddress6_[2]);
  362. ASSERT_TRUE(l_returned);
  363. detailCompareLease(leases[2], l_returned);
  364. l_returned = lmptr_->getLease6(leasetype6_[3], ioaddress6_[3]);
  365. ASSERT_TRUE(l_returned);
  366. detailCompareLease(leases[3], l_returned);
  367. // Check that we can't add a second lease with the same address
  368. EXPECT_FALSE(lmptr_->addLease(leases[1]));
  369. // Delete a lease, check that it's gone, and that we can't delete it
  370. // a second time.
  371. EXPECT_TRUE(lmptr_->deleteLease(ioaddress6_[1]));
  372. l_returned = lmptr_->getLease6(leasetype6_[1], ioaddress6_[1]);
  373. EXPECT_FALSE(l_returned);
  374. EXPECT_FALSE(lmptr_->deleteLease(ioaddress6_[1]));
  375. // Check that the second address is still there.
  376. l_returned = lmptr_->getLease6(leasetype6_[2], ioaddress6_[2]);
  377. ASSERT_TRUE(l_returned);
  378. detailCompareLease(leases[2], l_returned);
  379. }
  380. };