treenode_rrset_unittest.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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 <datasrc/memory/zone_data.h>
  20. #include <util/unittests/wiredata.h>
  21. #include <testutils/dnsmessage_test.h>
  22. #include <gtest/gtest.h>
  23. #include <boost/bind.hpp>
  24. #include <boost/shared_ptr.hpp>
  25. #include <string>
  26. #include <vector>
  27. using std::vector;
  28. using std::string;
  29. using namespace isc::dns;
  30. using namespace isc::dns::rdata;
  31. using namespace isc::datasrc::memory;
  32. using namespace isc::testutils;
  33. using isc::util::unittests::matchWireData;
  34. using isc::util::OutputBuffer;
  35. namespace {
  36. class TreeNodeRRsetTest : public ::testing::Test {
  37. protected:
  38. TreeNodeRRsetTest() :
  39. rrclass_(RRClass::IN()),
  40. origin_name_("example.com"), www_name_("www.example.com"),
  41. wildcard_name_("*.example.com"), match_name_("match.example.com"),
  42. ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
  43. a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
  44. "www.example.com. 3600 IN A 192.0.2.2")),
  45. aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA "
  46. "2001:db8::1\n")),
  47. dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
  48. a_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
  49. "A 5 2 3600 20120814220826 20120715220826 "
  50. "1234 example.com. FAKE")),
  51. aaaa_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG AAAA 5 2"
  52. " 3600 20120814220826 20120715220826 "
  53. "1234 example.com. FAKE\n"
  54. "www.example.com. 3600 IN RRSIG AAAA 5 2"
  55. " 3600 20120814220826 20120715220826 "
  56. "4321 example.com. FAKE\n")),
  57. txt_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG TXT 5 2"
  58. " 3600 20120814220826 20120715220826 "
  59. "1234 example.com. FAKE\n")),
  60. wildmatch_rrset_(textToRRset(
  61. "match.example.com. 3600 IN A 192.0.2.1\n"
  62. "match.example.com. 3600 IN A 192.0.2.2")),
  63. wildmatch_rrsig_rrset_(textToRRset(
  64. "match.example.com. 3600 IN RRSIG "
  65. "A 5 2 3600 20120814220826 20120715220826 "
  66. "1234 example.com. FAKE")),
  67. zone_data_(NULL), origin_node_(NULL), www_node_(NULL),
  68. wildcard_node_(NULL), ns_rdataset_(NULL), dname_rdataset_(NULL),
  69. a_rdataset_(NULL), aaaa_rdataset_(NULL), rrsig_only_rdataset_(NULL),
  70. wildcard_rdataset_(NULL)
  71. {}
  72. void SetUp() {
  73. // We create some common test data here in SetUp() so it will be
  74. // as exception safe as possible.
  75. zone_data_ = ZoneData::create(mem_sgmt_, origin_name_);
  76. zone_data_->insertName(mem_sgmt_, origin_name_, &origin_node_);
  77. ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
  78. ConstRRsetPtr());
  79. origin_node_->setData(ns_rdataset_);
  80. dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
  81. ConstRRsetPtr());
  82. ns_rdataset_->next = dname_rdataset_;
  83. zone_data_->insertName(mem_sgmt_, www_name_, &www_node_);
  84. a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
  85. a_rrsig_rrset_);
  86. www_node_->setData(a_rdataset_);
  87. aaaa_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_,
  88. aaaa_rrsig_rrset_);
  89. a_rdataset_->next = aaaa_rdataset_;
  90. // A rare (half broken) case of RRSIG-only set
  91. rrsig_only_rdataset_ = RdataSet::create(mem_sgmt_, encoder_,
  92. ConstRRsetPtr(),
  93. txt_rrsig_rrset_);
  94. aaaa_rdataset_->next = rrsig_only_rdataset_;
  95. zone_data_->insertName(mem_sgmt_, wildcard_name_, &wildcard_node_);
  96. wildcard_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
  97. a_rrsig_rrset_);
  98. wildcard_node_->setData(wildcard_rdataset_);
  99. }
  100. void TearDown() {
  101. ZoneData::destroy(mem_sgmt_, zone_data_, rrclass_);
  102. // detect any memory leak
  103. EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
  104. }
  105. const RRClass rrclass_;
  106. const Name origin_name_, www_name_, wildcard_name_, match_name_;
  107. isc::util::MemorySegmentLocal mem_sgmt_;
  108. RdataEncoder encoder_;
  109. MessageRenderer renderer_, renderer_expected_;
  110. ConstRRsetPtr ns_rrset_, a_rrset_, aaaa_rrset_, dname_rrset_,
  111. a_rrsig_rrset_, aaaa_rrsig_rrset_, txt_rrsig_rrset_,
  112. wildmatch_rrset_, wildmatch_rrsig_rrset_;
  113. ZoneData* zone_data_;
  114. ZoneNode* origin_node_;
  115. ZoneNode* www_node_;
  116. ZoneNode* wildcard_node_;
  117. RdataSet* ns_rdataset_;
  118. RdataSet* dname_rdataset_;
  119. RdataSet* a_rdataset_;
  120. RdataSet* aaaa_rdataset_;
  121. RdataSet* rrsig_only_rdataset_;
  122. RdataSet* wildcard_rdataset_; // for wildcard (type doesn't matter much)
  123. };
  124. void
  125. compareRRSIGData(RdataIteratorPtr rit, const void* data, size_t data_len) {
  126. ASSERT_FALSE(rit->isLast());
  127. OutputBuffer buffer(0);
  128. rit->getCurrent().toWire(buffer);
  129. matchWireData(data, data_len, buffer.getData(), buffer.getLength());
  130. rit->next();
  131. }
  132. // Check some trivial fields of a constructed TreeNodeRRset (passed as
  133. // AbstractRRset as we'd normally use it in polymorphic way).
  134. // Other complicated fields are checked through rendering tests.
  135. void
  136. checkBasicFields(const AbstractRRset& actual_rrset, const RdataSet* rdataset,
  137. const Name& expected_name,
  138. const RRClass& expected_class, const RRType& expected_type,
  139. const uint32_t expected_ttl,
  140. size_t expected_rdatacount, size_t expected_sigcount)
  141. {
  142. EXPECT_EQ(expected_name, actual_rrset.getName());
  143. EXPECT_EQ(expected_class, actual_rrset.getClass());
  144. EXPECT_EQ(expected_type, actual_rrset.getType());
  145. EXPECT_EQ(RRTTL(expected_ttl), actual_rrset.getTTL());
  146. EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
  147. EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
  148. // getRRsig() should return non NULL iff the RRset is expected to be signed
  149. if (expected_sigcount == 0) {
  150. EXPECT_FALSE(actual_rrset.getRRsig());
  151. } else {
  152. ConstRRsetPtr actual_sigrrset = actual_rrset.getRRsig();
  153. ASSERT_TRUE(actual_sigrrset);
  154. EXPECT_EQ(expected_name, actual_sigrrset->getName());
  155. EXPECT_EQ(expected_class, actual_sigrrset->getClass());
  156. EXPECT_EQ(RRType::RRSIG(), actual_sigrrset->getType());
  157. EXPECT_EQ(RRTTL(expected_ttl), actual_sigrrset->getTTL());
  158. EXPECT_EQ(expected_sigcount, actual_sigrrset->getRdataCount());
  159. // Compare each RRSIG RDATA
  160. RdataIteratorPtr rit = actual_sigrrset->getRdataIterator();
  161. RdataReader reader(expected_class, expected_type,
  162. rdataset->getDataBuf(), expected_rdatacount,
  163. expected_sigcount, &RdataReader::emptyNameAction,
  164. boost::bind(compareRRSIGData, rit, _1, _2));
  165. while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) {}
  166. EXPECT_TRUE(rit->isLast()); // should check all RDATAs
  167. }
  168. }
  169. // The following two are trivial wrapper to create a shared pointer
  170. // version of TreeNodeRRset object in order to work around dubious
  171. // behavior of some C++ compiler: they reject getting a const reference to
  172. // a temporary non-copyable object.
  173. boost::shared_ptr<TreeNodeRRset>
  174. createRRset(const RRClass& rrclass, const ZoneNode* node,
  175. const RdataSet* rdataset, bool dnssec_ok)
  176. {
  177. return (boost::shared_ptr<TreeNodeRRset>(
  178. new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok)));
  179. }
  180. boost::shared_ptr<TreeNodeRRset>
  181. createRRset(const Name& realname, const RRClass& rrclass, const ZoneNode* node,
  182. const RdataSet* rdataset, bool dnssec_ok)
  183. {
  184. return (boost::shared_ptr<TreeNodeRRset>(
  185. new TreeNodeRRset(realname, rrclass, node, rdataset,
  186. dnssec_ok)));
  187. }
  188. TEST_F(TreeNodeRRsetTest, create) {
  189. // Constructed with RRSIG, and it should be visible.
  190. checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true),
  191. a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
  192. 1);
  193. // Constructed with RRSIG, and it should be invisible.
  194. checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false),
  195. a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
  196. 0);
  197. // Constructed without RRSIG, and it would be visible (but of course won't)
  198. checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
  199. ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
  200. 1, 0);
  201. // Constructed without RRSIG, and it should be visible
  202. checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
  203. ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
  204. 1, 0);
  205. // RRSIG-only case (note the RRset's type is covered type)
  206. checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  207. true),
  208. rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
  209. 3600, 0, 1);
  210. // RRSIG-only case (note the RRset's type is covered type), but it's
  211. // invisible
  212. checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  213. false),
  214. rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
  215. 3600, 0, 0);
  216. // Wildcard substitution
  217. checkBasicFields(*createRRset(match_name_, rrclass_,
  218. wildcard_node_, wildcard_rdataset_,
  219. true),
  220. wildcard_rdataset_, match_name_, rrclass_, RRType::A(),
  221. 3600, 2, 1);
  222. }
  223. // The following two templated functions are helper to encapsulate the
  224. // concept truncation and handle MessageRenderer and OutputBuffer transparently
  225. // in templated test cases.
  226. template <typename OutputType>
  227. void
  228. setOutputLengthLimit(OutputType& output, size_t len_limit) {
  229. output.setLengthLimit(len_limit);
  230. }
  231. template <>
  232. void
  233. setOutputLengthLimit<OutputBuffer>(OutputBuffer&, size_t) {
  234. }
  235. template <typename OutputType>
  236. bool
  237. isOutputTruncated(OutputType& output) {
  238. return (output.isTruncated());
  239. }
  240. template <>
  241. bool
  242. isOutputTruncated<OutputBuffer>(OutputBuffer&) {
  243. return (false);
  244. }
  245. // Templated so we so can support OutputBuffer version of toWire().
  246. // We use the above helper templated functions for some renderer only methods.
  247. // We test two sets of cases: normal rendering case and case when truncation
  248. // is expected. The latter is effectively for MessageRenderer only.
  249. // If len_limit == 0, we consider it the normal case; otherwise it's for
  250. // truncation. prepended_name isn't used for the truncation case.
  251. template <typename OutputType>
  252. void
  253. checkToWireResult(OutputType& expected_output, OutputType& actual_output,
  254. const AbstractRRset& actual_rrset,
  255. const Name& prepended_name,
  256. ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
  257. bool dnssec_ok,
  258. size_t len_limit = 0,
  259. size_t expected_result = 0)
  260. {
  261. expected_output.clear();
  262. actual_output.clear();
  263. if (len_limit == 0) { // normal rendering
  264. // Prepare "actual" rendered data. We prepend a name to confirm the
  265. // owner name should be compressed in both cases.
  266. prepended_name.toWire(actual_output);
  267. const size_t rdata_count = rrset ? rrset->getRdataCount() : 0;
  268. const int expected_ret = (dnssec_ok && rrsig_rrset) ?
  269. rdata_count + rrsig_rrset->getRdataCount() : rdata_count;
  270. EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
  271. } else { // truncation
  272. setOutputLengthLimit(actual_output, len_limit);
  273. EXPECT_EQ(expected_result, actual_rrset.toWire(actual_output));
  274. EXPECT_TRUE(isOutputTruncated(actual_output)); // always true here
  275. }
  276. // Prepare "expected" data.
  277. if (len_limit == 0) { // normal rendering
  278. prepended_name.toWire(expected_output);
  279. } else { // truncation
  280. setOutputLengthLimit(expected_output, len_limit);
  281. }
  282. if (rrset) {
  283. rrset->toWire(expected_output);
  284. }
  285. if (!isOutputTruncated(expected_output) && dnssec_ok && rrsig_rrset) {
  286. rrsig_rrset->toWire(expected_output);
  287. }
  288. // Compare the two.
  289. matchWireData(expected_output.getData(), expected_output.getLength(),
  290. actual_output.getData(), actual_output.getLength());
  291. }
  292. TEST_F(TreeNodeRRsetTest, toWire) {
  293. MessageRenderer expected_renderer, actual_renderer;
  294. OutputBuffer expected_buffer(0), actual_buffer(0);
  295. {
  296. SCOPED_TRACE("with RRSIG, DNSSEC OK");
  297. const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
  298. checkToWireResult(expected_renderer, actual_renderer, rrset,
  299. www_name_, a_rrset_, a_rrsig_rrset_, true);
  300. // Currently the buffer version throws
  301. EXPECT_THROW(
  302. checkToWireResult(expected_buffer, actual_buffer, rrset,
  303. www_name_, a_rrset_, a_rrsig_rrset_, true),
  304. isc::Unexpected);
  305. }
  306. {
  307. SCOPED_TRACE("with RRSIG, DNSSEC not OK");
  308. const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, false);
  309. checkToWireResult(expected_renderer, actual_renderer, rrset,
  310. www_name_, a_rrset_, a_rrsig_rrset_, false);
  311. }
  312. {
  313. SCOPED_TRACE("without RRSIG, DNSSEC OK");
  314. const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_, true);
  315. checkToWireResult(expected_renderer, actual_renderer, rrset,
  316. origin_name_, ns_rrset_, ConstRRsetPtr(), true);
  317. }
  318. {
  319. SCOPED_TRACE("without RRSIG, DNSSEC not OK");
  320. const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_,
  321. false);
  322. checkToWireResult(expected_renderer, actual_renderer, rrset,
  323. origin_name_, ns_rrset_, ConstRRsetPtr(), false);
  324. }
  325. {
  326. // RDATA of DNAME DR shouldn't be compressed. Prepending "example.org"
  327. // will check that.
  328. SCOPED_TRACE("uncompressed RDATA");
  329. const TreeNodeRRset rrset(rrclass_, origin_node_, dname_rdataset_,
  330. false);
  331. checkToWireResult(expected_renderer, actual_renderer, rrset,
  332. Name("example.org"), dname_rrset_, ConstRRsetPtr(),
  333. false);
  334. }
  335. {
  336. SCOPED_TRACE("wildcard with RRSIG");
  337. checkToWireResult(expected_renderer, actual_renderer,
  338. *createRRset(match_name_, rrclass_, wildcard_node_,
  339. wildcard_rdataset_, true),
  340. origin_name_, wildmatch_rrset_,
  341. wildmatch_rrsig_rrset_, true);
  342. }
  343. {
  344. SCOPED_TRACE("wildcard without RRSIG");
  345. checkToWireResult(expected_renderer, actual_renderer,
  346. *createRRset(match_name_, rrclass_, wildcard_node_,
  347. wildcard_rdataset_, false),
  348. origin_name_, wildmatch_rrset_,
  349. wildmatch_rrsig_rrset_, false);
  350. }
  351. {
  352. // Very unusual case: the set only contains RRSIG (already rare)
  353. // and it's requested to be dumped to wire (can only happen in
  354. // ANY or type-RRSIG queries, which are rare also). But can still
  355. // happen.
  356. SCOPED_TRACE("RRSIG only, DNSSEC OK");
  357. const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
  358. true);
  359. checkToWireResult(expected_renderer, actual_renderer, rrset,
  360. www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,true);
  361. }
  362. {
  363. // Similar to the previous case, but DNSSEC records aren't requested.
  364. // In practice this case wouldn't happen, but API-wise possible, so
  365. // we test it explicitly.
  366. SCOPED_TRACE("RRSIG only, DNSSEC not OK");
  367. const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
  368. false);
  369. checkToWireResult(expected_renderer, actual_renderer, rrset,
  370. www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,false);
  371. }
  372. }
  373. TEST_F(TreeNodeRRsetTest, toWireTruncated) {
  374. MessageRenderer expected_renderer, actual_renderer;
  375. // dummy parameter to checkToWireResult (unused for the this test case)
  376. const Name& name = Name::ROOT_NAME();
  377. // Set the truncation limit to name len + 14 bytes of fixed data for A RR
  378. // (type, class, TTL, rdlen, and 4-byte IPv4 address). Then we can only
  379. // render just one RR, without any garbage trailing data.
  380. checkToWireResult(expected_renderer, actual_renderer,
  381. *createRRset(rrclass_, www_node_, a_rdataset_, true),
  382. name, a_rrset_, a_rrsig_rrset_, true,
  383. www_name_.getLength() + 14,
  384. 1); // 1 main RR, no RRSIG
  385. // The first main RRs should fit in the renderer (the name will be
  386. // fully compressed, so its size is 2 bytes), but the RRSIG doesn't.
  387. checkToWireResult(expected_renderer, actual_renderer,
  388. *createRRset(rrclass_, www_node_, a_rdataset_, true),
  389. name, a_rrset_, a_rrsig_rrset_, true,
  390. www_name_.getLength() + 14 + 2 + 14,
  391. 2); // 2 main RR, no RRSIG
  392. // This RRset has one main RR and two RRSIGs. Rendering the second RRSIG
  393. // causes truncation.
  394. // First, compute the rendered length for the main RR and a single RRSIG.
  395. // The length of the RRSIG should be the same if we "accidentally"
  396. // rendered the RRSIG for the A RR (which only contains one RRSIG).
  397. expected_renderer.clear();
  398. aaaa_rrset_->toWire(expected_renderer);
  399. a_rrsig_rrset_->toWire(expected_renderer);
  400. const size_t limit_len = expected_renderer.getLength();
  401. // Then perform the test
  402. checkToWireResult(expected_renderer, actual_renderer,
  403. *createRRset(rrclass_, www_node_, aaaa_rdataset_, true),
  404. name, aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len,
  405. 2); // 1 main RR, 1 RRSIG
  406. // RRSIG only case. Render length limit being 1, so it won't fit,
  407. // and will cause truncation.
  408. checkToWireResult(expected_renderer, actual_renderer,
  409. *createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  410. true),
  411. name, ConstRRsetPtr(), txt_rrsig_rrset_, true, 1,
  412. 0); // no RR
  413. }
  414. void
  415. checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
  416. for (vector<string>::const_iterator it = expected.begin();
  417. it != expected.end();
  418. ++it)
  419. {
  420. ASSERT_FALSE(rit->isLast());
  421. EXPECT_EQ(*it, rit->getCurrent().toText());
  422. rit->next();
  423. }
  424. // We should have reached the end of RDATA
  425. EXPECT_TRUE(rit->isLast());
  426. // move to the first RDATA again, and check the value.
  427. rit->first();
  428. if (!expected.empty()) {
  429. EXPECT_EQ(expected[0], rit->getCurrent().toText());
  430. } else {
  431. EXPECT_TRUE(rit->isLast());
  432. }
  433. }
  434. TEST_F(TreeNodeRRsetTest, getRdataIterator) {
  435. // This RRset should have 2 A RDATAs
  436. vector<string> expected;
  437. expected.push_back("192.0.2.1");
  438. expected.push_back("192.0.2.2");
  439. checkRdataIterator(expected,
  440. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
  441. getRdataIterator());
  442. // The iterator shouldn't work different with or without RRSIG
  443. checkRdataIterator(expected,
  444. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
  445. getRdataIterator());
  446. // This RRset should have 1 NS RDATA (containing name field)
  447. expected.clear();
  448. expected.push_back("ns.example.com.");
  449. checkRdataIterator(expected,
  450. TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
  451. false).getRdataIterator());
  452. // RRSIG only. Iterator will be empty and shouldn't cause any disruption.
  453. expected.clear();
  454. checkRdataIterator(expected,
  455. TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  456. true).getRdataIterator());
  457. }
  458. void
  459. checkToText(const AbstractRRset& actual_rrset,
  460. ConstRRsetPtr expected_rrset, ConstRRsetPtr expected_sig_rrset)
  461. {
  462. const string actual_text = actual_rrset.toText();
  463. const string expected_text =
  464. (expected_rrset ? expected_rrset->toText() : "") +
  465. (expected_sig_rrset ? expected_sig_rrset->toText() : "");
  466. EXPECT_EQ(expected_text, actual_text);
  467. }
  468. TEST_F(TreeNodeRRsetTest, toText) {
  469. // Constructed with RRSIG, and it should be visible.
  470. checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true),
  471. a_rrset_, a_rrsig_rrset_);
  472. // Constructed with RRSIG, and it should be invisible.
  473. checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, false),
  474. a_rrset_, ConstRRsetPtr());
  475. // Constructed without RRSIG, and it would be visible (but of course won't)
  476. checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
  477. ns_rrset_, ConstRRsetPtr());
  478. // Constructed without RRSIG, and it should be visible
  479. checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
  480. ns_rrset_, ConstRRsetPtr());
  481. // Wildcard expanded name with RRSIG
  482. checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
  483. wildcard_rdataset_, true),
  484. wildmatch_rrset_, wildmatch_rrsig_rrset_);
  485. // Wildcard expanded name without RRSIG
  486. checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
  487. wildcard_rdataset_, false),
  488. wildmatch_rrset_, ConstRRsetPtr());
  489. // RRSIG case
  490. checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  491. true),
  492. ConstRRsetPtr(), txt_rrsig_rrset_);
  493. // Similar to the previous case, but completely empty.
  494. checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
  495. false),
  496. ConstRRsetPtr(), ConstRRsetPtr());
  497. }
  498. TEST_F(TreeNodeRRsetTest, isSameKind) {
  499. const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
  500. // Same name (node), same type (rdataset) => same kind
  501. EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
  502. a_rdataset_, true)));
  503. // Same name (node), different type (rdataset) => not same kind
  504. EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
  505. aaaa_rdataset_, true)));
  506. // Different name, different type => not same kind
  507. EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
  508. ns_rdataset_, true)));
  509. // Different name, same type => not same kind.
  510. // Note: this shouldn't happen in our in-memory data source implementation,
  511. // but API doesn't prohibit it.
  512. EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
  513. a_rdataset_, true)));
  514. // Wildcard and expanded RRset
  515. const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_,
  516. wildcard_rdataset_, true);
  517. const TreeNodeRRset match_rrset(match_name_, rrclass_, wildcard_node_,
  518. wildcard_rdataset_, true);
  519. EXPECT_FALSE(wildcard_rrset.isSameKind(match_rrset));
  520. EXPECT_FALSE(match_rrset.isSameKind(wildcard_rrset));
  521. // Both are wildcard expanded, and have different names
  522. const TreeNodeRRset match2_rrset(Name("match2.example.com"), rrclass_,
  523. wildcard_node_, wildcard_rdataset_, true);
  524. EXPECT_FALSE(match_rrset.isSameKind(match2_rrset));
  525. EXPECT_FALSE(match2_rrset.isSameKind(match_rrset));
  526. // Pathological case. "badwild" is constructed as if expanded due to
  527. // a wildcard, but has the same owner name of the wildcard itself.
  528. // Technically, they should be considered of the same kind, but this
  529. // implementation considers they are not. But this case shouldn't happen
  530. // as long as the RRsets are only constructed inside the in-memory
  531. // zone finder implementation.
  532. const TreeNodeRRset badwild_rrset(wildcard_name_, rrclass_, wildcard_node_,
  533. wildcard_rdataset_, true);
  534. EXPECT_FALSE(wildcard_rrset.isSameKind(badwild_rrset));
  535. EXPECT_EQ(wildcard_rrset.toText(), badwild_rrset.toText());
  536. // Pathological case: Same name, same type, but different class.
  537. // This case should be impossible because if the RRsets share the same
  538. // tree node, they must belong to the same RR class. This case is
  539. // a caller's bug, and the isSameKind() implementation returns the
  540. // "wrong" (= true) answer.
  541. EXPECT_TRUE(rrset.isSameKind(*createRRset(RRClass::CH(), www_node_,
  542. a_rdataset_, true)));
  543. // Same kind of different RRset class
  544. EXPECT_TRUE(rrset.isSameKind(*a_rrset_));
  545. // Different kind of different RRset class
  546. EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_));
  547. }
  548. TEST_F(TreeNodeRRsetTest, unexpectedMethods) {
  549. // Note: buffer version of toWire() is checked in the toWire test.
  550. TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
  551. EXPECT_THROW(rrset.setTTL(RRTTL(0)), isc::Unexpected);
  552. EXPECT_THROW(rrset.setName(Name("example")), isc::Unexpected);
  553. EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
  554. isc::Unexpected);
  555. RdataPtr sig_rdata = createRdata(
  556. RRType::RRSIG(), rrclass_,
  557. "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE");
  558. EXPECT_THROW(rrset.addRRsig(sig_rdata), isc::Unexpected);
  559. EXPECT_THROW(rrset.addRRsig(*a_rrsig_rrset_), isc::Unexpected);
  560. EXPECT_THROW(rrset.addRRsig(a_rrsig_rrset_), isc::Unexpected);
  561. EXPECT_THROW(rrset.addRRsig(RRsetPtr()), isc::Unexpected);
  562. EXPECT_THROW(rrset.removeRRsig(), isc::Unexpected);
  563. }
  564. }