client_list_unittest.cc 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  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 <config.h>
  15. #include <datasrc/client_list.h>
  16. #include <datasrc/client.h>
  17. #include <datasrc/cache_config.h>
  18. #include <datasrc/zone_iterator.h>
  19. #include <datasrc/exceptions.h>
  20. #include <datasrc/memory/memory_client.h>
  21. #include <datasrc/memory/zone_table_segment.h>
  22. #include <datasrc/memory/zone_finder.h>
  23. #include <datasrc/memory/zone_writer.h>
  24. #include <datasrc/tests/mock_client.h>
  25. #include <dns/rrclass.h>
  26. #include <dns/rrttl.h>
  27. #include <dns/rdataclass.h>
  28. #include <gtest/gtest.h>
  29. #include <boost/shared_ptr.hpp>
  30. #include <set>
  31. #include <fstream>
  32. using namespace isc::datasrc;
  33. using isc::datasrc::unittest::MockDataSourceClient;
  34. using isc::datasrc::memory::InMemoryClient;
  35. using isc::datasrc::memory::ZoneTableSegment;
  36. using isc::datasrc::memory::InMemoryZoneFinder;
  37. using namespace isc::data;
  38. using namespace isc::dns;
  39. // don't import the entire boost namespace. It will unexpectedly hide uintXX_t
  40. // for some systems.
  41. using boost::shared_ptr;
  42. using namespace std;
  43. namespace {
  44. // The test version is the same as the normal version. We, however, add
  45. // some methods to dig directly in the internals, for the tests.
  46. class TestedList : public ConfigurableClientList {
  47. public:
  48. TestedList(const RRClass& rrclass) :
  49. ConfigurableClientList(rrclass)
  50. {}
  51. DataSources& getDataSources() { return (data_sources_); }
  52. // Overwrite the list's method to get a data source with given type
  53. // and configuration. We mock the data source and don't create the
  54. // container. This is just to avoid some complexity in the tests.
  55. virtual DataSourcePair getDataSourceClient(const string& type,
  56. const ConstElementPtr&
  57. configuration)
  58. {
  59. if (type == "error") {
  60. isc_throw(DataSourceError, "The error data source type");
  61. }
  62. if (type == "MasterFiles") {
  63. return (DataSourcePair(0, DataSourceClientContainerPtr()));
  64. }
  65. shared_ptr<MockDataSourceClient>
  66. ds(new MockDataSourceClient(type, configuration));
  67. // Make sure it is deleted when the test list is deleted.
  68. to_delete_.push_back(ds);
  69. return (DataSourcePair(ds.get(), DataSourceClientContainerPtr()));
  70. }
  71. private:
  72. // Hold list of data sources created internally, so they are preserved
  73. // until the end of the test and then deleted.
  74. vector<shared_ptr<MockDataSourceClient> > to_delete_;
  75. };
  76. const char* ds_zones[][3] = {
  77. {
  78. "example.org.",
  79. "example.com.",
  80. NULL
  81. },
  82. {
  83. "sub.example.org.",
  84. NULL, NULL
  85. },
  86. {
  87. NULL, NULL, NULL
  88. },
  89. {
  90. "sub.example.org.",
  91. NULL, NULL
  92. }
  93. };
  94. const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
  95. class ListTest : public ::testing::Test {
  96. public:
  97. ListTest() :
  98. rrclass_(RRClass::IN()),
  99. // The empty list corresponds to a list with no elements inside
  100. list_(new TestedList(rrclass_)),
  101. config_elem_(Element::fromJSON("["
  102. "{"
  103. " \"type\": \"test_type\","
  104. " \"params\": {}"
  105. "}]")),
  106. config_elem_zones_(Element::fromJSON("["
  107. "{"
  108. " \"type\": \"test_type\","
  109. " \"params\": [\"example.org\", \"example.com\", "
  110. " \"noiter.org\", \"null.org\"]"
  111. "}]")),
  112. ztable_segment_(ZoneTableSegment::create(rrclass_, "local"))
  113. {
  114. for (size_t i(0); i < ds_count; ++ i) {
  115. shared_ptr<MockDataSourceClient>
  116. ds(new MockDataSourceClient(ds_zones[i]));
  117. ds_.push_back(ds);
  118. ds_info_.push_back(ConfigurableClientList::DataSourceInfo(
  119. ds.get(), DataSourceClientContainerPtr(),
  120. boost::shared_ptr<internal::CacheConfig>(),
  121. rrclass_, ""));
  122. }
  123. }
  124. // Install a "fake" cached zone using a temporary underlying data source
  125. // client. If 'enabled' is set to false, emulate a disabled cache, in
  126. // which case there will be no data in memory.
  127. void prepareCache(size_t index, const Name& zone, bool enabled = true) {
  128. ConfigurableClientList::DataSourceInfo& dsrc_info =
  129. list_->getDataSources()[index];
  130. MockDataSourceClient* mock_client =
  131. static_cast<MockDataSourceClient*>(dsrc_info.data_src_client_);
  132. // Disable some default features of the mock to distinguish the
  133. // temporary case from normal case.
  134. mock_client->disableA();
  135. mock_client->disableBadIterator();
  136. // Build new cache config to load the specified zone, and replace
  137. // the data source info with the new config.
  138. ConstElementPtr cache_conf_elem =
  139. Element::fromJSON("{\"type\": \"mock\","
  140. " \"cache-enable\": " +
  141. string(enabled ? "true," : "false,") +
  142. " \"cache-zones\": "
  143. " [\"" + zone.toText() + "\"]}");
  144. boost::shared_ptr<internal::CacheConfig> cache_conf(
  145. new internal::CacheConfig("mock", mock_client, *cache_conf_elem,
  146. true));
  147. dsrc_info = ConfigurableClientList::DataSourceInfo(
  148. dsrc_info.data_src_client_,
  149. dsrc_info.container_,
  150. cache_conf, rrclass_, dsrc_info.name_);
  151. // Load the data into the zone table.
  152. if (enabled) {
  153. boost::scoped_ptr<memory::ZoneWriter> writer(
  154. new memory::ZoneWriter(
  155. *dsrc_info.ztable_segment_,
  156. cache_conf->getLoadAction(rrclass_, zone),
  157. zone, rrclass_));
  158. writer->load();
  159. writer->install();
  160. writer->cleanup(); // not absolutely necessary, but just in case
  161. }
  162. // On completion of load revert to the previous state of underlying
  163. // data source.
  164. mock_client->enableA();
  165. mock_client->enableBadIterator();
  166. }
  167. // Check the positive result is as we expect it.
  168. void positiveResult(const ClientList::FindResult& result,
  169. const shared_ptr<MockDataSourceClient>& dsrc,
  170. const Name& name, bool exact,
  171. const char* test, bool from_cache = false)
  172. {
  173. SCOPED_TRACE(test);
  174. ASSERT_NE(ZoneFinderPtr(), result.finder_);
  175. EXPECT_EQ(name, result.finder_->getOrigin());
  176. EXPECT_EQ(exact, result.exact_match_);
  177. // If it is a positive result, there's something to keep
  178. // alive, even when we don't know what it is.
  179. // Any better idea how to test it actually keeps the thing
  180. // alive?
  181. EXPECT_NE(shared_ptr<ClientList::FindResult::LifeKeeper>(),
  182. result.life_keeper_);
  183. if (from_cache) {
  184. EXPECT_NE(shared_ptr<InMemoryZoneFinder>(),
  185. boost::dynamic_pointer_cast<InMemoryZoneFinder>(
  186. result.finder_)) << "Finder is not from cache";
  187. EXPECT_TRUE(NULL !=
  188. dynamic_cast<InMemoryClient*>(result.dsrc_client_));
  189. } else {
  190. EXPECT_EQ(dsrc.get(), result.dsrc_client_);
  191. }
  192. }
  193. // Configure the list with multiple data sources, according to
  194. // some configuration. It uses the index as parameter, to be able to
  195. // loop through the configurations.
  196. void multiConfiguration(size_t index) {
  197. list_->getDataSources().clear();
  198. switch (index) {
  199. case 2:
  200. list_->getDataSources().push_back(ds_info_[2]);
  201. // The ds_[2] is empty. We just check that it doesn't confuse
  202. // us. Fall through to the case 0.
  203. case 0:
  204. list_->getDataSources().push_back(ds_info_[0]);
  205. list_->getDataSources().push_back(ds_info_[1]);
  206. break;
  207. case 1:
  208. // The other order
  209. list_->getDataSources().push_back(ds_info_[1]);
  210. list_->getDataSources().push_back(ds_info_[0]);
  211. break;
  212. case 3:
  213. list_->getDataSources().push_back(ds_info_[1]);
  214. list_->getDataSources().push_back(ds_info_[0]);
  215. // It is the same as ds_[1], but we take from the first one.
  216. // The first one to match is the correct one.
  217. list_->getDataSources().push_back(ds_info_[3]);
  218. break;
  219. default:
  220. FAIL() << "Unknown configuration index " << index;
  221. }
  222. }
  223. void checkDS(size_t index, const string& type, const string& params,
  224. bool cache) const
  225. {
  226. ASSERT_GT(list_->getDataSources().size(), index);
  227. MockDataSourceClient* ds(dynamic_cast<MockDataSourceClient*>(
  228. list_->getDataSources()[index].data_src_client_));
  229. // Comparing with NULL does not work
  230. ASSERT_NE(ds, static_cast<const MockDataSourceClient*>(NULL));
  231. EXPECT_EQ(type, ds->type_);
  232. EXPECT_TRUE(Element::fromJSON(params)->equals(*ds->configuration_));
  233. EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
  234. shared_ptr<InMemoryClient>());
  235. }
  236. ConfigurableClientList::CacheStatus doReload(
  237. const Name& origin, const string& datasrc_name = "");
  238. const RRClass rrclass_;
  239. shared_ptr<TestedList> list_;
  240. const ClientList::FindResult negative_result_;
  241. vector<shared_ptr<MockDataSourceClient> > ds_;
  242. vector<ConfigurableClientList::DataSourceInfo> ds_info_;
  243. const ConstElementPtr config_elem_, config_elem_zones_;
  244. shared_ptr<ZoneTableSegment> ztable_segment_;
  245. };
  246. // Test the test itself
  247. TEST_F(ListTest, selfTest) {
  248. EXPECT_EQ(result::SUCCESS, ds_[0]->findZone(Name("example.org")).code);
  249. EXPECT_EQ(result::PARTIALMATCH,
  250. ds_[0]->findZone(Name("sub.example.org")).code);
  251. EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("org")).code);
  252. EXPECT_EQ(result::NOTFOUND, ds_[1]->findZone(Name("example.org")).code);
  253. EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("aaa")).code);
  254. EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("zzz")).code);
  255. // Nothing to keep alive here.
  256. EXPECT_EQ(shared_ptr<ClientList::FindResult::LifeKeeper>(),
  257. negative_result_.life_keeper_);
  258. }
  259. // Test the list we create with empty configuration is, in fact, empty
  260. TEST_F(ListTest, emptyList) {
  261. EXPECT_TRUE(list_->getDataSources().empty());
  262. }
  263. // Check the values returned by a find on an empty list. It should be
  264. // a negative answer (nothing found) no matter if we want an exact or inexact
  265. // match.
  266. TEST_F(ListTest, emptySearch) {
  267. // No matter what we try, we don't get an answer.
  268. // Note: we don't have operator<< for the result class, so we cannot use
  269. // EXPECT_EQ. Same for other similar cases.
  270. EXPECT_TRUE(negative_result_ == list_->find(Name("example.org"), false,
  271. false));
  272. EXPECT_TRUE(negative_result_ == list_->find(Name("example.org"), false,
  273. true));
  274. EXPECT_TRUE(negative_result_ == list_->find(Name("example.org"), true,
  275. false));
  276. EXPECT_TRUE(negative_result_ == list_->find(Name("example.org"), true,
  277. true));
  278. }
  279. // Put a single data source inside the list and check it can find an
  280. // exact match if there's one.
  281. TEST_F(ListTest, singleDSExactMatch) {
  282. list_->getDataSources().push_back(ds_info_[0]);
  283. // This zone is not there
  284. EXPECT_TRUE(negative_result_ == list_->find(Name("org."), true));
  285. // But this one is, so check it.
  286. positiveResult(list_->find(Name("example.org"), true), ds_[0],
  287. Name("example.org"), true, "Exact match");
  288. // When asking for a sub zone of a zone there, we get nothing
  289. // (we want exact match, this would be partial one)
  290. EXPECT_TRUE(negative_result_ == list_->find(Name("sub.example.org."),
  291. true));
  292. }
  293. // When asking for a partial match, we get all that the exact one, but more.
  294. TEST_F(ListTest, singleDSBestMatch) {
  295. list_->getDataSources().push_back(ds_info_[0]);
  296. // This zone is not there
  297. EXPECT_TRUE(negative_result_ == list_->find(Name("org.")));
  298. // But this one is, so check it.
  299. positiveResult(list_->find(Name("example.org")), ds_[0],
  300. Name("example.org"), true, "Exact match");
  301. // When asking for a sub zone of a zone there, we get the parent
  302. // one.
  303. positiveResult(list_->find(Name("sub.example.org.")), ds_[0],
  304. Name("example.org"), false, "Subdomain match");
  305. }
  306. const char* const test_names[] = {
  307. "Sub second",
  308. "Sub first",
  309. "With empty",
  310. "With a duplicity"
  311. };
  312. TEST_F(ListTest, multiExactMatch) {
  313. // Run through all the multi-configurations
  314. for (size_t i(0); i < sizeof(test_names) / sizeof(*test_names); ++i) {
  315. SCOPED_TRACE(test_names[i]);
  316. multiConfiguration(i);
  317. // Something that is nowhere there
  318. EXPECT_TRUE(negative_result_ == list_->find(Name("org."), true));
  319. // This one is there exactly.
  320. positiveResult(list_->find(Name("example.org"), true), ds_[0],
  321. Name("example.org"), true, "Exact match");
  322. // This one too, but in a different data source.
  323. positiveResult(list_->find(Name("sub.example.org."), true), ds_[1],
  324. Name("sub.example.org"), true, "Subdomain match");
  325. // But this one is in neither data source.
  326. EXPECT_TRUE(negative_result_ ==
  327. list_->find(Name("sub.example.com."), true));
  328. }
  329. }
  330. TEST_F(ListTest, multiBestMatch) {
  331. // Run through all the multi-configurations
  332. for (size_t i(0); i < 4; ++ i) {
  333. SCOPED_TRACE(test_names[i]);
  334. multiConfiguration(i);
  335. // Something that is nowhere there
  336. EXPECT_TRUE(negative_result_ == list_->find(Name("org.")));
  337. // This one is there exactly.
  338. positiveResult(list_->find(Name("example.org")), ds_[0],
  339. Name("example.org"), true, "Exact match");
  340. // This one too, but in a different data source.
  341. positiveResult(list_->find(Name("sub.example.org.")), ds_[1],
  342. Name("sub.example.org"), true, "Subdomain match");
  343. // But this one is in neither data source. But it is a subdomain
  344. // of one of the zones in the first data source.
  345. positiveResult(list_->find(Name("sub.example.com.")), ds_[0],
  346. Name("example.com."), false, "Subdomain in com");
  347. }
  348. }
  349. // Check the configuration is empty when the list is empty
  350. TEST_F(ListTest, configureEmpty) {
  351. const ConstElementPtr elem(new ListElement);
  352. list_->configure(elem, true);
  353. EXPECT_TRUE(list_->getDataSources().empty());
  354. // Check the exact configuration is preserved
  355. EXPECT_EQ(elem, list_->getConfiguration());
  356. }
  357. // Check we can get multiple data sources and they are in the right order.
  358. TEST_F(ListTest, configureMulti) {
  359. const ConstElementPtr elem(Element::fromJSON("["
  360. "{"
  361. " \"type\": \"type1\","
  362. " \"cache-enable\": false,"
  363. " \"params\": {}"
  364. "},"
  365. "{"
  366. " \"type\": \"type2\","
  367. " \"cache-enable\": false,"
  368. " \"params\": {}"
  369. "}]"
  370. ));
  371. list_->configure(elem, true);
  372. EXPECT_EQ(2, list_->getDataSources().size());
  373. checkDS(0, "type1", "{}", false);
  374. checkDS(1, "type2", "{}", false);
  375. // Check the exact configuration is preserved
  376. EXPECT_EQ(elem, list_->getConfiguration());
  377. }
  378. // Check we can pass whatever we want to the params
  379. TEST_F(ListTest, configureParams) {
  380. const char* params[] = {
  381. "true",
  382. "false",
  383. "null",
  384. "\"hello\"",
  385. "42",
  386. "[]",
  387. "{}",
  388. NULL
  389. };
  390. for (const char** param(params); *param; ++param) {
  391. SCOPED_TRACE(*param);
  392. ConstElementPtr elem(Element::fromJSON(string("["
  393. "{"
  394. " \"type\": \"t\","
  395. " \"cache-enable\": false,"
  396. " \"params\": ") + *param +
  397. "}]"));
  398. list_->configure(elem, true);
  399. EXPECT_EQ(1, list_->getDataSources().size());
  400. checkDS(0, "t", *param, false);
  401. }
  402. }
  403. TEST_F(ListTest, status) {
  404. EXPECT_TRUE(list_->getStatus().empty());
  405. const ConstElementPtr elem(Element::fromJSON("["
  406. "{"
  407. " \"type\": \"type1\","
  408. " \"cache-enable\": false,"
  409. " \"params\": {}"
  410. "},"
  411. "{"
  412. " \"type\": \"type2\","
  413. " \"cache-enable\": true,"
  414. " \"cache-zones\": [],"
  415. " \"name\": \"Test name\","
  416. " \"params\": {}"
  417. "}]"
  418. ));
  419. list_->configure(elem, true);
  420. const vector<DataSourceStatus> statuses(list_->getStatus());
  421. ASSERT_EQ(2, statuses.size());
  422. EXPECT_EQ("type1", statuses[0].getName());
  423. EXPECT_EQ(SEGMENT_UNUSED, statuses[0].getSegmentState());
  424. EXPECT_THROW(statuses[0].getSegmentType(), isc::InvalidOperation);
  425. EXPECT_EQ("Test name", statuses[1].getName());
  426. EXPECT_EQ(SEGMENT_INUSE, statuses[1].getSegmentState());
  427. EXPECT_EQ("local", statuses[1].getSegmentType());
  428. }
  429. TEST_F(ListTest, wrongConfig) {
  430. const char* configs[] = {
  431. // A lot of stuff missing from there
  432. "[{\"type\": \"test_type\", \"params\": 13}, {}]",
  433. // Some bad types completely
  434. "{}",
  435. "true",
  436. "42",
  437. "null",
  438. "[{\"type\": \"test_type\", \"params\": 13}, true]",
  439. "[{\"type\": \"test_type\", \"params\": 13}, []]",
  440. "[{\"type\": \"test_type\", \"params\": 13}, 42]",
  441. // Bad type of type
  442. "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": 42}]",
  443. "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": true}]",
  444. "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": null}]",
  445. "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": []}]",
  446. "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": {}}]",
  447. // Bad type of cache-enable
  448. "[{\"type\": \"test_type\", \"params\": 13}, "
  449. "{\"type\": \"x\", \"cache-enable\": 13, \"cache-zones\": []}]",
  450. "[{\"type\": \"test_type\", \"params\": 13}, "
  451. "{\"type\": \"x\", \"cache-enable\": \"xx\", \"cache-zones\": []}]",
  452. "[{\"type\": \"test_type\", \"params\": 13}, "
  453. "{\"type\": \"x\", \"cache-enable\": [], \"cache-zones\": []}]",
  454. "[{\"type\": \"test_type\", \"params\": 13}, "
  455. "{\"type\": \"x\", \"cache-enable\": {}, \"cache-zones\": []}]",
  456. "[{\"type\": \"test_type\", \"params\": 13}, "
  457. "{\"type\": \"x\", \"cache-enable\": null, \"cache-zones\": []}]",
  458. // Bad type of cache-zones
  459. "[{\"type\": \"test_type\", \"params\": 13}, "
  460. "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": \"x\"}]",
  461. "[{\"type\": \"test_type\", \"params\": 13}, "
  462. "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": true}]",
  463. "[{\"type\": \"test_type\", \"params\": 13}, "
  464. "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": null}]",
  465. "[{\"type\": \"test_type\", \"params\": 13}, "
  466. "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": 13}]",
  467. "[{\"type\": \"test_type\", \"params\": 13}, "
  468. "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": {}}]",
  469. // Some bad inputs for MasterFiles special case
  470. // It must have the cache enabled
  471. "[{\"type\": \"test_type\", \"params\": 13}, "
  472. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  473. "\"params\": {}}]",
  474. // No cache-zones allowed here
  475. "[{\"type\": \"test_type\", \"params\": 13}, "
  476. "{\"type\": \"MasterFiles\", \"cache-enable\": true,"
  477. "\"param\": {}, \"cache-zones\": []}]",
  478. // Some bad types of params
  479. "[{\"type\": \"test_type\", \"params\": 13}, "
  480. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  481. "\"params\": []}]",
  482. "[{\"type\": \"test_type\", \"params\": 13}, "
  483. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  484. "\"params\": 13}]",
  485. "[{\"type\": \"test_type\", \"params\": 13}, "
  486. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  487. "\"params\": true}]",
  488. "[{\"type\": \"test_type\", \"params\": 13}, "
  489. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  490. "\"params\": null}]",
  491. "[{\"type\": \"test_type\", \"params\": 13}, "
  492. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  493. "\"params\": \"x\"}]",
  494. "[{\"type\": \"test_type\", \"params\": 13}, "
  495. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  496. "\"params\": {\".\": 13}}]",
  497. "[{\"type\": \"test_type\", \"params\": 13}, "
  498. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  499. "\"params\": {\".\": true}}]",
  500. "[{\"type\": \"test_type\", \"params\": 13}, "
  501. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  502. "\"params\": {\".\": null}}]",
  503. "[{\"type\": \"test_type\", \"params\": 13}, "
  504. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  505. "\"params\": {\".\": []}}]",
  506. "[{\"type\": \"test_type\", \"params\": 13}, "
  507. "{\"type\": \"MasterFiles\", \"cache-enable\": false,"
  508. "\"params\": {\".\": {}}}]",
  509. NULL
  510. };
  511. // Put something inside to see it survives the exception
  512. list_->configure(config_elem_, true);
  513. checkDS(0, "test_type", "{}", false);
  514. for (const char** config(configs); *config; ++config) {
  515. SCOPED_TRACE(*config);
  516. ConstElementPtr elem(Element::fromJSON(*config));
  517. EXPECT_THROW(list_->configure(elem, true),
  518. ConfigurableClientList::ConfigurationError);
  519. // Still untouched
  520. checkDS(0, "test_type", "{}", false);
  521. EXPECT_EQ(1, list_->getDataSources().size());
  522. }
  523. }
  524. // The param thing defaults to null. Cache is not used yet.
  525. TEST_F(ListTest, defaults) {
  526. const ConstElementPtr elem(Element::fromJSON("["
  527. "{"
  528. " \"type\": \"type1\""
  529. "}]"));
  530. list_->configure(elem, true);
  531. EXPECT_EQ(1, list_->getDataSources().size());
  532. checkDS(0, "type1", "null", false);
  533. }
  534. // Check we can call the configure multiple times, to change the configuration
  535. TEST_F(ListTest, reconfigure) {
  536. const ConstElementPtr empty(new ListElement);
  537. list_->configure(config_elem_, true);
  538. checkDS(0, "test_type", "{}", false);
  539. list_->configure(empty, true);
  540. EXPECT_TRUE(list_->getDataSources().empty());
  541. list_->configure(config_elem_, true);
  542. checkDS(0, "test_type", "{}", false);
  543. }
  544. // Make sure the data source error exception from the factory is propagated
  545. TEST_F(ListTest, dataSrcError) {
  546. const ConstElementPtr elem(Element::fromJSON("["
  547. "{"
  548. " \"type\": \"error\""
  549. "}]"));
  550. list_->configure(config_elem_, true);
  551. checkDS(0, "test_type", "{}", false);
  552. EXPECT_THROW(list_->configure(elem, true), DataSourceError);
  553. checkDS(0, "test_type", "{}", false);
  554. }
  555. // Check we can get the cache
  556. TEST_F(ListTest, configureCacheEmpty) {
  557. const ConstElementPtr elem(Element::fromJSON("["
  558. "{"
  559. " \"type\": \"type1\","
  560. " \"cache-enable\": true,"
  561. " \"cache-zones\": [],"
  562. " \"params\": {}"
  563. "},"
  564. "{"
  565. " \"type\": \"type2\","
  566. " \"cache-enable\": false,"
  567. " \"cache-zones\": [],"
  568. " \"params\": {}"
  569. "}]"
  570. ));
  571. list_->configure(elem, true);
  572. EXPECT_EQ(2, list_->getDataSources().size());
  573. checkDS(0, "type1", "{}", true);
  574. checkDS(1, "type2", "{}", false);
  575. }
  576. // But no cache if we disallow it globally
  577. TEST_F(ListTest, configureCacheDisabled) {
  578. const ConstElementPtr elem(Element::fromJSON("["
  579. "{"
  580. " \"type\": \"type1\","
  581. " \"cache-enable\": true,"
  582. " \"cache-zones\": [],"
  583. " \"params\": {}"
  584. "},"
  585. "{"
  586. " \"type\": \"type2\","
  587. " \"cache-enable\": false,"
  588. " \"cache-zones\": [],"
  589. " \"params\": {}"
  590. "}]"
  591. ));
  592. list_->configure(elem, false);
  593. EXPECT_EQ(2, list_->getDataSources().size());
  594. checkDS(0, "type1", "{}", false);
  595. checkDS(1, "type2", "{}", false);
  596. }
  597. // Put some zones into the cache
  598. TEST_F(ListTest, cacheZones) {
  599. const ConstElementPtr elem(Element::fromJSON("["
  600. "{"
  601. " \"type\": \"type1\","
  602. " \"cache-enable\": true,"
  603. " \"cache-zones\": [\"example.org\", \"example.com\"],"
  604. " \"params\": [\"example.org\", \"example.com\", \"exmaple.cz\"]"
  605. "}]"));
  606. list_->configure(elem, true);
  607. checkDS(0, "type1", "[\"example.org\", \"example.com\", \"exmaple.cz\"]",
  608. true);
  609. const shared_ptr<InMemoryClient> cache(list_->getDataSources()[0].cache_);
  610. EXPECT_EQ(2, cache->getZoneCount());
  611. EXPECT_EQ(result::SUCCESS, cache->findZone(Name("example.org")).code);
  612. EXPECT_EQ(result::SUCCESS, cache->findZone(Name("example.com")).code);
  613. EXPECT_EQ(result::NOTFOUND, cache->findZone(Name("example.cz")).code);
  614. EXPECT_EQ(RRClass::IN(),
  615. cache->findZone(Name("example.org")).zone_finder->getClass());
  616. // These are cached and answered from the cache
  617. positiveResult(list_->find(Name("example.com.")), ds_[0],
  618. Name("example.com."), true, "com", true);
  619. positiveResult(list_->find(Name("example.org.")), ds_[0],
  620. Name("example.org."), true, "org", true);
  621. positiveResult(list_->find(Name("sub.example.com.")), ds_[0],
  622. Name("example.com."), false, "Subdomain of com", true);
  623. // For now, the ones not cached are ignored.
  624. EXPECT_TRUE(negative_result_ == list_->find(Name("example.cz.")));
  625. }
  626. // Check the caching handles misbehaviour from the data source and
  627. // misconfiguration gracefully
  628. TEST_F(ListTest, badCache) {
  629. list_->configure(config_elem_, true);
  630. checkDS(0, "test_type", "{}", false);
  631. // First, the zone is not in the data source. configure() should still
  632. // succeed, and the existence zone should be cached.
  633. const ConstElementPtr elem1(Element::fromJSON("["
  634. "{"
  635. " \"type\": \"test_type\","
  636. " \"cache-enable\": true,"
  637. " \"cache-zones\": [\"example.org\", \"example.com\"],"
  638. " \"params\": [\"example.org\"]"
  639. "}]"));
  640. list_->configure(elem1, true); // shouldn't cause disruption
  641. checkDS(0, "test_type", "[\"example.org\"]", true);
  642. const shared_ptr<InMemoryClient> cache(list_->getDataSources()[0].cache_);
  643. EXPECT_EQ(1, cache->getZoneCount());
  644. EXPECT_EQ(result::SUCCESS, cache->findZone(Name("example.org")).code);
  645. // Now, the zone doesn't give an iterator
  646. const ConstElementPtr elem2(Element::fromJSON("["
  647. "{"
  648. " \"type\": \"type1\","
  649. " \"cache-enable\": true,"
  650. " \"cache-zones\": [\"noiter.org\"],"
  651. " \"params\": [\"noiter.org\"]"
  652. "}]"));
  653. EXPECT_THROW(list_->configure(elem2, true), isc::NotImplemented);
  654. checkDS(0, "test_type", "[\"example.org\"]", true);
  655. // Now, the zone returns NULL iterator
  656. const ConstElementPtr elem3(Element::fromJSON("["
  657. "{"
  658. " \"type\": \"type1\","
  659. " \"cache-enable\": true,"
  660. " \"cache-zones\": [\"null.org\"],"
  661. " \"params\": [\"null.org\"]"
  662. "}]"));
  663. EXPECT_THROW(list_->configure(elem3, true), isc::Unexpected);
  664. checkDS(0, "test_type", "[\"example.org\"]", true);
  665. // The autodetection of zones is not enabled
  666. const ConstElementPtr elem4(Element::fromJSON("["
  667. "{"
  668. " \"type\": \"type1\","
  669. " \"cache-enable\": true,"
  670. " \"params\": [\"example.org\"]"
  671. "}]"));
  672. EXPECT_THROW(list_->configure(elem4, true), isc::NotImplemented);
  673. checkDS(0, "test_type", "[\"example.org\"]", true);
  674. }
  675. // This test relies on the property of mapped type of cache.
  676. TEST_F(ListTest,
  677. #ifdef USE_SHARED_MEMORY
  678. cacheInNonWritableSegment
  679. #else
  680. DISABLED_cacheInNonWritableSegment
  681. #endif
  682. )
  683. {
  684. // Initializing data source with non writable zone table memory segment
  685. // is possible. Loading is just postponed
  686. const ConstElementPtr elem(Element::fromJSON("["
  687. "{"
  688. " \"type\": \"test_type\","
  689. " \"cache-enable\": true,"
  690. " \"cache-type\": \"mapped\","
  691. " \"cache-zones\": [\"example.org\"],"
  692. " \"params\": [\"example.org\"]"
  693. "}]"));
  694. list_->configure(elem, true); // no disruption
  695. checkDS(0, "test_type", "[\"example.org\"]", true);
  696. const shared_ptr<InMemoryClient> cache(list_->getDataSources()[0].cache_);
  697. // Likewise, reload attempt will fail.
  698. EXPECT_EQ(ConfigurableClientList::CACHE_NOT_WRITABLE,
  699. doReload(Name("example.org")));
  700. }
  701. TEST_F(ListTest, masterFiles) {
  702. const ConstElementPtr elem(Element::fromJSON("["
  703. "{"
  704. " \"type\": \"MasterFiles\","
  705. " \"cache-enable\": true,"
  706. " \"params\": {"
  707. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  708. " }"
  709. "}]"));
  710. list_->configure(elem, true);
  711. // It has only the cache
  712. EXPECT_EQ(static_cast<const DataSourceClient*>(NULL),
  713. list_->getDataSources()[0].data_src_client_);
  714. // And it can search
  715. positiveResult(list_->find(Name(".")), ds_[0], Name("."), true, "com",
  716. true);
  717. // If cache is not enabled, nothing is loaded
  718. list_->configure(elem, false);
  719. EXPECT_EQ(0, list_->getDataSources().size());
  720. }
  721. // Test the names are set correctly and collission is detected.
  722. TEST_F(ListTest, names) {
  723. // Explicit name
  724. const ConstElementPtr elem1(Element::fromJSON("["
  725. "{"
  726. " \"type\": \"MasterFiles\","
  727. " \"cache-enable\": true,"
  728. " \"params\": {"
  729. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  730. " },"
  731. " \"name\": \"Whatever\""
  732. "}]"));
  733. list_->configure(elem1, true);
  734. EXPECT_EQ("Whatever", list_->getDataSources()[0].name_);
  735. // Default name
  736. const ConstElementPtr elem2(Element::fromJSON("["
  737. "{"
  738. " \"type\": \"MasterFiles\","
  739. " \"cache-enable\": true,"
  740. " \"params\": {"
  741. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  742. " }"
  743. "}]"));
  744. list_->configure(elem2, true);
  745. EXPECT_EQ("MasterFiles", list_->getDataSources()[0].name_);
  746. // Collission
  747. const ConstElementPtr elem3(Element::fromJSON("["
  748. "{"
  749. " \"type\": \"MasterFiles\","
  750. " \"cache-enable\": true,"
  751. " \"params\": {"
  752. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  753. " }"
  754. "},"
  755. "{"
  756. " \"type\": \"MasterFiles\","
  757. " \"cache-enable\": true,"
  758. " \"params\": {"
  759. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  760. " },"
  761. " \"name\": \"MasterFiles\""
  762. "}]"));
  763. EXPECT_THROW(list_->configure(elem3, true),
  764. ConfigurableClientList::ConfigurationError);
  765. }
  766. TEST_F(ListTest, BadMasterFile) {
  767. // Configuration should succeed, and the good zones in the list
  768. // below should be loaded. No bad zones should be loaded.
  769. const ConstElementPtr elem(Element::fromJSON("["
  770. "{"
  771. " \"type\": \"MasterFiles\","
  772. " \"cache-enable\": true,"
  773. " \"params\": {"
  774. // good zone
  775. " \"example.com.\": \"" TEST_DATA_DIR "/example.com.flattened\","
  776. // bad zone (empty file)
  777. " \"example.net.\": \"" TEST_DATA_DIR "/example.net-empty\","
  778. // bad zone (data doesn't validate: see the file for details)
  779. " \"example.edu.\": \"" TEST_DATA_DIR "/example.edu-broken\","
  780. // bad zone (file doesn't exist)
  781. " \"example.info.\": \"" TEST_DATA_DIR "/example.info-nonexist\","
  782. // bad zone (data doesn't match the zone name)
  783. " \"foo.bar.\": \"" TEST_DATA_DIR "/example.org.nsec3-signed\","
  784. // good zone
  785. " \".\": \"" TEST_DATA_DIR "/root.zone\""
  786. " }"
  787. "}]"));
  788. EXPECT_NO_THROW({
  789. // This should not throw even if there are any zone loading
  790. // errors.
  791. list_->configure(elem, true);
  792. });
  793. positiveResult(list_->find(Name("example.com."), true), ds_[0],
  794. Name("example.com."), true, "example.com", true);
  795. EXPECT_TRUE(negative_result_ == list_->find(Name("example.org."), true));
  796. EXPECT_TRUE(negative_result_ == list_->find(Name("foo.bar"), true));
  797. EXPECT_TRUE(negative_result_ == list_->find(Name("example.net."), true));
  798. EXPECT_TRUE(negative_result_ == list_->find(Name("example.edu."), true));
  799. EXPECT_TRUE(negative_result_ == list_->find(Name("example.info."), true));
  800. positiveResult(list_->find(Name(".")), ds_[0], Name("."), true, "root",
  801. true);
  802. }
  803. ConfigurableClientList::CacheStatus
  804. ListTest::doReload(const Name& origin, const string& datasrc_name) {
  805. ConfigurableClientList::ZoneWriterPair
  806. result(list_->getCachedZoneWriter(origin, datasrc_name));
  807. if (result.first == ConfigurableClientList::ZONE_SUCCESS) {
  808. // Can't use ASSERT_NE here, it would want to return(), which
  809. // it can't in non-void function.
  810. if (result.second) {
  811. result.second->load();
  812. result.second->install();
  813. result.second->cleanup();
  814. } else {
  815. ADD_FAILURE() << "getCachedZoneWriter returned ZONE_SUCCESS, "
  816. "but the writer is NULL";
  817. }
  818. } else {
  819. EXPECT_EQ(static_cast<memory::ZoneWriter*>(NULL), result.second.get());
  820. }
  821. return (result.first);
  822. }
  823. // Test we can reload a zone
  824. TEST_F(ListTest, reloadSuccess) {
  825. list_->configure(config_elem_zones_, true);
  826. const Name name("example.org");
  827. prepareCache(0, name);
  828. // The cache currently contains a tweaked version of zone, which
  829. // doesn't have "tstzonedata" A record. So the lookup should result
  830. // in NXDOMAIN.
  831. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  832. list_->find(name).finder_->
  833. find(Name("tstzonedata").concatenate(name),
  834. RRType::A())->code);
  835. // Now reload the full zone. It should be there now.
  836. EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS, doReload(name));
  837. EXPECT_EQ(ZoneFinder::SUCCESS,
  838. list_->find(name).finder_->
  839. find(Name("tstzonedata").concatenate(name),
  840. RRType::A())->code);
  841. }
  842. // The cache is not enabled. The load should be rejected.
  843. TEST_F(ListTest, reloadNotAllowed) {
  844. list_->configure(config_elem_zones_, false);
  845. const Name name("example.org");
  846. // We put the cache in even when not enabled. This won't confuse the thing.
  847. prepareCache(0, name);
  848. // See the reloadSuccess test. This should result in NXDOMAIN.
  849. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  850. list_->find(name).finder_->
  851. find(Name("tstzonedata").concatenate(name),
  852. RRType::A())->code);
  853. // Now reload. It should reject it.
  854. EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, doReload(name));
  855. // Nothing changed here
  856. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  857. list_->find(name).finder_->
  858. find(Name("tstzonedata").concatenate(name),
  859. RRType::A())->code);
  860. }
  861. // Similar to the previous case, but the cache is disabled in config.
  862. TEST_F(ListTest, reloadNotEnabled) {
  863. list_->configure(config_elem_zones_, true);
  864. const Name name("example.org");
  865. // We put the cache, actually disabling it.
  866. prepareCache(0, name, false);
  867. // In this case we cannot really look up due to the limitation of
  868. // the mock implementation. We only check reload fails.
  869. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_CACHED, doReload(name));
  870. }
  871. // Test several cases when the zone does not exist
  872. TEST_F(ListTest, reloadNoSuchZone) {
  873. list_->configure(config_elem_zones_, true);
  874. const Name name("example.org");
  875. // We put the cache in even when not enabled. This won't confuse the
  876. // reload method, as that one looks at the real state of things, not
  877. // at the configuration.
  878. prepareCache(0, Name("example.com"));
  879. // Not in the data sources
  880. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
  881. doReload(Name("exmaple.cz")));
  882. // If it's not configured to be cached, it won't be reloaded.
  883. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_CACHED, doReload(name));
  884. // Partial match
  885. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
  886. doReload(Name("sub.example.com")));
  887. // Nothing changed here - these zones don't exist
  888. EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
  889. list_->find(name).dsrc_client_);
  890. EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
  891. list_->find(Name("example.cz")).dsrc_client_);
  892. EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
  893. list_->find(Name("sub.example.com"), true).dsrc_client_);
  894. // Not reloaded, so A record shouldn't be visible yet.
  895. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  896. list_->find(Name("example.com")).finder_->
  897. find(Name("tstzonedata.example.com"),
  898. RRType::A())->code);
  899. }
  900. // Check we gracefully reject reloading (i.e. no exception) when a zone
  901. // disappeared in the underlying data source when we want to reload it
  902. TEST_F(ListTest, reloadZoneGone) {
  903. list_->configure(config_elem_zones_, true);
  904. const Name name("example.org");
  905. // We put in a cache for non-existent zone. This emulates being loaded
  906. // and then the zone disappearing. We prefill the cache, so we can check
  907. // it.
  908. prepareCache(0, name);
  909. // The (cached) zone contains zone's SOA
  910. EXPECT_EQ(ZoneFinder::SUCCESS,
  911. list_->find(name).finder_->find(name, RRType::SOA())->code);
  912. // Remove the zone from the data source.
  913. static_cast<MockDataSourceClient*>(
  914. list_->getDataSources()[0].data_src_client_)->eraseZone(name);
  915. // The zone is not there, so reload doesn't take place.
  916. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND, doReload(name));
  917. // The (cached) zone is not hurt.
  918. EXPECT_EQ(ZoneFinder::SUCCESS,
  919. list_->find(name).finder_->find(name, RRType::SOA())->code);
  920. }
  921. TEST_F(ListTest, reloadNewZone) {
  922. // Test the case where a zone to be cached originally doesn't exist
  923. // in the underlying data source and is added later. reload() will
  924. // succeed once it's available in the data source.
  925. const ConstElementPtr elem(Element::fromJSON("["
  926. "{"
  927. " \"type\": \"test_type\","
  928. " \"cache-enable\": true,"
  929. " \"cache-zones\": [\"example.org\", \"example.com\"],"
  930. " \"params\": [\"example.org\"]"
  931. "}]"));
  932. list_->configure(elem, true);
  933. checkDS(0, "test_type", "[\"example.org\"]", true); // no example.com
  934. // We can't reload it either
  935. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
  936. doReload(Name("example.com")));
  937. // If we add the zone, we can now reload it
  938. EXPECT_TRUE(static_cast<MockDataSourceClient*>(
  939. list_->getDataSources()[0].data_src_client_)->
  940. insertZone(Name("example.com")));
  941. EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS,
  942. doReload(Name("example.com")));
  943. }
  944. // The underlying data source throws. Check we don't modify the state.
  945. TEST_F(ListTest, reloadZoneThrow) {
  946. list_->configure(config_elem_zones_, true);
  947. const Name name("noiter.org");
  948. prepareCache(0, name);
  949. // The zone contains stuff now
  950. EXPECT_EQ(ZoneFinder::SUCCESS,
  951. list_->find(name).finder_->find(name, RRType::SOA())->code);
  952. // The iterator throws, so abort the reload.
  953. EXPECT_THROW(doReload(name), isc::NotImplemented);
  954. // The zone is not hurt.
  955. EXPECT_EQ(ZoneFinder::SUCCESS,
  956. list_->find(name).finder_->find(name, RRType::SOA())->code);
  957. }
  958. TEST_F(ListTest, reloadNullIterator) {
  959. list_->configure(config_elem_zones_, true);
  960. const Name name("null.org");
  961. prepareCache(0, name);
  962. // The zone contains stuff now
  963. EXPECT_EQ(ZoneFinder::SUCCESS,
  964. list_->find(name).finder_->find(name, RRType::SOA())->code);
  965. // The iterator throws, so abort the reload.
  966. EXPECT_THROW(doReload(name), isc::Unexpected);
  967. // The zone is not hurt.
  968. EXPECT_EQ(ZoneFinder::SUCCESS,
  969. list_->find(name).finder_->find(name, RRType::SOA())->code);
  970. }
  971. // Test we can reload the master files too (special-cased)
  972. TEST_F(ListTest, reloadMasterFile) {
  973. const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_DIR
  974. "/root.zone " TEST_DATA_BUILDDIR "/root.zone.copied";
  975. if (system(install_cmd) != 0) {
  976. // any exception will do, this is failure in test setup, but
  977. // nice to show the command that fails, and shouldn't be caught
  978. isc_throw(isc::Exception,
  979. "Error setting up; command failed: " << install_cmd);
  980. }
  981. const ConstElementPtr elem(Element::fromJSON("["
  982. "{"
  983. " \"type\": \"MasterFiles\","
  984. " \"cache-enable\": true,"
  985. " \"params\": {"
  986. " \".\": \"" TEST_DATA_BUILDDIR "/root.zone.copied\""
  987. " }"
  988. "}]"));
  989. list_->configure(elem, true);
  990. // Add a record that is not in the zone
  991. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  992. list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
  993. RRType::TXT())->code);
  994. ofstream f;
  995. f.open(TEST_DATA_BUILDDIR "/root.zone.copied", ios::out | ios::app);
  996. f << "nosuchdomain.\t\t3600\tIN\tTXT\ttest" << std::endl;
  997. f.close();
  998. // Do the reload.
  999. EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS, doReload(Name(".")));
  1000. // It is here now.
  1001. EXPECT_EQ(ZoneFinder::SUCCESS,
  1002. list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
  1003. RRType::TXT())->code);
  1004. }
  1005. TEST_F(ListTest, reloadByDataSourceName) {
  1006. // We use three data sources (and their clients). 2nd and 3rd have
  1007. // the same name of the zones.
  1008. const ConstElementPtr config_elem = Element::fromJSON(
  1009. "[{\"type\": \"test_type1\", \"params\": [\"example.org\"]},"
  1010. " {\"type\": \"test_type2\", \"params\": [\"example.com\"]},"
  1011. " {\"type\": \"test_type3\", \"params\": [\"example.com\"]}]");
  1012. list_->configure(config_elem, true);
  1013. // Prepare in-memory cache for the 1st and 2nd data sources.
  1014. prepareCache(0, Name("example.org"));
  1015. prepareCache(1, Name("example.com"));
  1016. // Normal case: both zone name and data source name matches.
  1017. // See the reloadSuccess test about the NXDOMAIN/SUCCESS checks.
  1018. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1019. list_->find(Name("tstzonedata.example.com")).finder_->
  1020. find(Name("tstzonedata.example.com"), RRType::A())->code);
  1021. EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS,
  1022. doReload(Name("example.com"), "test_type2"));
  1023. EXPECT_EQ(ZoneFinder::SUCCESS,
  1024. list_->find(Name("tstzonedata.example.com")).finder_->
  1025. find(Name("tstzonedata.example.com"), RRType::A())->code);
  1026. // The specified zone exists in the first entry of the list, but a
  1027. // different data source name is specified (in which the specified zone
  1028. // doesn't exist), so reloading should fail, and the cache status of the
  1029. // first data source shouldn't change.
  1030. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1031. list_->find(Name("tstzonedata.example.org")).finder_->
  1032. find(Name("tstzonedata.example.org"), RRType::A())->code);
  1033. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
  1034. doReload(Name("example.org"), "test_type2"));
  1035. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1036. list_->find(Name("tstzonedata.example.org")).finder_->
  1037. find(Name("tstzonedata.example.org"), RRType::A())->code);
  1038. // Likewise, if a specific data source is given, normal name matching
  1039. // isn't suppressed and the 3rd data source will be used. There cache
  1040. // is disabled, so reload should fail due to "not cached".
  1041. EXPECT_EQ(ConfigurableClientList::ZONE_NOT_CACHED,
  1042. doReload(Name("example.com"), "test_type3"));
  1043. // specified name of data source doesn't exist.
  1044. EXPECT_EQ(ConfigurableClientList::DATASRC_NOT_FOUND,
  1045. doReload(Name("example.org"), "test_type4"));
  1046. }
  1047. // Check the status holds data
  1048. TEST(DataSourceStatus, status) {
  1049. const DataSourceStatus status("Test", SEGMENT_INUSE, "local");
  1050. EXPECT_EQ("Test", status.getName());
  1051. EXPECT_EQ(SEGMENT_INUSE, status.getSegmentState());
  1052. EXPECT_EQ("local", status.getSegmentType());
  1053. const DataSourceStatus status_unused("Unused", SEGMENT_UNUSED, "");
  1054. EXPECT_EQ("Unused", status_unused.getName());
  1055. EXPECT_EQ(SEGMENT_UNUSED, status_unused.getSegmentState());
  1056. EXPECT_THROW(status_unused.getSegmentType(), isc::InvalidOperation);
  1057. }
  1058. }