treenode_rrset_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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 <util/buffer.h>
  15. #include <util/memory_segment_local.h>
  16. #include <datasrc/memory/treenode_rrset.h>
  17. #include <datasrc/memory/rdataset.h>
  18. #include <datasrc/memory/rdata_serialization.h>
  19. #include <util/unittests/wiredata.h>
  20. #include <testutils/dnsmessage_test.h>
  21. #include <gtest/gtest.h>
  22. #include <string>
  23. #include <vector>
  24. using std::vector;
  25. using std::string;
  26. using namespace isc::dns;
  27. using namespace isc::dns::rdata;
  28. using namespace isc::datasrc::memory;
  29. using namespace isc::testutils;
  30. using isc::util::unittests::matchWireData;
  31. using isc::util::OutputBuffer;
  32. namespace {
  33. class TreeNodeRRsetTest : public ::testing::Test {
  34. protected:
  35. TreeNodeRRsetTest() :
  36. rrclass_(RRClass::IN()),
  37. origin_name_("example.com"), www_name_("www.example.com"),
  38. ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
  39. a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
  40. "www.example.com. 3600 IN A 192.0.2.2")),
  41. dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
  42. rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
  43. "A 5 2 3600 20120814220826 20120715220826 "
  44. "1234 example.com. FAKE")),
  45. tree_(NULL)
  46. {}
  47. void SetUp() {
  48. // We create some common test data here in SetUp() so it will be
  49. // as exception safe as possible.
  50. tree_ = ZoneTree::create(mem_sgmt_, true);
  51. tree_->insert(mem_sgmt_, origin_name_, &origin_node_);
  52. ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
  53. ConstRRsetPtr());
  54. origin_node_->setData(mem_sgmt_, ns_rdataset_);
  55. dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
  56. ConstRRsetPtr());
  57. ns_rdataset_->next = dname_rdataset_;
  58. tree_->insert(mem_sgmt_, www_name_, &www_node_);
  59. a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
  60. rrsig_rrset_);
  61. www_node_->setData(mem_sgmt_, a_rdataset_);
  62. }
  63. void TearDown() {
  64. ZoneTree::destroy(mem_sgmt_, tree_);
  65. // detect any memory leak
  66. EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
  67. }
  68. const RRClass rrclass_;
  69. const Name origin_name_, www_name_;
  70. isc::util::MemorySegmentLocal mem_sgmt_;
  71. RdataEncoder encoder_;
  72. MessageRenderer renderer_, renderer_expected_;
  73. ConstRRsetPtr ns_rrset_, a_rrset_, dname_rrset_, rrsig_rrset_;
  74. ZoneTree* tree_;
  75. ZoneNode* origin_node_;
  76. ZoneNode* www_node_;
  77. RdataSet* ns_rdataset_;
  78. RdataSet* dname_rdataset_;
  79. RdataSet* a_rdataset_;
  80. };
  81. TEST_F(TreeNodeRRsetTest, create) {
  82. const TreeNodeRRset rrset1(rrclass_, www_node_, a_rdataset_, true);
  83. EXPECT_EQ(rrclass_, rrset1.getClass());
  84. EXPECT_EQ(RRType::A(), rrset1.getType());
  85. EXPECT_EQ(www_name_, rrset1.getName());
  86. EXPECT_EQ(2, rrset1.getRdataCount());
  87. EXPECT_EQ(1, rrset1.getRRsigDataCount());
  88. const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, false);
  89. EXPECT_EQ(rrclass_, rrset2.getClass());
  90. EXPECT_EQ(RRType::A(), rrset2.getType());
  91. EXPECT_EQ(www_name_, rrset2.getName());
  92. EXPECT_EQ(2, rrset2.getRdataCount());
  93. EXPECT_EQ(0, rrset2.getRRsigDataCount());
  94. }
  95. // Templated if and when we support OutputBuffer version of toWire().
  96. // Right now, we take a minimalist approach, only implementing testing the
  97. // renderer version.
  98. template <typename OutputType>
  99. void
  100. checkToWireResult(OutputType& expected_output, OutputType& actual_output,
  101. const TreeNodeRRset& actual_rrset,
  102. const Name& prepended_name,
  103. ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
  104. bool dnssec_ok)
  105. {
  106. expected_output.clear();
  107. actual_output.clear();
  108. // Prepare "actual" rendered data. We prepend a name to confirm the
  109. // owner name should be compressed in both cases.
  110. prepended_name.toWire(actual_output);
  111. const int expected_ret = (dnssec_ok && rrsig_rrset) ?
  112. rrset->getRdataCount() + rrsig_rrset->getRdataCount() :
  113. rrset->getRdataCount();
  114. EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
  115. // Prepare "expected" data.
  116. prepended_name.toWire(expected_output);
  117. rrset->toWire(expected_output);
  118. if (dnssec_ok && rrsig_rrset) {
  119. rrsig_rrset->toWire(expected_output);
  120. }
  121. // Compare the two.
  122. matchWireData(expected_output.getData(), expected_output.getLength(),
  123. actual_output.getData(), actual_output.getLength());
  124. }
  125. TEST_F(TreeNodeRRsetTest, toWire) {
  126. MessageRenderer expected_renderer, actual_renderer;
  127. {
  128. SCOPED_TRACE("with RRSIG, DNSSEC OK");
  129. const TreeNodeRRset rrset1(rrclass_, www_node_, a_rdataset_, true);
  130. checkToWireResult(expected_renderer, actual_renderer, rrset1,
  131. www_name_, a_rrset_, rrsig_rrset_, true);
  132. EXPECT_FALSE(actual_renderer.isTruncated());
  133. }
  134. {
  135. SCOPED_TRACE("with RRSIG, DNSSEC not OK");
  136. const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, false);
  137. checkToWireResult(expected_renderer, actual_renderer, rrset2,
  138. www_name_, a_rrset_, rrsig_rrset_, false);
  139. EXPECT_FALSE(actual_renderer.isTruncated());
  140. }
  141. {
  142. SCOPED_TRACE("without RRSIG, DNSSEC OK");
  143. const TreeNodeRRset rrset3(rrclass_, origin_node_, ns_rdataset_, true);
  144. checkToWireResult(expected_renderer, actual_renderer, rrset3,
  145. origin_name_, ns_rrset_, ConstRRsetPtr(), true);
  146. EXPECT_FALSE(actual_renderer.isTruncated());
  147. }
  148. {
  149. SCOPED_TRACE("without RRSIG, DNSSEC not OK");
  150. const TreeNodeRRset rrset4(rrclass_, origin_node_, ns_rdataset_,
  151. false);
  152. checkToWireResult(expected_renderer, actual_renderer, rrset4,
  153. origin_name_, ns_rrset_, ConstRRsetPtr(), false);
  154. EXPECT_FALSE(actual_renderer.isTruncated());
  155. }
  156. {
  157. // RDATA of DNAME DR shouldn't be compressed. Prepending "example.org"
  158. // will check that.
  159. SCOPED_TRACE("uncompressed RDATA");
  160. const TreeNodeRRset rrset5(rrclass_, origin_node_, dname_rdataset_,
  161. false);
  162. checkToWireResult(expected_renderer, actual_renderer, rrset5,
  163. Name("example.org"), dname_rrset_, ConstRRsetPtr(),
  164. false);
  165. EXPECT_FALSE(actual_renderer.isTruncated());
  166. }
  167. }
  168. void
  169. checkTruncationResult(MessageRenderer& expected_renderer,
  170. MessageRenderer& actual_renderer,
  171. const TreeNodeRRset& actual_rrset,
  172. ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
  173. bool dnssec_ok, size_t len_limit, size_t expected_result)
  174. {
  175. expected_renderer.clear();
  176. actual_renderer.clear();
  177. actual_renderer.setLengthLimit(len_limit);
  178. EXPECT_EQ(expected_result, actual_rrset.toWire(actual_renderer));
  179. EXPECT_TRUE(actual_renderer.isTruncated()); // always true in this test
  180. expected_renderer.setLengthLimit(len_limit);
  181. rrset->toWire(expected_renderer);
  182. if (!expected_renderer.isTruncated() && dnssec_ok && rrsig_rrset) {
  183. rrsig_rrset->toWire(expected_renderer);
  184. }
  185. matchWireData(expected_renderer.getData(), expected_renderer.getLength(),
  186. actual_renderer.getData(), actual_renderer.getLength());
  187. }
  188. TEST_F(TreeNodeRRsetTest, toWireTruncated) {
  189. MessageRenderer expected_renderer, actual_renderer;
  190. // Set the truncation limit to name len + 14 bytes of fixed data for A RR
  191. // (type, class, TTL, rdlen, and 4-byte IPv4 address). Then we can only
  192. // render just one RR, without any garbage trailing data.
  193. checkTruncationResult(expected_renderer, actual_renderer,
  194. TreeNodeRRset(rrclass_, www_node_, a_rdataset_,
  195. true),
  196. a_rrset_, rrsig_rrset_, true,
  197. www_name_.getLength() + 14,
  198. 1);
  199. // The first normal RRs should fit in the renderer (the name will be
  200. // fully compressed, so its size is 2 bytes), but the RRSIG doesn't.
  201. checkTruncationResult(expected_renderer, actual_renderer,
  202. TreeNodeRRset(rrclass_, www_node_, a_rdataset_,
  203. true),
  204. a_rrset_, rrsig_rrset_, true,
  205. www_name_.getLength() + 14 + 2 + 14, 2);
  206. }
  207. void
  208. checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
  209. for (vector<string>::const_iterator it = expected.begin();
  210. it != expected.end();
  211. ++it)
  212. {
  213. ASSERT_FALSE(rit->isLast());
  214. EXPECT_EQ(*it, rit->getCurrent().toText());
  215. rit->next();
  216. }
  217. // We should have reached the end of RDATA
  218. EXPECT_TRUE(rit->isLast());
  219. // move to the first RDATA again, and check the value.
  220. rit->first();
  221. EXPECT_EQ(expected[0], rit->getCurrent().toText());
  222. }
  223. TEST_F(TreeNodeRRsetTest, getRdataIterator) {
  224. // This RRset should have 2 A RDATAs
  225. vector<string> expected;
  226. expected.push_back("192.0.2.1");
  227. expected.push_back("192.0.2.2");
  228. checkRdataIterator(expected,
  229. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
  230. getRdataIterator());
  231. // The iterator shouldn't work different with or without RRSIG
  232. checkRdataIterator(expected,
  233. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
  234. getRdataIterator());
  235. // This RRset should have 1 NS RDATA (containing name field)
  236. expected.clear();
  237. expected.push_back("ns.example.com.");
  238. checkRdataIterator(expected,
  239. TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
  240. false).getRdataIterator());
  241. }
  242. }