memory_datasrc_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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 <exceptions/exceptions.h>
  15. #include <dns/name.h>
  16. #include <dns/rrclass.h>
  17. #include <dns/rrttl.h>
  18. #include <dns/masterload.h>
  19. #include <datasrc/memory_datasrc.h>
  20. #include <gtest/gtest.h>
  21. using namespace isc::dns;
  22. using namespace isc::datasrc;
  23. namespace {
  24. // Commonly used result codes (Who should write the prefix all the time)
  25. using result::SUCCESS;
  26. using result::EXIST;
  27. class MemoryDataSrcTest : public ::testing::Test {
  28. protected:
  29. MemoryDataSrcTest() : rrclass(RRClass::IN())
  30. {}
  31. RRClass rrclass;
  32. MemoryDataSrc memory_datasrc;
  33. };
  34. TEST_F(MemoryDataSrcTest, add_find_Zone) {
  35. // test add zone
  36. // Bogus zone (NULL)
  37. EXPECT_THROW(memory_datasrc.addZone(ZonePtr()), isc::InvalidParameter);
  38. // add zones with different names one by one
  39. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  40. ZonePtr(new MemoryZone(RRClass::IN(), Name("a")))));
  41. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  42. ZonePtr(new MemoryZone(RRClass::CH(), Name("b")))));
  43. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  44. ZonePtr(new MemoryZone(RRClass::IN(), Name("c")))));
  45. // add zones with the same name suffix
  46. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  47. ZonePtr(new MemoryZone(RRClass::CH(),
  48. Name("x.d.e.f")))));
  49. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  50. ZonePtr(new MemoryZone(RRClass::CH(),
  51. Name("o.w.y.d.e.f")))));
  52. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  53. ZonePtr(new MemoryZone(RRClass::CH(),
  54. Name("p.w.y.d.e.f")))));
  55. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  56. ZonePtr(new MemoryZone(RRClass::IN(),
  57. Name("q.w.y.d.e.f")))));
  58. // add super zone and its subzone
  59. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  60. ZonePtr(new MemoryZone(RRClass::CH(), Name("g.h")))));
  61. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  62. ZonePtr(new MemoryZone(RRClass::IN(), Name("i.g.h")))));
  63. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  64. ZonePtr(new MemoryZone(RRClass::IN(),
  65. Name("z.d.e.f")))));
  66. EXPECT_EQ(result::SUCCESS, memory_datasrc.addZone(
  67. ZonePtr(new MemoryZone(RRClass::IN(),
  68. Name("j.z.d.e.f")))));
  69. // different zone class isn't allowed.
  70. EXPECT_EQ(result::EXIST, memory_datasrc.addZone(
  71. ZonePtr(new MemoryZone(RRClass::CH(),
  72. Name("q.w.y.d.e.f")))));
  73. // names are compared in a case insensitive manner.
  74. EXPECT_EQ(result::EXIST, memory_datasrc.addZone(
  75. ZonePtr(new MemoryZone(RRClass::IN(),
  76. Name("Q.W.Y.d.E.f")))));
  77. // test find zone
  78. EXPECT_EQ(result::SUCCESS, memory_datasrc.findZone(Name("a")).code);
  79. EXPECT_EQ(Name("a"),
  80. memory_datasrc.findZone(Name("a")).zone->getOrigin());
  81. EXPECT_EQ(result::SUCCESS,
  82. memory_datasrc.findZone(Name("j.z.d.e.f")).code);
  83. EXPECT_EQ(Name("j.z.d.e.f"),
  84. memory_datasrc.findZone(Name("j.z.d.e.f")).zone->getOrigin());
  85. // NOTFOUND
  86. EXPECT_EQ(result::NOTFOUND, memory_datasrc.findZone(Name("d.e.f")).code);
  87. EXPECT_EQ(ConstZonePtr(), memory_datasrc.findZone(Name("d.e.f")).zone);
  88. EXPECT_EQ(result::NOTFOUND,
  89. memory_datasrc.findZone(Name("w.y.d.e.f")).code);
  90. EXPECT_EQ(ConstZonePtr(),
  91. memory_datasrc.findZone(Name("w.y.d.e.f")).zone);
  92. // there's no exact match. the result should be the longest match,
  93. // and the code should be PARTIALMATCH.
  94. EXPECT_EQ(result::PARTIALMATCH,
  95. memory_datasrc.findZone(Name("j.g.h")).code);
  96. EXPECT_EQ(Name("g.h"),
  97. memory_datasrc.findZone(Name("g.h")).zone->getOrigin());
  98. EXPECT_EQ(result::PARTIALMATCH,
  99. memory_datasrc.findZone(Name("z.i.g.h")).code);
  100. EXPECT_EQ(Name("i.g.h"),
  101. memory_datasrc.findZone(Name("z.i.g.h")).zone->getOrigin());
  102. }
  103. TEST_F(MemoryDataSrcTest, getZoneCount) {
  104. EXPECT_EQ(0, memory_datasrc.getZoneCount());
  105. memory_datasrc.addZone(
  106. ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
  107. EXPECT_EQ(1, memory_datasrc.getZoneCount());
  108. // duplicate add. counter shouldn't change
  109. memory_datasrc.addZone(
  110. ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
  111. EXPECT_EQ(1, memory_datasrc.getZoneCount());
  112. // add one more
  113. memory_datasrc.addZone(
  114. ZonePtr(new MemoryZone(rrclass, Name("example.org"))));
  115. EXPECT_EQ(2, memory_datasrc.getZoneCount());
  116. }
  117. /// \brief Test fixture for the MemoryZone class
  118. class MemoryZoneTest : public ::testing::Test {
  119. public:
  120. MemoryZoneTest() :
  121. class_(RRClass::IN()),
  122. origin_("example.org"),
  123. ns_name_("ns.example.org"),
  124. child_ns_name_("child.example.org"),
  125. child_glue_name_("ns.child.example.org"),
  126. grandchild_ns_name_("grand.child.example.org"),
  127. grandchild_glue_name_("ns.grand.child.example.org"),
  128. zone_(class_, origin_),
  129. rr_out_(new RRset(Name("example.com"), class_, RRType::A(),
  130. RRTTL(300))),
  131. rr_ns_(new RRset(origin_, class_, RRType::NS(), RRTTL(300))),
  132. rr_ns_a_(new RRset(ns_name_, class_, RRType::A(), RRTTL(300))),
  133. rr_ns_aaaa_(new RRset(ns_name_, class_, RRType::AAAA(), RRTTL(300))),
  134. rr_a_(new RRset(origin_, class_, RRType::A(), RRTTL(300))),
  135. rr_child_ns_(new RRset(child_ns_name_, class_, RRType::NS(),
  136. RRTTL(300))),
  137. rr_child_glue_(new RRset(child_glue_name_, class_, RRType::A(),
  138. RRTTL(300))),
  139. rr_grandchild_ns_(new RRset(grandchild_ns_name_, class_, RRType::NS(),
  140. RRTTL(300))),
  141. rr_grandchild_glue_(new RRset(grandchild_glue_name_, class_,
  142. RRType::AAAA(), RRTTL(300)))
  143. {
  144. }
  145. // Some data to test with
  146. const RRClass class_;
  147. const Name origin_, ns_name_, child_ns_name_, child_glue_name_,
  148. grandchild_ns_name_, grandchild_glue_name_;
  149. // The zone to torture by tests
  150. MemoryZone zone_;
  151. /*
  152. * Some RRsets to put inside the zone.
  153. * They are empty, but the MemoryZone does not have a reason to look
  154. * inside anyway. We will check it finds them and does not change
  155. * the pointer.
  156. */
  157. ConstRRsetPtr
  158. // Out of zone RRset
  159. rr_out_,
  160. // NS of example.org
  161. rr_ns_,
  162. // A of ns.example.org
  163. rr_ns_a_,
  164. // AAAA of ns.example.org
  165. rr_ns_aaaa_,
  166. // A of example.org
  167. rr_a_;
  168. ConstRRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  169. ConstRRsetPtr rr_child_glue_; // glue RR of the child domain
  170. ConstRRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  171. ConstRRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  172. /**
  173. * \brief Test one find query to the zone.
  174. *
  175. * Asks a query to the zone and checks it does not throw and returns
  176. * expected results. It returns nothing, it just signals failures
  177. * to GTEST.
  178. *
  179. * \param name The name to ask for.
  180. * \param rrtype The RRType to ask of.
  181. * \param result The expected code of the result.
  182. * \param check_answer Should a check against equality of the answer be
  183. * done?
  184. * \param answer The expected rrset, if any should be returned.
  185. * \param zone Check different MemoryZone object than zone_ (if NULL,
  186. * uses zone_)
  187. */
  188. void findTest(const Name& name, const RRType& rrtype, Zone::Result result,
  189. bool check_answer = true,
  190. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  191. MemoryZone *zone = NULL,
  192. Zone::FindOptions options = Zone::FIND_DEFAULT)
  193. {
  194. if (!zone) {
  195. zone = &zone_;
  196. }
  197. // The whole block is inside, because we need to check the result and
  198. // we can't assign to FindResult
  199. EXPECT_NO_THROW({
  200. Zone::FindResult find_result(zone->find(name, rrtype,
  201. options));
  202. // Check it returns correct answers
  203. EXPECT_EQ(result, find_result.code);
  204. if (check_answer) {
  205. EXPECT_EQ(answer, find_result.rrset);
  206. }
  207. });
  208. }
  209. };
  210. /**
  211. * \brief Test MemoryZone::MemoryZone constructor.
  212. *
  213. * Takes the created zone and checks its properties they are the same
  214. * as passed parameters.
  215. */
  216. TEST_F(MemoryZoneTest, constructor) {
  217. ASSERT_EQ(class_, zone_.getClass());
  218. ASSERT_EQ(origin_, zone_.getOrigin());
  219. }
  220. /**
  221. * \brief Test adding.
  222. *
  223. * We test that it throws at the correct moments and the correct exceptions.
  224. * And we test the return value.
  225. */
  226. TEST_F(MemoryZoneTest, add) {
  227. // This one does not belong to this zone
  228. EXPECT_THROW(zone_.add(rr_out_), MemoryZone::OutOfZone);
  229. // Test null pointer
  230. EXPECT_THROW(zone_.add(ConstRRsetPtr()), MemoryZone::NullRRset);
  231. // Now put all the data we have there. It should throw nothing
  232. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  233. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  234. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  235. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  236. // Try putting there something twice, it should be rejected
  237. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_)));
  238. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_a_)));
  239. }
  240. // Test adding child zones and zone cut handling
  241. TEST_F(MemoryZoneTest, delegationNS) {
  242. // add in-zone data
  243. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  244. // install a zone cut
  245. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  246. // below the zone cut
  247. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  248. true, rr_child_ns_);
  249. // at the zone cut
  250. findTest(Name("child.example.org"), RRType::A(), Zone::DELEGATION,
  251. true, rr_child_ns_);
  252. findTest(Name("child.example.org"), RRType::NS(), Zone::DELEGATION,
  253. true, rr_child_ns_);
  254. // finding NS for the apex (origin) node. This must not be confused
  255. // with delegation due to the existence of an NS RR.
  256. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  257. // unusual case of "nested delegation": the highest cut should be used.
  258. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  259. findTest(Name("www.grand.child.example.org"), RRType::A(),
  260. Zone::DELEGATION, true, rr_child_ns_); // note: !rr_grandchild_ns_
  261. }
  262. TEST_F(MemoryZoneTest, glue) {
  263. // install zone data:
  264. // a zone cut
  265. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
  266. // glue for this cut
  267. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
  268. // a nested zone cut (unusual)
  269. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_ns_)));
  270. // glue under the deeper zone cut
  271. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_glue_)));
  272. // by default glue is hidden due to the zone cut
  273. findTest(child_glue_name_, RRType::A(), Zone::DELEGATION, true,
  274. rr_child_ns_);
  275. // If we do it in the "glue OK" mode, we should find the exact match.
  276. findTest(child_glue_name_, RRType::A(), Zone::SUCCESS, true,
  277. rr_child_glue_, NULL, Zone::FIND_GLUE_OK);
  278. // glue OK + NXRRSET case
  279. findTest(child_glue_name_, RRType::AAAA(), Zone::NXRRSET, true,
  280. ConstRRsetPtr(), NULL, Zone::FIND_GLUE_OK);
  281. // glue OK + NXDOMAIN case
  282. findTest(Name("www.child.example.org"), RRType::A(), Zone::DELEGATION,
  283. true, rr_child_ns_, NULL, Zone::FIND_GLUE_OK);
  284. // TODO:
  285. // glue name would match a wildcard under a zone cut: wildcard match
  286. // shouldn't happen under a cut and result must be PARTIALMATCH
  287. // (This case cannot be tested yet)
  288. // nested cut case. The glue should be found.
  289. findTest(grandchild_glue_name_, RRType::AAAA(), Zone::SUCCESS,
  290. true, rr_grandchild_glue_, NULL, Zone::FIND_GLUE_OK);
  291. // A non-existent name in nested cut. This should result in delegation
  292. // at the highest zone cut.
  293. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  294. Zone::DELEGATION, true, rr_child_ns_, NULL, Zone::FIND_GLUE_OK);
  295. }
  296. // Test adding DNAMEs and resulting delegation handling
  297. // Listing ideas only for now
  298. TEST_F(MemoryZoneTest, delegationDNAME) {
  299. // apex DNAME: allowed by spec. No DNAME delegation at the apex;
  300. // descendants are subject to delegation.
  301. // Other cases of NS and DNAME mixture are prohibited.
  302. // BIND 9 doesn't reject such cases at load time, however.
  303. // DNAME and ordinary types (allowed by spec)
  304. }
  305. /**
  306. * \brief Test searching.
  307. *
  308. * Check it finds or does not find correctly and does not throw exceptions.
  309. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  310. * directly there, it just tells it doesn't exist.
  311. */
  312. TEST_F(MemoryZoneTest, find) {
  313. // Fill some data inside
  314. // Now put all the data we have there. It should throw nothing
  315. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
  316. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_a_)));
  317. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_aaaa_)));
  318. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
  319. // These two should be successful
  320. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  321. findTest(ns_name_, RRType::A(), Zone::SUCCESS, true, rr_ns_a_);
  322. // These domain exist but don't have the provided RRType
  323. findTest(origin_, RRType::AAAA(), Zone::NXRRSET);
  324. findTest(ns_name_, RRType::NS(), Zone::NXRRSET);
  325. // These domains don't exist (and one is out of the zone)
  326. findTest(Name("nothere.example.org"), RRType::A(), Zone::NXDOMAIN);
  327. findTest(Name("example.net"), RRType::A(), Zone::NXDOMAIN);
  328. }
  329. TEST_F(MemoryZoneTest, load) {
  330. // Put some data inside the zone
  331. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_.add(rr_ns_)));
  332. // Loading with different origin should fail
  333. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/root.zone"), MasterLoadError);
  334. // See the original data is still there, survived the exception
  335. findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
  336. // Create correct zone
  337. MemoryZone rootzone(class_, Name("."));
  338. // Try putting something inside
  339. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  340. // Load the zone. It should overwrite/remove the above RRset
  341. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  342. // Now see there are some rrsets (we don't look inside, though)
  343. findTest(Name("."), RRType::SOA(), Zone::SUCCESS, false, ConstRRsetPtr(),
  344. &rootzone);
  345. findTest(Name("."), RRType::NS(), Zone::SUCCESS, false, ConstRRsetPtr(),
  346. &rootzone);
  347. findTest(Name("a.root-servers.net."), RRType::A(), Zone::SUCCESS, false,
  348. ConstRRsetPtr(), &rootzone);
  349. // But this should no longer be here
  350. findTest(ns_name_, RRType::AAAA(), Zone::NXDOMAIN, true, ConstRRsetPtr(),
  351. &rootzone);
  352. // Try loading zone that is wrong in a different way
  353. EXPECT_THROW(zone_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  354. MasterLoadError);
  355. }
  356. }