master_loader_unittest.cc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  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. loader_->load();
  137. EXPECT_TRUE(loader_->loadedSucessfully());
  138. EXPECT_TRUE(errors_.empty());
  139. EXPECT_TRUE(warnings_.empty());
  140. checkBasicRRs();
  141. }
  142. // Test the $INCLUDE directive
  143. TEST_F(MasterLoaderTest, include) {
  144. // Test various cases of include
  145. const char* includes[] = {
  146. "$include",
  147. "$INCLUDE",
  148. "$Include",
  149. "$InCluDe",
  150. "\"$INCLUDE\"",
  151. NULL
  152. };
  153. for (const char** include = includes; *include != NULL; ++include) {
  154. SCOPED_TRACE(*include);
  155. clear();
  156. // Prepare input source that has the include and some more data
  157. // below (to see it returns back to the original source).
  158. const string include_str = string(*include) + " " +
  159. TEST_DATA_SRCDIR + "/example.org\nwww 3600 IN AAAA 2001:db8::1\n";
  160. stringstream ss(include_str);
  161. setLoader(ss, Name("example.org."), RRClass::IN(),
  162. MasterLoader::MANY_ERRORS);
  163. loader_->load();
  164. EXPECT_TRUE(loader_->loadedSucessfully());
  165. EXPECT_TRUE(errors_.empty());
  166. EXPECT_TRUE(warnings_.empty());
  167. checkBasicRRs();
  168. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  169. }
  170. }
  171. TEST_F(MasterLoaderTest, origin) {
  172. // Various forms of the directive
  173. const char* origins[] = {
  174. "$origin",
  175. "$ORIGIN",
  176. "$Origin",
  177. "$OrigiN",
  178. "\"$ORIGIN\"",
  179. NULL
  180. };
  181. for (const char** origin = origins; *origin != NULL; ++origin) {
  182. SCOPED_TRACE(*origin);
  183. clear();
  184. const string directive = *origin;
  185. const string input =
  186. "@ 1H IN A 192.0.2.1\n" +
  187. directive + " sub.example.org.\n"
  188. "\"www\" 1H IN A 192.0.2.1\n" +
  189. // Relative name in the origin
  190. directive + " relative\n"
  191. "@ 1H IN A 192.0.2.1\n"
  192. // Origin is _not_ used here (absolute name)
  193. "noorigin.example.org. 60M IN A 192.0.2.1\n";
  194. stringstream ss(input);
  195. setLoader(ss, Name("example.org."), RRClass::IN(),
  196. MasterLoader::MANY_ERRORS);
  197. loader_->load();
  198. EXPECT_TRUE(loader_->loadedSucessfully());
  199. EXPECT_TRUE(errors_.empty());
  200. EXPECT_TRUE(warnings_.empty());
  201. checkARR("example.org");
  202. checkARR("www.sub.example.org");
  203. checkARR("relative.sub.example.org");
  204. checkARR("noorigin.example.org");
  205. }
  206. }
  207. // Test the source is correctly popped even after error
  208. TEST_F(MasterLoaderTest, popAfterError) {
  209. const string include_str = "$include " TEST_DATA_SRCDIR
  210. "/broken.zone\nwww 3600 IN AAAA 2001:db8::1\n";
  211. stringstream ss(include_str);
  212. // We don't test without MANY_ERRORS, we want to see what happens
  213. // after the error.
  214. setLoader(ss, Name("example.org."), RRClass::IN(),
  215. MasterLoader::MANY_ERRORS);
  216. loader_->load();
  217. EXPECT_FALSE(loader_->loadedSucessfully());
  218. EXPECT_EQ(1, errors_.size()); // For the broken RR
  219. EXPECT_EQ(1, warnings_.size()); // For missing EOLN
  220. // The included file doesn't contain anything usable, but the
  221. // line after the include should be there.
  222. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  223. }
  224. // Check it works the same when created based on a stream, not filename
  225. TEST_F(MasterLoaderTest, streamConstructor) {
  226. stringstream zone_stream(prepareZone("", true));
  227. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  228. MasterLoader::MANY_ERRORS);
  229. EXPECT_FALSE(loader_->loadedSucessfully());
  230. loader_->load();
  231. EXPECT_TRUE(loader_->loadedSucessfully());
  232. EXPECT_TRUE(errors_.empty());
  233. EXPECT_TRUE(warnings_.empty());
  234. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  235. "admin.example.org. 1234 3600 1800 2419200 7200");
  236. checkRR("correct.example.org", RRType::A(), "192.0.2.2");
  237. }
  238. // Try loading data incrementally.
  239. TEST_F(MasterLoaderTest, incrementalLoad) {
  240. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  241. RRClass::IN(), MasterLoader::MANY_ERRORS);
  242. EXPECT_FALSE(loader_->loadedSucessfully());
  243. EXPECT_FALSE(loader_->loadIncremental(2));
  244. EXPECT_FALSE(loader_->loadedSucessfully());
  245. EXPECT_TRUE(errors_.empty());
  246. EXPECT_TRUE(warnings_.empty());
  247. checkRR("example.org", RRType::SOA(),
  248. "ns1.example.org. admin.example.org. "
  249. "1234 3600 1800 2419200 7200");
  250. checkRR("example.org", RRType::NS(), "ns1.example.org.");
  251. // The third one is not loaded yet
  252. EXPECT_TRUE(rrsets_.empty());
  253. // Load the rest.
  254. EXPECT_TRUE(loader_->loadIncremental(20));
  255. EXPECT_TRUE(loader_->loadedSucessfully());
  256. EXPECT_TRUE(errors_.empty());
  257. EXPECT_TRUE(warnings_.empty());
  258. checkRR("www.example.org", RRType::A(), "192.0.2.1");
  259. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  260. }
  261. // Try loading from file that doesn't exist. There should be single error
  262. // saying so.
  263. TEST_F(MasterLoaderTest, invalidFile) {
  264. setLoader("This file doesn't exist at all",
  265. Name("exmaple.org."), RRClass::IN(), MasterLoader::MANY_ERRORS);
  266. // Nothing yet. The loader is dormant until invoked.
  267. // Is it really what we want?
  268. EXPECT_TRUE(errors_.empty());
  269. loader_->load();
  270. EXPECT_TRUE(warnings_.empty());
  271. EXPECT_TRUE(rrsets_.empty());
  272. ASSERT_EQ(1, errors_.size());
  273. EXPECT_EQ(0, errors_[0].find("Error opening the input source file: ")) <<
  274. "Different error: " << errors_[0];
  275. }
  276. struct ErrorCase {
  277. const char* const line; // The broken line in master file
  278. const char* const reason; // If non NULL, the reason string
  279. const char* const problem; // Description of the problem for SCOPED_TRACE
  280. } const error_cases[] = {
  281. { "www... 3600 IN A 192.0.2.1", NULL, "Invalid name" },
  282. { "www FORTNIGHT IN A 192.0.2.1", NULL, "Invalid TTL" },
  283. { "www 3600 XX A 192.0.2.1", NULL, "Invalid class" },
  284. { "www 3600 IN A bad_ip", NULL, "Invalid Rdata" },
  285. { "www 3600 IN", NULL, "Unexpected EOLN" },
  286. { "www 3600 CH TXT nothing", NULL, "Class mismatch" },
  287. { "www \"3600\" IN A 192.0.2.1", NULL, "Quoted TTL" },
  288. { "www 3600 \"IN\" A 192.0.2.1", NULL, "Quoted class" },
  289. { "www 3600 IN \"A\" 192.0.2.1", NULL, "Quoted type" },
  290. { "unbalanced)paren 3600 IN A 192.0.2.1", NULL, "Token error 1" },
  291. { "www 3600 unbalanced)paren A 192.0.2.1", NULL,
  292. "Token error 2" },
  293. // Check the unknown directive. The rest looks like ordinary RR,
  294. // so we see the $ is actually special.
  295. { "$UNKNOWN 3600 IN A 192.0.2.1", NULL, "Unknown $ directive" },
  296. { "$INCLUD " TEST_DATA_SRCDIR "/example.org", "Unknown directive 'INCLUD'",
  297. "Include too short" },
  298. { "$INCLUDES " TEST_DATA_SRCDIR "/example.org",
  299. "Unknown directive 'INCLUDES'", "Include too long" },
  300. { "$INCLUDE", "unexpected end of input", "Missing include path" },
  301. // The following two error messages are system dependant, omitting
  302. { "$INCLUDE /file/not/found", NULL, "Include file not found" },
  303. { "$INCLUDE /file/not/found example.org. and here goes bunch of garbage",
  304. NULL, "Include file not found and garbage at the end of line" },
  305. { "$ORIGIN", "unexpected end of input", "Missing origin name" },
  306. { "$ORIGIN invalid...name", "duplicate period in invalid...name",
  307. "Invalid name for origin" },
  308. { "$ORIGIN )brokentoken", "unbalanced parentheses",
  309. "Broken token in origin" },
  310. { "$ORIGIN example.org. garbage", "Extra tokens at the end of line",
  311. "Garbage after origin" },
  312. { "$ORIGI name.", "Unknown directive 'ORIGI'", "$ORIGIN too short" },
  313. { "$ORIGINAL name.", "Unknown directive 'ORIGINAL'", "$ORIGIN too long" },
  314. { "$TTL 100 extra-garbage", "Extra tokens at the end of line",
  315. "$TTL with extra token" },
  316. { "$TTL", "unexpected end of input", "missing TTL" },
  317. { "$TTL No-ttl", "Unknown unit used: N in: No-ttl", "bad TTL" },
  318. { "$TTL \"100\"", "invalid TTL: \"100\"", "bad TTL, quoted" },
  319. { "$TT 100", "Unknown directive 'TT'", "bad directive, too short" },
  320. { "$TTLLIKE 100", "Unknown directive 'TTLLIKE'", "bad directive, extra" },
  321. { NULL, NULL, NULL }
  322. };
  323. // A commonly used helper to check callback message.
  324. void
  325. checkCallbackMessage(const string& actual_msg, const string& expected_msg,
  326. size_t expected_line) {
  327. // The actual message should begin with the expected message.
  328. EXPECT_EQ(0, actual_msg.find(expected_msg)) << "actual message: " <<
  329. actual_msg << " expected: " <<
  330. expected_msg;
  331. // and it should end with "...:<line_num>]"
  332. const string line_desc = ":" + lexical_cast<string>(expected_line) + "]";
  333. EXPECT_EQ(actual_msg.size() - line_desc.size(),
  334. actual_msg.find(line_desc)) << "Expected on line " <<
  335. expected_line;
  336. }
  337. // Test a broken zone is handled properly. We test several problems,
  338. // both in strict and lenient mode.
  339. TEST_F(MasterLoaderTest, brokenZone) {
  340. for (const ErrorCase* ec = error_cases; ec->line != NULL; ++ec) {
  341. SCOPED_TRACE(ec->problem);
  342. const string zone(prepareZone(ec->line, true));
  343. {
  344. SCOPED_TRACE("Strict mode");
  345. clear();
  346. stringstream zone_stream(zone);
  347. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  348. MasterLoader::DEFAULT);
  349. EXPECT_FALSE(loader_->loadedSucessfully());
  350. EXPECT_THROW(loader_->load(), MasterLoaderError);
  351. EXPECT_FALSE(loader_->loadedSucessfully());
  352. EXPECT_EQ(1, errors_.size());
  353. if (ec->reason != NULL) {
  354. checkCallbackMessage(errors_.at(0), ec->reason, 2);
  355. }
  356. EXPECT_TRUE(warnings_.empty());
  357. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  358. "admin.example.org. 1234 3600 1800 2419200 7200");
  359. // In the strict mode, it is aborted. The last RR is not
  360. // even attempted.
  361. EXPECT_TRUE(rrsets_.empty());
  362. }
  363. {
  364. SCOPED_TRACE("Lenient mode");
  365. clear();
  366. stringstream zone_stream(zone);
  367. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  368. MasterLoader::MANY_ERRORS);
  369. EXPECT_FALSE(loader_->loadedSucessfully());
  370. EXPECT_NO_THROW(loader_->load());
  371. EXPECT_FALSE(loader_->loadedSucessfully());
  372. EXPECT_EQ(1, errors_.size());
  373. EXPECT_TRUE(warnings_.empty());
  374. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  375. "admin.example.org. 1234 3600 1800 2419200 7200");
  376. // This one is below the error one.
  377. checkRR("correct.example.org", RRType::A(), "192.0.2.2");
  378. EXPECT_TRUE(rrsets_.empty());
  379. }
  380. {
  381. SCOPED_TRACE("Error at EOF");
  382. // This case is interesting only in the lenient mode.
  383. clear();
  384. const string zoneEOF(prepareZone(ec->line, false));
  385. stringstream zone_stream(zoneEOF);
  386. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  387. MasterLoader::MANY_ERRORS);
  388. EXPECT_FALSE(loader_->loadedSucessfully());
  389. EXPECT_NO_THROW(loader_->load());
  390. EXPECT_FALSE(loader_->loadedSucessfully());
  391. EXPECT_EQ(1, errors_.size()) << errors_[0] << "\n" << errors_[1];
  392. // The unexpected EOF warning
  393. EXPECT_EQ(1, warnings_.size());
  394. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  395. "admin.example.org. 1234 3600 1800 2419200 7200");
  396. EXPECT_TRUE(rrsets_.empty());
  397. }
  398. }
  399. }
  400. // Check that a garbage after the include generates an error, but not fatal
  401. // one (in lenient mode) and we can recover.
  402. TEST_F(MasterLoaderTest, includeWithGarbage) {
  403. // Include an origin (example.org) because we expect it to be handled
  404. // soon and we don't want it to break here.
  405. const string include_str("$INCLUDE " TEST_DATA_SRCDIR
  406. "/example.org example.org. bunch of other stuff\n"
  407. "www 3600 IN AAAA 2001:db8::1\n");
  408. stringstream zone_stream(include_str);
  409. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  410. MasterLoader::MANY_ERRORS);
  411. EXPECT_NO_THROW(loader_->load());
  412. EXPECT_FALSE(loader_->loadedSucessfully());
  413. ASSERT_EQ(1, errors_.size());
  414. checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
  415. // It says something about extra tokens at the end
  416. EXPECT_NE(string::npos, errors_[0].find("Extra"));
  417. EXPECT_TRUE(warnings_.empty());
  418. checkBasicRRs();
  419. checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
  420. }
  421. // Check we error about garbage at the end of $ORIGIN line (but the line
  422. // works).
  423. TEST_F(MasterLoaderTest, originWithGarbage) {
  424. const string origin_str = "$ORIGIN www More garbage here\n"
  425. "@ 1H IN A 192.0.2.1\n";
  426. stringstream ss(origin_str);
  427. setLoader(ss, Name("example.org."), RRClass::IN(),
  428. MasterLoader::MANY_ERRORS);
  429. EXPECT_NO_THROW(loader_->load());
  430. EXPECT_FALSE(loader_->loadedSucessfully());
  431. ASSERT_EQ(1, errors_.size());
  432. checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
  433. EXPECT_TRUE(warnings_.empty());
  434. checkARR("www.example.org");
  435. }
  436. // Test we can pass both file to include and the origin to switch
  437. TEST_F(MasterLoaderTest, includeAndOrigin) {
  438. // First, switch origin to something else, so we can check it is
  439. // switched back.
  440. const string include_string = "$ORIGIN www\n"
  441. "@ 1H IN A 192.0.2.1\n"
  442. // Then include the file with data and switch origin back
  443. "$INCLUDE " TEST_DATA_SRCDIR "/example.org example.org.\n"
  444. // Another RR to see the switch survives after we exit include
  445. "www 1H IN A 192.0.2.1\n";
  446. stringstream ss(include_string);
  447. setLoader(ss, Name("example.org"), RRClass::IN(),
  448. MasterLoader::MANY_ERRORS);
  449. // Successfully load the data
  450. loader_->load();
  451. EXPECT_TRUE(loader_->loadedSucessfully());
  452. EXPECT_TRUE(errors_.empty());
  453. EXPECT_TRUE(warnings_.empty());
  454. // And check it's the correct data
  455. checkARR("www.example.org");
  456. checkBasicRRs();
  457. checkARR("www.example.org");
  458. }
  459. // Like above, but the origin after include is bogus. The whole line should
  460. // be rejected.
  461. TEST_F(MasterLoaderTest, includeAndBadOrigin) {
  462. const string include_string =
  463. "$INCLUDE " TEST_DATA_SRCDIR "/example.org example..org.\n"
  464. // Another RR to see the switch survives after we exit include
  465. "www 1H IN A 192.0.2.1\n";
  466. stringstream ss(include_string);
  467. setLoader(ss, Name("example.org"), RRClass::IN(),
  468. MasterLoader::MANY_ERRORS);
  469. loader_->load();
  470. EXPECT_FALSE(loader_->loadedSucessfully());
  471. EXPECT_EQ(1, errors_.size());
  472. checkCallbackMessage(errors_.at(0), "duplicate period in example..org.",
  473. 1);
  474. EXPECT_TRUE(warnings_.empty());
  475. // And check it's the correct data
  476. checkARR("www.example.org");
  477. }
  478. // Check the origin doesn't get outside of the included file.
  479. TEST_F(MasterLoaderTest, includeOriginRestore) {
  480. const string include_string = "$INCLUDE " TEST_DATA_SRCDIR "/origincheck.txt\n"
  481. "@ 1H IN A 192.0.2.1\n";
  482. stringstream ss(include_string);
  483. setLoader(ss, Name("example.org"), RRClass::IN(),
  484. MasterLoader::MANY_ERRORS);
  485. // Successfully load the data
  486. loader_->load();
  487. EXPECT_TRUE(loader_->loadedSucessfully());
  488. EXPECT_TRUE(errors_.empty());
  489. EXPECT_TRUE(warnings_.empty());
  490. // And check it's the correct data
  491. checkARR("www.example.org");
  492. checkARR("example.org");
  493. }
  494. // Check we restore the last name for initial whitespace when returning from
  495. // include. But we do produce a warning if there's one just ofter the include.
  496. TEST_F(MasterLoaderTest, includeAndInitialWS) {
  497. const string include_string = "xyz 1H IN A 192.0.2.1\n"
  498. "$INCLUDE " TEST_DATA_SRCDIR "/example.org\n"
  499. " 1H IN A 192.0.2.1\n";
  500. stringstream ss(include_string);
  501. setLoader(ss, Name("example.org"), RRClass::IN(),
  502. MasterLoader::MANY_ERRORS);
  503. // Successfully load the data
  504. loader_->load();
  505. EXPECT_TRUE(loader_->loadedSucessfully());
  506. EXPECT_TRUE(errors_.empty());
  507. EXPECT_EQ(1, warnings_.size());
  508. checkCallbackMessage(warnings_.at(0),
  509. "Ambiguous previous name previous name for use in "
  510. "place of initial whitespace", 3);
  511. checkARR("xyz.example.org");
  512. checkBasicRRs();
  513. checkARR("xyz.example.org");
  514. }
  515. // Test for "$TTL"
  516. TEST_F(MasterLoaderTest, ttlDirective) {
  517. stringstream zone_stream;
  518. // Set the default TTL with $TTL followed by an RR omitting the TTL
  519. zone_stream << "$TTL 1800\nexample.org. IN A 192.0.2.1\n";
  520. // $TTL can be quoted. Also testing the case of $TTL being changed.
  521. zone_stream << "\"$TTL\" 100\na.example.org. IN A 192.0.2.2\n";
  522. // Extended TTL form is accepted.
  523. zone_stream << "$TTL 1H\nb.example.org. IN A 192.0.2.3\n";
  524. // Matching is case insensitive.
  525. zone_stream << "$tTl 360\nc.example.org. IN A 192.0.2.4\n";
  526. // Maximum allowable TTL
  527. zone_stream << "$TTL 2147483647\nd.example.org. IN A 192.0.2.5\n";
  528. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  529. MasterLoader::DEFAULT);
  530. loader_->load();
  531. EXPECT_TRUE(loader_->loadedSucessfully());
  532. checkRR("example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  533. checkRR("a.example.org", RRType::A(), "192.0.2.2", RRTTL(100));
  534. checkRR("b.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
  535. checkRR("c.example.org", RRType::A(), "192.0.2.4", RRTTL(360));
  536. checkRR("d.example.org", RRType::A(), "192.0.2.5", RRTTL(2147483647));
  537. }
  538. TEST_F(MasterLoaderTest, ttlFromSOA) {
  539. // No $TTL, and the SOA doesn't have an explicit TTL field. Its minimum
  540. // TTL field will be used as the RR's TTL, and it'll be used as the
  541. // default TTL for others.
  542. stringstream zone_stream("example.org. IN SOA . . 0 0 0 0 1800\n"
  543. "a.example.org. IN A 192.0.2.1\n");
  544. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  545. MasterLoader::DEFAULT);
  546. loader_->load();
  547. EXPECT_TRUE(loader_->loadedSucessfully());
  548. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(1800));
  549. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  550. // The use of SOA minimum TTL should have caused a warning.
  551. EXPECT_EQ(1, warnings_.size());
  552. checkCallbackMessage(warnings_.at(0),
  553. "no TTL specified; using SOA MINTTL instead", 1);
  554. }
  555. TEST_F(MasterLoaderTest, ttlFromPrevious) {
  556. // No available default TTL. 2nd and 3rd RR will use the TTL of the
  557. // 1st RR. This will result in a warning, but only for the first time.
  558. stringstream zone_stream("a.example.org. 1800 IN A 192.0.2.1\n"
  559. "b.example.org. IN A 192.0.2.2\n"
  560. "c.example.org. IN A 192.0.2.3\n");
  561. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  562. MasterLoader::DEFAULT);
  563. loader_->load();
  564. EXPECT_TRUE(loader_->loadedSucessfully());
  565. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
  566. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
  567. checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(1800));
  568. EXPECT_EQ(1, warnings_.size());
  569. checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
  570. }
  571. TEST_F(MasterLoaderTest, ttlFromPreviousSOA) {
  572. // Mixture of the previous two cases: SOA has explicit TTL, followed by
  573. // an RR without an explicit TTL. In this case the minimum TTL won't be
  574. // recognized as the "default TTL".
  575. stringstream zone_stream("example.org. 100 IN SOA . . 0 0 0 0 1800\n"
  576. "a.example.org. IN A 192.0.2.1\n");
  577. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  578. MasterLoader::DEFAULT);
  579. loader_->load();
  580. EXPECT_TRUE(loader_->loadedSucessfully());
  581. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(100));
  582. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(100));
  583. EXPECT_EQ(1, warnings_.size());
  584. checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
  585. }
  586. TEST_F(MasterLoaderTest, ttlUnknown) {
  587. // No available TTL is known for the first RR.
  588. stringstream zone_stream("a.example.org. IN A 192.0.2.1\n");
  589. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  590. MasterLoader::DEFAULT);
  591. EXPECT_THROW(loader_->load(), MasterLoaderError);
  592. }
  593. TEST_F(MasterLoaderTest, ttlUnknownAndContinue) {
  594. stringstream zone_stream("a.example.org. IN A 192.0.2.1\n"
  595. "b.example.org. 1800 IN A 192.0.2.2\n");
  596. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  597. MasterLoader::MANY_ERRORS);
  598. loader_->load();
  599. EXPECT_FALSE(loader_->loadedSucessfully());
  600. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
  601. EXPECT_TRUE(warnings_.empty());
  602. EXPECT_EQ(1, errors_.size());
  603. checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
  604. }
  605. TEST_F(MasterLoaderTest, ttlUnknownAndEOF) {
  606. // Similar to the previous case, but the input will be abruptly terminated
  607. // after the offending RR. This will cause an additional warning.
  608. stringstream zone_stream("a.example.org. IN A 192.0.2.1");
  609. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  610. MasterLoader::MANY_ERRORS);
  611. loader_->load();
  612. EXPECT_FALSE(loader_->loadedSucessfully());
  613. EXPECT_TRUE(rrsets_.empty());
  614. EXPECT_EQ(1, errors_.size());
  615. checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
  616. // RDATA implementation can complain about it, too. To be independent of
  617. // its details, we focus on the very last warning.
  618. EXPECT_FALSE(warnings_.empty());
  619. checkCallbackMessage(*warnings_.rbegin(), "File does not end with newline",
  620. 1);
  621. }
  622. TEST_F(MasterLoaderTest, ttlOverflow) {
  623. stringstream zone_stream;
  624. zone_stream << "example.org. IN SOA . . 0 0 0 0 2147483648\n";
  625. zone_stream << "$TTL 3600\n"; // reset to an in-range value
  626. zone_stream << "$TTL 2147483649\n" << "a.example.org. IN A 192.0.2.1\n";
  627. zone_stream << "$TTL 3600\n"; // reset to an in-range value
  628. zone_stream << "b.example.org. 2147483650 IN A 192.0.2.2\n";
  629. setLoader(zone_stream, Name("example.org."), RRClass::IN(),
  630. MasterLoader::DEFAULT);
  631. loader_->load();
  632. EXPECT_TRUE(loader_->loadedSucessfully());
  633. EXPECT_EQ(3, rrsets_.size());
  634. checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 2147483648", RRTTL(0));
  635. checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(0));
  636. checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(0));
  637. EXPECT_EQ(4, warnings_.size());
  638. checkCallbackMessage(warnings_.at(1),
  639. "TTL 2147483648 > MAXTTL, setting to 0 per RFC2181",
  640. 1);
  641. checkCallbackMessage(warnings_.at(2),
  642. "TTL 2147483649 > MAXTTL, setting to 0 per RFC2181",
  643. 3);
  644. checkCallbackMessage(warnings_.at(3),
  645. "TTL 2147483650 > MAXTTL, setting to 0 per RFC2181",
  646. 6);
  647. }
  648. // Test the constructor rejects empty add callback.
  649. TEST_F(MasterLoaderTest, emptyCallback) {
  650. EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
  651. Name("example.org"), RRClass::IN(), callbacks_,
  652. AddRRCallback()), isc::InvalidParameter);
  653. // And the same with the second constructor
  654. stringstream ss("");
  655. EXPECT_THROW(MasterLoader(ss, Name("example.org"), RRClass::IN(),
  656. callbacks_, AddRRCallback()),
  657. isc::InvalidParameter);
  658. }
  659. // Check it throws when we try to load after loading was complete.
  660. TEST_F(MasterLoaderTest, loadTwice) {
  661. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  662. RRClass::IN(), MasterLoader::MANY_ERRORS);
  663. loader_->load();
  664. EXPECT_THROW(loader_->load(), isc::InvalidOperation);
  665. // Don't check them, they are not interesting, so suppress the error
  666. // at TearDown
  667. rrsets_.clear();
  668. }
  669. // Load 0 items should be rejected
  670. TEST_F(MasterLoaderTest, loadZero) {
  671. setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
  672. RRClass::IN(), MasterLoader::MANY_ERRORS);
  673. EXPECT_THROW(loader_->loadIncremental(0), isc::InvalidParameter);
  674. }
  675. // Test there's a warning when the file terminates without end of
  676. // line.
  677. TEST_F(MasterLoaderTest, noEOLN) {
  678. // No \n at the end
  679. const string input("example.org. 3600 IN SOA ns1.example.org. "
  680. "admin.example.org. 1234 3600 1800 2419200 7200");
  681. stringstream ss(input);
  682. setLoader(ss, Name("example.org."), RRClass::IN(),
  683. MasterLoader::MANY_ERRORS);
  684. loader_->load();
  685. EXPECT_TRUE(loader_->loadedSucessfully());
  686. EXPECT_TRUE(errors_.empty()) << errors_[0];
  687. // There should be one warning about the EOLN
  688. EXPECT_EQ(1, warnings_.size());
  689. checkRR("example.org", RRType::SOA(), "ns1.example.org. "
  690. "admin.example.org. 1234 3600 1800 2419200 7200");
  691. }
  692. // Test it rejects when we don't have the previous name to use in place of
  693. // initial whitespace
  694. TEST_F(MasterLoaderTest, noPreviousName) {
  695. const string input(" 1H IN A 192.0.2.1\n");
  696. stringstream ss(input);
  697. setLoader(ss, Name("example.org."), RRClass::IN(),
  698. MasterLoader::MANY_ERRORS);
  699. loader_->load();
  700. EXPECT_FALSE(loader_->loadedSucessfully());
  701. EXPECT_EQ(1, errors_.size());
  702. checkCallbackMessage(errors_.at(0), "No previous name to use in place of "
  703. "initial whitespace", 1);
  704. EXPECT_TRUE(warnings_.empty());
  705. }
  706. }