zone_data_unittest.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright (C) 2012 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 "memory_segment_test.h"
  15. #include <dns/rdataclass.h>
  16. #include <exceptions/exceptions.h>
  17. #include <dns/name.h>
  18. #include <dns/labelsequence.h>
  19. #include <dns/rrclass.h>
  20. #include <datasrc/memory/rdata_encoder.h>
  21. #include <datasrc/memory/rdataset.h>
  22. #include <datasrc/memory/zone_data.h>
  23. #include <testutils/dnsmessage_test.h>
  24. #include <gtest/gtest.h>
  25. #include <new> // for bad_alloc
  26. #include <string>
  27. using namespace isc::dns;
  28. using namespace isc::dns::rdata;
  29. using namespace isc::datasrc::memory;
  30. using namespace isc::datasrc::memory::test;
  31. using namespace isc::testutils;
  32. namespace {
  33. // With this single fixture we'll test both NSEC3Data and ZoneData
  34. class ZoneDataTest : public ::testing::Test {
  35. protected:
  36. ZoneDataTest() :
  37. nsec3_data_(NULL), param_rdata_("1 0 12 aabbccdd"),
  38. param_rdata_nosalt_("1 1 10 -"),
  39. param_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a')),
  40. nsec3_rdata_("1 0 12 aabbccdd TDK23RP6 SOA"),
  41. nsec3_rdata_nosalt_("1 1 10 - TDK23RP6 SOA"),
  42. nsec3_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a') +
  43. " TDK23RP6 SOA"),
  44. zname_("example.com"),
  45. zone_data_(ZoneData::create(mem_sgmt_, zname_)),
  46. a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1")),
  47. aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA 2001:db8::1")),
  48. nsec3_rrset_(textToRRset("TDK23RP6.example.com. 3600 IN NSEC3 "
  49. "1 0 12 aabbccdd TDK23RP6 SOA"))
  50. {}
  51. void TearDown() {
  52. if (nsec3_data_ != NULL) {
  53. NSEC3Data::destroy(mem_sgmt_, nsec3_data_, RRClass::IN());
  54. }
  55. if (zone_data_ != NULL) {
  56. ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
  57. }
  58. // detect any memory leak in the test memory segment
  59. EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
  60. }
  61. MemorySegmentTest mem_sgmt_;
  62. NSEC3Data* nsec3_data_;
  63. const generic::NSEC3PARAM param_rdata_, param_rdata_nosalt_,
  64. param_rdata_largesalt_;
  65. const generic::NSEC3 nsec3_rdata_, nsec3_rdata_nosalt_,
  66. nsec3_rdata_largesalt_;
  67. const Name zname_;
  68. ZoneData* zone_data_;
  69. const ConstRRsetPtr a_rrset_, aaaa_rrset_, nsec3_rrset_;
  70. RdataEncoder encoder_;
  71. };
  72. // Shared by both test cases using NSEC3 and NSEC3PARAM Rdata
  73. template <typename RdataType>
  74. void
  75. checkNSEC3Data(MemorySegmentTest& mem_sgmt, const RdataType& expect_rdata) {
  76. NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt, expect_rdata);
  77. // Internal tree should be created and empty.
  78. EXPECT_EQ(0, nsec3_data->getNSEC3Tree().getNodeCount());
  79. EXPECT_EQ(expect_rdata.getHashalg(), nsec3_data->hashalg);
  80. EXPECT_EQ(expect_rdata.getFlags(), nsec3_data->flags);
  81. EXPECT_EQ(expect_rdata.getIterations(), nsec3_data->iterations);
  82. EXPECT_EQ(expect_rdata.getSalt().size(), nsec3_data->getSaltLen());
  83. if (expect_rdata.getSalt().size() > 0) {
  84. EXPECT_EQ(0, memcmp(&expect_rdata.getSalt()[0],
  85. nsec3_data->getSaltData(),
  86. expect_rdata.getSalt().size()));
  87. }
  88. NSEC3Data::destroy(mem_sgmt, nsec3_data, RRClass::IN());
  89. }
  90. void
  91. checkFindRdataSet(const ZoneTree& tree, const Name& name, RRType type,
  92. const RdataSet* expected_set)
  93. {
  94. ZoneNode* node = NULL;
  95. tree.find(name, &node);
  96. ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
  97. EXPECT_EQ(expected_set, RdataSet::find(node->getData(), type));
  98. }
  99. TEST_F(ZoneDataTest, createNSEC3Data) {
  100. // Create an NSEC3Data object from various types of RDATA (of NSEC3PARAM
  101. // and of NSEC3), check if the resulting parameters match.
  102. checkNSEC3Data(mem_sgmt_, param_rdata_); // one 'usual' form of params
  103. checkNSEC3Data(mem_sgmt_, param_rdata_nosalt_); // empty salt
  104. checkNSEC3Data(mem_sgmt_, param_rdata_largesalt_); // max-len salt
  105. // Same concepts of the tests, using NSEC3 RDATA.
  106. checkNSEC3Data(mem_sgmt_, nsec3_rdata_);
  107. checkNSEC3Data(mem_sgmt_, nsec3_rdata_nosalt_);
  108. checkNSEC3Data(mem_sgmt_, nsec3_rdata_largesalt_);
  109. }
  110. TEST_F(ZoneDataTest, addNSEC3) {
  111. nsec3_data_ = NSEC3Data::create(mem_sgmt_, param_rdata_);
  112. ZoneNode* node = NULL;
  113. nsec3_data_->insertName(mem_sgmt_, nsec3_rrset_->getName(), &node);
  114. ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
  115. EXPECT_TRUE(node->isEmpty()); // initially it should be empty
  116. RdataSet* rdataset_nsec3 =
  117. RdataSet::create(mem_sgmt_, encoder_, nsec3_rrset_, ConstRRsetPtr());
  118. node->setData(rdataset_nsec3);
  119. // Confirm we can find the added ones from the zone data.
  120. checkFindRdataSet(nsec3_data_->getNSEC3Tree(), nsec3_rrset_->getName(),
  121. RRType::NSEC3(), rdataset_nsec3);
  122. // TearDown() will confirm there's no leak on destroy
  123. }
  124. TEST_F(ZoneDataTest, getOriginNode) {
  125. EXPECT_EQ(LabelSequence(zname_), zone_data_->getOriginNode()->getLabels());
  126. }
  127. TEST_F(ZoneDataTest, exceptionSafetyOnCreate) {
  128. // Note: below, we use our knowledge of how memory allocation happens
  129. // within the NSEC3Data, the zone data and the underlying domain tree
  130. // implementation. We'll emulate rare situations where allocate() fails
  131. // with an exception, and confirm it doesn't cause any harsh disruption
  132. // or leak.
  133. // Creating internal NSEC3 tree will succeed, but allocation of NSEC3Data
  134. // will fail due to bad_alloc. It shouldn't cause memory leak
  135. // (that would be caught in TearDown()).
  136. mem_sgmt_.setThrowCount(2);
  137. EXPECT_THROW(NSEC3Data::create(mem_sgmt_, param_rdata_), std::bad_alloc);
  138. // allocate() will throw on the insertion of the origin node.
  139. mem_sgmt_.setThrowCount(2);
  140. EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
  141. // allocate() will throw on creating the zone data.
  142. mem_sgmt_.setThrowCount(3);
  143. EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
  144. // These incomplete create() attempts shouldn't cause memory leak
  145. // (that would be caught in TearDown()).
  146. }
  147. TEST_F(ZoneDataTest, addRdataSets) {
  148. // Insert a name to the zone, and add a couple the data (RdataSet) objects
  149. // to the corresponding node.
  150. ZoneNode* node = NULL;
  151. zone_data_->insertName(mem_sgmt_, a_rrset_->getName(), &node);
  152. ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
  153. EXPECT_TRUE(node->isEmpty()); // initially it should be empty
  154. RdataSet* rdataset_a =
  155. RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr());
  156. node->setData(rdataset_a);
  157. RdataSet* rdataset_aaaa =
  158. RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_, ConstRRsetPtr());
  159. // make a linked list and replace the list head
  160. rdataset_aaaa->next = rdataset_a;
  161. node->setData(rdataset_aaaa);
  162. // Confirm we can find the added ones from the zone data.
  163. checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
  164. RRType::A(), rdataset_a);
  165. checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
  166. RRType::AAAA(), rdataset_aaaa);
  167. // There's no NS (or anything other than AAAA or A) RdataSet in the list
  168. checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
  169. RRType::NS(), NULL);
  170. // TearDown() will confirm there's no leak on destroy
  171. }
  172. TEST_F(ZoneDataTest, getSetNSEC3Data) {
  173. // Initially there's no NSEC3 data
  174. EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
  175. // isNSEC3Signed is true iff zone data has non NULL NSEC3 data
  176. EXPECT_FALSE(zone_data_->isNSEC3Signed());
  177. // Set a new one. The set method should return NULL. The get method
  178. // should return the new one.
  179. NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, param_rdata_);
  180. NSEC3Data* old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data);
  181. EXPECT_EQ(static_cast<NSEC3Data*>(NULL), old_nsec3_data);
  182. EXPECT_EQ(nsec3_data, zone_data_->getNSEC3Data());
  183. EXPECT_TRUE(zone_data_->isNSEC3Signed());
  184. // Replace an existing one with a yet another one.
  185. // We're responsible for destroying the old one.
  186. NSEC3Data* nsec3_data2 = NSEC3Data::create(mem_sgmt_, nsec3_rdata_);
  187. old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data2);
  188. EXPECT_EQ(nsec3_data, old_nsec3_data);
  189. EXPECT_EQ(nsec3_data2, zone_data_->getNSEC3Data());
  190. EXPECT_TRUE(zone_data_->isNSEC3Signed());
  191. NSEC3Data::destroy(mem_sgmt_, old_nsec3_data, RRClass::IN());
  192. // Setting NULL clears any existing one.
  193. old_nsec3_data = zone_data_->setNSEC3Data(NULL);
  194. EXPECT_EQ(nsec3_data2, old_nsec3_data);
  195. EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
  196. EXPECT_FALSE(zone_data_->isNSEC3Signed());
  197. // Then set it again. The zone data should destroy it on its own
  198. // destruction.
  199. zone_data_->setNSEC3Data(old_nsec3_data);
  200. }
  201. TEST_F(ZoneDataTest, isSigned) {
  202. // By default it's considered unsigned
  203. EXPECT_FALSE(zone_data_->isSigned());
  204. // declare it's signed, the isSigned() says so too
  205. zone_data_->setSigned(true);
  206. EXPECT_TRUE(zone_data_->isSigned());
  207. // change it to unsigned again
  208. zone_data_->setSigned(false);
  209. EXPECT_FALSE(zone_data_->isSigned());
  210. }
  211. }