nameserver_address_store_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. /// \brief Test Deleter Objects
  16. ///
  17. /// This file contains tests for the "deleter" classes within the nameserver
  18. /// address store. These act to delete zones from the zone hash table when
  19. /// the element reaches the top of the LRU list.
  20. #include <dns/rrttl.h>
  21. #include <dns/rdataclass.h>
  22. #include <gtest/gtest.h>
  23. #include <boost/shared_ptr.hpp>
  24. #include <boost/lexical_cast.hpp>
  25. #include <boost/foreach.hpp>
  26. #include <string.h>
  27. #include <vector>
  28. #include <cassert>
  29. #include "nameserver_address_store.h"
  30. #include "nsas_entry_compare.h"
  31. #include "nameserver_entry.h"
  32. #include "zone_entry.h"
  33. #include "nsas_test.h"
  34. using namespace isc::dns;
  35. using namespace std;
  36. using namespace boost;
  37. namespace isc {
  38. namespace nsas {
  39. /// \brief NSAS Store
  40. ///
  41. /// This is a subclass of the NameserverAddressStore class, with methods to
  42. /// access the internal members to check that the deleter objects are working.
  43. class DerivedNsas : public NameserverAddressStore {
  44. public:
  45. /// \brief Constructor
  46. ///
  47. /// \param hashsize Size of the zone hash table
  48. /// \param lrusize Size of the zone hash table
  49. DerivedNsas(ResolverInterface& resolver, uint32_t hashsize,
  50. uint32_t lrusize) :
  51. NameserverAddressStore(resolver, hashsize, lrusize)
  52. {}
  53. /// \brief Virtual Destructor
  54. virtual ~DerivedNsas()
  55. {}
  56. /// \brief Add Nameserver Entry to Hash and LRU Tables
  57. void AddNameserverEntry(boost::shared_ptr<NameserverEntry>& entry) {
  58. HashKey h = entry->hashKey();
  59. nameserver_hash_.add(entry, h);
  60. nameserver_lru_.add(entry);
  61. }
  62. /// \brief Add Zone Entry to Hash and LRU Tables
  63. void AddZoneEntry(boost::shared_ptr<ZoneEntry>& entry) {
  64. HashKey h = entry->hashKey();
  65. zone_hash_.add(entry, h);
  66. zone_lru_.add(entry);
  67. }
  68. };
  69. /// \brief Text Fixture Class
  70. class NameserverAddressStoreTest : public ::testing::Test {
  71. protected:
  72. NameserverAddressStoreTest() :
  73. authority_(new RRset(Name("example.net."), RRClass::IN(), RRType::NS(),
  74. RRTTL(128)))
  75. {
  76. // Constructor - initialize a set of nameserver and zone objects. For convenience,
  77. // these are stored in vectors.
  78. for (int i = 1; i <= 9; ++i) {
  79. std::string name = "nameserver" + boost::lexical_cast<std::string>(i);
  80. nameservers_.push_back(boost::shared_ptr<NameserverEntry>(new NameserverEntry(name, (40 + i))));
  81. }
  82. for (int i = 1; i <= 9; ++i) {
  83. std::string name = "zone" + boost::lexical_cast<std::string>(i);
  84. zones_.push_back(boost::shared_ptr<ZoneEntry>(new ZoneEntry(name, (40 + i))));
  85. }
  86. // A nameserver serving data
  87. authority_->addRdata(rdata::generic::NS(Name("ns.example.com.")));
  88. // This is reused because of convenience, clear it just in case
  89. NSASCallback::results.clear();
  90. }
  91. // Vector of pointers to nameserver and zone entries.
  92. std::vector<boost::shared_ptr<NameserverEntry> > nameservers_;
  93. std::vector<boost::shared_ptr<ZoneEntry> > zones_;
  94. RRsetPtr authority_;
  95. class TestResolver : public ResolverInterface {
  96. public:
  97. typedef pair<QuestionPtr, CallbackPtr> Request;
  98. vector<Request> requests;
  99. virtual void resolve(QuestionPtr q, CallbackPtr c) {
  100. requests.push_back(Request(q, c));
  101. }
  102. QuestionPtr operator[](size_t index) {
  103. return (requests[index].first);
  104. }
  105. } defaultTestResolver;
  106. /**
  107. * Looks if the two provided requests in resolver are A and AAAA.
  108. * Sorts them so index1 is A.
  109. */
  110. void asksIPs(const Name& name, size_t index1, size_t index2) {
  111. size_t max = (index1 < index2) ? index2 : index1;
  112. ASSERT_GT(defaultTestResolver.requests.size(), max);
  113. EXPECT_EQ(name, defaultTestResolver[index1]->getName());
  114. EXPECT_EQ(name, defaultTestResolver[index2]->getName());
  115. EXPECT_EQ(RRClass::IN(), defaultTestResolver[index1]->getClass());
  116. EXPECT_EQ(RRClass::IN(), defaultTestResolver[index2]->getClass());
  117. // If they are the other way around, swap
  118. if (defaultTestResolver[index1]->getType() == RRType::AAAA() &&
  119. defaultTestResolver[index2]->getType() == RRType::A())
  120. {
  121. TestResolver::Request tmp(defaultTestResolver.requests[index1]);
  122. defaultTestResolver.requests[index1] =
  123. defaultTestResolver.requests[index2];
  124. defaultTestResolver.requests[index2] = tmp;
  125. }
  126. // Check the correct addresses
  127. EXPECT_EQ(RRType::A(), defaultTestResolver[index1]->getType());
  128. EXPECT_EQ(RRType::AAAA(), defaultTestResolver[index1]->getType());
  129. }
  130. class NSASCallback : public AddressRequestCallback {
  131. public:
  132. typedef pair<bool, asiolink::IOAddress> Result;
  133. static vector<Result> results;
  134. virtual void success(const asiolink::IOAddress& address) {
  135. results.push_back(Result(true, address));
  136. }
  137. virtual void unreachable() {
  138. results.push_back(Result(false,
  139. asiolink::IOAddress("0.0.0.0")));
  140. }
  141. };
  142. boost::shared_ptr<AddressRequestCallback> getCallback() {
  143. return (boost::shared_ptr<AddressRequestCallback>(new NSASCallback));
  144. }
  145. };
  146. vector<NameserverAddressStoreTest::NSASCallback::Result>
  147. NameserverAddressStoreTest::NSASCallback::results;
  148. /// \brief Remove Zone Entry from Hash Table
  149. ///
  150. /// Check that when an entry reaches the top of the zone LRU list, it is removed from the
  151. /// hash table as well.
  152. TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) {
  153. // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and
  154. // nameserver tables).
  155. DerivedNsas nsas(defaultTestResolver, 2, 2);
  156. // Add six entries to the tables. After addition the reference count of each element
  157. // should be 3 - one for the entry in the zones_ vector, and one each for the entries
  158. // in the LRU list and hash table.
  159. for (int i = 1; i <= 6; ++i) {
  160. EXPECT_EQ(1, zones_[i].use_count());
  161. nsas.AddZoneEntry(zones_[i]);
  162. EXPECT_EQ(3, zones_[i].use_count());
  163. }
  164. // Adding another entry should cause the first one to drop off the LRU list, which
  165. // should also trigger the deletion of the entry from the hash table. This should
  166. // reduce its use count to 1.
  167. EXPECT_EQ(1, zones_[7].use_count());
  168. nsas.AddZoneEntry(zones_[7]);
  169. EXPECT_EQ(3, zones_[7].use_count());
  170. EXPECT_EQ(1, zones_[1].use_count());
  171. }
  172. /// \brief Remove Entry from Hash Table
  173. ///
  174. /// Check that when an entry reaches the top of the LRU list, it is removed from the
  175. /// hash table as well.
  176. TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) {
  177. // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and
  178. // nameserver tables).
  179. DerivedNsas nsas(defaultTestResolver, 2, 2);
  180. // Add six entries to the tables. After addition the reference count of each element
  181. // should be 3 - one for the entry in the nameservers_ vector, and one each for the entries
  182. // in the LRU list and hash table.
  183. for (int i = 1; i <= 6; ++i) {
  184. EXPECT_EQ(1, nameservers_[i].use_count());
  185. nsas.AddNameserverEntry(nameservers_[i]);
  186. EXPECT_EQ(3, nameservers_[i].use_count());
  187. }
  188. // Adding another entry should cause the first one to drop off the LRU list, which
  189. // should also trigger the deletion of the entry from the hash table. This should
  190. // reduce its use count to 1.
  191. EXPECT_EQ(1, nameservers_[7].use_count());
  192. nsas.AddNameserverEntry(nameservers_[7]);
  193. EXPECT_EQ(3, nameservers_[7].use_count());
  194. EXPECT_EQ(1, nameservers_[1].use_count());
  195. }
  196. /**
  197. * \short Try lookup on empty store.
  198. *
  199. * Check if it asks correct questions and it keeps correct internal state.
  200. */
  201. TEST_F(NameserverAddressStoreTest, emptyLookup) {
  202. DerivedNsas nsas(defaultTestResolver, 10, 10);
  203. // Ask it a question
  204. nsas.lookup("example.net.", RRClass::IN().getCode(), *authority_,
  205. vector<AbstractRRset>(), getCallback());
  206. // It should ask for IP addresses for example.com.
  207. ASSERT_EQ(2, defaultTestResolver.requests.size());
  208. asksIPs(Name("example.com."), 0, 1);
  209. // Ask another question for the same zone
  210. nsas.lookup("example.net.", RRClass::IN().getCode(), *authority_,
  211. vector<AbstractRRset>(), getCallback());
  212. // It should ask no more questions now
  213. EXPECT_EQ(2, defaultTestResolver.requests.size());
  214. // Ask another question with different zone but the same nameserver
  215. authority_->setName(Name("example.com."));
  216. nsas.lookup("example.com.", RRClass::IN().getCode(), *authority_,
  217. vector<AbstractRRset>(), getCallback());
  218. // It still should ask nothing
  219. EXPECT_EQ(2, defaultTestResolver.requests.size());
  220. // We provide IP address of one nameserver, it should generate all the
  221. // results
  222. RRsetPtr answer(new RRset(Name("example.com."), RRClass::IN(), RRType::A(),
  223. RRTTL(100)));
  224. answer->addRdata(rdata::in::A("192.0.2.1"));
  225. Message address(Message::RENDER); // Not able to create different one
  226. address.addRRset(Section::ANSWER(), answer);
  227. address.addRRset(Section::AUTHORITY(), authority_);
  228. address.addQuestion(defaultTestResolver[0]);
  229. defaultTestResolver.requests[0].second->success(address);
  230. EXPECT_EQ(3, NSASCallback::results.size());
  231. BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) {
  232. EXPECT_TRUE(result.first);
  233. EXPECT_EQ("192.0.2.1", result.second.toText());
  234. }
  235. }
  236. /// \short Test invalid authority section.
  237. TEST_F(NameserverAddressStoreTest, invalidAuthority) {
  238. DerivedNsas nsas(defaultTestResolver, 2, 2);
  239. EXPECT_THROW(nsas.lookup("example.net.", RRClass::CH().getCode(),
  240. *authority_, vector<AbstractRRset>(), getCallback()),
  241. InconsistentZone);
  242. EXPECT_EQ(0, defaultTestResolver.requests.size());
  243. EXPECT_EQ(0, NSASCallback::results.size());
  244. EXPECT_THROW(nsas.lookup("example.com.", RRClass::IN().getCode(),
  245. *authority_, vector<AbstractRRset>(), getCallback()),
  246. InconsistentZone);
  247. EXPECT_EQ(0, defaultTestResolver.requests.size());
  248. EXPECT_EQ(0, NSASCallback::results.size());
  249. BasicRRset aAuthority(Name("example.net."), RRClass::IN(), RRType::A(),
  250. RRTTL(128));
  251. EXPECT_THROW(nsas.lookup("example.net.", RRClass::IN().getCode(),
  252. aAuthority, vector<AbstractRRset>(),
  253. getCallback()), NotNS);
  254. EXPECT_EQ(0, defaultTestResolver.requests.size());
  255. EXPECT_EQ(0, NSASCallback::results.size());
  256. }
  257. } // namespace nsas
  258. } // namespace isc