memory_datasrc_unittest.cc 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <sstream>
  15. #include <vector>
  16. #include <boost/bind.hpp>
  17. #include <exceptions/exceptions.h>
  18. #include <dns/masterload.h>
  19. #include <dns/name.h>
  20. #include <dns/rdata.h>
  21. #include <dns/rdataclass.h>
  22. #include <dns/rrclass.h>
  23. #include <dns/rrsetlist.h>
  24. #include <dns/rrttl.h>
  25. #include <dns/masterload.h>
  26. #include <datasrc/memory_datasrc.h>
  27. #include <datasrc/data_source.h>
  28. #include <datasrc/iterator.h>
  29. #include <gtest/gtest.h>
  30. using namespace std;
  31. using namespace isc::dns;
  32. using namespace isc::dns::rdata;
  33. using namespace isc::datasrc;
  34. namespace {
  35. // Commonly used result codes (Who should write the prefix all the time)
  36. using result::SUCCESS;
  37. using result::EXIST;
  38. class InMemoryClientTest : public ::testing::Test {
  39. protected:
  40. InMemoryClientTest() : rrclass(RRClass::IN())
  41. {}
  42. RRClass rrclass;
  43. InMemoryClient memory_client;
  44. };
  45. TEST_F(InMemoryClientTest, add_find_Zone) {
  46. // test add zone
  47. // Bogus zone (NULL)
  48. EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
  49. isc::InvalidParameter);
  50. // add zones with different names one by one
  51. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  52. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  53. Name("a")))));
  54. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  55. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  56. Name("b")))));
  57. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  58. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  59. Name("c")))));
  60. // add zones with the same name suffix
  61. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  62. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  63. Name("x.d.e.f")))));
  64. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  65. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  66. Name("o.w.y.d.e.f")))));
  67. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  68. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  69. Name("p.w.y.d.e.f")))));
  70. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  71. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  72. Name("q.w.y.d.e.f")))));
  73. // add super zone and its subzone
  74. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  75. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  76. Name("g.h")))));
  77. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  78. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  79. Name("i.g.h")))));
  80. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  81. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  82. Name("z.d.e.f")))));
  83. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  84. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  85. Name("j.z.d.e.f")))));
  86. // different zone class isn't allowed.
  87. EXPECT_EQ(result::EXIST, memory_client.addZone(
  88. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  89. Name("q.w.y.d.e.f")))));
  90. // names are compared in a case insensitive manner.
  91. EXPECT_EQ(result::EXIST, memory_client.addZone(
  92. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  93. Name("Q.W.Y.d.E.f")))));
  94. // test find zone
  95. EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
  96. EXPECT_EQ(Name("a"),
  97. memory_client.findZone(Name("a")).zone_finder->getOrigin());
  98. EXPECT_EQ(result::SUCCESS,
  99. memory_client.findZone(Name("j.z.d.e.f")).code);
  100. EXPECT_EQ(Name("j.z.d.e.f"),
  101. memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
  102. getOrigin());
  103. // NOTFOUND
  104. EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
  105. EXPECT_EQ(ConstZoneFinderPtr(),
  106. memory_client.findZone(Name("d.e.f")).zone_finder);
  107. EXPECT_EQ(result::NOTFOUND,
  108. memory_client.findZone(Name("w.y.d.e.f")).code);
  109. EXPECT_EQ(ConstZoneFinderPtr(),
  110. memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
  111. // there's no exact match. the result should be the longest match,
  112. // and the code should be PARTIALMATCH.
  113. EXPECT_EQ(result::PARTIALMATCH,
  114. memory_client.findZone(Name("j.g.h")).code);
  115. EXPECT_EQ(Name("g.h"),
  116. memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
  117. EXPECT_EQ(result::PARTIALMATCH,
  118. memory_client.findZone(Name("z.i.g.h")).code);
  119. EXPECT_EQ(Name("i.g.h"),
  120. memory_client.findZone(Name("z.i.g.h")).zone_finder->
  121. getOrigin());
  122. }
  123. TEST_F(InMemoryClientTest, iterator) {
  124. // Just some preparations of data
  125. boost::shared_ptr<InMemoryZoneFinder>
  126. zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
  127. RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
  128. RRTTL(300)));
  129. aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
  130. RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  131. RRTTL(300)));
  132. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
  133. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
  134. RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
  135. RRTTL(300)));
  136. subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
  137. EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
  138. // First, the zone is not there, so it should throw
  139. EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
  140. // This zone is not there either, even when there's a zone containing this
  141. EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
  142. // Now, an empty zone
  143. ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
  144. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  145. // It throws Unexpected when we are past the end
  146. EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
  147. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
  148. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
  149. EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
  150. // Check it with full zone, one by one.
  151. // It should be in ascending order in case of InMemory data source
  152. // (isn't guaranteed in general)
  153. iterator = memory_client.getIterator(Name("a"));
  154. EXPECT_EQ(aRRsetA, iterator->getNextRRset());
  155. EXPECT_EQ(aRRsetAAAA, iterator->getNextRRset());
  156. EXPECT_EQ(subRRsetA, iterator->getNextRRset());
  157. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  158. }
  159. TEST_F(InMemoryClientTest, getZoneCount) {
  160. EXPECT_EQ(0, memory_client.getZoneCount());
  161. memory_client.addZone(
  162. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  163. Name("example.com"))));
  164. EXPECT_EQ(1, memory_client.getZoneCount());
  165. // duplicate add. counter shouldn't change
  166. memory_client.addZone(
  167. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  168. Name("example.com"))));
  169. EXPECT_EQ(1, memory_client.getZoneCount());
  170. // add one more
  171. memory_client.addZone(
  172. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  173. Name("example.org"))));
  174. EXPECT_EQ(2, memory_client.getZoneCount());
  175. }
  176. // A helper callback of masterLoad() used in InMemoryZoneFinderTest.
  177. void
  178. setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
  179. *(*it) = rrset;
  180. ++it;
  181. }
  182. /// \brief Test fixture for the InMemoryZoneFinder class
  183. class InMemoryZoneFinderTest : public ::testing::Test {
  184. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  185. // to store the RRset. Used to build test data below.
  186. struct RRsetData {
  187. const char* const text; // textual representation of an RRset
  188. RRsetPtr* rrset;
  189. };
  190. public:
  191. InMemoryZoneFinderTest() :
  192. class_(RRClass::IN()),
  193. origin_("example.org"),
  194. zone_finder_(class_, origin_)
  195. {
  196. // Build test RRsets. Below, we construct an RRset for
  197. // each textual RR(s) of zone_data, and assign it to the corresponding
  198. // rr_xxx.
  199. const RRsetData zone_data[] = {
  200. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  201. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  202. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  203. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  204. {"cname.example.org. 300 IN CNAME canonical.example.org",
  205. &rr_cname_},
  206. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  207. {"dname.example.org. 300 IN DNAME target.example.org.",
  208. &rr_dname_},
  209. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  210. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  211. &rr_dname_ns_},
  212. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  213. {"child.example.org. 300 IN NS ns.child.example.org.",
  214. &rr_child_ns_},
  215. {"ns.child.example.org. 300 IN A 192.0.2.153",
  216. &rr_child_glue_},
  217. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  218. &rr_grandchild_ns_},
  219. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  220. &rr_grandchild_glue_},
  221. {"dname.child.example.org. 300 IN DNAME example.com.",
  222. &rr_child_dname_},
  223. {"example.com. 300 IN A 192.0.2.10", &rr_out_},
  224. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  225. {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
  226. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  227. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  228. &rr_nested_emptywild_},
  229. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  230. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  231. &rr_dnamewild_},
  232. {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
  233. {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
  234. {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
  235. &rr_not_wild_another_},
  236. {NULL, NULL}
  237. };
  238. stringstream zone_data_stream;
  239. vector<RRsetPtr*> rrsets;
  240. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  241. zone_data_stream << zone_data[i].text << "\n";
  242. rrsets.push_back(zone_data[i].rrset);
  243. }
  244. vector<RRsetPtr*>::iterator it = rrsets.begin();
  245. masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
  246. boost::bind(setRRset, _1, it));
  247. }
  248. // Some data to test with
  249. const RRClass class_;
  250. const Name origin_;
  251. // The zone finder to torture by tests
  252. InMemoryZoneFinder zone_finder_;
  253. /*
  254. * Some RRsets to put inside the zone.
  255. */
  256. RRsetPtr
  257. // Out of zone RRset
  258. rr_out_,
  259. // NS of example.org
  260. rr_ns_,
  261. // A of ns.example.org
  262. rr_ns_a_,
  263. // AAAA of ns.example.org
  264. rr_ns_aaaa_,
  265. // A of example.org
  266. rr_a_;
  267. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  268. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  269. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  270. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  271. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  272. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  273. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  274. RRsetPtr rr_child_glue_; // glue RR of the child domain
  275. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  276. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  277. RRsetPtr rr_child_dname_; // A DNAME under NS
  278. RRsetPtr rr_wild_;
  279. RRsetPtr rr_emptywild_;
  280. RRsetPtr rr_nested_emptywild_;
  281. RRsetPtr rr_nswild_, rr_dnamewild_;
  282. RRsetPtr rr_child_wild_;
  283. RRsetPtr rr_under_wild_;
  284. RRsetPtr rr_not_wild_;
  285. RRsetPtr rr_not_wild_another_;
  286. /**
  287. * \brief Test one find query to the zone finder.
  288. *
  289. * Asks a query to the zone finder and checks it does not throw and returns
  290. * expected results. It returns nothing, it just signals failures
  291. * to GTEST.
  292. *
  293. * \param name The name to ask for.
  294. * \param rrtype The RRType to ask of.
  295. * \param result The expected code of the result.
  296. * \param check_answer Should a check against equality of the answer be
  297. * done?
  298. * \param answer The expected rrset, if any should be returned.
  299. * \param zone_finder Check different InMemoryZoneFinder object than
  300. * zone_finder_ (if NULL, uses zone_finder_)
  301. * \param check_wild_answer Checks that the answer has the same RRs, type
  302. * class and TTL as the eqxpected answer and that the name corresponds
  303. * to the one searched. It is meant for checking answers for wildcard
  304. * queries.
  305. */
  306. void findTest(const Name& name, const RRType& rrtype,
  307. ZoneFinder::Result result,
  308. bool check_answer = true,
  309. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  310. RRsetList* target = NULL,
  311. InMemoryZoneFinder* zone_finder = NULL,
  312. ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
  313. bool check_wild_answer = false)
  314. {
  315. if (zone_finder == NULL) {
  316. zone_finder = &zone_finder_;
  317. }
  318. // The whole block is inside, because we need to check the result and
  319. // we can't assign to FindResult
  320. EXPECT_NO_THROW({
  321. ZoneFinder::FindResult find_result(zone_finder->find(
  322. name, rrtype,
  323. target, options));
  324. // Check it returns correct answers
  325. EXPECT_EQ(result, find_result.code);
  326. if (check_answer) {
  327. EXPECT_EQ(answer, find_result.rrset);
  328. } else if (check_wild_answer) {
  329. ASSERT_NE(ConstRRsetPtr(), answer) <<
  330. "Wrong test, don't check for wild names if you expect "
  331. "empty answer";
  332. ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
  333. "No answer found";
  334. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  335. RdataIteratorPtr actualIt(
  336. find_result.rrset->getRdataIterator());
  337. while (!expectedIt->isLast() && !actualIt->isLast()) {
  338. EXPECT_EQ(0, expectedIt->getCurrent().compare(
  339. actualIt->getCurrent())) << "The RRs differ ('" <<
  340. expectedIt->getCurrent().toText() << "', '" <<
  341. actualIt->getCurrent().toText() << "')";
  342. expectedIt->next();
  343. actualIt->next();
  344. }
  345. EXPECT_TRUE(expectedIt->isLast()) <<
  346. "Result has less RRs than expected";
  347. EXPECT_TRUE(actualIt->isLast()) <<
  348. "Result has more RRs than expected";
  349. EXPECT_EQ(answer->getClass(),
  350. find_result.rrset->getClass());
  351. EXPECT_EQ(answer->getType(),
  352. find_result.rrset->getType());
  353. EXPECT_EQ(answer->getTTL(),
  354. find_result.rrset->getTTL());
  355. EXPECT_EQ(name, find_result.rrset->getName());
  356. }
  357. });
  358. }
  359. // Internal part of the cancelWildcard test that is multiple times
  360. void doCancelWildcardTest();
  361. };
  362. /**
  363. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  364. *
  365. * Takes the created zone finder and checks its properties they are the same
  366. * as passed parameters.
  367. */
  368. TEST_F(InMemoryZoneFinderTest, constructor) {
  369. ASSERT_EQ(class_, zone_finder_.getClass());
  370. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  371. }
  372. /**
  373. * \brief Test adding.
  374. *
  375. * We test that it throws at the correct moments and the correct exceptions.
  376. * And we test the return value.
  377. */
  378. TEST_F(InMemoryZoneFinderTest, add) {
  379. // This one does not belong to this zone
  380. EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
  381. // Test null pointer
  382. EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
  383. InMemoryZoneFinder::NullRRset);
  384. // Now put all the data we have there. It should throw nothing
  385. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  386. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  387. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  388. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  389. // Try putting there something twice, it should be rejected
  390. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
  391. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
  392. }
  393. TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
  394. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  395. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  396. }
  397. TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
  398. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  399. EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
  400. }
  401. TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
  402. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
  403. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  404. }
  405. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  406. // install CNAME RR
  407. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  408. // Find A RR of the same. Should match the CNAME
  409. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  410. rr_cname_);
  411. // Find the CNAME itself. Should result in normal SUCCESS
  412. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  413. rr_cname_);
  414. }
  415. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  416. // There's nothing special when we find a CNAME under a zone cut
  417. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  418. // so we test this case explicitly.
  419. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  420. RRsetPtr rr_cname_under_cut_(new RRset(Name("cname.child.example.org"),
  421. class_, RRType::CNAME(),
  422. RRTTL(300)));
  423. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
  424. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  425. ZoneFinder::CNAME, true, rr_cname_under_cut_, NULL, NULL,
  426. ZoneFinder::FIND_GLUE_OK);
  427. }
  428. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  429. // Having a CNAME there is disallowed too, but it is tested by
  430. // addOtherThenCNAME and addCNAMEThenOther.
  431. TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
  432. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  433. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  434. }
  435. /*
  436. * These two tests ensure that we can't have DNAME and NS at the same
  437. * node with the exception of the apex of zone (forbidden by RFC 2672)
  438. */
  439. TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
  440. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  441. EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
  442. }
  443. TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
  444. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
  445. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  446. }
  447. // It is allowed to have NS and DNAME at apex
  448. TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
  449. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  450. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  451. // The NS should be possible to be found, below should be DNAME, not
  452. // delegation
  453. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  454. findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
  455. rr_dname_apex_);
  456. }
  457. TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
  458. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  459. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  460. }
  461. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  462. // 2672 as well.
  463. // Search under a DNAME record. It should return the DNAME
  464. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  465. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  466. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  467. true, rr_dname_);
  468. }
  469. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  470. // influences only the data below (see RFC 2672, section 3)
  471. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  472. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  473. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
  474. const Name dname_name(rr_dname_->getName());
  475. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  476. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  477. rr_dname_);
  478. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  479. }
  480. // Try searching something that is both under NS and DNAME, without and with
  481. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  482. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  483. zone_finder_.add(rr_child_ns_);
  484. zone_finder_.add(rr_child_dname_);
  485. Name lowName("below.dname.child.example.org.");
  486. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  487. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  488. NULL, NULL, ZoneFinder::FIND_GLUE_OK);
  489. }
  490. // Test adding child zones and zone cut handling
  491. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  492. // add in-zone data
  493. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  494. // install a zone cut
  495. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  496. // below the zone cut
  497. findTest(Name("www.child.example.org"), RRType::A(),
  498. ZoneFinder::DELEGATION, true, rr_child_ns_);
  499. // at the zone cut
  500. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  501. true, rr_child_ns_);
  502. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  503. true, rr_child_ns_);
  504. // finding NS for the apex (origin) node. This must not be confused
  505. // with delegation due to the existence of an NS RR.
  506. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  507. // unusual case of "nested delegation": the highest cut should be used.
  508. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  509. findTest(Name("www.grand.child.example.org"), RRType::A(),
  510. // note: !rr_grandchild_ns_
  511. ZoneFinder::DELEGATION, true, rr_child_ns_);
  512. }
  513. TEST_F(InMemoryZoneFinderTest, findAny) {
  514. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  515. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  516. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  517. // origin
  518. RRsetList origin_rrsets;
  519. findTest(origin_, RRType::ANY(), ZoneFinder::SUCCESS, true,
  520. ConstRRsetPtr(), &origin_rrsets);
  521. EXPECT_EQ(2, origin_rrsets.size());
  522. EXPECT_EQ(rr_a_, origin_rrsets.findRRset(RRType::A(), RRClass::IN()));
  523. EXPECT_EQ(rr_ns_, origin_rrsets.findRRset(RRType::NS(), RRClass::IN()));
  524. // out zone name
  525. RRsetList out_rrsets;
  526. findTest(Name("example.com"), RRType::ANY(), ZoneFinder::NXDOMAIN, true,
  527. ConstRRsetPtr(), &out_rrsets);
  528. EXPECT_EQ(0, out_rrsets.size());
  529. RRsetList glue_child_rrsets;
  530. findTest(rr_child_glue_->getName(), RRType::ANY(), ZoneFinder::SUCCESS,
  531. true, ConstRRsetPtr(), &glue_child_rrsets);
  532. EXPECT_EQ(rr_child_glue_, glue_child_rrsets.findRRset(RRType::A(),
  533. RRClass::IN()));
  534. EXPECT_EQ(1, glue_child_rrsets.size());
  535. // TODO: test NXRRSET case after rbtree non-terminal logic has
  536. // been implemented
  537. // add zone cut
  538. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  539. // zone cut
  540. RRsetList child_rrsets;
  541. findTest(rr_child_ns_->getName(), RRType::ANY(), ZoneFinder::DELEGATION,
  542. true, rr_child_ns_, &child_rrsets);
  543. EXPECT_EQ(0, child_rrsets.size());
  544. // glue for this zone cut
  545. RRsetList new_glue_child_rrsets;
  546. findTest(rr_child_glue_->getName(), RRType::ANY(), ZoneFinder::DELEGATION,
  547. true, rr_child_ns_, &new_glue_child_rrsets);
  548. EXPECT_EQ(0, new_glue_child_rrsets.size());
  549. }
  550. TEST_F(InMemoryZoneFinderTest, glue) {
  551. // install zone data:
  552. // a zone cut
  553. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  554. // glue for this cut
  555. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  556. // a nested zone cut (unusual)
  557. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  558. // glue under the deeper zone cut
  559. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
  560. // by default glue is hidden due to the zone cut
  561. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  562. true, rr_child_ns_);
  563. // If we do it in the "glue OK" mode, we should find the exact match.
  564. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  565. rr_child_glue_, NULL, NULL, ZoneFinder::FIND_GLUE_OK);
  566. // glue OK + NXRRSET case
  567. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  568. true, ConstRRsetPtr(), NULL, NULL, ZoneFinder::FIND_GLUE_OK);
  569. // glue OK + NXDOMAIN case
  570. findTest(Name("www.child.example.org"), RRType::A(),
  571. ZoneFinder::DELEGATION, true, rr_child_ns_, NULL, NULL,
  572. ZoneFinder::FIND_GLUE_OK);
  573. // nested cut case. The glue should be found.
  574. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  575. ZoneFinder::SUCCESS,
  576. true, rr_grandchild_glue_, NULL, NULL, ZoneFinder::FIND_GLUE_OK);
  577. // A non-existent name in nested cut. This should result in delegation
  578. // at the highest zone cut.
  579. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  580. ZoneFinder::DELEGATION, true, rr_child_ns_, NULL, NULL,
  581. ZoneFinder::FIND_GLUE_OK);
  582. }
  583. /**
  584. * \brief Test searching.
  585. *
  586. * Check it finds or does not find correctly and does not throw exceptions.
  587. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  588. * directly there, it just tells it doesn't exist.
  589. */
  590. TEST_F(InMemoryZoneFinderTest, find) {
  591. // Fill some data inside
  592. // Now put all the data we have there. It should throw nothing
  593. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  594. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  595. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  596. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  597. // These two should be successful
  598. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  599. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  600. rr_ns_a_);
  601. // These domain exist but don't have the provided RRType
  602. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET);
  603. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET);
  604. // These domains don't exist (and one is out of the zone)
  605. findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN);
  606. findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN);
  607. }
  608. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  609. /*
  610. * The backend RBTree for this test should look like as follows:
  611. * example.org
  612. * |
  613. * baz (empty; easy case)
  614. * / | \
  615. * bar | x.foo ('foo' part is empty; a bit trickier)
  616. * bbb
  617. * /
  618. * aaa
  619. */
  620. // Construct the test zone
  621. const char* const names[] = {
  622. "bar.example.org", "x.foo.example.org", "aaa.baz.example.org",
  623. "bbb.baz.example.org.", NULL};
  624. for (int i = 0; names[i] != NULL; ++i) {
  625. ConstRRsetPtr rrset(new RRset(Name(names[i]), class_, RRType::A(),
  626. RRTTL(300)));
  627. EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
  628. }
  629. // empty node matching, easy case: the node for 'baz' exists with
  630. // no data.
  631. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  632. // empty node matching, a trickier case: the node for 'foo' is part of
  633. // "x.foo", which should be considered an empty node.
  634. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  635. // "org" is contained in "example.org", but it shouldn't be treated as
  636. // NXRRSET because it's out of zone.
  637. // Note: basically we don't expect such a query to be performed (the common
  638. // operation is to identify the best matching zone first then perform
  639. // search it), but we shouldn't be confused even in the unexpected case.
  640. findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN);
  641. }
  642. TEST_F(InMemoryZoneFinderTest, load) {
  643. // Put some data inside the zone
  644. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
  645. // Loading with different origin should fail
  646. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  647. MasterLoadError);
  648. // See the original data is still there, survived the exception
  649. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  650. // Create correct zone
  651. InMemoryZoneFinder rootzone(class_, Name("."));
  652. // Try putting something inside
  653. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  654. // Load the zone. It should overwrite/remove the above RRset
  655. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  656. // Now see there are some rrsets (we don't look inside, though)
  657. findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
  658. ConstRRsetPtr(), NULL, &rootzone);
  659. findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
  660. ConstRRsetPtr(), NULL, &rootzone);
  661. findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
  662. false, ConstRRsetPtr(), NULL, &rootzone);
  663. // But this should no longer be here
  664. findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
  665. ConstRRsetPtr(), NULL, &rootzone);
  666. // Try loading zone that is wrong in a different way
  667. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  668. MasterLoadError);
  669. }
  670. /*
  671. * Test that puts a (simple) wildcard into the zone and checks we can
  672. * correctly find the data.
  673. */
  674. TEST_F(InMemoryZoneFinderTest, wildcard) {
  675. /*
  676. * example.org.
  677. * |
  678. * wild (not *.wild, should have wild mark)
  679. * |
  680. * *
  681. */
  682. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  683. // Search at the parent. The parent will not have the A, but it will
  684. // be in the wildcard (so check the wildcard isn't matched at the parent)
  685. {
  686. SCOPED_TRACE("Search at parrent");
  687. findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  688. }
  689. // Search the original name of wildcard
  690. {
  691. SCOPED_TRACE("Search directly at *");
  692. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  693. true, rr_wild_);
  694. }
  695. // Search "created" name.
  696. {
  697. SCOPED_TRACE("Search at created child");
  698. findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  699. false, rr_wild_, NULL, NULL, ZoneFinder::FIND_DEFAULT, true);
  700. }
  701. // Search another created name, this time little bit lower
  702. {
  703. SCOPED_TRACE("Search at created grand-child");
  704. findTest(Name("a.b.wild.example.org"), RRType::A(),
  705. ZoneFinder::SUCCESS, false, rr_wild_, NULL, NULL,
  706. ZoneFinder::FIND_DEFAULT, true);
  707. }
  708. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
  709. {
  710. SCOPED_TRACE("Search under non-wildcard");
  711. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  712. ZoneFinder::NXDOMAIN);
  713. }
  714. }
  715. /*
  716. * Test that we don't match a wildcard if we get under delegation.
  717. * By 4.3.3 of RFC1034:
  718. * "Wildcard RRs do not apply:
  719. * - When the query is in another zone. That is, delegation cancels
  720. * the wildcard defaults."
  721. */
  722. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  723. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
  724. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  725. {
  726. SCOPED_TRACE("Looking under delegation point");
  727. findTest(Name("a.child.example.org"), RRType::A(),
  728. ZoneFinder::DELEGATION, true, rr_child_ns_);
  729. }
  730. {
  731. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  732. findTest(Name("a.child.example.org"), RRType::A(),
  733. ZoneFinder::DELEGATION, true, rr_child_ns_, NULL, NULL,
  734. ZoneFinder::FIND_GLUE_OK);
  735. }
  736. }
  737. // Tests combination of wildcard and ANY.
  738. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  739. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  740. // First try directly the name (normal match)
  741. {
  742. SCOPED_TRACE("Asking direcly for *");
  743. RRsetList target;
  744. findTest(Name("*.wild.example.org"), RRType::ANY(),
  745. ZoneFinder::SUCCESS, true, ConstRRsetPtr(), &target);
  746. ASSERT_EQ(1, target.size());
  747. EXPECT_EQ(RRType::A(), (*target.begin())->getType());
  748. EXPECT_EQ(Name("*.wild.example.org"), (*target.begin())->getName());
  749. }
  750. // Then a wildcard match
  751. {
  752. SCOPED_TRACE("Asking in the wild way");
  753. RRsetList target;
  754. findTest(Name("a.wild.example.org"), RRType::ANY(),
  755. ZoneFinder::SUCCESS, true, ConstRRsetPtr(), &target);
  756. ASSERT_EQ(1, target.size());
  757. EXPECT_EQ(RRType::A(), (*target.begin())->getType());
  758. EXPECT_EQ(Name("a.wild.example.org"), (*target.begin())->getName());
  759. }
  760. }
  761. // Test there's nothing in the wildcard in the middle if we load
  762. // wild.*.foo.example.org.
  763. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  764. /*
  765. * example.org.
  766. * foo
  767. * *
  768. * wild
  769. */
  770. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
  771. {
  772. SCOPED_TRACE("Asking for the original record under wildcard");
  773. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  774. ZoneFinder::SUCCESS, true, rr_emptywild_);
  775. }
  776. {
  777. SCOPED_TRACE("Asking for A record");
  778. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  779. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  780. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  781. }
  782. {
  783. SCOPED_TRACE("Asking for ANY record");
  784. RRsetList normalTarget;
  785. findTest(Name("*.foo.example.org"), RRType::ANY(), ZoneFinder::NXRRSET,
  786. true, ConstRRsetPtr(), &normalTarget);
  787. EXPECT_EQ(0, normalTarget.size());
  788. RRsetList wildTarget;
  789. findTest(Name("a.foo.example.org"), RRType::ANY(),
  790. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), &wildTarget);
  791. EXPECT_EQ(0, wildTarget.size());
  792. }
  793. {
  794. SCOPED_TRACE("Asking on the non-terminal");
  795. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  796. ZoneFinder::NXRRSET);
  797. }
  798. }
  799. // Same as emptyWildcard, but with multiple * in the path.
  800. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  801. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
  802. {
  803. SCOPED_TRACE("Asking for the original record under wildcards");
  804. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  805. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  806. }
  807. {
  808. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  809. const char* names[] = {
  810. "baz.foo.*.bar.example.org",
  811. "baz.foo.baz.bar.example.org",
  812. "*.foo.baz.bar.example.org",
  813. NULL
  814. };
  815. for (const char** name(names); *name != NULL; ++ name) {
  816. SCOPED_TRACE(string("Node ") + *name);
  817. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  818. }
  819. }
  820. // Domains to test
  821. const char* names[] = {
  822. "*.foo.*.bar.example.org",
  823. "foo.*.bar.example.org",
  824. "*.bar.example.org",
  825. "bar.example.org",
  826. NULL
  827. };
  828. {
  829. SCOPED_TRACE("Asking directly for A on parent nodes");
  830. for (const char** name(names); *name != NULL; ++ name) {
  831. SCOPED_TRACE(string("Node ") + *name);
  832. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  833. }
  834. }
  835. {
  836. SCOPED_TRACE("Asking for ANY on parent nodes");
  837. for (const char** name(names); *name != NULL; ++ name) {
  838. SCOPED_TRACE(string("Node ") + *name);
  839. RRsetList target;
  840. findTest(Name(*name), RRType::ANY(), ZoneFinder::NXRRSET, true,
  841. ConstRRsetPtr(), &target);
  842. EXPECT_EQ(0, target.size());
  843. }
  844. }
  845. }
  846. // We run this part twice from the below test, in two slightly different
  847. // situations
  848. void
  849. InMemoryZoneFinderTest::doCancelWildcardTest() {
  850. // These should be canceled
  851. {
  852. SCOPED_TRACE("Canceled under foo.wild.example.org");
  853. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  854. ZoneFinder::NXDOMAIN);
  855. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  856. ZoneFinder::NXDOMAIN);
  857. }
  858. // This is existing, non-wildcard domain, shouldn't wildcard at all
  859. {
  860. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  861. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  862. ZoneFinder::SUCCESS, true, rr_not_wild_);
  863. }
  864. // These should be caught by the wildcard
  865. {
  866. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  867. const char* names[] = {
  868. "aaa.bbb.wild.example.org",
  869. "aaa.zzz.wild.example.org",
  870. "zzz.wild.example.org",
  871. NULL
  872. };
  873. for (const char** name(names); *name != NULL; ++ name) {
  874. SCOPED_TRACE(string("Node ") + *name);
  875. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  876. rr_wild_, NULL, NULL, ZoneFinder::FIND_DEFAULT, true);
  877. }
  878. }
  879. // This shouldn't be wildcarded, it's an existing domain
  880. {
  881. SCOPED_TRACE("The foo.wild.example.org itself");
  882. findTest(Name("foo.wild.example.org"), RRType::A(),
  883. ZoneFinder::NXRRSET);
  884. }
  885. }
  886. /*
  887. * This tests that if there's a name between the wildcard domain and the
  888. * searched one, it will not trigger wildcard, for example, if we have
  889. * *.wild.example.org and bar.foo.wild.example.org, then we know
  890. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  891. * aaa.foo.wild.example.org should return NXDOMAIN.
  892. *
  893. * Tests few cases "around" the canceled wildcard match, to see something that
  894. * shouldn't be canceled isn't.
  895. */
  896. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  897. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  898. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  899. {
  900. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  901. doCancelWildcardTest();
  902. }
  903. // Try putting another one under foo.wild....
  904. // The result should be the same but it will be done in another way in the
  905. // code, because the foo.wild.example.org will exist in the tree.
  906. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  907. {
  908. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  909. doCancelWildcardTest();
  910. }
  911. }
  912. TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
  913. // We reject loading the zone if it contains a wildcard name for
  914. // NS or DNAME.
  915. EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
  916. EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
  917. InMemoryZoneFinder::AddError);
  918. }
  919. TEST_F(InMemoryZoneFinderTest, swap) {
  920. // build one zone finder with some data
  921. InMemoryZoneFinder finder1(class_, origin_);
  922. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
  923. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
  924. // build another zone finder of a different RR class with some other data
  925. const Name other_origin("version.bind");
  926. ASSERT_NE(origin_, other_origin); // make sure these two are different
  927. InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
  928. EXPECT_EQ(result::SUCCESS,
  929. finder2.add(RRsetPtr(new RRset(Name("version.bind"),
  930. RRClass::CH(), RRType::TXT(),
  931. RRTTL(0)))));
  932. finder1.swap(finder2);
  933. EXPECT_EQ(other_origin, finder1.getOrigin());
  934. EXPECT_EQ(origin_, finder2.getOrigin());
  935. EXPECT_EQ(RRClass::CH(), finder1.getClass());
  936. EXPECT_EQ(RRClass::IN(), finder2.getClass());
  937. // make sure the zone data is swapped, too
  938. findTest(origin_, RRType::NS(), ZoneFinder::NXDOMAIN, false,
  939. ConstRRsetPtr(), NULL, &finder1);
  940. findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
  941. ConstRRsetPtr(), NULL, &finder1);
  942. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
  943. ConstRRsetPtr(), NULL, &finder2);
  944. findTest(other_origin, RRType::TXT(), ZoneFinder::NXDOMAIN, false,
  945. ConstRRsetPtr(), NULL, &finder2);
  946. }
  947. TEST_F(InMemoryZoneFinderTest, getFileName) {
  948. // for an empty zone the file name should also be empty.
  949. EXPECT_TRUE(zone_finder_.getFileName().empty());
  950. // if loading a zone fails the file name shouldn't be set.
  951. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  952. MasterLoadError);
  953. EXPECT_TRUE(zone_finder_.getFileName().empty());
  954. // after a successful load, the specified file name should be set
  955. InMemoryZoneFinder rootzone(class_, Name("."));
  956. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  957. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  958. // overriding load, which will fail
  959. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  960. MasterLoadError);
  961. // the file name should be intact.
  962. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  963. // After swap, file names should also be swapped.
  964. zone_finder_.swap(rootzone);
  965. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
  966. EXPECT_TRUE(rootzone.getFileName().empty());
  967. }
  968. }