memory_datasrc_unittest.cc 35 KB

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