memory_datasrc_unittest.cc 47 KB

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