memory_datasrc_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. // Copyright (C) 2011 CZ NIC
  3. //
  4. // Permission to use, copy, modify, and/or distribute this software for any
  5. // purpose with or without fee is hereby granted, provided that the above
  6. // copyright notice and this permission notice appear in all copies.
  7. //
  8. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  9. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. // PERFORMANCE OF THIS SOFTWARE.
  15. #include <sstream>
  16. #include <vector>
  17. #include <boost/bind.hpp>
  18. #include <exceptions/exceptions.h>
  19. #include <dns/masterload.h>
  20. #include <dns/name.h>
  21. #include <dns/rdata.h>
  22. #include <dns/rdataclass.h>
  23. #include <dns/rrclass.h>
  24. #include <dns/rrsetlist.h>
  25. #include <dns/rrttl.h>
  26. #include <dns/masterload.h>
  27. #include <datasrc/memory_datasrc.h>
  28. #include <gtest/gtest.h>
  29. using namespace std;
  30. using namespace isc::dns;
  31. using namespace isc::dns::rdata;
  32. using namespace isc::datasrc;
  33. namespace {
  34. // Commonly used result codes (Who should write the prefix all the time)
  35. using result::SUCCESS;
  36. using result::EXIST;
  37. class MemoryDataSrcTest : public ::testing::Test {
  38. protected:
  39. MemoryDataSrcTest() : rrclass(RRClass::IN())
  40. {}
  41. RRClass rrclass;
  42. MemoryDataSrc memory_datasrc;
  43. };
  44. TEST_F(MemoryDataSrcTest, add_find_Zone) {
  45. // test add zone
  46. // Bogus zone (NULL)
  47. EXPECT_THROW(memory_datasrc.addZone(ZonePtr()), isc::InvalidParameter);
  48. // add zones with different names one by one
  49. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  50. ZonePtr(new MemoryZone(RRClass::IN(), Name("a")))));
  51. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  52. ZonePtr(new MemoryZone(RRClass::CH(), Name("b")))));
  53. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  54. ZonePtr(new MemoryZone(RRClass::IN(), Name("c")))));
  55. // add zones with the same name suffix
  56. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  57. ZonePtr(new MemoryZone(RRClass::CH(),
  58. Name("x.d.e.f")))));
  59. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  60. ZonePtr(new MemoryZone(RRClass::CH(),
  61. Name("o.w.y.d.e.f")))));
  62. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  63. ZonePtr(new MemoryZone(RRClass::CH(),
  64. Name("p.w.y.d.e.f")))));
  65. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  66. ZonePtr(new MemoryZone(RRClass::IN(),
  67. Name("q.w.y.d.e.f")))));
  68. // add super zone and its subzone
  69. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  70. ZonePtr(new MemoryZone(RRClass::CH(), Name("g.h")))));
  71. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  72. ZonePtr(new MemoryZone(RRClass::IN(), Name("i.g.h")))));
  73. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  74. ZonePtr(new MemoryZone(RRClass::IN(),
  75. Name("z.d.e.f")))));
  76. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  77. ZonePtr(new MemoryZone(RRClass::IN(),
  78. Name("j.z.d.e.f")))));
  79. // different zone class isn't allowed.
  80. EXPECT_EQ(result::EXIST, memory_datasrc.addZone(
  81. ZonePtr(new MemoryZone(RRClass::CH(),
  82. Name("q.w.y.d.e.f")))));
  83. // names are compared in a case insensitive manner.
  84. EXPECT_EQ(result::EXIST, memory_datasrc.addZone(
  85. ZonePtr(new MemoryZone(RRClass::IN(),
  86. Name("Q.W.Y.d.E.f")))));
  87. // test find zone
  88. EXPECT_EQ(result::SUCCESS, memory_datasrc.findZone(Name("a")).code);
  89. EXPECT_EQ(Name("a"),
  90. memory_datasrc.findZone(Name("a")).zone->getOrigin());
  91. EXPECT_EQ(result::SUCCESS,
  92. memory_datasrc.findZone(Name("j.z.d.e.f")).code);
  93. EXPECT_EQ(Name("j.z.d.e.f"),
  94. memory_datasrc.findZone(Name("j.z.d.e.f")).zone->getOrigin());
  95. // NOTFOUND
  96. EXPECT_EQ(result::NOTFOUND, memory_datasrc.findZone(Name("d.e.f")).code);
  97. EXPECT_EQ(ConstZonePtr(), memory_datasrc.findZone(Name("d.e.f")).zone);
  98. EXPECT_EQ(result::NOTFOUND,
  99. memory_datasrc.findZone(Name("w.y.d.e.f")).code);
  100. EXPECT_EQ(ConstZonePtr(),
  101. memory_datasrc.findZone(Name("w.y.d.e.f")).zone);
  102. // there's no exact match. the result should be the longest match,
  103. // and the code should be PARTIALMATCH.
  104. EXPECT_EQ(result::PARTIALMATCH,
  105. memory_datasrc.findZone(Name("j.g.h")).code);
  106. EXPECT_EQ(Name("g.h"),
  107. memory_datasrc.findZone(Name("g.h")).zone->getOrigin());
  108. EXPECT_EQ(result::PARTIALMATCH,
  109. memory_datasrc.findZone(Name("z.i.g.h")).code);
  110. EXPECT_EQ(Name("i.g.h"),
  111. memory_datasrc.findZone(Name("z.i.g.h")).zone->getOrigin());
  112. }
  113. TEST_F(MemoryDataSrcTest, getZoneCount) {
  114. EXPECT_EQ(0, memory_datasrc.getZoneCount());
  115. memory_datasrc.addZone(
  116. ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
  117. EXPECT_EQ(1, memory_datasrc.getZoneCount());
  118. // duplicate add. counter shouldn't change
  119. memory_datasrc.addZone(
  120. ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
  121. EXPECT_EQ(1, memory_datasrc.getZoneCount());
  122. // add one more
  123. memory_datasrc.addZone(
  124. ZonePtr(new MemoryZone(rrclass, Name("example.org"))));
  125. EXPECT_EQ(2, memory_datasrc.getZoneCount());
  126. }
  127. // A helper callback of masterLoad() used in MemoryZoneTest.
  128. void
  129. setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
  130. *(*it) = rrset;
  131. ++it;
  132. }
  133. /// \brief Test fixture for the MemoryZone class
  134. class MemoryZoneTest : public ::testing::Test {
  135. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  136. // to store the RRset. Used to build test data below.
  137. struct RRsetData {
  138. const char* const text; // textual representation of an RRset
  139. RRsetPtr* rrset;
  140. };
  141. public:
  142. MemoryZoneTest() :
  143. class_(RRClass::IN()),
  144. origin_("example.org"),
  145. zone_(class_, origin_)
  146. {
  147. // Build test RRsets. Below, we construct an RRset for
  148. // each textual RR(s) of zone_data, and assign it to the corresponding
  149. // rr_xxx.
  150. const RRsetData zone_data[] = {
  151. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  152. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  153. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  154. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  155. {"cname.example.org. 300 IN CNAME canonical.example.org",
  156. &rr_cname_},
  157. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  158. {"dname.example.org. 300 IN DNAME target.example.org.",
  159. &rr_dname_},
  160. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  161. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  162. &rr_dname_ns_},
  163. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  164. {"child.example.org. 300 IN NS ns.child.example.org.",
  165. &rr_child_ns_},
  166. {"ns.child.example.org. 300 IN A 192.0.2.153",
  167. &rr_child_glue_},
  168. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  169. &rr_grandchild_ns_},
  170. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  171. &rr_grandchild_glue_},
  172. {"dname.child.example.org. 300 IN DNAME example.com.",
  173. &rr_child_dname_},
  174. {"example.com. 300 IN A 192.0.2.10", &rr_out_}
  175. };
  176. stringstream zone_data_stream;
  177. vector<RRsetPtr*> rrsets;
  178. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  179. zone_data_stream << zone_data[i].text << "\n";
  180. rrsets.push_back(zone_data[i].rrset);
  181. }
  182. vector<RRsetPtr*>::iterator it = rrsets.begin();
  183. masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
  184. boost::bind(setRRset, _1, it));
  185. }
  186. // Some data to test with
  187. const RRClass class_;
  188. const Name origin_;
  189. // The zone to torture by tests
  190. MemoryZone zone_;
  191. /*
  192. * Some RRsets to put inside the zone.
  193. */
  194. RRsetPtr
  195. // Out of zone RRset
  196. rr_out_,
  197. // NS of example.org
  198. rr_ns_,
  199. // A of ns.example.org
  200. rr_ns_a_,
  201. // AAAA of ns.example.org
  202. rr_ns_aaaa_,
  203. // A of example.org
  204. rr_a_;
  205. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  206. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  207. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  208. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  209. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  210. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  211. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  212. RRsetPtr rr_child_glue_; // glue RR of the child domain
  213. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  214. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  215. RRsetPtr rr_child_dname_; // A DNAME under NS
  216. /**
  217. * \brief Test one find query to the zone.
  218. *
  219. * Asks a query to the zone and checks it does not throw and returns
  220. * expected results. It returns nothing, it just signals failures
  221. * to GTEST.
  222. *
  223. * \param name The name to ask for.
  224. * \param rrtype The RRType to ask of.
  225. * \param result The expected code of the result.
  226. * \param check_answer Should a check against equality of the answer be
  227. * done?
  228. * \param answer The expected rrset, if any should be returned.
  229. * \param zone Check different MemoryZone object than zone_ (if NULL,
  230. * uses zone_)
  231. */
  232. void findTest(const Name& name, const RRType& rrtype, Zone::Result result,
  233. bool check_answer = true,
  234. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  235. RRsetList* target = NULL,
  236. MemoryZone* zone = NULL,
  237. Zone::FindOptions options = Zone::FIND_DEFAULT)
  238. {
  239. if (!zone) {
  240. zone = &zone_;
  241. }
  242. // The whole block is inside, because we need to check the result and
  243. // we can't assign to FindResult
  244. EXPECT_NO_THROW({
  245. Zone::FindResult find_result(zone->find(name, rrtype, target,
  246. options));
  247. // Check it returns correct answers
  248. EXPECT_EQ(result, find_result.code);
  249. if (check_answer) {
  250. EXPECT_EQ(answer, find_result.rrset);
  251. }
  252. });
  253. }
  254. };
  255. /**
  256. * \brief Test MemoryZone::MemoryZone constructor.
  257. *
  258. * Takes the created zone and checks its properties they are the same
  259. * as passed parameters.
  260. */
  261. TEST_F(MemoryZoneTest, constructor) {
  262. ASSERT_EQ(class_, zone_.getClass());
  263. ASSERT_EQ(origin_, zone_.getOrigin());
  264. }
  265. /**
  266. * \brief Test adding.
  267. *
  268. * We test that it throws at the correct moments and the correct exceptions.
  269. * And we test the return value.
  270. */
  271. TEST_F(MemoryZoneTest, add) {
  272. // This one does not belong to this zone
  273. EXPECT_THROW(zone_.add(rr_out_), MemoryZone::OutOfZone);
  274. // Test null pointer
  275. EXPECT_THROW(zone_.add(ConstRRsetPtr()), MemoryZone::NullRRset);
  276. // Now put all the data we have there. It should throw nothing
  277. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  278. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  279. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  280. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  281. // Try putting there something twice, it should be rejected
  282. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_)));
  283. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_a_)));
  284. }
  285. TEST_F(MemoryZoneTest, addMultipleCNAMEs) {
  286. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  287. EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
  288. }
  289. TEST_F(MemoryZoneTest, addCNAMEThenOther) {
  290. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
  291. EXPECT_THROW(zone_.add(rr_cname_a_), MemoryZone::AddError);
  292. }
  293. TEST_F(MemoryZoneTest, addOtherThenCNAME) {
  294. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_a_));
  295. EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
  296. }
  297. TEST_F(MemoryZoneTest, findCNAME) {
  298. // install CNAME RR
  299. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
  300. // Find A RR of the same. Should match the CNAME
  301. findTest(rr_cname_->getName(), RRType::NS(), Zone::CNAME, true, rr_cname_);
  302. // Find the CNAME itself. Should result in normal SUCCESS
  303. findTest(rr_cname_->getName(), RRType::CNAME(), Zone::SUCCESS, true,
  304. rr_cname_);
  305. }
  306. TEST_F(MemoryZoneTest, findCNAMEUnderZoneCut) {
  307. // There's nothing special when we find a CNAME under a zone cut
  308. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  309. // so we test this case explicitly.
  310. EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_));
  311. RRsetPtr rr_cname_under_cut_(new RRset(Name("cname.child.example.org"),
  312. class_, RRType::CNAME(),
  313. RRTTL(300)));
  314. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_under_cut_));
  315. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  316. Zone::CNAME, true, rr_cname_under_cut_, NULL, NULL,
  317. Zone::FIND_GLUE_OK);
  318. }
  319. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  320. // Having a CNAME there is disallowed too, but it is tested by
  321. // addOtherThenCNAME and addCNAMEThenOther.
  322. TEST_F(MemoryZoneTest, addMultipleDNAMEs) {
  323. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  324. EXPECT_THROW(zone_.add(rr_dname_), MemoryZone::AddError);
  325. }
  326. /*
  327. * These two tests ensure that we can't have DNAME and NS at the same
  328. * node with the exception of the apex of zone (forbidden by RFC 2672)
  329. */
  330. TEST_F(MemoryZoneTest, addDNAMEThenNS) {
  331. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  332. EXPECT_THROW(zone_.add(rr_dname_ns_), MemoryZone::AddError);
  333. }
  334. TEST_F(MemoryZoneTest, addNSThenDNAME) {
  335. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_ns_)));
  336. EXPECT_THROW(zone_.add(rr_dname_), MemoryZone::AddError);
  337. }
  338. // It is allowed to have NS and DNAME at apex
  339. TEST_F(MemoryZoneTest, DNAMEAndNSAtApex) {
  340. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_apex_)));
  341. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  342. // The NS should be possible to be found, below should be DNAME, not
  343. // delegation
  344. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  345. findTest(rr_child_ns_->getName(), RRType::A(), Zone::DNAME, true,
  346. rr_dname_apex_);
  347. }
  348. TEST_F(MemoryZoneTest, NSAndDNAMEAtApex) {
  349. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  350. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_apex_)));
  351. }
  352. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  353. // 2672 as well.
  354. // Search under a DNAME record. It should return the DNAME
  355. TEST_F(MemoryZoneTest, findBelowDNAME) {
  356. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  357. findTest(Name("below.dname.example.org"), RRType::A(), Zone::DNAME, true,
  358. rr_dname_);
  359. }
  360. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  361. // influences only the data below (see RFC 2672, section 3)
  362. TEST_F(MemoryZoneTest, findAtDNAME) {
  363. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  364. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_a_)));
  365. const Name dname_name(rr_dname_->getName());
  366. findTest(dname_name, RRType::A(), Zone::SUCCESS, true, rr_dname_a_);
  367. findTest(dname_name, RRType::DNAME(), Zone::SUCCESS, true, rr_dname_);
  368. findTest(dname_name, RRType::TXT(), Zone::NXRRSET, true);
  369. }
  370. // Try searching something that is both under NS and DNAME, without and with
  371. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  372. TEST_F(MemoryZoneTest, DNAMEUnderNS) {
  373. zone_.add(rr_child_ns_);
  374. zone_.add(rr_child_dname_);
  375. Name lowName("below.dname.child.example.org.");
  376. findTest(lowName, RRType::A(), Zone::DELEGATION, true, rr_child_ns_);
  377. findTest(lowName, RRType::A(), Zone::DNAME, true, rr_child_dname_, NULL,
  378. NULL, Zone::FIND_GLUE_OK);
  379. }
  380. // Test adding child zones and zone cut handling
  381. TEST_F(MemoryZoneTest, delegationNS) {
  382. // add in-zone data
  383. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  384. // install a zone cut
  385. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  386. // below the zone cut
  387. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  388. true, rr_child_ns_);
  389. // at the zone cut
  390. findTest(Name("child.example.org"), RRType::A(), Zone::DELEGATION,
  391. true, rr_child_ns_);
  392. findTest(Name("child.example.org"), RRType::NS(), Zone::DELEGATION,
  393. true, rr_child_ns_);
  394. // finding NS for the apex (origin) node. This must not be confused
  395. // with delegation due to the existence of an NS RR.
  396. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  397. // unusual case of "nested delegation": the highest cut should be used.
  398. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  399. findTest(Name("www.grand.child.example.org"), RRType::A(),
  400. Zone::DELEGATION, true, rr_child_ns_); // note: !rr_grandchild_ns_
  401. }
  402. TEST_F(MemoryZoneTest, findAny) {
  403. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  404. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  405. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
  406. // origin
  407. RRsetList origin_rrsets;
  408. findTest(origin_, RRType::ANY(), Zone::SUCCESS, true,
  409. ConstRRsetPtr(), &origin_rrsets);
  410. EXPECT_EQ(2, origin_rrsets.size());
  411. EXPECT_EQ(rr_a_, origin_rrsets.findRRset(RRType::A(), RRClass::IN()));
  412. EXPECT_EQ(rr_ns_, origin_rrsets.findRRset(RRType::NS(), RRClass::IN()));
  413. // out zone name
  414. RRsetList out_rrsets;
  415. findTest(Name("example.com"), RRType::ANY(), Zone::NXDOMAIN, true,
  416. ConstRRsetPtr(), &out_rrsets);
  417. EXPECT_EQ(0, out_rrsets.size());
  418. RRsetList glue_child_rrsets;
  419. findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::SUCCESS, true,
  420. ConstRRsetPtr(), &glue_child_rrsets);
  421. EXPECT_EQ(rr_child_glue_, glue_child_rrsets.findRRset(RRType::A(),
  422. RRClass::IN()));
  423. EXPECT_EQ(1, glue_child_rrsets.size());
  424. // TODO: test NXRRSET case after rbtree non-terminal logic has
  425. // been implemented
  426. // add zone cut
  427. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  428. // zone cut
  429. RRsetList child_rrsets;
  430. findTest(rr_child_ns_->getName(), RRType::ANY(), Zone::DELEGATION, true,
  431. rr_child_ns_, &child_rrsets);
  432. EXPECT_EQ(0, child_rrsets.size());
  433. // glue for this zone cut
  434. RRsetList new_glue_child_rrsets;
  435. findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::DELEGATION, true,
  436. rr_child_ns_, &new_glue_child_rrsets);
  437. EXPECT_EQ(0, new_glue_child_rrsets.size());
  438. }
  439. TEST_F(MemoryZoneTest, glue) {
  440. // install zone data:
  441. // a zone cut
  442. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  443. // glue for this cut
  444. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
  445. // a nested zone cut (unusual)
  446. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  447. // glue under the deeper zone cut
  448. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_glue_)));
  449. // by default glue is hidden due to the zone cut
  450. findTest(rr_child_glue_->getName(), RRType::A(), Zone::DELEGATION, true,
  451. rr_child_ns_);
  452. // If we do it in the "glue OK" mode, we should find the exact match.
  453. findTest(rr_child_glue_->getName(), RRType::A(), Zone::SUCCESS, true,
  454. rr_child_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
  455. // glue OK + NXRRSET case
  456. findTest(rr_child_glue_->getName(), RRType::AAAA(), Zone::NXRRSET, true,
  457. ConstRRsetPtr(), NULL, NULL, Zone::FIND_GLUE_OK);
  458. // glue OK + NXDOMAIN case
  459. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  460. true, rr_child_ns_, NULL, NULL, Zone::FIND_GLUE_OK);
  461. // TODO:
  462. // glue name would match a wildcard under a zone cut: wildcard match
  463. // shouldn't happen under a cut and result must be PARTIALMATCH
  464. // (This case cannot be tested yet)
  465. // nested cut case. The glue should be found.
  466. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  467. Zone::SUCCESS,
  468. true, rr_grandchild_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
  469. // A non-existent name in nested cut. This should result in delegation
  470. // at the highest zone cut.
  471. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  472. Zone::DELEGATION, true, rr_child_ns_, NULL, NULL,
  473. Zone::FIND_GLUE_OK);
  474. }
  475. /**
  476. * \brief Test searching.
  477. *
  478. * Check it finds or does not find correctly and does not throw exceptions.
  479. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  480. * directly there, it just tells it doesn't exist.
  481. */
  482. TEST_F(MemoryZoneTest, find) {
  483. // Fill some data inside
  484. // Now put all the data we have there. It should throw nothing
  485. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  486. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  487. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  488. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  489. // These two should be successful
  490. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  491. findTest(rr_ns_a_->getName(), RRType::A(), Zone::SUCCESS, true, rr_ns_a_);
  492. // These domain exist but don't have the provided RRType
  493. findTest(origin_, RRType::AAAA(), Zone::NXRRSET);
  494. findTest(rr_ns_a_->getName(), RRType::NS(), Zone::NXRRSET);
  495. // These domains don't exist (and one is out of the zone)
  496. findTest(Name("nothere.example.org"), RRType::A(), Zone::NXDOMAIN);
  497. findTest(Name("example.net"), RRType::A(), Zone::NXDOMAIN);
  498. }
  499. TEST_F(MemoryZoneTest, load) {
  500. // Put some data inside the zone
  501. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_.add(rr_ns_)));
  502. // Loading with different origin should fail
  503. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/root.zone"), MasterLoadError);
  504. // See the original data is still there, survived the exception
  505. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  506. // Create correct zone
  507. MemoryZone rootzone(class_, Name("."));
  508. // Try putting something inside
  509. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  510. // Load the zone. It should overwrite/remove the above RRset
  511. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  512. // Now see there are some rrsets (we don't look inside, though)
  513. findTest(Name("."), RRType::SOA(), Zone::SUCCESS, false, ConstRRsetPtr(),
  514. NULL, &rootzone);
  515. findTest(Name("."), RRType::NS(), Zone::SUCCESS, false, ConstRRsetPtr(),
  516. NULL, &rootzone);
  517. findTest(Name("a.root-servers.net."), RRType::A(), Zone::SUCCESS, false,
  518. ConstRRsetPtr(), NULL, &rootzone);
  519. // But this should no longer be here
  520. findTest(rr_ns_a_->getName(), RRType::AAAA(), Zone::NXDOMAIN, true,
  521. ConstRRsetPtr(), NULL, &rootzone);
  522. // Try loading zone that is wrong in a different way
  523. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  524. MasterLoadError);
  525. }
  526. TEST_F(MemoryZoneTest, swap) {
  527. // build one zone with some data
  528. MemoryZone zone1(class_, origin_);
  529. EXPECT_EQ(result::SUCCESS, zone1.add(rr_ns_));
  530. EXPECT_EQ(result::SUCCESS, zone1.add(rr_ns_aaaa_));
  531. // build another zone of a different RR class with some other data
  532. const Name other_origin("version.bind");
  533. ASSERT_NE(origin_, other_origin); // make sure these two are different
  534. MemoryZone zone2(RRClass::CH(), other_origin);
  535. EXPECT_EQ(result::SUCCESS,
  536. zone2.add(RRsetPtr(new RRset(Name("version.bind"),
  537. RRClass::CH(), RRType::TXT(),
  538. RRTTL(0)))));
  539. zone1.swap(zone2);
  540. EXPECT_EQ(other_origin, zone1.getOrigin());
  541. EXPECT_EQ(origin_, zone2.getOrigin());
  542. EXPECT_EQ(RRClass::CH(), zone1.getClass());
  543. EXPECT_EQ(RRClass::IN(), zone2.getClass());
  544. // make sure the zone data is swapped, too
  545. findTest(origin_, RRType::NS(), Zone::NXDOMAIN, false, ConstRRsetPtr(),
  546. NULL, &zone1);
  547. findTest(other_origin, RRType::TXT(), Zone::SUCCESS, false,
  548. ConstRRsetPtr(), NULL, &zone1);
  549. findTest(origin_, RRType::NS(), Zone::SUCCESS, false, ConstRRsetPtr(),
  550. NULL, &zone2);
  551. findTest(other_origin, RRType::TXT(), Zone::NXDOMAIN, false,
  552. ConstRRsetPtr(), NULL, &zone2);
  553. }
  554. TEST_F(MemoryZoneTest, getFileName) {
  555. // for an empty zone the file name should also be empty.
  556. EXPECT_TRUE(zone_.getFileName().empty());
  557. // if loading a zone fails the file name shouldn't be set.
  558. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/root.zone"), MasterLoadError);
  559. EXPECT_TRUE(zone_.getFileName().empty());
  560. // after a successful load, the specified file name should be set
  561. MemoryZone rootzone(class_, Name("."));
  562. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  563. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  564. // overriding load, which will fail
  565. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  566. MasterLoadError);
  567. // the file name should be intact.
  568. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  569. // After swap, file names should also be swapped.
  570. zone_.swap(rootzone);
  571. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_.getFileName());
  572. EXPECT_TRUE(rootzone.getFileName().empty());
  573. }
  574. }