zone_entry_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright (C) 2010 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. // $Id$
  15. #include <gtest/gtest.h>
  16. #include <boost/shared_ptr.hpp>
  17. #include <dns/rrclass.h>
  18. #include <dns/rdataclass.h>
  19. #include "../asiolink.h"
  20. #include "../zone_entry.h"
  21. #include "../nameserver_entry.h"
  22. #include "../address_request_callback.h"
  23. #include "../nsas_entry_compare.h"
  24. #include "../hash_deleter.h"
  25. #include "nsas_test.h"
  26. using namespace isc::nsas;
  27. using namespace asiolink;
  28. using namespace std;
  29. using namespace boost;
  30. using namespace isc::dns;
  31. namespace {
  32. /// \brief Test Fixture Class
  33. class ZoneEntryTest : public TestWithRdata {
  34. protected:
  35. /// \brief Constructor
  36. ZoneEntryTest() :
  37. nameserver_table_(new HashTable<NameserverEntry>(
  38. new NsasEntryCompare<NameserverEntry>)),
  39. nameserver_lru_(new LruList<NameserverEntry>(
  40. (3 * nameserver_table_->tableSize()),
  41. new HashDeleter<NameserverEntry>(*nameserver_table_))),
  42. resolver_(new TestResolver),
  43. callback_(new Callback)
  44. { }
  45. /// \brief Tables of nameservers to pass into zone entry constructor
  46. shared_ptr<HashTable<NameserverEntry> > nameserver_table_;
  47. shared_ptr<LruList<NameserverEntry> > nameserver_lru_;
  48. /// \brief The resolver
  49. shared_ptr<TestResolver> resolver_;
  50. struct Callback : public AddressRequestCallback {
  51. Callback() : unreachable_count_(0) {}
  52. size_t unreachable_count_;
  53. vector<IOAddress> successes_;
  54. virtual void unreachable() { unreachable_count_ ++; }
  55. virtual void success(const IOAddress& address) {
  56. successes_.push_back(address);
  57. }
  58. };
  59. shared_ptr<Callback> callback_;
  60. };
  61. /// \brief Inherited version with access into its internals for tests
  62. class InheritedZoneEntry : public ZoneEntry {
  63. public:
  64. InheritedZoneEntry(shared_ptr<ResolverInterface> resolver,
  65. const isc::dns::AbstractRRset& authority,
  66. shared_ptr<HashTable<NameserverEntry> > nameserver_table,
  67. shared_ptr<LruList<NameserverEntry> > nameserver_lru) :
  68. ZoneEntry(resolver, authority, nameserver_table, nameserver_lru)
  69. { }
  70. InheritedZoneEntry(shared_ptr<ResolverInterface> resolver,
  71. const std::string& name, uint16_t class_code,
  72. shared_ptr<HashTable<NameserverEntry> > nameserver_table,
  73. shared_ptr<LruList<NameserverEntry> > nameserver_lru) :
  74. ZoneEntry(resolver, name, class_code, nameserver_table,
  75. nameserver_lru)
  76. { }
  77. NameserverVector& nameservers() { return nameservers_; }
  78. };
  79. /// Tests of the default constructor
  80. TEST_F(ZoneEntryTest, DefaultConstructor) {
  81. // Default constructor should not create any RRsets
  82. InheritedZoneEntry alpha(resolver_, EXAMPLE_CO_UK,
  83. RRClass::IN().getCode(), nameserver_table_, nameserver_lru_);
  84. EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName());
  85. EXPECT_EQ(RRClass::IN().getCode(), alpha.getClass());
  86. EXPECT_TRUE(alpha.nameservers().empty());
  87. }
  88. /// Tests of constructor from referral data
  89. TEST_F(ZoneEntryTest, ReferralConstructor) {
  90. InheritedZoneEntry alpha(resolver_, rr_single_, nameserver_table_,
  91. nameserver_lru_);
  92. // It should load the name and class from the referral info
  93. EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName());
  94. EXPECT_EQ(RRClass::IN().getCode(), alpha.getClass());
  95. EXPECT_EQ(1, alpha.nameservers().size());
  96. EXPECT_EQ("ns.example.net.", alpha.nameservers()[0]->getName());
  97. // TODO Test with some additional data once NameserverEntry supports them?
  98. }
  99. // It should answer negatively right away if there are no nameservers
  100. TEST_F(ZoneEntryTest, CallbackNoNS) {
  101. shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
  102. rr_empty_, nameserver_table_, nameserver_lru_));
  103. // It should accept the callback
  104. EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
  105. // And tell imediatelly that it is unreachable (when it has no nameservers)
  106. EXPECT_TRUE(callback_->successes_.empty());
  107. EXPECT_EQ(1, callback_->unreachable_count_);
  108. }
  109. // Check it accepts the first callback with 0 TTL
  110. TEST_F(ZoneEntryTest, CallbackZeroTTL) {
  111. // Make it zero TTL, so it expires right away
  112. rr_single_.setTTL(RRTTL(0));
  113. shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
  114. rr_single_, nameserver_table_, nameserver_lru_));
  115. // It should accept the callback
  116. EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
  117. // It should not be answered yet, it should ask for the IP addresses
  118. EXPECT_TRUE(callback_->successes_.empty());
  119. EXPECT_EQ(0, callback_->unreachable_count_);
  120. resolver_->asksIPs(ns_name_, 0, 1);
  121. // It should reject another one, as it has zero TTL
  122. EXPECT_FALSE(zone->addCallback(callback_, ANY_OK, zone));
  123. }
  124. // Check it answers callbacks when we give it addresses
  125. TEST_F(ZoneEntryTest, CallbacksAnswered) {
  126. shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
  127. rr_single_, nameserver_table_, nameserver_lru_));
  128. // It should be in NOT_ASKED state
  129. EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState());
  130. // It should accept the callback
  131. EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
  132. // It should not be answered yet, it should ask for the IP addresses
  133. EXPECT_TRUE(callback_->successes_.empty());
  134. EXPECT_EQ(0, callback_->unreachable_count_);
  135. resolver_->asksIPs(ns_name_, 0, 1);
  136. // We should be IN_PROGRESS
  137. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  138. // Give two more callbacks, with different address families
  139. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  140. EXPECT_TRUE(zone->addCallback(callback_, V6_ONLY, zone));
  141. // Nothing more is asked
  142. EXPECT_EQ(2, resolver_->requests.size());
  143. resolver_->answer(0, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"));
  144. // Two are answered (ANY and V4)
  145. ASSERT_EQ(2, callback_->successes_.size());
  146. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0]));
  147. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[1]));
  148. // None are rejected
  149. EXPECT_EQ(0, callback_->unreachable_count_);
  150. // We are still in progress, not everything arrived
  151. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  152. resolver_->answer(1, ns_name_, RRType::AAAA(),
  153. rdata::in::AAAA("2001:db8::1"));
  154. // This should answer the third callback
  155. ASSERT_EQ(3, callback_->successes_.size());
  156. EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[2]));
  157. EXPECT_EQ(0, callback_->unreachable_count_);
  158. // It should think it is ready
  159. EXPECT_EQ(Fetchable::READY, zone->getState());
  160. // When we ask something more, it should be answered right away
  161. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  162. EXPECT_EQ(2, resolver_->requests.size());
  163. ASSERT_EQ(4, callback_->successes_.size());
  164. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[3]));
  165. EXPECT_EQ(0, callback_->unreachable_count_);
  166. }
  167. // Pretend the server can be reached only by IPv4
  168. TEST_F(ZoneEntryTest, CallbacksAOnly) {
  169. shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
  170. rr_single_, nameserver_table_, nameserver_lru_));
  171. // It should be in NOT_ASKED state
  172. EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState());
  173. // It should accept the callback
  174. EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
  175. // It should not be answered yet, it should ask for the IP addresses
  176. EXPECT_TRUE(callback_->successes_.empty());
  177. EXPECT_EQ(0, callback_->unreachable_count_);
  178. resolver_->asksIPs(ns_name_, 0, 1);
  179. // We should be IN_PROGRESS
  180. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  181. // Give two more callbacks, with different address families
  182. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  183. EXPECT_TRUE(zone->addCallback(callback_, V6_ONLY, zone));
  184. resolver_->requests[1].second->failure();
  185. // One should be rejected, but two still stay, they have chance
  186. EXPECT_EQ(0, callback_->successes_.size());
  187. EXPECT_EQ(1, callback_->unreachable_count_);
  188. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  189. // Answer the A one and see it answers what can be answered
  190. ASSERT_EQ(2, callback_->successes_.size());
  191. resolver_->answer(0, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"));
  192. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0]));
  193. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[1]));
  194. EXPECT_EQ(1, callback_->unreachable_count_);
  195. // Everything arriwed, so we are ready
  196. EXPECT_EQ(Fetchable::READY, zone->getState());
  197. // Try asking something more
  198. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  199. EXPECT_EQ(2, resolver_->requests.size());
  200. ASSERT_EQ(3, callback_->successes_.size());
  201. EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[2]));
  202. EXPECT_EQ(1, callback_->unreachable_count_);
  203. EXPECT_TRUE(zone->addCallback(callback_, V6_ONLY, zone));
  204. EXPECT_EQ(2, resolver_->requests.size());
  205. EXPECT_EQ(3, callback_->successes_.size());
  206. EXPECT_EQ(2, callback_->unreachable_count_);
  207. }
  208. // See it tries hard enough to get address and tries both nameservers
  209. TEST_F(ZoneEntryTest, CallbackTwoNS) {
  210. shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
  211. rrns_, nameserver_table_, nameserver_lru_));
  212. // It should be in NOT_ASKED state
  213. EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState());
  214. // It should accept the callback
  215. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  216. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  217. // It asks a question (we do not know which nameserver)
  218. resolver_->asksIPs((*resolver_)[0]->getName(), 0, 1);
  219. resolver_->requests[0].second->failure();
  220. // Nothing should be answered or failed yet
  221. EXPECT_EQ(0, callback_->unreachable_count_);
  222. EXPECT_EQ(0, callback_->successes_.size());
  223. // It should be still IN_PROGRESS and ask the second nameserver
  224. // (at last now, if not before)
  225. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  226. resolver_->asksIPs((*resolver_)[2]->getName(), 2, 3);
  227. // Fail the second one
  228. resolver_->requests[2].second->failure();
  229. // The callback should be failed now, as there is no chance of getting
  230. // v4 address
  231. EXPECT_EQ(1, callback_->unreachable_count_);
  232. EXPECT_EQ(0, callback_->successes_.size());
  233. // We should still be IN_PROGRESS, waiting for v6
  234. EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState());
  235. // And question for v6 or any should still wait while v4 should be failed
  236. // right away
  237. EXPECT_TRUE(zone->addCallback(callback_, V6_ONLY, zone));
  238. EXPECT_EQ(1, callback_->unreachable_count_);
  239. EXPECT_EQ(0, callback_->successes_.size());
  240. EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
  241. EXPECT_EQ(1, callback_->unreachable_count_);
  242. EXPECT_EQ(0, callback_->successes_.size());
  243. EXPECT_TRUE(zone->addCallback(callback_, V4_ONLY, zone));
  244. EXPECT_EQ(2, callback_->unreachable_count_);
  245. EXPECT_EQ(0, callback_->successes_.size());
  246. // Answer the IPv6 one
  247. resolver_->answer(1, (*resolver_)[1]->getName(), RRType::AAAA(),
  248. rdata::in::AAAA("2001:db8::1"));
  249. // Ready, as we have at last some address
  250. EXPECT_EQ(Fetchable::READY, zone->getState());
  251. // The other callbacks should be answered now
  252. EXPECT_EQ(2, callback_->unreachable_count_);
  253. ASSERT_EQ(2, callback_->successes_.size());
  254. EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[0]));
  255. EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[1]));
  256. }
  257. } // namespace