zone_table_unittest.cc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 <exceptions/exceptions.h>
  15. #include <util/memory_segment_local.h>
  16. #include <dns/name.h>
  17. #include <dns/rrclass.h>
  18. #include <datasrc/result.h>
  19. #include <datasrc/memory/zone_data.h>
  20. #include <datasrc/memory/zone_table.h>
  21. #include <datasrc/memory/segment_object_holder.h>
  22. #include <datasrc/tests/memory/memory_segment_mock.h>
  23. #include <gtest/gtest.h>
  24. #include <new> // for bad_alloc
  25. using namespace isc::dns;
  26. using namespace isc::datasrc;
  27. using namespace isc::datasrc::memory;
  28. using namespace isc::datasrc::memory::detail;
  29. namespace {
  30. class ZoneTableTest : public ::testing::Test {
  31. protected:
  32. ZoneTableTest() : zclass_(RRClass::IN()),
  33. zname1(Name("example.com")),
  34. zname2(Name("example.net")),
  35. zname3(Name("example")),
  36. zone_table(ZoneTable::create(mem_sgmt_, zclass_))
  37. {}
  38. ~ZoneTableTest() {
  39. if (zone_table != NULL) {
  40. ZoneTable::destroy(mem_sgmt_, zone_table);
  41. }
  42. }
  43. void TearDown() {
  44. ZoneTable::destroy(mem_sgmt_, zone_table);
  45. zone_table = NULL;
  46. EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
  47. }
  48. const RRClass zclass_;
  49. const Name zname1, zname2, zname3;
  50. test::MemorySegmentMock mem_sgmt_;
  51. ZoneTable* zone_table;
  52. };
  53. TEST_F(ZoneTableTest, create) {
  54. // Test about creating a zone table. Normal case covers through other
  55. // tests. We only check exception safety by letting the test memory
  56. // segment throw.
  57. mem_sgmt_.setThrowCount(2);
  58. EXPECT_THROW(ZoneTable::create(mem_sgmt_, zclass_), std::bad_alloc);
  59. // This shouldn't cause memory leak (that would be caught in TearDown()).
  60. }
  61. TEST_F(ZoneTableTest, addZone) {
  62. // By default there's no zone contained.
  63. EXPECT_EQ(0, zone_table->getZoneCount());
  64. // It doesn't accept NULL as zone data
  65. EXPECT_THROW(zone_table->addZone(mem_sgmt_, zname1, NULL),
  66. isc::InvalidParameter);
  67. EXPECT_EQ(0, zone_table->getZoneCount()); // count is still 0
  68. // or an empty zone data
  69. SegmentObjectHolder<ZoneData, RRClass> holder_empty(
  70. mem_sgmt_, zclass_);
  71. holder_empty.set(ZoneData::create(mem_sgmt_));
  72. EXPECT_THROW(zone_table->addZone(mem_sgmt_, zname1, holder_empty.get()),
  73. isc::InvalidParameter);
  74. SegmentObjectHolder<ZoneData, RRClass> holder1(
  75. mem_sgmt_, zclass_);
  76. holder1.set(ZoneData::create(mem_sgmt_, zname1));
  77. const ZoneData* data1(holder1.get());
  78. // Normal successful case.
  79. const ZoneTable::AddResult result1(zone_table->addZone(mem_sgmt_, zname1,
  80. holder1.release()));
  81. EXPECT_EQ(result::SUCCESS, result1.code);
  82. EXPECT_EQ(static_cast<const ZoneData*>(NULL), result1.zone_data);
  83. // It got released by it
  84. EXPECT_EQ(static_cast<const ZoneData*>(NULL), holder1.get());
  85. EXPECT_EQ(1, zone_table->getZoneCount()); // count is now incremented
  86. // Duplicate add replaces the existing data wit the newly added one.
  87. SegmentObjectHolder<ZoneData, RRClass> holder2(mem_sgmt_, zclass_);
  88. holder2.set(ZoneData::create(mem_sgmt_, zname1));
  89. const ZoneTable::AddResult result2(zone_table->addZone(mem_sgmt_, zname1,
  90. holder2.release()));
  91. EXPECT_EQ(result::EXIST, result2.code);
  92. // The old one gets out
  93. EXPECT_EQ(data1, result2.zone_data);
  94. // It releases this one even when we replace the old zone
  95. EXPECT_EQ(static_cast<const ZoneData*>(NULL), holder2.get());
  96. // We need to release the old one manually
  97. ZoneData::destroy(mem_sgmt_, result2.zone_data, zclass_);
  98. EXPECT_EQ(1, zone_table->getZoneCount()); // count doesn't change.
  99. SegmentObjectHolder<ZoneData, RRClass> holder3(
  100. mem_sgmt_, zclass_);
  101. holder3.set(ZoneData::create(mem_sgmt_, Name("EXAMPLE.COM")));
  102. // names are compared in a case insensitive manner.
  103. const ZoneTable::AddResult result3(zone_table->addZone(mem_sgmt_,
  104. Name("EXAMPLE.COM"),
  105. holder3.release()));
  106. EXPECT_EQ(result::EXIST, result3.code);
  107. ZoneData::destroy(mem_sgmt_, result3.zone_data, zclass_);
  108. // Add some more different ones. Should just succeed.
  109. SegmentObjectHolder<ZoneData, RRClass> holder4(
  110. mem_sgmt_, zclass_);
  111. holder4.set(ZoneData::create(mem_sgmt_, zname2));
  112. EXPECT_EQ(result::SUCCESS,
  113. zone_table->addZone(mem_sgmt_, zname2, holder4.release()).code);
  114. EXPECT_EQ(2, zone_table->getZoneCount());
  115. SegmentObjectHolder<ZoneData, RRClass> holder5(
  116. mem_sgmt_, zclass_);
  117. holder5.set(ZoneData::create(mem_sgmt_, zname3));
  118. EXPECT_EQ(result::SUCCESS,
  119. zone_table->addZone(mem_sgmt_, zname3, holder5.release()).code);
  120. EXPECT_EQ(3, zone_table->getZoneCount());
  121. // Have the memory segment throw an exception in extending the internal
  122. // tree. We'll destroy it after that via SegmentObjectHolder.
  123. SegmentObjectHolder<ZoneData, RRClass> holder6(
  124. mem_sgmt_, zclass_);
  125. holder6.set(ZoneData::create(mem_sgmt_, Name("example.org")));
  126. mem_sgmt_.setThrowCount(1);
  127. EXPECT_THROW(zone_table->addZone(mem_sgmt_, Name("example.org"),
  128. holder6.get()),
  129. std::bad_alloc);
  130. }
  131. TEST_F(ZoneTableTest, addEmptyZone) {
  132. // By default there's no zone contained.
  133. EXPECT_EQ(0, zone_table->getZoneCount());
  134. // Adding an empty zone. It should succeed.
  135. const ZoneTable::AddResult result1 =
  136. zone_table->addEmptyZone(mem_sgmt_, zname1);
  137. EXPECT_EQ(result::SUCCESS, result1.code);
  138. EXPECT_EQ(static_cast<const ZoneData*>(NULL), result1.zone_data);
  139. EXPECT_EQ(1, zone_table->getZoneCount());
  140. // The empty zone can be "found", with the ZONE_EMPTY flag on, and the
  141. // returned ZoneData being NULL.
  142. const ZoneTable::FindResult fresult1 = zone_table->findZone(zname1);
  143. EXPECT_EQ(result::SUCCESS, fresult1.code);
  144. EXPECT_EQ(result::ZONE_EMPTY, fresult1.flags);
  145. EXPECT_EQ(static_cast<const ZoneData*>(NULL), fresult1.zone_data);
  146. // Replacing an empty zone with non-empty one. Should be no problem, but
  147. // the empty zone data are not returned in the result structure; it's
  148. // internal to the ZoneTable implementation.
  149. SegmentObjectHolder<ZoneData, RRClass> holder2(mem_sgmt_, zclass_);
  150. holder2.set(ZoneData::create(mem_sgmt_, zname1));
  151. const ZoneTable::AddResult result2(zone_table->addZone(mem_sgmt_, zname1,
  152. holder2.release()));
  153. EXPECT_EQ(result::EXIST, result2.code);
  154. EXPECT_EQ(static_cast<const ZoneData*>(NULL), result2.zone_data);
  155. EXPECT_EQ(1, zone_table->getZoneCount());
  156. // Replacing a non-empty zone with an empty one is also okay. It's not
  157. // different from replacing with another non-empty one.
  158. const ZoneTable::AddResult result3 =
  159. zone_table->addEmptyZone(mem_sgmt_, zname1);
  160. EXPECT_EQ(result::EXIST, result3.code);
  161. EXPECT_NE(static_cast<const ZoneData*>(NULL), result3.zone_data);
  162. ZoneData::destroy(mem_sgmt_, result3.zone_data, zclass_);
  163. EXPECT_EQ(1, zone_table->getZoneCount());
  164. }
  165. TEST_F(ZoneTableTest, findZone) {
  166. SegmentObjectHolder<ZoneData, RRClass> holder1(
  167. mem_sgmt_, zclass_);
  168. holder1.set(ZoneData::create(mem_sgmt_, zname1));
  169. ZoneData* zone_data = holder1.get();
  170. EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zname1,
  171. holder1.release()).code);
  172. SegmentObjectHolder<ZoneData, RRClass> holder2(
  173. mem_sgmt_, zclass_);
  174. holder2.set(ZoneData::create(mem_sgmt_, zname2));
  175. EXPECT_EQ(result::SUCCESS,
  176. zone_table->addZone(mem_sgmt_, zname2, holder2.release()).code);
  177. SegmentObjectHolder<ZoneData, RRClass> holder3(
  178. mem_sgmt_, zclass_);
  179. holder3.set(ZoneData::create(mem_sgmt_, zname3));
  180. EXPECT_EQ(result::SUCCESS,
  181. zone_table->addZone(mem_sgmt_, zname3, holder3.release()).code);
  182. const ZoneTable::FindResult find_result1 =
  183. zone_table->findZone(Name("example.com"));
  184. EXPECT_EQ(result::SUCCESS, find_result1.code);
  185. EXPECT_EQ(zone_data, find_result1.zone_data);
  186. EXPECT_EQ(result::NOTFOUND,
  187. zone_table->findZone(Name("example.org")).code);
  188. EXPECT_EQ(static_cast<ZoneData*>(NULL),
  189. zone_table->findZone(Name("example.org")).zone_data);
  190. // there's no exact match. the result should be the longest match,
  191. // and the code should be PARTIALMATCH.
  192. EXPECT_EQ(result::PARTIALMATCH,
  193. zone_table->findZone(Name("www.example.com")).code);
  194. EXPECT_EQ(zone_data,
  195. zone_table->findZone(Name("www.example.com")).zone_data);
  196. // make sure the partial match is indeed the longest match by adding
  197. // a zone with a shorter origin and query again.
  198. SegmentObjectHolder<ZoneData, RRClass> holder4(
  199. mem_sgmt_, zclass_);
  200. holder4.set(ZoneData::create(mem_sgmt_, Name("com")));
  201. EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, Name("com"),
  202. holder4.release()).code);
  203. EXPECT_EQ(zone_data,
  204. zone_table->findZone(Name("www.example.com")).zone_data);
  205. }
  206. }