memory_datasrc_unittest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  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. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  176. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  177. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  178. &rr_nested_emptywild_},
  179. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  180. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  181. &rr_dnamewild_},
  182. {NULL, NULL}
  183. };
  184. stringstream zone_data_stream;
  185. vector<RRsetPtr*> rrsets;
  186. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  187. zone_data_stream << zone_data[i].text << "\n";
  188. rrsets.push_back(zone_data[i].rrset);
  189. }
  190. vector<RRsetPtr*>::iterator it = rrsets.begin();
  191. masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
  192. boost::bind(setRRset, _1, it));
  193. }
  194. // Some data to test with
  195. const RRClass class_;
  196. const Name origin_;
  197. // The zone to torture by tests
  198. MemoryZone zone_;
  199. /*
  200. * Some RRsets to put inside the zone.
  201. */
  202. RRsetPtr
  203. // Out of zone RRset
  204. rr_out_,
  205. // NS of example.org
  206. rr_ns_,
  207. // A of ns.example.org
  208. rr_ns_a_,
  209. // AAAA of ns.example.org
  210. rr_ns_aaaa_,
  211. // A of example.org
  212. rr_a_;
  213. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  214. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  215. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  216. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  217. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  218. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  219. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  220. RRsetPtr rr_child_glue_; // glue RR of the child domain
  221. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  222. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  223. RRsetPtr rr_child_dname_; // A DNAME under NS
  224. RRsetPtr rr_wild_;
  225. RRsetPtr rr_emptywild_;
  226. RRsetPtr rr_nested_emptywild_;
  227. RRsetPtr rr_nswild_, rr_dnamewild_;
  228. /**
  229. * \brief Test one find query to the zone.
  230. *
  231. * Asks a query to the zone and checks it does not throw and returns
  232. * expected results. It returns nothing, it just signals failures
  233. * to GTEST.
  234. *
  235. * \param name The name to ask for.
  236. * \param rrtype The RRType to ask of.
  237. * \param result The expected code of the result.
  238. * \param check_answer Should a check against equality of the answer be
  239. * done?
  240. * \param answer The expected rrset, if any should be returned.
  241. * \param zone Check different MemoryZone object than zone_ (if NULL,
  242. * uses zone_)
  243. * \param check_wild_answer Checks that the answer has the same RRs, type
  244. * class and TTL as the eqxpected answer and that the name corresponds
  245. * to the one searched. It is meant for checking answers for wildcard
  246. * queries.
  247. */
  248. void findTest(const Name& name, const RRType& rrtype, Zone::Result result,
  249. bool check_answer = true,
  250. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  251. RRsetList* target = NULL,
  252. MemoryZone* zone = NULL,
  253. Zone::FindOptions options = Zone::FIND_DEFAULT,
  254. bool check_wild_answer = false)
  255. {
  256. if (!zone) {
  257. zone = &zone_;
  258. }
  259. // The whole block is inside, because we need to check the result and
  260. // we can't assign to FindResult
  261. EXPECT_NO_THROW({
  262. Zone::FindResult find_result(zone->find(name, rrtype, target,
  263. options));
  264. // Check it returns correct answers
  265. EXPECT_EQ(result, find_result.code);
  266. if (check_answer) {
  267. EXPECT_EQ(answer, find_result.rrset);
  268. } else if (check_wild_answer) {
  269. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  270. RdataIteratorPtr gotIt(answer->getRdataIterator());
  271. while (!expectedIt->isLast() && !gotIt->isLast()) {
  272. EXPECT_EQ(0, expectedIt->getCurrent().compare(
  273. gotIt->getCurrent())) << "The RRs differ ('" <<
  274. expectedIt->getCurrent().toText() << "', '" <<
  275. gotIt->getCurrent().toText() << "')";
  276. expectedIt->next();
  277. gotIt->next();
  278. }
  279. EXPECT_TRUE(expectedIt->isLast()) <<
  280. "Result has less RRs than expected";
  281. EXPECT_TRUE(gotIt->isLast()) <<
  282. "Result has more RRs than expected";
  283. EXPECT_EQ(answer->getType(),
  284. find_result.rrset->getType());
  285. EXPECT_EQ(answer->getType(),
  286. find_result.rrset->getType());
  287. EXPECT_EQ(answer->getTTL(),
  288. find_result.rrset->getTTL());
  289. EXPECT_EQ(name, find_result.rrset->getName());
  290. }
  291. });
  292. }
  293. };
  294. /**
  295. * \brief Test MemoryZone::MemoryZone constructor.
  296. *
  297. * Takes the created zone and checks its properties they are the same
  298. * as passed parameters.
  299. */
  300. TEST_F(MemoryZoneTest, constructor) {
  301. ASSERT_EQ(class_, zone_.getClass());
  302. ASSERT_EQ(origin_, zone_.getOrigin());
  303. }
  304. /**
  305. * \brief Test adding.
  306. *
  307. * We test that it throws at the correct moments and the correct exceptions.
  308. * And we test the return value.
  309. */
  310. TEST_F(MemoryZoneTest, add) {
  311. // This one does not belong to this zone
  312. EXPECT_THROW(zone_.add(rr_out_), MemoryZone::OutOfZone);
  313. // Test null pointer
  314. EXPECT_THROW(zone_.add(ConstRRsetPtr()), MemoryZone::NullRRset);
  315. // Now put all the data we have there. It should throw nothing
  316. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  317. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  318. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  319. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  320. // Try putting there something twice, it should be rejected
  321. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_)));
  322. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_a_)));
  323. }
  324. TEST_F(MemoryZoneTest, addMultipleCNAMEs) {
  325. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  326. EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
  327. }
  328. TEST_F(MemoryZoneTest, addCNAMEThenOther) {
  329. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
  330. EXPECT_THROW(zone_.add(rr_cname_a_), MemoryZone::AddError);
  331. }
  332. TEST_F(MemoryZoneTest, addOtherThenCNAME) {
  333. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_a_));
  334. EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
  335. }
  336. TEST_F(MemoryZoneTest, findCNAME) {
  337. // install CNAME RR
  338. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
  339. // Find A RR of the same. Should match the CNAME
  340. findTest(rr_cname_->getName(), RRType::NS(), Zone::CNAME, true, rr_cname_);
  341. // Find the CNAME itself. Should result in normal SUCCESS
  342. findTest(rr_cname_->getName(), RRType::CNAME(), Zone::SUCCESS, true,
  343. rr_cname_);
  344. }
  345. TEST_F(MemoryZoneTest, findCNAMEUnderZoneCut) {
  346. // There's nothing special when we find a CNAME under a zone cut
  347. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  348. // so we test this case explicitly.
  349. EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_));
  350. RRsetPtr rr_cname_under_cut_(new RRset(Name("cname.child.example.org"),
  351. class_, RRType::CNAME(),
  352. RRTTL(300)));
  353. EXPECT_EQ(SUCCESS, zone_.add(rr_cname_under_cut_));
  354. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  355. Zone::CNAME, true, rr_cname_under_cut_, NULL, NULL,
  356. Zone::FIND_GLUE_OK);
  357. }
  358. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  359. // Having a CNAME there is disallowed too, but it is tested by
  360. // addOtherThenCNAME and addCNAMEThenOther.
  361. TEST_F(MemoryZoneTest, addMultipleDNAMEs) {
  362. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  363. EXPECT_THROW(zone_.add(rr_dname_), MemoryZone::AddError);
  364. }
  365. /*
  366. * These two tests ensure that we can't have DNAME and NS at the same
  367. * node with the exception of the apex of zone (forbidden by RFC 2672)
  368. */
  369. TEST_F(MemoryZoneTest, addDNAMEThenNS) {
  370. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  371. EXPECT_THROW(zone_.add(rr_dname_ns_), MemoryZone::AddError);
  372. }
  373. TEST_F(MemoryZoneTest, addNSThenDNAME) {
  374. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_ns_)));
  375. EXPECT_THROW(zone_.add(rr_dname_), MemoryZone::AddError);
  376. }
  377. // It is allowed to have NS and DNAME at apex
  378. TEST_F(MemoryZoneTest, DNAMEAndNSAtApex) {
  379. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_apex_)));
  380. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  381. // The NS should be possible to be found, below should be DNAME, not
  382. // delegation
  383. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  384. findTest(rr_child_ns_->getName(), RRType::A(), Zone::DNAME, true,
  385. rr_dname_apex_);
  386. }
  387. TEST_F(MemoryZoneTest, NSAndDNAMEAtApex) {
  388. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  389. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_apex_)));
  390. }
  391. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  392. // 2672 as well.
  393. // Search under a DNAME record. It should return the DNAME
  394. TEST_F(MemoryZoneTest, findBelowDNAME) {
  395. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  396. findTest(Name("below.dname.example.org"), RRType::A(), Zone::DNAME, true,
  397. rr_dname_);
  398. }
  399. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  400. // influences only the data below (see RFC 2672, section 3)
  401. TEST_F(MemoryZoneTest, findAtDNAME) {
  402. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
  403. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_a_)));
  404. const Name dname_name(rr_dname_->getName());
  405. findTest(dname_name, RRType::A(), Zone::SUCCESS, true, rr_dname_a_);
  406. findTest(dname_name, RRType::DNAME(), Zone::SUCCESS, true, rr_dname_);
  407. findTest(dname_name, RRType::TXT(), Zone::NXRRSET, true);
  408. }
  409. // Try searching something that is both under NS and DNAME, without and with
  410. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  411. TEST_F(MemoryZoneTest, DNAMEUnderNS) {
  412. zone_.add(rr_child_ns_);
  413. zone_.add(rr_child_dname_);
  414. Name lowName("below.dname.child.example.org.");
  415. findTest(lowName, RRType::A(), Zone::DELEGATION, true, rr_child_ns_);
  416. findTest(lowName, RRType::A(), Zone::DNAME, true, rr_child_dname_, NULL,
  417. NULL, Zone::FIND_GLUE_OK);
  418. }
  419. // Test adding child zones and zone cut handling
  420. TEST_F(MemoryZoneTest, delegationNS) {
  421. // add in-zone data
  422. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  423. // install a zone cut
  424. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  425. // below the zone cut
  426. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  427. true, rr_child_ns_);
  428. // at the zone cut
  429. findTest(Name("child.example.org"), RRType::A(), Zone::DELEGATION,
  430. true, rr_child_ns_);
  431. findTest(Name("child.example.org"), RRType::NS(), Zone::DELEGATION,
  432. true, rr_child_ns_);
  433. // finding NS for the apex (origin) node. This must not be confused
  434. // with delegation due to the existence of an NS RR.
  435. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  436. // unusual case of "nested delegation": the highest cut should be used.
  437. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  438. findTest(Name("www.grand.child.example.org"), RRType::A(),
  439. Zone::DELEGATION, true, rr_child_ns_); // note: !rr_grandchild_ns_
  440. }
  441. TEST_F(MemoryZoneTest, findAny) {
  442. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  443. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  444. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
  445. // origin
  446. RRsetList origin_rrsets;
  447. findTest(origin_, RRType::ANY(), Zone::SUCCESS, true,
  448. ConstRRsetPtr(), &origin_rrsets);
  449. EXPECT_EQ(2, origin_rrsets.size());
  450. EXPECT_EQ(rr_a_, origin_rrsets.findRRset(RRType::A(), RRClass::IN()));
  451. EXPECT_EQ(rr_ns_, origin_rrsets.findRRset(RRType::NS(), RRClass::IN()));
  452. // out zone name
  453. RRsetList out_rrsets;
  454. findTest(Name("example.com"), RRType::ANY(), Zone::NXDOMAIN, true,
  455. ConstRRsetPtr(), &out_rrsets);
  456. EXPECT_EQ(0, out_rrsets.size());
  457. RRsetList glue_child_rrsets;
  458. findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::SUCCESS, true,
  459. ConstRRsetPtr(), &glue_child_rrsets);
  460. EXPECT_EQ(rr_child_glue_, glue_child_rrsets.findRRset(RRType::A(),
  461. RRClass::IN()));
  462. EXPECT_EQ(1, glue_child_rrsets.size());
  463. // TODO: test NXRRSET case after rbtree non-terminal logic has
  464. // been implemented
  465. // add zone cut
  466. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  467. // zone cut
  468. RRsetList child_rrsets;
  469. findTest(rr_child_ns_->getName(), RRType::ANY(), Zone::DELEGATION, true,
  470. rr_child_ns_, &child_rrsets);
  471. EXPECT_EQ(0, child_rrsets.size());
  472. // glue for this zone cut
  473. RRsetList new_glue_child_rrsets;
  474. findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::DELEGATION, true,
  475. rr_child_ns_, &new_glue_child_rrsets);
  476. EXPECT_EQ(0, new_glue_child_rrsets.size());
  477. }
  478. TEST_F(MemoryZoneTest, glue) {
  479. // install zone data:
  480. // a zone cut
  481. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  482. // glue for this cut
  483. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
  484. // a nested zone cut (unusual)
  485. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  486. // glue under the deeper zone cut
  487. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_glue_)));
  488. // by default glue is hidden due to the zone cut
  489. findTest(rr_child_glue_->getName(), RRType::A(), Zone::DELEGATION, true,
  490. rr_child_ns_);
  491. // If we do it in the "glue OK" mode, we should find the exact match.
  492. findTest(rr_child_glue_->getName(), RRType::A(), Zone::SUCCESS, true,
  493. rr_child_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
  494. // glue OK + NXRRSET case
  495. findTest(rr_child_glue_->getName(), RRType::AAAA(), Zone::NXRRSET, true,
  496. ConstRRsetPtr(), NULL, NULL, Zone::FIND_GLUE_OK);
  497. // glue OK + NXDOMAIN case
  498. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  499. true, rr_child_ns_, NULL, NULL, Zone::FIND_GLUE_OK);
  500. // TODO:
  501. // glue name would match a wildcard under a zone cut: wildcard match
  502. // shouldn't happen under a cut and result must be PARTIALMATCH
  503. // (This case cannot be tested yet)
  504. // nested cut case. The glue should be found.
  505. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  506. Zone::SUCCESS,
  507. true, rr_grandchild_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
  508. // A non-existent name in nested cut. This should result in delegation
  509. // at the highest zone cut.
  510. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  511. Zone::DELEGATION, true, rr_child_ns_, NULL, NULL,
  512. Zone::FIND_GLUE_OK);
  513. }
  514. /**
  515. * \brief Test searching.
  516. *
  517. * Check it finds or does not find correctly and does not throw exceptions.
  518. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  519. * directly there, it just tells it doesn't exist.
  520. */
  521. TEST_F(MemoryZoneTest, find) {
  522. // Fill some data inside
  523. // Now put all the data we have there. It should throw nothing
  524. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  525. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  526. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  527. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  528. // These two should be successful
  529. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  530. findTest(rr_ns_a_->getName(), RRType::A(), Zone::SUCCESS, true, rr_ns_a_);
  531. // These domain exist but don't have the provided RRType
  532. findTest(origin_, RRType::AAAA(), Zone::NXRRSET);
  533. findTest(rr_ns_a_->getName(), RRType::NS(), Zone::NXRRSET);
  534. // These domains don't exist (and one is out of the zone)
  535. findTest(Name("nothere.example.org"), RRType::A(), Zone::NXDOMAIN);
  536. findTest(Name("example.net"), RRType::A(), Zone::NXDOMAIN);
  537. }
  538. TEST_F(MemoryZoneTest, emptyNode) {
  539. /*
  540. * The backend RBTree for this test should look like as follows:
  541. * example.org
  542. * |
  543. * baz (empty; easy case)
  544. * / | \
  545. * bar | x.foo ('foo' part is empty; a bit trickier)
  546. * bbb
  547. * /
  548. * aaa
  549. */
  550. // Construct the test zone
  551. const char* const names[] = {
  552. "bar.example.org", "x.foo.example.org", "aaa.baz.example.org",
  553. "bbb.baz.example.org.", NULL};
  554. for (int i = 0; names[i] != NULL; ++i) {
  555. ConstRRsetPtr rrset(new RRset(Name(names[i]), class_, RRType::A(),
  556. RRTTL(300)));
  557. EXPECT_EQ(SUCCESS, zone_.add(rrset));
  558. }
  559. // empty node matching, easy case: the node for 'baz' exists with
  560. // no data.
  561. findTest(Name("baz.example.org"), RRType::A(), Zone::NXRRSET);
  562. // empty node matching, a trickier case: the node for 'foo' is part of
  563. // "x.foo", which should be considered an empty node.
  564. findTest(Name("foo.example.org"), RRType::A(), Zone::NXRRSET);
  565. // "org" is contained in "example.org", but it shouldn't be treated as
  566. // NXRRSET because it's out of zone.
  567. // Note: basically we don't expect such a query to be performed (the common
  568. // operation is to identify the best matching zone first then perform
  569. // search it), but we shouldn't be confused even in the unexpected case.
  570. findTest(Name("org"), RRType::A(), Zone::NXDOMAIN);
  571. }
  572. TEST_F(MemoryZoneTest, load) {
  573. // Put some data inside the zone
  574. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_.add(rr_ns_)));
  575. // Loading with different origin should fail
  576. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/root.zone"), MasterLoadError);
  577. // See the original data is still there, survived the exception
  578. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  579. // Create correct zone
  580. MemoryZone rootzone(class_, Name("."));
  581. // Try putting something inside
  582. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  583. // Load the zone. It should overwrite/remove the above RRset
  584. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  585. // Now see there are some rrsets (we don't look inside, though)
  586. findTest(Name("."), RRType::SOA(), Zone::SUCCESS, false, ConstRRsetPtr(),
  587. NULL, &rootzone);
  588. findTest(Name("."), RRType::NS(), Zone::SUCCESS, false, ConstRRsetPtr(),
  589. NULL, &rootzone);
  590. findTest(Name("a.root-servers.net."), RRType::A(), Zone::SUCCESS, false,
  591. ConstRRsetPtr(), NULL, &rootzone);
  592. // But this should no longer be here
  593. findTest(rr_ns_a_->getName(), RRType::AAAA(), Zone::NXDOMAIN, true,
  594. ConstRRsetPtr(), NULL, &rootzone);
  595. // Try loading zone that is wrong in a different way
  596. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  597. MasterLoadError);
  598. }
  599. /*
  600. * Test that puts a (simple) wildcard into the zone and checks we can
  601. * correctly find the data.
  602. */
  603. TEST_F(MemoryZoneTest, wildcard) {
  604. /*
  605. * example.org.
  606. * |
  607. * wild (not *.wild, should have wild mark)
  608. * |
  609. * *
  610. */
  611. EXPECT_EQ(SUCCESS, zone_.add(rr_wild_));
  612. // Search at the parent. The parent will not have the A, but it will be here
  613. {
  614. SCOPED_TRACE("Search at parrent");
  615. findTest(Name("wild.example.org"), RRType::A(), Zone::NXRRSET);
  616. }
  617. // Search the original name of wildcard
  618. {
  619. SCOPED_TRACE("Search directly at *");
  620. findTest(Name("*.wild.example.org"), RRType::A(), Zone::SUCCESS, true,
  621. rr_wild_);
  622. }
  623. // Search "created" name.
  624. // TODO We need to synthetize the name correctly, there'll be different rrset
  625. {
  626. SCOPED_TRACE("Search at created child");
  627. findTest(Name("a.wild.example.org"), RRType::A(), Zone::SUCCESS, true,
  628. rr_wild_);
  629. }
  630. // Search another created name, this time little bit lower
  631. {
  632. SCOPED_TRACE("Search at created grand-child");
  633. findTest(Name("a.b.wild.example.org"), RRType::A(), Zone::SUCCESS,
  634. true, rr_wild_);
  635. }
  636. }
  637. // Note: once #507 is merged, findTest() would succeed whether or not
  638. // we load the wildcard correctly, so the test will become meaningless.
  639. // The plan is to clean them up when we complete #551 (then the effect of
  640. // load will be indirectly tested via find() tests).
  641. TEST_F(MemoryZoneTest, loadEmptyWildcard) {
  642. /*
  643. * example.org.
  644. * foo
  645. * *
  646. * wild
  647. */
  648. EXPECT_EQ(SUCCESS, zone_.add(rr_emptywild_));
  649. findTest(Name("*.foo.example.org"), RRType::A(), Zone::NXRRSET);
  650. findTest(Name("foo.example.org"), RRType::A(), Zone::NXRRSET);
  651. }
  652. // same note as loadEmptyWildcard applies.
  653. TEST_F(MemoryZoneTest, loadNestedEmptyWildcard) {
  654. EXPECT_EQ(SUCCESS, zone_.add(rr_nested_emptywild_));
  655. findTest(Name("*.foo.*.bar.example.org"), RRType::A(), Zone::NXRRSET);
  656. findTest(Name("foo.*.bar.example.org"), RRType::A(), Zone::NXRRSET);
  657. findTest(Name("*.bar.example.org"), RRType::A(), Zone::NXRRSET);
  658. findTest(Name("bar.example.org"), RRType::A(), Zone::NXRRSET);
  659. }
  660. TEST_F(MemoryZoneTest, loadBadWildcard) {
  661. // We reject loading the zone if it contains a wildcard name for
  662. // NS or DNAME.
  663. EXPECT_THROW(zone_.add(rr_nswild_), MemoryZone::AddError);
  664. EXPECT_THROW(zone_.add(rr_dnamewild_), MemoryZone::AddError);
  665. }
  666. TEST_F(MemoryZoneTest, swap) {
  667. // build one zone with some data
  668. MemoryZone zone1(class_, origin_);
  669. EXPECT_EQ(result::SUCCESS, zone1.add(rr_ns_));
  670. EXPECT_EQ(result::SUCCESS, zone1.add(rr_ns_aaaa_));
  671. // build another zone of a different RR class with some other data
  672. const Name other_origin("version.bind");
  673. ASSERT_NE(origin_, other_origin); // make sure these two are different
  674. MemoryZone zone2(RRClass::CH(), other_origin);
  675. EXPECT_EQ(result::SUCCESS,
  676. zone2.add(RRsetPtr(new RRset(Name("version.bind"),
  677. RRClass::CH(), RRType::TXT(),
  678. RRTTL(0)))));
  679. zone1.swap(zone2);
  680. EXPECT_EQ(other_origin, zone1.getOrigin());
  681. EXPECT_EQ(origin_, zone2.getOrigin());
  682. EXPECT_EQ(RRClass::CH(), zone1.getClass());
  683. EXPECT_EQ(RRClass::IN(), zone2.getClass());
  684. // make sure the zone data is swapped, too
  685. findTest(origin_, RRType::NS(), Zone::NXDOMAIN, false, ConstRRsetPtr(),
  686. NULL, &zone1);
  687. findTest(other_origin, RRType::TXT(), Zone::SUCCESS, false,
  688. ConstRRsetPtr(), NULL, &zone1);
  689. findTest(origin_, RRType::NS(), Zone::SUCCESS, false, ConstRRsetPtr(),
  690. NULL, &zone2);
  691. findTest(other_origin, RRType::TXT(), Zone::NXDOMAIN, false,
  692. ConstRRsetPtr(), NULL, &zone2);
  693. }
  694. TEST_F(MemoryZoneTest, getFileName) {
  695. // for an empty zone the file name should also be empty.
  696. EXPECT_TRUE(zone_.getFileName().empty());
  697. // if loading a zone fails the file name shouldn't be set.
  698. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/root.zone"), MasterLoadError);
  699. EXPECT_TRUE(zone_.getFileName().empty());
  700. // after a successful load, the specified file name should be set
  701. MemoryZone rootzone(class_, Name("."));
  702. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  703. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  704. // overriding load, which will fail
  705. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  706. MasterLoadError);
  707. // the file name should be intact.
  708. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  709. // After swap, file names should also be swapped.
  710. zone_.swap(rootzone);
  711. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_.getFileName());
  712. EXPECT_TRUE(rootzone.getFileName().empty());
  713. }
  714. }