zone_loader_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. // Copyright (C) 2012 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 <datasrc/zone_loader.h>
  15. #include <datasrc/data_source.h>
  16. #include <datasrc/rrset_collection_base.h>
  17. #include <datasrc/memory/zone_table_segment.h>
  18. #include <datasrc/memory/memory_client.h>
  19. #include <dns/rrclass.h>
  20. #include <dns/name.h>
  21. #include <dns/rrset.h>
  22. #include <dns/rdataclass.h>
  23. #include <util/memory_segment_local.h>
  24. #include <exceptions/exceptions.h>
  25. #include <gtest/gtest.h>
  26. #include <boost/shared_ptr.hpp>
  27. #include <boost/scoped_ptr.hpp>
  28. #include <boost/foreach.hpp>
  29. #include <string>
  30. #include <vector>
  31. using namespace isc::dns;
  32. using namespace isc::datasrc;
  33. using boost::shared_ptr;
  34. using std::string;
  35. using std::vector;
  36. namespace {
  37. class MockClient : public DataSourceClient {
  38. public:
  39. MockClient() :
  40. commit_called_(false),
  41. missing_zone_(false),
  42. rrclass_(RRClass::IN())
  43. {}
  44. class Finder : public ZoneFinder {
  45. public:
  46. Finder(const Name& origin) :
  47. origin_(origin)
  48. {}
  49. Name getOrigin() const {
  50. return (origin_);
  51. }
  52. RRClass getClass() const {
  53. return (RRClass::IN());
  54. }
  55. // The rest is not to be called, so they throw.
  56. shared_ptr<Context> find(const Name&, const RRType&,
  57. const FindOptions)
  58. {
  59. isc_throw(isc::NotImplemented, "Not implemented");
  60. }
  61. shared_ptr<Context> findAll(const Name&,
  62. vector<ConstRRsetPtr>&,
  63. const FindOptions)
  64. {
  65. isc_throw(isc::NotImplemented, "Not implemented");
  66. }
  67. FindNSEC3Result findNSEC3(const Name&, bool) {
  68. isc_throw(isc::NotImplemented, "Not implemented");
  69. }
  70. private:
  71. Name origin_;
  72. };
  73. class Iterator : public ZoneIterator {
  74. public:
  75. Iterator(const Name& origin) :
  76. origin_(origin),
  77. soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
  78. RRTTL(3600)))
  79. {
  80. // The RData here is bogus, but it is not used to anything. There
  81. // just needs to be some.
  82. soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
  83. Name::ROOT_NAME(),
  84. 0, 0, 0, 0, 0));
  85. rrsets_.push_back(soa_);
  86. // There is no NS record on purpose here.
  87. // Dummy A rrset. This is used for checking zone data after
  88. // reload.
  89. RRsetPtr rrset(new RRset(Name("tstzonedata").concatenate(origin_),
  90. RRClass::IN(), RRType::A(),
  91. RRTTL(3600)));
  92. rrset->addRdata(rdata::in::A("192.0.2.1"));
  93. rrsets_.push_back(rrset);
  94. rrsets_.push_back(ConstRRsetPtr());
  95. it_ = rrsets_.begin();
  96. }
  97. virtual isc::dns::ConstRRsetPtr getNextRRset() {
  98. ConstRRsetPtr result = *it_;
  99. ++it_;
  100. return (result);
  101. }
  102. virtual isc::dns::ConstRRsetPtr getSOA() const {
  103. return (soa_);
  104. }
  105. private:
  106. const Name origin_;
  107. const RRsetPtr soa_;
  108. std::vector<ConstRRsetPtr> rrsets_;
  109. std::vector<ConstRRsetPtr>::const_iterator it_;
  110. };
  111. virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
  112. bool) const
  113. {
  114. if (name != Name("example.org")) {
  115. isc_throw(DataSourceError, "No such zone");
  116. }
  117. return (ZoneIteratorPtr(new Iterator(Name("example.org"))));
  118. }
  119. virtual FindResult findZone(const Name& name) const {
  120. const Name origin("example.org");
  121. const ZoneFinderPtr finder(new Finder(origin));
  122. NameComparisonResult compar(origin.compare(name));
  123. switch (compar.getRelation()) {
  124. case NameComparisonResult::EQUAL:
  125. return (FindResult(result::SUCCESS, finder));
  126. case NameComparisonResult::SUPERDOMAIN:
  127. return (FindResult(result::PARTIALMATCH, finder));
  128. default:
  129. return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
  130. }
  131. };
  132. virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
  133. getJournalReader(const Name&, uint32_t, uint32_t) const
  134. {
  135. isc_throw(isc::NotImplemented, "Method not used in tests");
  136. }
  137. virtual ZoneUpdaterPtr getUpdater(const Name& name, bool replace,
  138. bool journaling) const;
  139. // We store some information about what was happening here.
  140. // It is publicly accessible, since this is private testing class
  141. // anyway, so no need to dress it fancy into getters. Some are mutable,
  142. // since many client methods are const, but we still want to know they
  143. // were called.
  144. mutable vector<Name> provided_updaters_;
  145. vector<RRsetPtr> rrsets_;
  146. // List of rrsets as texts, for easier manipulation
  147. vector<string> rrset_texts_;
  148. bool commit_called_;
  149. // If set to true, getUpdater returns NULL
  150. bool missing_zone_;
  151. // The pretended class of the client. Usualy IN, but can be overriden.
  152. RRClass rrclass_;
  153. };
  154. // Test implementation of RRsetCollectionBase. This is currently just a
  155. // wrapper around \c isc::datasrc::RRsetCollectionBase;
  156. // \c isc::datasrc::RRsetCollectionBase may become an abstract class in
  157. // the future.
  158. class TestRRsetCollection : public isc::datasrc::RRsetCollectionBase {
  159. public:
  160. TestRRsetCollection(ZoneUpdater& updater,
  161. const isc::dns::RRClass& rrclass) :
  162. isc::datasrc::RRsetCollectionBase(updater, rrclass)
  163. {}
  164. };
  165. // The updater isn't really correct according to the API. For example,
  166. // the whole client can be committed only once in its lifetime. The
  167. // updaters would influence each other if there were more. But we
  168. // don't need more updaters in the same test, so it doesn't matter
  169. // and this way, it is much simpler.
  170. class Updater : public ZoneUpdater {
  171. public:
  172. Updater(MockClient* client, const Name& name) :
  173. client_(client),
  174. finder_(client_->rrclass_, name, client_->rrsets_)
  175. {}
  176. virtual ZoneFinder& getFinder() {
  177. return (finder_);
  178. }
  179. virtual isc::dns::RRsetCollectionBase& getRRsetCollection() {
  180. if (!rrset_collection_) {
  181. rrset_collection_.reset(new TestRRsetCollection(*this,
  182. client_->rrclass_));
  183. }
  184. return (*rrset_collection_);
  185. }
  186. virtual void addRRset(const isc::dns::AbstractRRset& rrset) {
  187. if (client_->commit_called_) {
  188. isc_throw(DataSourceError, "Add after commit");
  189. }
  190. // We need to copy the RRset. We don't do it properly (we omit the
  191. // signature, for example), because we don't need to.
  192. RRsetPtr new_rrset(new isc::dns::BasicRRset(rrset.getName(),
  193. rrset.getClass(),
  194. rrset.getType(),
  195. rrset.getTTL()));
  196. for (isc::dns::RdataIteratorPtr i(rrset.getRdataIterator());
  197. !i->isLast(); i->next()) {
  198. new_rrset->addRdata(i->getCurrent());
  199. }
  200. client_->rrsets_.push_back(new_rrset);
  201. client_->rrset_texts_.push_back(rrset.toText());
  202. }
  203. virtual void deleteRRset(const isc::dns::AbstractRRset&) {
  204. isc_throw(isc::NotImplemented, "Method not used in tests");
  205. }
  206. virtual void commit() {
  207. client_->commit_called_ = true;
  208. }
  209. private:
  210. MockClient* client_;
  211. boost::scoped_ptr<TestRRsetCollection> rrset_collection_;
  212. class Finder : public ZoneFinder {
  213. public:
  214. Finder(const RRClass& rrclass, const Name& name,
  215. const vector<RRsetPtr>& rrsets) :
  216. class_(rrclass),
  217. name_(name),
  218. rrsets_(rrsets)
  219. {}
  220. virtual RRClass getClass() const {
  221. return (class_);
  222. }
  223. virtual Name getOrigin() const {
  224. return (name_);
  225. }
  226. virtual shared_ptr<Context> find(const Name& name, const RRType& type,
  227. const FindOptions options)
  228. {
  229. // The method is not completely correct. It ignores many special
  230. // cases and also the options except for the result. But this is
  231. // enough for the tests. We care only about exact match here.
  232. BOOST_FOREACH(const RRsetPtr& rrset, rrsets_) {
  233. if (rrset->getName() == name && rrset->getType() == type) {
  234. return (shared_ptr<Context>(
  235. new GenericContext(*this, options,
  236. ResultContext(SUCCESS, rrset))));
  237. }
  238. }
  239. return (shared_ptr<Context>(
  240. new GenericContext(*this, options,
  241. ResultContext(NXRRSET, ConstRRsetPtr()))));
  242. }
  243. virtual shared_ptr<Context> findAll(const Name&,
  244. vector<ConstRRsetPtr>&,
  245. const FindOptions)
  246. {
  247. isc_throw(isc::NotImplemented, "Method not used in tests");
  248. }
  249. virtual FindNSEC3Result findNSEC3(const Name&, bool) {
  250. isc_throw(isc::NotImplemented, "Method not used in tests");
  251. }
  252. private:
  253. const RRClass class_;
  254. const Name name_;
  255. const vector<RRsetPtr>& rrsets_;
  256. } finder_;
  257. };
  258. ZoneUpdaterPtr
  259. MockClient::getUpdater(const Name& name, bool replace, bool journaling) const {
  260. if (missing_zone_) {
  261. return (ZoneUpdaterPtr());
  262. }
  263. EXPECT_TRUE(replace);
  264. EXPECT_FALSE(journaling);
  265. provided_updaters_.push_back(name);
  266. // const_cast is bad. But the const on getUpdater seems wrong in the first
  267. // place, since updater will be modifying the data there. And the updater
  268. // wants to store data into the client so we can examine it later.
  269. return (ZoneUpdaterPtr(new Updater(const_cast<MockClient*>(this), name)));
  270. }
  271. class ZoneLoaderTest : public ::testing::Test {
  272. protected:
  273. ZoneLoaderTest() :
  274. rrclass_(RRClass::IN())
  275. {
  276. // Use ROOT_NAME as a placeholder; it will be ignored if filename is
  277. // null.
  278. prepareSource(Name::ROOT_NAME(), NULL);
  279. }
  280. void prepareSource(const Name& zone, const char* filename) {
  281. // Cleanup the existing data in the right order
  282. source_client_.reset();
  283. ztable_segment_.reset();
  284. // (re)configure zone table, then (re)construct the in-memory client
  285. // with it.
  286. ztable_segment_.reset(memory::ZoneTableSegment::create(rrclass_,
  287. "local"));
  288. source_client_.reset(new memory::InMemoryClient(ztable_segment_,
  289. rrclass_));
  290. if (filename) {
  291. source_client_->load(zone, string(TEST_DATA_DIR) + "/" + filename);
  292. }
  293. }
  294. private:
  295. const RRClass rrclass_;
  296. // This is because of the in-memory client. We use it to read data
  297. // from. It is still easier than setting up sqlite3 client, since
  298. // we have this one in the linked library.
  299. // FIXME: We should be destroying it by ZoneTableSegment::destroy.
  300. // But the shared pointer won't let us, will it?
  301. shared_ptr<memory::ZoneTableSegment> ztable_segment_;
  302. protected:
  303. boost::scoped_ptr<memory::InMemoryClient> source_client_;
  304. // This one is mocked. It will help us see what is happening inside.
  305. // Also, mocking it is simpler than setting up an sqlite3 client.
  306. MockClient destination_client_;
  307. };
  308. // Use the loader to load an unsigned zone.
  309. TEST_F(ZoneLoaderTest, copyUnsigned) {
  310. prepareSource(Name::ROOT_NAME(), "root.zone");
  311. ZoneLoader loader(destination_client_, Name::ROOT_NAME(), *source_client_);
  312. // It gets the updater directly in the constructor
  313. ASSERT_EQ(1, destination_client_.provided_updaters_.size());
  314. EXPECT_EQ(Name::ROOT_NAME(), destination_client_.provided_updaters_[0]);
  315. // Counter is initialized to 0, progress is "unknown" in case of copy.
  316. EXPECT_EQ(0, loader.getRRCount());
  317. EXPECT_EQ(ZoneLoader::PROGRESS_UNKNOWN, loader.getProgress());
  318. // Now load the whole zone
  319. loader.load();
  320. EXPECT_TRUE(destination_client_.commit_called_);
  321. // We don't check the whole zone. We check the first and last and the
  322. // count, which should be enough.
  323. // The count is 34 because we expect the RRs to be separated.
  324. EXPECT_EQ(34, destination_client_.rrsets_.size());
  325. // Check various counters. getRRCount should be identical of the RRs
  326. // we've seen. Progress is still "unknown" in the copy operation.
  327. EXPECT_EQ(destination_client_.rrsets_.size(), loader.getRRCount());
  328. EXPECT_EQ(ZoneLoader::PROGRESS_UNKNOWN, loader.getProgress());
  329. // Ensure known order.
  330. std::sort(destination_client_.rrset_texts_.begin(),
  331. destination_client_.rrset_texts_.end());
  332. EXPECT_EQ(". 518400 IN NS a.root-servers.net.\n",
  333. destination_client_.rrset_texts_.front());
  334. EXPECT_EQ("m.root-servers.net. 3600000 IN AAAA 2001:dc3::35\n",
  335. destination_client_.rrset_texts_.back());
  336. // It isn't possible to try again now
  337. EXPECT_THROW(loader.load(), isc::InvalidOperation);
  338. EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
  339. // Even 0, which should load nothing, returns the error
  340. EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
  341. }
  342. // Try loading incrementally.
  343. TEST_F(ZoneLoaderTest, copyUnsignedIncremental) {
  344. prepareSource(Name::ROOT_NAME(), "root.zone");
  345. ZoneLoader loader(destination_client_, Name::ROOT_NAME(), *source_client_);
  346. // Try loading few RRs first.
  347. loader.loadIncremental(10);
  348. // We should get the 10 we asked for
  349. EXPECT_EQ(10, destination_client_.rrsets_.size());
  350. // Not committed yet, we didn't complete the loading
  351. EXPECT_FALSE(destination_client_.commit_called_);
  352. // Check we can get intermediate counters. Progress is always "unknown"
  353. // in case of copy.
  354. EXPECT_EQ(destination_client_.rrsets_.size(), loader.getRRCount());
  355. EXPECT_EQ(ZoneLoader::PROGRESS_UNKNOWN, loader.getProgress());
  356. // This is unusual, but allowed. Check it doesn't do anything
  357. loader.loadIncremental(0);
  358. EXPECT_EQ(10, destination_client_.rrsets_.size());
  359. EXPECT_FALSE(destination_client_.commit_called_);
  360. // We can finish the rest
  361. loader.loadIncremental(30);
  362. EXPECT_EQ(34, destination_client_.rrsets_.size());
  363. EXPECT_TRUE(destination_client_.commit_called_);
  364. // No more loading now
  365. EXPECT_THROW(loader.load(), isc::InvalidOperation);
  366. EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
  367. EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
  368. }
  369. // Check we can load RRSIGs and NSEC3 (which could break due to them being
  370. // in separate namespace)
  371. TEST_F(ZoneLoaderTest, copySigned) {
  372. prepareSource(Name("example.org"), "example.org.nsec3-signed");
  373. ZoneLoader loader(destination_client_, Name("example.org"),
  374. *source_client_);
  375. loader.load();
  376. // All the RRs are there, including the ones in NSEC3 namespace
  377. EXPECT_EQ(14, destination_client_.rrsets_.size());
  378. EXPECT_TRUE(destination_client_.commit_called_);
  379. // Same trick with sorting to know where they are
  380. std::sort(destination_client_.rrset_texts_.begin(),
  381. destination_client_.rrset_texts_.end());
  382. // Due to the R at the beginning, this one should be last
  383. EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
  384. "1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG\n",
  385. destination_client_.rrset_texts_[0]);
  386. EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
  387. "NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
  388. " EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
  389. "KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
  390. "/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=\n",
  391. destination_client_.rrset_texts_[1]);
  392. }
  393. // If the destination zone does not exist, it throws
  394. TEST_F(ZoneLoaderTest, copyMissingDestination) {
  395. destination_client_.missing_zone_ = true;
  396. prepareSource(Name::ROOT_NAME(), "root.zone");
  397. EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
  398. *source_client_), DataSourceError);
  399. }
  400. // If the source zone does not exist, it throws
  401. TEST_F(ZoneLoaderTest, copyMissingSource) {
  402. EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
  403. *source_client_), DataSourceError);
  404. }
  405. // The class of the source and destination are different
  406. TEST_F(ZoneLoaderTest, classMismatch) {
  407. destination_client_.rrclass_ = RRClass::CH();
  408. prepareSource(Name::ROOT_NAME(), "root.zone");
  409. EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
  410. *source_client_), isc::InvalidParameter);
  411. }
  412. // Load an unsigned zone, all at once
  413. TEST_F(ZoneLoaderTest, loadUnsigned) {
  414. ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
  415. TEST_DATA_DIR "/root.zone");
  416. // Counter and progress are initialized to 0.
  417. EXPECT_EQ(0, loader.getRRCount());
  418. EXPECT_EQ(0, loader.getProgress());
  419. // It gets the updater directly in the constructor
  420. ASSERT_EQ(1, destination_client_.provided_updaters_.size());
  421. EXPECT_EQ(Name::ROOT_NAME(), destination_client_.provided_updaters_[0]);
  422. // Now load the whole zone
  423. loader.load();
  424. EXPECT_TRUE(destination_client_.commit_called_);
  425. // We don't check the whole zone. We check the first and last and the
  426. // count, which should be enough.
  427. // The count is 34 because we expect the RRs to be separated.
  428. EXPECT_EQ(34, destination_client_.rrsets_.size());
  429. // getRRCount should be identical of the RRs we've seen. progress
  430. // should reach 100% (= 1).
  431. EXPECT_EQ(destination_client_.rrsets_.size(), loader.getRRCount());
  432. EXPECT_EQ(1, loader.getProgress());
  433. // Ensure known order.
  434. std::sort(destination_client_.rrset_texts_.begin(),
  435. destination_client_.rrset_texts_.end());
  436. EXPECT_EQ(". 518400 IN NS a.root-servers.net.\n",
  437. destination_client_.rrset_texts_.front());
  438. EXPECT_EQ("m.root-servers.net. 3600000 IN AAAA 2001:dc3::35\n",
  439. destination_client_.rrset_texts_.back());
  440. // It isn't possible to try again now
  441. EXPECT_THROW(loader.load(), isc::InvalidOperation);
  442. EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
  443. // Even 0, which should load nothing, returns the error
  444. EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
  445. }
  446. // Try loading from master file incrementally.
  447. TEST_F(ZoneLoaderTest, loadUnsignedIncremental) {
  448. ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
  449. TEST_DATA_DIR "/root.zone");
  450. // Counters are initialized to 0.
  451. EXPECT_EQ(0, loader.getRRCount());
  452. EXPECT_EQ(0, loader.getProgress());
  453. // Try loading few RRs first.
  454. loader.loadIncremental(10);
  455. // We should get the 10 we asked for
  456. EXPECT_EQ(10, destination_client_.rrsets_.size());
  457. // Not committed yet, we didn't complete the loading
  458. EXPECT_FALSE(destination_client_.commit_called_);
  459. EXPECT_EQ(10, destination_client_.rrsets_.size());
  460. EXPECT_FALSE(destination_client_.commit_called_);
  461. // Check we can get intermediate counters. Expected progress is calculated
  462. // based on the size of the zone file and the offset to the end of 10th RR
  463. // (subject to future changes to the file, but we assume it's a rare
  464. // event.). The expected value should be the exact expression that
  465. // getProgress() should do internally, so EXPECT_EQ() should work here,
  466. // but floating-point comparison can be always tricky we use
  467. // EXPECT_DOUBLE_EQ just in case.
  468. EXPECT_EQ(destination_client_.rrsets_.size(), loader.getRRCount());
  469. // file size = 1541, offset = 428 (27.77%).
  470. EXPECT_DOUBLE_EQ(static_cast<double>(428) / 1541, loader.getProgress());
  471. // We can finish the rest
  472. loader.loadIncremental(30);
  473. EXPECT_EQ(34, destination_client_.rrsets_.size());
  474. EXPECT_TRUE(destination_client_.commit_called_);
  475. // Counters are updated accordingly. Progress should reach 100%.
  476. EXPECT_EQ(destination_client_.rrsets_.size(), loader.getRRCount());
  477. EXPECT_EQ(1, loader.getProgress());
  478. // No more loading now
  479. EXPECT_THROW(loader.load(), isc::InvalidOperation);
  480. EXPECT_THROW(loader.loadIncremental(1), isc::InvalidOperation);
  481. EXPECT_THROW(loader.loadIncremental(0), isc::InvalidOperation);
  482. }
  483. // If the destination zone does not exist, it throws
  484. TEST_F(ZoneLoaderTest, loadMissingDestination) {
  485. destination_client_.missing_zone_ = true;
  486. EXPECT_THROW(ZoneLoader(destination_client_, Name::ROOT_NAME(),
  487. TEST_DATA_DIR "/root.zone"), DataSourceError);
  488. }
  489. // Check we can load RRSIGs and NSEC3 (which could break due to them being
  490. // in separate namespace)
  491. TEST_F(ZoneLoaderTest, loadSigned) {
  492. ZoneLoader loader(destination_client_, Name("example.org"),
  493. TEST_DATA_DIR "/example.org.nsec3-signed");
  494. loader.load();
  495. // All the RRs are there, including the ones in NSEC3 namespace
  496. EXPECT_EQ(14, destination_client_.rrsets_.size());
  497. EXPECT_TRUE(destination_client_.commit_called_);
  498. // Same trick with sorting to know where they are
  499. std::sort(destination_client_.rrset_texts_.begin(),
  500. destination_client_.rrset_texts_.end());
  501. // Due to the R at the beginning, this one should be last
  502. EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
  503. "1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG\n",
  504. destination_client_.rrset_texts_[0]);
  505. EXPECT_EQ("09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
  506. "NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
  507. " EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
  508. "KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
  509. "/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=\n",
  510. destination_client_.rrset_texts_[1]);
  511. }
  512. // Test it throws when there's no such file
  513. TEST_F(ZoneLoaderTest, loadNoSuchFile) {
  514. ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
  515. "This file does not exist");
  516. EXPECT_THROW(loader.load(), MasterFileError);
  517. EXPECT_FALSE(destination_client_.commit_called_);
  518. }
  519. // And it also throws when there's a syntax error in the master file
  520. TEST_F(ZoneLoaderTest, loadSyntaxError) {
  521. ZoneLoader loader(destination_client_, Name::ROOT_NAME(),
  522. // This is not a master file for sure
  523. // (misusing a file that happens to be there
  524. // already).
  525. TEST_DATA_DIR "/example.org.sqlite3");
  526. EXPECT_THROW(loader.load(), MasterFileError);
  527. EXPECT_FALSE(destination_client_.commit_called_);
  528. }
  529. // Test there's validation of the data in the zone loader.
  530. TEST_F(ZoneLoaderTest, loadCheck) {
  531. ZoneLoader loader(destination_client_, Name("example.org"),
  532. TEST_DATA_DIR "/novalidate.zone");
  533. EXPECT_THROW(loader.loadIncremental(10), ZoneContentError);
  534. // The messages go to the log. We don't have an easy way to examine them.
  535. EXPECT_FALSE(destination_client_.commit_called_);
  536. }
  537. // Check a warning doesn't disrupt the loading of the zone
  538. TEST_F(ZoneLoaderTest, loadCheckWarn) {
  539. ZoneLoader loader(destination_client_, Name("example.org"),
  540. TEST_DATA_DIR "/checkwarn.zone");
  541. EXPECT_TRUE(loader.loadIncremental(10));
  542. // The messages go to the log. We don't have an easy way to examine them.
  543. // But the zone was committed and contains all 3 RRs
  544. EXPECT_TRUE(destination_client_.commit_called_);
  545. EXPECT_EQ(3, destination_client_.rrsets_.size());
  546. }
  547. TEST_F(ZoneLoaderTest, copyCheckWarn) {
  548. prepareSource(Name("example.org"), "checkwarn.zone");
  549. ZoneLoader loader(destination_client_, Name("example.org"),
  550. *source_client_);
  551. EXPECT_TRUE(loader.loadIncremental(10));
  552. // The messages go to the log. We don't have an easy way to examine them.
  553. // But the zone was committed and contains all 3 RRs
  554. EXPECT_TRUE(destination_client_.commit_called_);
  555. EXPECT_EQ(3, destination_client_.rrsets_.size());
  556. }
  557. // Test there's validation of the data in the zone loader when copying
  558. // from another data source.
  559. TEST_F(ZoneLoaderTest, copyCheck) {
  560. // In this test, my_source_client provides a zone that does not
  561. // validate (no NS).
  562. MockClient my_source_client;
  563. ZoneLoader loader(destination_client_, Name("example.org"),
  564. my_source_client);
  565. EXPECT_THROW(loader.loadIncremental(10), ZoneContentError);
  566. // The messages go to the log. We don't have an easy way to examine them.
  567. EXPECT_FALSE(destination_client_.commit_called_);
  568. }
  569. }