rrcollator_unittest.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright (C) 2012-2013 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 <dns/name.h>
  16. #include <dns/master_loader.h>
  17. #include <dns/master_loader_callbacks.h>
  18. #include <dns/rrclass.h>
  19. #include <dns/rrcollator.h>
  20. #include <dns/rdata.h>
  21. #include <dns/rrset.h>
  22. #include <dns/rrttl.h>
  23. #include <gtest/gtest.h>
  24. #include <boost/bind.hpp>
  25. #include <sstream>
  26. #include <vector>
  27. using std::vector;
  28. using namespace isc::dns;
  29. using namespace isc::dns::rdata;
  30. namespace {
  31. typedef RRCollator::AddRRsetCallback AddRRsetCallback;
  32. void
  33. addRRset(const RRsetPtr& rrset, vector<ConstRRsetPtr>* to_append,
  34. const bool* do_throw) {
  35. if (*do_throw) {
  36. isc_throw(isc::Unexpected, "faked failure");
  37. }
  38. to_append->push_back(rrset);
  39. }
  40. class RRCollatorTest : public ::testing::Test {
  41. protected:
  42. RRCollatorTest() :
  43. origin_("example.com"), rrclass_(RRClass::IN()), rrttl_(3600),
  44. throw_from_callback_(false),
  45. collator_(boost::bind(addRRset, _1, &rrsets_, &throw_from_callback_)),
  46. rr_callback_(collator_.getCallback()),
  47. a_rdata1_(createRdata(RRType::A(), rrclass_, "192.0.2.1")),
  48. a_rdata2_(createRdata(RRType::A(), rrclass_, "192.0.2.2")),
  49. txt_rdata_(createRdata(RRType::TXT(), rrclass_, "test")),
  50. sig_rdata1_(createRdata(RRType::RRSIG(), rrclass_,
  51. "A 5 3 3600 20000101000000 20000201000000 "
  52. "12345 example.com. FAKE")),
  53. sig_rdata2_(createRdata(RRType::RRSIG(), rrclass_,
  54. "NS 5 3 3600 20000101000000 20000201000000 "
  55. "12345 example.com. FAKE"))
  56. {}
  57. void checkRRset(const Name& expected_name, const RRClass& expected_class,
  58. const RRType& expected_type, const RRTTL& expected_ttl,
  59. const vector<ConstRdataPtr>& expected_rdatas) {
  60. SCOPED_TRACE(expected_name.toText(true) + "/" +
  61. expected_class.toText() + "/" + expected_type.toText());
  62. // This test always clears rrsets_ to confirm RRsets are added
  63. // one-by-one
  64. ASSERT_EQ(1, rrsets_.size());
  65. ConstRRsetPtr actual = rrsets_[0];
  66. EXPECT_EQ(expected_name, actual->getName());
  67. EXPECT_EQ(expected_class, actual->getClass());
  68. EXPECT_EQ(expected_type, actual->getType());
  69. EXPECT_EQ(expected_ttl, actual->getTTL());
  70. ASSERT_EQ(expected_rdatas.size(), actual->getRdataCount());
  71. vector<ConstRdataPtr>::const_iterator it = expected_rdatas.begin();
  72. for (RdataIteratorPtr rit = actual->getRdataIterator();
  73. !rit->isLast();
  74. rit->next()) {
  75. EXPECT_EQ(0, rit->getCurrent().compare(**it));
  76. ++it;
  77. }
  78. rrsets_.clear();
  79. }
  80. const Name origin_;
  81. const RRClass rrclass_;
  82. const RRTTL rrttl_;
  83. vector<ConstRRsetPtr> rrsets_;
  84. bool throw_from_callback_;
  85. RRCollator collator_;
  86. AddRRCallback rr_callback_;
  87. const RdataPtr a_rdata1_, a_rdata2_, txt_rdata_, sig_rdata1_, sig_rdata2_;
  88. vector<ConstRdataPtr> rdatas_; // placeholder for expected data
  89. };
  90. TEST_F(RRCollatorTest, basicCases) {
  91. // Add two RRs belonging to the same RRset. These will be buffered.
  92. rr_callback_(origin_, rrclass_, RRType::A(), rrttl_, a_rdata1_);
  93. EXPECT_TRUE(rrsets_.empty()); // not yet given as an RRset
  94. rr_callback_(origin_, rrclass_, RRType::A(), rrttl_, a_rdata2_);
  95. EXPECT_TRUE(rrsets_.empty()); // still not given
  96. // Add another type of RR. This completes the construction of the A RRset,
  97. // which will be given via the callback.
  98. rr_callback_(origin_, rrclass_, RRType::TXT(), rrttl_, txt_rdata_);
  99. rdatas_.push_back(a_rdata1_);
  100. rdatas_.push_back(a_rdata2_);
  101. checkRRset(origin_, rrclass_, RRType::A(), rrttl_, rdatas_);
  102. // Add the same type of RR but of different name. This should make another
  103. // callback for the previous TXT RR.
  104. rr_callback_(Name("txt.example.com"), rrclass_, RRType::TXT(), rrttl_,
  105. txt_rdata_);
  106. rdatas_.clear();
  107. rdatas_.push_back(txt_rdata_);
  108. checkRRset(origin_, rrclass_, RRType::TXT(), rrttl_, rdatas_);
  109. // Add the same type and name of RR but of different class (rare case
  110. // in practice)
  111. rr_callback_(Name("txt.example.com"), RRClass::CH(), RRType::TXT(), rrttl_,
  112. txt_rdata_);
  113. rdatas_.clear();
  114. rdatas_.push_back(txt_rdata_);
  115. checkRRset(Name("txt.example.com"), rrclass_, RRType::TXT(), rrttl_,
  116. rdatas_);
  117. // Tell the collator we are done, then we'll see the last RR as an RRset.
  118. collator_.flush();
  119. checkRRset(Name("txt.example.com"), RRClass::CH(), RRType::TXT(), rrttl_,
  120. rdatas_);
  121. // Redundant flush() will be no-op.
  122. collator_.flush();
  123. EXPECT_TRUE(rrsets_.empty());
  124. }
  125. TEST_F(RRCollatorTest, minTTLFirst) {
  126. // RRs of the same RRset but has different TTLs. The first RR has
  127. // the smaller TTL, which should be used for the TTL of the RRset.
  128. rr_callback_(origin_, rrclass_, RRType::A(), RRTTL(10), a_rdata1_);
  129. rr_callback_(origin_, rrclass_, RRType::A(), RRTTL(20), a_rdata2_);
  130. rdatas_.push_back(a_rdata1_);
  131. rdatas_.push_back(a_rdata2_);
  132. collator_.flush();
  133. checkRRset(origin_, rrclass_, RRType::A(), RRTTL(10), rdatas_);
  134. }
  135. TEST_F(RRCollatorTest, maxTTLFirst) {
  136. // RRs of the same RRset but has different TTLs. The second RR has
  137. // the smaller TTL, which should be used for the TTL of the RRset.
  138. rr_callback_(origin_, rrclass_, RRType::A(), RRTTL(20), a_rdata1_);
  139. rr_callback_(origin_, rrclass_, RRType::A(), RRTTL(10), a_rdata2_);
  140. rdatas_.push_back(a_rdata1_);
  141. rdatas_.push_back(a_rdata2_);
  142. collator_.flush();
  143. checkRRset(origin_, rrclass_, RRType::A(), RRTTL(10), rdatas_);
  144. }
  145. TEST_F(RRCollatorTest, addRRSIGs) {
  146. // RRSIG is special; they are also distinguished by their covered types.
  147. rr_callback_(origin_, rrclass_, RRType::RRSIG(), rrttl_, sig_rdata1_);
  148. rr_callback_(origin_, rrclass_, RRType::RRSIG(), rrttl_, sig_rdata2_);
  149. rdatas_.push_back(sig_rdata1_);
  150. checkRRset(origin_, rrclass_, RRType::RRSIG(), rrttl_, rdatas_);
  151. }
  152. TEST_F(RRCollatorTest, emptyFlush) {
  153. collator_.flush();
  154. EXPECT_TRUE(rrsets_.empty());
  155. }
  156. TEST_F(RRCollatorTest, throwFromCallback) {
  157. // Adding an A RR
  158. rr_callback_(origin_, rrclass_, RRType::A(), rrttl_, a_rdata1_);
  159. // Adding a TXT RR, which would trigger RRset callback, but in this test
  160. // it throws. The added TXT RR will be effectively lost.
  161. throw_from_callback_ = true;
  162. EXPECT_THROW(rr_callback_(origin_, rrclass_, RRType::TXT(), rrttl_,
  163. txt_rdata_), isc::Unexpected);
  164. // We'll only see the A RR.
  165. throw_from_callback_ = false;
  166. collator_.flush();
  167. rdatas_.push_back(a_rdata1_);
  168. checkRRset(origin_, rrclass_, RRType::A(), rrttl_, rdatas_);
  169. }
  170. TEST_F(RRCollatorTest, withMasterLoader) {
  171. // Test a simple case with MasterLoader. There shouldn't be anything
  172. // special, but that's the mainly intended usage of the collator, so we
  173. // check it explicitly.
  174. std::istringstream ss("example.com. 3600 IN A 192.0.2.1\n");
  175. MasterLoader loader(ss, origin_, rrclass_,
  176. MasterLoaderCallbacks::getNullCallbacks(),
  177. collator_.getCallback());
  178. loader.load();
  179. collator_.flush();
  180. rdatas_.push_back(a_rdata1_);
  181. checkRRset(origin_, rrclass_, RRType::A(), rrttl_, rdatas_);
  182. }
  183. }