master_loader_unittest.cc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  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 <dns/master_loader_callbacks.h>
  15. #include <dns/master_loader.h>
  16. #include <dns/rrtype.h>
  17. #include <dns/rrset.h>
  18. #include <dns/rrclass.h>
  19. #include <dns/rrttl.h>
  20. #include <dns/name.h>
  21. #include <dns/rdata.h>
  22. #include <gtest/gtest.h>
  23. #include <boost/bind.hpp>
  24. #include <boost/lexical_cast.hpp>
  25. #include <boost/scoped_ptr.hpp>
  26. #include <string>
  27. #include <vector>
  28. #include <list>
  29. #include <sstream>
  30. using namespace isc::dns;
  31. using std::vector;
  32. using std::string;
  33. using std::list;
  34. using std::stringstream;
  35. using std::endl;
  36. using boost::lexical_cast;
  37. namespace {
  38. class MasterLoaderTest : public ::testing::Test {
  39. public:
  40. MasterLoaderTest() :
  41. callbacks_(boost::bind(&MasterLoaderTest::callback, this,
  42. &errors_, _1, _2, _3),
  43. boost::bind(&MasterLoaderTest::callback, this,
  44. &warnings_, _1, _2, _3))
  45. {}
  46. void TearDown() {
  47. // Check there are no more RRs we didn't expect
  48. EXPECT_TRUE(rrsets_.empty());
  49. }
  50. /// Concatenate file, line, and reason, and add it to either errors
  51. /// or warnings
  52. void callback(vector<string>* target, const std::string& file, size_t line,
  53. const std::string& reason)
  54. {
  55. std::stringstream ss;
  56. ss << reason << " [" << file << ":" << line << "]";
  57. target->push_back(ss.str());
  58. }
  59. void addRRset(const Name& name, const RRClass& rrclass,
  60. const RRType& rrtype, const RRTTL& rrttl,
  61. const rdata::RdataPtr& data) {
  62. const RRsetPtr rrset(new BasicRRset(name, rrclass, rrtype, rrttl));
  63. rrset->addRdata(data);
  64. rrsets_.push_back(rrset);
  65. }
  66. void setLoader(const char* file, const Name& origin,
  67. const RRClass& rrclass, const MasterLoader::Options options)
  68. {
  69. loader_.reset(new MasterLoader(file, origin, rrclass, callbacks_,
  70. boost::bind(&MasterLoaderTest::addRRset,
  71. this, _1, _2, _3, _4, _5),
  72. options));
  73. }
  74. void setLoader(std::istream& stream, const Name& origin,
  75. const RRClass& rrclass, const MasterLoader::Options options)
  76. {
  77. loader_.reset(new MasterLoader(stream, origin, rrclass, callbacks_,
  78. boost::bind(&MasterLoaderTest::addRRset,
  79. this, _1, _2, _3, _4, _5),
  80. options));
  81. }
  82. static string prepareZone(const string& line, bool include_last) {
  83. string result;
  84. result += "example.org. 3600 IN SOA ns1.example.org. "
  85. "admin.example.org. 1234 3600 1800 2419200 7200\n";
  86. result += line;
  87. if (include_last) {
  88. result += "\n";
  89. result += "correct 3600 IN A 192.0.2.2\n";
  90. }
  91. return (result);
  92. }
  93. void clear() {
  94. warnings_.clear();
  95. errors_.clear();
  96. rrsets_.clear();
  97. }
  98. // Check the next RR in the ones produced by the loader
  99. // Other than passed arguments are checked to be the default for the tests
  100. void checkRR(const string& name, const RRType& type, const string& data,
  101. const RRTTL& rrttl = RRTTL(3600)) {
  102. ASSERT_FALSE(rrsets_.empty());
  103. RRsetPtr current = rrsets_.front();
  104. rrsets_.pop_front();
  105. EXPECT_EQ(Name(name), current->getName());
  106. EXPECT_EQ(type, current->getType());
  107. EXPECT_EQ(RRClass::IN(), current->getClass());
  108. EXPECT_EQ(rrttl, current->getTTL());
  109. ASSERT_EQ(1, current->getRdataCount());
  110. EXPECT_EQ(0, isc::dns::rdata::createRdata(type, RRClass::IN(), data)->
  111. compare(current->getRdataIterator()->getCurrent()));
  112. }
  113. void checkBasicRRs() {
  114. checkRR("example.org", RRType::SOA(),
  115. "ns1.example.org. admin.example.org. "
  116. "1234 3600 1800 2419200 7200");
  117. checkRR("example.org", RRType::NS(), "ns1.example.org.");
  118. checkRR("www.example.org", RRType::A(), "192.0.2.1");
  119. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  120. }
  121. void checkARR(const string& name) {
  122. checkRR(name, RRType::A(), "192.0.2.1");
  123. }
  124. MasterLoaderCallbacks callbacks_;
  125. boost::scoped_ptr<MasterLoader> loader_;
  126. vector<string> errors_;
  127. vector<string> warnings_;
  128. list<RRsetPtr> rrsets_;
  129. };
  130. // Test simple loading. The zone file contains no tricky things, and nothing is
  131. // omitted. No RRset contains more than one RR Also no errors or warnings.
  132. TEST_F(MasterLoaderTest, basicLoad) {
  133. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  134. RRClass::IN(), MasterLoader::MANY_ERRORS);
  135. EXPECT_FALSE(loader_->loadedSucessfully());
  136. // The following three should be set to 0 initially in case the loader
  137. // is constructed from a file name.
  138. EXPECT_EQ(0, loader_->getSize());
  139. EXPECT_EQ(0, loader_->getPosition());
  140. loader_->load();
  141. EXPECT_TRUE(loader_->loadedSucessfully());
  142. EXPECT_TRUE(errors_.empty());
  143. EXPECT_TRUE(warnings_.empty());
  144. // Hardcode expected values taken from the test data file, assuming it
  145. // won't change too often.
  146. EXPECT_EQ(549, loader_->getSize());
  147. EXPECT_EQ(549, loader_->getPosition());
  148. checkBasicRRs();
  149. }
  150. // Test the $INCLUDE directive
  151. TEST_F(MasterLoaderTest, include) {
  152. // Test various cases of include
  153. const char* includes[] = {
  154. "$include",
  155. "$INCLUDE",
  156. "$Include",
  157. "$InCluDe",
  158. "\"$INCLUDE\"",
  159. NULL
  160. };
  161. for (const char** include = includes; *include != NULL; ++include) {
  162. SCOPED_TRACE(*include);
  163. clear();
  164. // Prepare input source that has the include and some more data
  165. // below (to see it returns back to the original source).
  166. const string include_str = string(*include) + " " +
  167. TEST_DATA_SRCDIR + "/example.org\nwww 3600 IN AAAA 2001:db8::1\n";
  168. stringstream ss(include_str);
  169. setLoader(ss, Name("example.org."), RRClass::IN(),
  170. MasterLoader::MANY_ERRORS);
  171. loader_->load();
  172. EXPECT_TRUE(loader_->loadedSucessfully());
  173. EXPECT_TRUE(errors_.empty());
  174. EXPECT_TRUE(warnings_.empty());
  175. checkBasicRRs();
  176. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  177. }
  178. }
  179. TEST_F(MasterLoaderTest, includeAndIncremental) {
  180. // Check getSize() and getPosition() are adjusted before and after
  181. // $INCLUDE.
  182. const string first_rr = "before.example.org. 0 A 192.0.2.1\n";
  183. const string include_str = "$INCLUDE " TEST_DATA_SRCDIR "/example.org";
  184. const string zone_data = first_rr + include_str + "\n" +
  185. "www 3600 IN AAAA 2001:db8::1\n";
  186. stringstream ss(zone_data);
  187. setLoader(ss, Name("example.org."), RRClass::IN(), MasterLoader::DEFAULT);
  188. // On construction, getSize() returns the size of the data (exclude the
  189. // the file to be included); position is set to 0.
  190. EXPECT_EQ(zone_data.size(), loader_->getSize());
  191. EXPECT_EQ(0, loader_->getPosition());
  192. // Read the first RR. getSize() doesn't change; position should be
  193. // at the end of the first line.
  194. loader_->loadIncremental(1);
  195. EXPECT_EQ(zone_data.size(), loader_->getSize());
  196. EXPECT_EQ(first_rr.size(), loader_->getPosition());
  197. // Read next 4. It includes $INCLUDE processing. Magic number of 549
  198. // is the size of the test zone file (see above); 506 is the position in
  199. // the file at the end of 4th RR (due to extra comments it's smaller than
  200. // the file size).
  201. loader_->loadIncremental(4);
  202. EXPECT_EQ(zone_data.size() + 549, loader_->getSize());
  203. EXPECT_EQ(first_rr.size() + include_str.size() + 506,
  204. loader_->getPosition());
  205. // Read the last one. At this point getSize and getPosition return
  206. // the same value, indicating progress of 100%.
  207. loader_->loadIncremental(1);
  208. EXPECT_EQ(zone_data.size() + 549, loader_->getSize());
  209. EXPECT_EQ(zone_data.size() + 549, loader_->getPosition());
  210. // we were not interested in checking RRs in this test. clear them to
  211. // not confuse TearDown().
  212. rrsets_.clear();
  213. }
  214. // A commonly used helper to check callback message.
  215. void
  216. checkCallbackMessage(const string& actual_msg, const string& expected_msg,
  217. size_t expected_line) {
  218. // The actual message should begin with the expected message.
  219. EXPECT_EQ(0, actual_msg.find(expected_msg)) << "actual message: " <<
  220. actual_msg << " expected: " <<
  221. expected_msg;
  222. // and it should end with "...:<line_num>]"
  223. const string line_desc = ":" + lexical_cast<string>(expected_line) + "]";
  224. EXPECT_EQ(actual_msg.size() - line_desc.size(),
  225. actual_msg.find(line_desc)) << "Expected on line " <<
  226. expected_line;
  227. }
  228. TEST_F(MasterLoaderTest, origin) {
  229. // Various forms of the directive
  230. const char* origins[] = {
  231. "$origin",
  232. "$ORIGIN",
  233. "$Origin",
  234. "$OrigiN",
  235. "\"$ORIGIN\"",
  236. NULL
  237. };
  238. for (const char** origin = origins; *origin != NULL; ++origin) {
  239. SCOPED_TRACE(*origin);
  240. clear();
  241. const string directive = *origin;
  242. const string input =
  243. "@ 1H IN A 192.0.2.1\n" +
  244. directive + " sub.example.org.\n"
  245. "\"www\" 1H IN A 192.0.2.1\n" +
  246. // Relative name in the origin
  247. directive + " relative\n"
  248. "@ 1H IN A 192.0.2.1\n"
  249. // Origin is _not_ used here (absolute name)
  250. "noorigin.example.org. 60M IN A 192.0.2.1\n";
  251. stringstream ss(input);
  252. setLoader(ss, Name("example.org."), RRClass::IN(),
  253. MasterLoader::MANY_ERRORS);
  254. loader_->load();
  255. EXPECT_TRUE(loader_->loadedSucessfully());
  256. EXPECT_TRUE(errors_.empty());
  257. // There's a relative origin in it, we warn about that.
  258. EXPECT_EQ(1, warnings_.size());
  259. checkCallbackMessage(warnings_.at(0),
  260. "The new origin is relative, did you really mean "
  261. "relative.sub.example.org.?", 4);
  262. checkARR("example.org");
  263. checkARR("www.sub.example.org");
  264. checkARR("relative.sub.example.org");
  265. checkARR("noorigin.example.org");
  266. }
  267. }
  268. // Test the source is correctly popped even after error
  269. TEST_F(MasterLoaderTest, popAfterError) {
  270. const string include_str = "$include " TEST_DATA_SRCDIR
  271. "/broken.zone\nwww 3600 IN AAAA 2001:db8::1\n";
  272. stringstream ss(include_str);
  273. // We perform the test with MANY_ERRORS, we want to see what happens
  274. // after the error.
  275. setLoader(ss, Name("example.org."), RRClass::IN(),
  276. MasterLoader::MANY_ERRORS);
  277. loader_->load();
  278. EXPECT_FALSE(loader_->loadedSucessfully());
  279. EXPECT_EQ(1, errors_.size()); // For the broken RR
  280. EXPECT_EQ(1, warnings_.size()); // For missing EOLN
  281. // The included file doesn't contain anything usable, but the
  282. // line after the include should be there.
  283. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  284. }
  285. // Check it works the same when created based on a stream, not filename
  286. TEST_F(MasterLoaderTest, streamConstructor) {
  287. const string zone_data(prepareZone("", true));
  288. stringstream zone_stream(zone_data);
  289. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  290. MasterLoader::MANY_ERRORS);
  291. EXPECT_FALSE(loader_->loadedSucessfully());
  292. // Unlike the basicLoad test, if we construct the loader from a stream
  293. // getSize() returns the data size in the stream immediately after the
  294. // construction.
  295. EXPECT_EQ(zone_data.size(), loader_->getSize());
  296. EXPECT_EQ(0, loader_->getPosition());
  297. loader_->load();
  298. EXPECT_TRUE(loader_->loadedSucessfully());
  299. EXPECT_TRUE(errors_.empty());
  300. EXPECT_TRUE(warnings_.empty());
  301. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  302. "admin.example.org. 1234 3600 1800 2419200 7200");
  303. checkRR("correct.example.org", RRType::A(), "192.0.2.2");
  304. // On completion of the load, both getSize() and getPosition() return the
  305. // size of the data.
  306. EXPECT_EQ(zone_data.size(), loader_->getSize());
  307. EXPECT_EQ(zone_data.size(), loader_->getPosition());
  308. }
  309. // Try loading data incrementally.
  310. TEST_F(MasterLoaderTest, incrementalLoad) {
  311. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  312. RRClass::IN(), MasterLoader::MANY_ERRORS);
  313. EXPECT_FALSE(loader_->loadedSucessfully());
  314. EXPECT_FALSE(loader_->loadIncremental(2));
  315. EXPECT_FALSE(loader_->loadedSucessfully());
  316. EXPECT_TRUE(errors_.empty());
  317. EXPECT_TRUE(warnings_.empty());
  318. checkRR("example.org", RRType::SOA(),
  319. "ns1.example.org. admin.example.org. "
  320. "1234 3600 1800 2419200 7200");
  321. checkRR("example.org", RRType::NS(), "ns1.example.org.");
  322. // The third one is not loaded yet
  323. EXPECT_TRUE(rrsets_.empty());
  324. // Load the rest.
  325. EXPECT_TRUE(loader_->loadIncremental(20));
  326. EXPECT_TRUE(loader_->loadedSucessfully());
  327. EXPECT_TRUE(errors_.empty());
  328. EXPECT_TRUE(warnings_.empty());
  329. checkRR("www.example.org", RRType::A(), "192.0.2.1");
  330. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  331. }
  332. // Try loading from file that doesn't exist. There should be single error
  333. // saying so.
  334. TEST_F(MasterLoaderTest, invalidFile) {
  335. setLoader("This file doesn't exist at all",
  336. Name("exmaple.org."), RRClass::IN(), MasterLoader::MANY_ERRORS);
  337. // Nothing yet. The loader is dormant until invoked.
  338. // Is it really what we want?
  339. EXPECT_TRUE(errors_.empty());
  340. loader_->load();
  341. EXPECT_TRUE(warnings_.empty());
  342. EXPECT_TRUE(rrsets_.empty());
  343. ASSERT_EQ(1, errors_.size());
  344. EXPECT_EQ(0, errors_[0].find("Error opening the input source file: ")) <<
  345. "Different error: " << errors_[0];
  346. }
  347. struct ErrorCase {
  348. const char* const line; // The broken line in master file
  349. const char* const reason; // If non NULL, the reason string
  350. const char* const problem; // Description of the problem for SCOPED_TRACE
  351. } const error_cases[] = {
  352. { "www... 3600 IN A 192.0.2.1", NULL, "Invalid name" },
  353. { "www FORTNIGHT IN A 192.0.2.1", NULL, "Invalid TTL" },
  354. { "www 3600 XX A 192.0.2.1", NULL, "Invalid class" },
  355. { "www 3600 IN A bad_ip", NULL, "Invalid Rdata" },
  356. // Parameter ordering errors
  357. { "www IN A 3600 192.168.2.7",
  358. "createRdata from text failed: IN/A RDATA construction from text failed",
  359. "Incorrect order of class, TTL and type" },
  360. { "www A IN 3600 192.168.2.8",
  361. "createRdata from text failed: IN/A RDATA construction from text failed",
  362. "Incorrect order of class, TTL and type" },
  363. { "www 3600 A IN 192.168.2.7",
  364. "createRdata from text failed: IN/A RDATA construction from text failed",
  365. "Incorrect order of class, TTL and type" },
  366. { "www A 3600 IN 192.168.2.8",
  367. "createRdata from text failed: IN/A RDATA construction from text failed",
  368. "Incorrect order of class, TTL and type" },
  369. // Missing type and Rdata
  370. { "www", "unexpected end of input", "Missing type and Rdata" },
  371. { "www 3600", "unexpected end of input", "Missing type and Rdata" },
  372. { "www IN", "unexpected end of input", "Missing type and Rdata" },
  373. { "www 3600 IN", "unexpected end of input", "Missing type and Rdata" },
  374. { "www IN 3600", "unexpected end of input", "Missing type and Rdata" },
  375. // Missing Rdata
  376. { "www A",
  377. "createRdata from text failed: IN/A RDATA construction from text failed",
  378. "Missing Rdata" },
  379. { "www 3600 A",
  380. "createRdata from text failed: IN/A RDATA construction from text failed",
  381. "Missing Rdata" },
  382. { "www IN A",
  383. "createRdata from text failed: IN/A RDATA construction from text failed",
  384. "Missing Rdata" },
  385. { "www 3600 IN A",
  386. "createRdata from text failed: IN/A RDATA construction from text failed",
  387. "Missing Rdata" },
  388. { "www IN 3600 A",
  389. "createRdata from text failed: IN/A RDATA construction from text failed",
  390. "Missing Rdata" },
  391. { "www 3600 IN", NULL, "Unexpected EOLN" },
  392. { "www 3600 CH TXT nothing", "Class mismatch: CH vs. IN",
  393. "Class mismatch" },
  394. { "www \"3600\" IN A 192.0.2.1", NULL, "Quoted TTL" },
  395. { "www 3600 \"IN\" A 192.0.2.1", NULL, "Quoted class" },
  396. { "www 3600 IN \"A\" 192.0.2.1", NULL, "Quoted type" },
  397. { "unbalanced)paren 3600 IN A 192.0.2.1", NULL, "Token error 1" },
  398. { "www 3600 unbalanced)paren A 192.0.2.1", NULL,
  399. "Token error 2" },
  400. // Check the unknown directive. The rest looks like ordinary RR,
  401. // so we see the $ is actually special.
  402. { "$UNKNOWN 3600 IN A 192.0.2.1", NULL, "Unknown $ directive" },
  403. { "$INCLUD " TEST_DATA_SRCDIR "/example.org", "Unknown directive 'INCLUD'",
  404. "Include too short" },
  405. { "$INCLUDES " TEST_DATA_SRCDIR "/example.org",
  406. "Unknown directive 'INCLUDES'", "Include too long" },
  407. { "$INCLUDE", "unexpected end of input", "Missing include path" },
  408. // The following two error messages are system dependant, omitting
  409. { "$INCLUDE /file/not/found", NULL, "Include file not found" },
  410. { "$INCLUDE /file/not/found example.org. and here goes bunch of garbage",
  411. NULL, "Include file not found and garbage at the end of line" },
  412. { "$ORIGIN", "unexpected end of input", "Missing origin name" },
  413. { "$ORIGIN invalid...name", "duplicate period in invalid...name",
  414. "Invalid name for origin" },
  415. { "$ORIGIN )brokentoken", "unbalanced parentheses",
  416. "Broken token in origin" },
  417. { "$ORIGIN example.org. garbage", "Extra tokens at the end of line",
  418. "Garbage after origin" },
  419. { "$ORIGI name.", "Unknown directive 'ORIGI'", "$ORIGIN too short" },
  420. { "$ORIGINAL name.", "Unknown directive 'ORIGINAL'", "$ORIGIN too long" },
  421. { "$TTL 100 extra-garbage", "Extra tokens at the end of line",
  422. "$TTL with extra token" },
  423. { "$TTL", "unexpected end of input", "missing TTL" },
  424. { "$TTL No-ttl", "Unknown unit used: N in: No-ttl", "bad TTL" },
  425. { "$TTL \"100\"", "invalid TTL: \"100\"", "bad TTL, quoted" },
  426. { "$TT 100", "Unknown directive 'TT'", "bad directive, too short" },
  427. { "$TTLLIKE 100", "Unknown directive 'TTLLIKE'", "bad directive, extra" },
  428. { NULL, NULL, NULL }
  429. };
  430. // Test a broken zone is handled properly. We test several problems,
  431. // both in strict and lenient mode.
  432. TEST_F(MasterLoaderTest, brokenZone) {
  433. for (const ErrorCase* ec = error_cases; ec->line != NULL; ++ec) {
  434. SCOPED_TRACE(ec->problem);
  435. const string zone(prepareZone(ec->line, true));
  436. {
  437. SCOPED_TRACE("Strict mode");
  438. clear();
  439. stringstream zone_stream(zone);
  440. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  441. MasterLoader::DEFAULT);
  442. EXPECT_FALSE(loader_->loadedSucessfully());
  443. EXPECT_THROW(loader_->load(), MasterLoaderError);
  444. EXPECT_FALSE(loader_->loadedSucessfully());
  445. EXPECT_EQ(1, errors_.size());
  446. if (ec->reason != NULL) {
  447. checkCallbackMessage(errors_.at(0), ec->reason, 2);
  448. }
  449. EXPECT_TRUE(warnings_.empty());
  450. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  451. "admin.example.org. 1234 3600 1800 2419200 7200");
  452. // In the strict mode, it is aborted. The last RR is not
  453. // even attempted.
  454. EXPECT_TRUE(rrsets_.empty());
  455. }
  456. {
  457. SCOPED_TRACE("Lenient mode");
  458. clear();
  459. stringstream zone_stream(zone);
  460. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  461. MasterLoader::MANY_ERRORS);
  462. EXPECT_FALSE(loader_->loadedSucessfully());
  463. EXPECT_NO_THROW(loader_->load());
  464. EXPECT_FALSE(loader_->loadedSucessfully());
  465. EXPECT_EQ(1, errors_.size());
  466. EXPECT_TRUE(warnings_.empty());
  467. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  468. "admin.example.org. 1234 3600 1800 2419200 7200");
  469. // This one is below the error one.
  470. checkRR("correct.example.org", RRType::A(), "192.0.2.2");
  471. EXPECT_TRUE(rrsets_.empty());
  472. }
  473. {
  474. SCOPED_TRACE("Error at EOF");
  475. // This case is interesting only in the lenient mode.
  476. clear();
  477. const string zoneEOF(prepareZone(ec->line, false));
  478. stringstream zone_stream(zoneEOF);
  479. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  480. MasterLoader::MANY_ERRORS);
  481. EXPECT_FALSE(loader_->loadedSucessfully());
  482. EXPECT_NO_THROW(loader_->load());
  483. EXPECT_FALSE(loader_->loadedSucessfully());
  484. EXPECT_EQ(1, errors_.size()) << errors_[0] << "\n" << errors_[1];
  485. // The unexpected EOF warning
  486. EXPECT_EQ(1, warnings_.size());
  487. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  488. "admin.example.org. 1234 3600 1800 2419200 7200");
  489. EXPECT_TRUE(rrsets_.empty());
  490. }
  491. }
  492. }
  493. // Check that a garbage after the include generates an error, but not fatal
  494. // one (in lenient mode) and we can recover.
  495. TEST_F(MasterLoaderTest, includeWithGarbage) {
  496. // Include an origin (example.org) because we expect it to be handled
  497. // soon and we don't want it to break here.
  498. const string include_str("$INCLUDE " TEST_DATA_SRCDIR
  499. "/example.org example.org. bunch of other stuff\n"
  500. "www 3600 IN AAAA 2001:db8::1\n");
  501. stringstream zone_stream(include_str);
  502. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  503. MasterLoader::MANY_ERRORS);
  504. EXPECT_NO_THROW(loader_->load());
  505. EXPECT_FALSE(loader_->loadedSucessfully());
  506. ASSERT_EQ(1, errors_.size());
  507. checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
  508. // It says something about extra tokens at the end
  509. EXPECT_NE(string::npos, errors_[0].find("Extra"));
  510. EXPECT_TRUE(warnings_.empty());
  511. checkBasicRRs();
  512. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  513. }
  514. // Check we error about garbage at the end of $ORIGIN line (but the line
  515. // works).
  516. TEST_F(MasterLoaderTest, originWithGarbage) {
  517. const string origin_str = "$ORIGIN www.example.org. More garbage here\n"
  518. "@ 1H IN A 192.0.2.1\n";
  519. stringstream ss(origin_str);
  520. setLoader(ss, Name("example.org."), RRClass::IN(),
  521. MasterLoader::MANY_ERRORS);
  522. EXPECT_NO_THROW(loader_->load());
  523. EXPECT_FALSE(loader_->loadedSucessfully());
  524. ASSERT_EQ(1, errors_.size());
  525. checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
  526. EXPECT_TRUE(warnings_.empty());
  527. checkARR("www.example.org");
  528. }
  529. // Test we can pass both file to include and the origin to switch
  530. TEST_F(MasterLoaderTest, includeAndOrigin) {
  531. // First, switch origin to something else, so we can check it is
  532. // switched back.
  533. const string include_string = "$ORIGIN www.example.org.\n"
  534. "@ 1H IN A 192.0.2.1\n"
  535. // Then include the file with data and switch origin back
  536. "$INCLUDE " TEST_DATA_SRCDIR "/example.org example.org.\n"
  537. // Another RR to see we fall back to the previous origin.
  538. "www 1H IN A 192.0.2.1\n";
  539. stringstream ss(include_string);
  540. setLoader(ss, Name("example.org"), RRClass::IN(),
  541. MasterLoader::MANY_ERRORS);
  542. // Successfully load the data
  543. loader_->load();
  544. EXPECT_TRUE(loader_->loadedSucessfully());
  545. EXPECT_TRUE(errors_.empty());
  546. EXPECT_TRUE(warnings_.empty());
  547. // And check it's the correct data
  548. checkARR("www.example.org");
  549. checkBasicRRs();
  550. checkARR("www.www.example.org");
  551. }
  552. // Like above, but the origin after include is bogus. The whole line should
  553. // be rejected.
  554. TEST_F(MasterLoaderTest, includeAndBadOrigin) {
  555. const string include_string =
  556. "$INCLUDE " TEST_DATA_SRCDIR "/example.org example..org.\n"
  557. // Another RR to see the switch survives after we exit include
  558. "www 1H IN A 192.0.2.1\n";
  559. stringstream ss(include_string);
  560. setLoader(ss, Name("example.org"), RRClass::IN(),
  561. MasterLoader::MANY_ERRORS);
  562. loader_->load();
  563. EXPECT_FALSE(loader_->loadedSucessfully());
  564. EXPECT_EQ(1, errors_.size());
  565. checkCallbackMessage(errors_.at(0), "duplicate period in example..org.",
  566. 1);
  567. EXPECT_TRUE(warnings_.empty());
  568. // And check it's the correct data
  569. checkARR("www.example.org");
  570. }
  571. // Check the origin doesn't get outside of the included file.
  572. TEST_F(MasterLoaderTest, includeOriginRestore) {
  573. const string include_string =
  574. "$INCLUDE " TEST_DATA_SRCDIR "/origincheck.txt\n"
  575. "@ 1H IN A 192.0.2.1\n";
  576. stringstream ss(include_string);
  577. setLoader(ss, Name("example.org"), RRClass::IN(),
  578. MasterLoader::MANY_ERRORS);
  579. // Successfully load the data
  580. loader_->load();
  581. EXPECT_TRUE(loader_->loadedSucessfully());
  582. EXPECT_TRUE(errors_.empty());
  583. EXPECT_TRUE(warnings_.empty());
  584. // And check it's the correct data
  585. checkARR("www.example.org");
  586. checkARR("example.org");
  587. }
  588. // Check we restore the last name for initial whitespace when returning from
  589. // include. But we do produce a warning if there's one just ofter the include.
  590. TEST_F(MasterLoaderTest, includeAndInitialWS) {
  591. const string include_string = "xyz 1H IN A 192.0.2.1\n"
  592. "$INCLUDE " TEST_DATA_SRCDIR "/example.org\n"
  593. " 1H IN A 192.0.2.1\n";
  594. stringstream ss(include_string);
  595. setLoader(ss, Name("example.org"), RRClass::IN(),
  596. MasterLoader::MANY_ERRORS);
  597. // Successfully load the data
  598. loader_->load();
  599. EXPECT_TRUE(loader_->loadedSucessfully());
  600. EXPECT_TRUE(errors_.empty());
  601. EXPECT_EQ(1, warnings_.size());
  602. checkCallbackMessage(warnings_.at(0),
  603. "Owner name omitted around $INCLUDE, the result might "
  604. "not be as expected", 3);
  605. checkARR("xyz.example.org");
  606. checkBasicRRs();
  607. checkARR("xyz.example.org");
  608. }
  609. // Test for "$TTL"
  610. TEST_F(MasterLoaderTest, ttlDirective) {
  611. stringstream zone_stream;
  612. // Set the default TTL with $TTL followed by an RR omitting the TTL
  613. zone_stream << "$TTL 1800\nexample.org. IN A 192.0.2.1\n";
  614. // $TTL can be quoted. Also testing the case of $TTL being changed.
  615. zone_stream << "\"$TTL\" 100\na.example.org. IN A 192.0.2.2\n";
  616. // Extended TTL form is accepted.
  617. zone_stream << "$TTL 1H\nb.example.org. IN A 192.0.2.3\n";
  618. // Matching is case insensitive.
  619. zone_stream << "$tTl 360\nc.example.org. IN A 192.0.2.4\n";
  620. // Maximum allowable TTL
  621. zone_stream << "$TTL 2147483647\nd.example.org. IN A 192.0.2.5\n";
  622. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  623. MasterLoader::DEFAULT);
  624. loader_->load();
  625. EXPECT_TRUE(loader_->loadedSucessfully());
  626. checkRR("example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  627. checkRR("a.example.org", RRType::A(), "192.0.2.2", RRTTL(100));
  628. checkRR("b.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
  629. checkRR("c.example.org", RRType::A(), "192.0.2.4", RRTTL(360));
  630. checkRR("d.example.org", RRType::A(), "192.0.2.5", RRTTL(2147483647));
  631. }
  632. TEST_F(MasterLoaderTest, ttlFromSOA) {
  633. // No $TTL, and the SOA doesn't have an explicit TTL field. Its minimum
  634. // TTL field will be used as the RR's TTL, and it'll be used as the
  635. // default TTL for others.
  636. stringstream zone_stream("example.org. IN SOA . . 0 0 0 0 1800\n"
  637. "a.example.org. IN A 192.0.2.1\n");
  638. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  639. MasterLoader::DEFAULT);
  640. loader_->load();
  641. EXPECT_TRUE(loader_->loadedSucessfully());
  642. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(1800));
  643. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  644. // The use of SOA minimum TTL should have caused a warning.
  645. EXPECT_EQ(1, warnings_.size());
  646. checkCallbackMessage(warnings_.at(0),
  647. "no TTL specified; using SOA MINTTL instead", 1);
  648. }
  649. TEST_F(MasterLoaderTest, ttlFromPrevious) {
  650. // No available default TTL. 2nd and 3rd RR will use the TTL of the
  651. // 1st RR. This will result in a warning, but only for the first time.
  652. stringstream zone_stream("a.example.org. 1800 IN A 192.0.2.1\n"
  653. "b.example.org. IN A 192.0.2.2\n"
  654. "c.example.org. IN A 192.0.2.3\n");
  655. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  656. MasterLoader::DEFAULT);
  657. loader_->load();
  658. EXPECT_TRUE(loader_->loadedSucessfully());
  659. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  660. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
  661. checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(1800));
  662. EXPECT_EQ(1, warnings_.size());
  663. checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
  664. }
  665. TEST_F(MasterLoaderTest, RRParamsOrdering) {
  666. // We test the order and existence of TTL, class and type. See
  667. // MasterLoader::MasterLoaderImpl::parseRRParams() for ordering.
  668. stringstream zone_stream;
  669. // <TTL> <class> <type> <RDATA>
  670. zone_stream << "a.example.org. 1800 IN A 192.0.2.1\n";
  671. // <type> <RDATA>
  672. zone_stream << "b.example.org. A 192.0.2.2\n";
  673. // <class> <TTL> <type> <RDATA>
  674. zone_stream << "c.example.org. IN 3600 A 192.0.2.3\n";
  675. // <TTL> <type> <RDATA>
  676. zone_stream << "d.example.org. 7200 A 192.0.2.4\n";
  677. // <class> <type> <RDATA>
  678. zone_stream << "e.example.org. IN A 192.0.2.5\n";
  679. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  680. MasterLoader::DEFAULT);
  681. loader_->load();
  682. EXPECT_TRUE(loader_->loadedSucessfully());
  683. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  684. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
  685. checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
  686. checkRR("d.example.org", RRType::A(), "192.0.2.4", RRTTL(7200));
  687. checkRR("e.example.org", RRType::A(), "192.0.2.5", RRTTL(7200));
  688. EXPECT_EQ(1, warnings_.size());
  689. checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
  690. }
  691. TEST_F(MasterLoaderTest, ttlFromPreviousSOA) {
  692. // Mixture of the previous two cases: SOA has explicit TTL, followed by
  693. // an RR without an explicit TTL. In this case the minimum TTL won't be
  694. // recognized as the "default TTL".
  695. stringstream zone_stream("example.org. 100 IN SOA . . 0 0 0 0 1800\n"
  696. "a.example.org. IN A 192.0.2.1\n");
  697. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  698. MasterLoader::DEFAULT);
  699. loader_->load();
  700. EXPECT_TRUE(loader_->loadedSucessfully());
  701. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(100));
  702. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(100));
  703. EXPECT_EQ(1, warnings_.size());
  704. checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
  705. }
  706. TEST_F(MasterLoaderTest, ttlUnknown) {
  707. // No available TTL is known for the first RR.
  708. stringstream zone_stream("a.example.org. IN A 192.0.2.1\n");
  709. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  710. MasterLoader::DEFAULT);
  711. EXPECT_THROW(loader_->load(), MasterLoaderError);
  712. }
  713. TEST_F(MasterLoaderTest, ttlUnknownAndContinue) {
  714. stringstream zone_stream("a.example.org. IN A 192.0.2.1\n"
  715. "b.example.org. 1800 IN A 192.0.2.2\n");
  716. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  717. MasterLoader::MANY_ERRORS);
  718. loader_->load();
  719. EXPECT_FALSE(loader_->loadedSucessfully());
  720. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
  721. EXPECT_TRUE(warnings_.empty());
  722. EXPECT_EQ(1, errors_.size());
  723. checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
  724. }
  725. TEST_F(MasterLoaderTest, ttlUnknownAndEOF) {
  726. // Similar to the previous case, but the input will be abruptly terminated
  727. // after the offending RR. This will cause an additional warning.
  728. stringstream zone_stream("a.example.org. IN A 192.0.2.1");
  729. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  730. MasterLoader::MANY_ERRORS);
  731. loader_->load();
  732. EXPECT_FALSE(loader_->loadedSucessfully());
  733. EXPECT_TRUE(rrsets_.empty());
  734. EXPECT_EQ(1, errors_.size());
  735. checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
  736. // RDATA implementation can complain about it, too. To be independent of
  737. // its details, we focus on the very last warning.
  738. EXPECT_FALSE(warnings_.empty());
  739. checkCallbackMessage(*warnings_.rbegin(), "File does not end with newline",
  740. 1);
  741. }
  742. TEST_F(MasterLoaderTest, ttlOverflow) {
  743. stringstream zone_stream;
  744. zone_stream << "example.org. IN SOA . . 0 0 0 0 2147483648\n";
  745. zone_stream << "$TTL 3600\n"; // reset to an in-range value
  746. zone_stream << "$TTL 2147483649\n" << "a.example.org. IN A 192.0.2.1\n";
  747. zone_stream << "$TTL 3600\n"; // reset to an in-range value
  748. zone_stream << "b.example.org. 2147483650 IN A 192.0.2.2\n";
  749. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  750. MasterLoader::DEFAULT);
  751. loader_->load();
  752. EXPECT_TRUE(loader_->loadedSucessfully());
  753. EXPECT_EQ(3, rrsets_.size());
  754. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 2147483648", RRTTL(0));
  755. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(0));
  756. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(0));
  757. EXPECT_EQ(4, warnings_.size());
  758. checkCallbackMessage(warnings_.at(1),
  759. "TTL 2147483648 > MAXTTL, setting to 0 per RFC2181",
  760. 1);
  761. checkCallbackMessage(warnings_.at(2),
  762. "TTL 2147483649 > MAXTTL, setting to 0 per RFC2181",
  763. 3);
  764. checkCallbackMessage(warnings_.at(3),
  765. "TTL 2147483650 > MAXTTL, setting to 0 per RFC2181",
  766. 6);
  767. }
  768. // Test the constructor rejects empty add callback.
  769. TEST_F(MasterLoaderTest, emptyCallback) {
  770. EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
  771. Name("example.org"), RRClass::IN(), callbacks_,
  772. AddRRCallback()), isc::InvalidParameter);
  773. // And the same with the second constructor
  774. stringstream ss("");
  775. EXPECT_THROW(MasterLoader(ss, Name("example.org"), RRClass::IN(),
  776. callbacks_, AddRRCallback()),
  777. isc::InvalidParameter);
  778. }
  779. // Check it throws when we try to load after loading was complete.
  780. TEST_F(MasterLoaderTest, loadTwice) {
  781. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  782. RRClass::IN(), MasterLoader::MANY_ERRORS);
  783. loader_->load();
  784. EXPECT_THROW(loader_->load(), isc::InvalidOperation);
  785. // Don't check them, they are not interesting, so suppress the error
  786. // at TearDown
  787. rrsets_.clear();
  788. }
  789. // Load 0 items should be rejected
  790. TEST_F(MasterLoaderTest, loadZero) {
  791. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  792. RRClass::IN(), MasterLoader::MANY_ERRORS);
  793. EXPECT_THROW(loader_->loadIncremental(0), isc::InvalidParameter);
  794. }
  795. // Test there's a warning when the file terminates without end of
  796. // line.
  797. TEST_F(MasterLoaderTest, noEOLN) {
  798. // No \n at the end
  799. const string input("example.org. 3600 IN SOA ns1.example.org. "
  800. "admin.example.org. 1234 3600 1800 2419200 7200");
  801. stringstream ss(input);
  802. setLoader(ss, Name("example.org."), RRClass::IN(),
  803. MasterLoader::MANY_ERRORS);
  804. loader_->load();
  805. EXPECT_TRUE(loader_->loadedSucessfully());
  806. EXPECT_TRUE(errors_.empty());
  807. // There should be one warning about the EOLN
  808. EXPECT_EQ(1, warnings_.size());
  809. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  810. "admin.example.org. 1234 3600 1800 2419200 7200");
  811. }
  812. // Test it rejects when we don't have the previous name to use in place of
  813. // initial whitespace
  814. TEST_F(MasterLoaderTest, noPreviousName) {
  815. const string input(" 1H IN A 192.0.2.1\n");
  816. stringstream ss(input);
  817. setLoader(ss, Name("example.org."), RRClass::IN(),
  818. MasterLoader::MANY_ERRORS);
  819. loader_->load();
  820. EXPECT_FALSE(loader_->loadedSucessfully());
  821. EXPECT_EQ(1, errors_.size());
  822. checkCallbackMessage(errors_.at(0), "No previous name to use in place of "
  823. "initial whitespace", 1);
  824. EXPECT_TRUE(warnings_.empty());
  825. }
  826. // Check we warn if the first RR in an included file has omitted name
  827. TEST_F(MasterLoaderTest, previousInInclude) {
  828. const string input("www 1H IN A 192.0.2.1\n"
  829. "$INCLUDE " TEST_DATA_SRCDIR "/omitcheck.txt\n");
  830. stringstream ss(input);
  831. setLoader(ss, Name("example.org"), RRClass::IN(),
  832. MasterLoader::MANY_ERRORS);
  833. loader_->load();
  834. EXPECT_TRUE(loader_->loadedSucessfully());
  835. EXPECT_TRUE(errors_.empty());
  836. // There should be one warning about the EOLN
  837. EXPECT_EQ(1, warnings_.size());
  838. checkCallbackMessage(warnings_.at(0), "Owner name omitted around "
  839. "$INCLUDE, the result might not be as expected", 1);
  840. checkARR("www.example.org");
  841. checkARR("www.example.org");
  842. }
  843. }