datasrc_clients_builder_unittest.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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 <util/unittests/check_valgrind.h>
  16. #include <dns/name.h>
  17. #include <dns/rrclass.h>
  18. #include <cc/data.h>
  19. #include <datasrc/client.h>
  20. #include <datasrc/factory.h>
  21. #include <auth/datasrc_clients_mgr.h>
  22. #include <auth/datasrc_config.h>
  23. #include <testutils/dnsmessage_test.h>
  24. #include "test_datasrc_clients_mgr.h"
  25. #include "datasrc_util.h"
  26. #include <gtest/gtest.h>
  27. #include <boost/function.hpp>
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30. #include <cstdlib>
  31. #include <string>
  32. #include <sstream>
  33. #include <cerrno>
  34. using isc::data::ConstElementPtr;
  35. using namespace isc::dns;
  36. using namespace isc::data;
  37. using namespace isc::datasrc;
  38. using namespace isc::auth::datasrc_clientmgr_internal;
  39. using namespace isc::auth::unittest;
  40. using namespace isc::testutils;
  41. namespace {
  42. class DataSrcClientsBuilderTest : public ::testing::Test {
  43. protected:
  44. DataSrcClientsBuilderTest() :
  45. clients_map(new std::map<RRClass,
  46. boost::shared_ptr<ConfigurableClientList> >),
  47. write_end(-1), read_end(-1),
  48. builder(&command_queue, &callback_queue, &cond, &queue_mutex,
  49. &clients_map, &map_mutex, generateSockets()),
  50. cond(command_queue, delayed_command_queue), rrclass(RRClass::IN()),
  51. shutdown_cmd(SHUTDOWN, ConstElementPtr(), FinishedCallback()),
  52. noop_cmd(NOOP, ConstElementPtr(), FinishedCallback())
  53. {}
  54. ~ DataSrcClientsBuilderTest() {
  55. }
  56. void configureZones(); // used for loadzone related tests
  57. ClientListMapPtr clients_map; // configured clients
  58. std::list<Command> command_queue; // test command queue
  59. std::list<Command> delayed_command_queue; // commands available after wait
  60. std::list<FinishedCallback> callback_queue; // Callbacks from commands
  61. int write_end, read_end;
  62. TestDataSrcClientsBuilder builder;
  63. TestCondVar cond;
  64. TestMutex queue_mutex;
  65. TestMutex map_mutex;
  66. const RRClass rrclass;
  67. const Command shutdown_cmd;
  68. const Command noop_cmd;
  69. private:
  70. int generateSockets() {
  71. int pair[2];
  72. int result = socketpair(AF_LOCAL, SOCK_STREAM, 0, pair);
  73. assert(result == 0);
  74. write_end = pair[0];
  75. read_end = pair[1];
  76. return write_end;
  77. }
  78. };
  79. TEST_F(DataSrcClientsBuilderTest, runSingleCommand) {
  80. // A simplest case, just to check the basic behavior.
  81. command_queue.push_back(shutdown_cmd);
  82. builder.run();
  83. EXPECT_TRUE(command_queue.empty());
  84. EXPECT_EQ(0, cond.wait_count); // no wait because command queue is not empty
  85. EXPECT_EQ(1, queue_mutex.lock_count);
  86. EXPECT_EQ(1, queue_mutex.unlock_count);
  87. // No callback scheduled, none called.
  88. EXPECT_TRUE(callback_queue.empty());
  89. // Not woken up.
  90. char c;
  91. int result = recv(read_end, &c, 1, MSG_DONTWAIT);
  92. EXPECT_EQ(-1, result);
  93. EXPECT_TRUE(errno == EAGAIN || errno == EWOULDBLOCK);
  94. }
  95. // Just to have a valid function callback to pass
  96. void emptyCallsback() {}
  97. // Check a command finished callback is passed
  98. TEST_F(DataSrcClientsBuilderTest, commandFinished) {
  99. command_queue.push_back(Command(SHUTDOWN, ConstElementPtr(),
  100. emptyCallsback));
  101. builder.run();
  102. EXPECT_EQ(0, cond.wait_count); // no wait because command queue is not empty
  103. // Once for picking up data, once for putting the callback there
  104. EXPECT_EQ(2, queue_mutex.lock_count);
  105. EXPECT_EQ(2, queue_mutex.unlock_count);
  106. // There's one callback in the queue
  107. ASSERT_EQ(1, callback_queue.size());
  108. // Not using EXPECT_EQ, as that produces warning in printing out the result
  109. EXPECT_TRUE(emptyCallsback == callback_queue.front());
  110. // And we are woken up.
  111. char c;
  112. int result = recv(read_end, &c, 1, MSG_DONTWAIT);
  113. EXPECT_EQ(1, result);
  114. }
  115. // Test that low-level errors with the synchronization socket
  116. // (an unexpected condition) is detected and program aborted.
  117. TEST_F(DataSrcClientsBuilderTest, finishedCrash) {
  118. command_queue.push_back(Command(SHUTDOWN, ConstElementPtr(),
  119. emptyCallsback));
  120. // Break the socket
  121. close(write_end);
  122. EXPECT_DEATH_IF_SUPPORTED({builder.run();}, "");
  123. }
  124. TEST_F(DataSrcClientsBuilderTest, runMultiCommands) {
  125. // Two NOOP commands followed by SHUTDOWN. We should see two doNoop()
  126. // calls.
  127. command_queue.push_back(noop_cmd);
  128. command_queue.push_back(noop_cmd);
  129. command_queue.push_back(shutdown_cmd);
  130. builder.run();
  131. EXPECT_TRUE(command_queue.empty());
  132. EXPECT_EQ(1, queue_mutex.lock_count);
  133. EXPECT_EQ(1, queue_mutex.unlock_count);
  134. EXPECT_EQ(2, queue_mutex.noop_count);
  135. }
  136. TEST_F(DataSrcClientsBuilderTest, exception) {
  137. // Let the noop command handler throw exceptions and see if we can see
  138. // them. Right now, we simply abort to prevent the system from running
  139. // with half-broken state. Eventually we should introduce a better
  140. // error handling.
  141. if (!isc::util::unittests::runningOnValgrind()) {
  142. command_queue.push_back(noop_cmd);
  143. queue_mutex.throw_from_noop = TestMutex::EXCLASS;
  144. EXPECT_DEATH_IF_SUPPORTED({builder.run();}, "");
  145. command_queue.push_back(noop_cmd);
  146. queue_mutex.throw_from_noop = TestMutex::INTEGER;
  147. EXPECT_DEATH_IF_SUPPORTED({builder.run();}, "");
  148. }
  149. command_queue.push_back(noop_cmd);
  150. command_queue.push_back(shutdown_cmd); // we need to stop the loop
  151. queue_mutex.throw_from_noop = TestMutex::INTERNAL;
  152. builder.run();
  153. }
  154. TEST_F(DataSrcClientsBuilderTest, condWait) {
  155. // command_queue is originally empty, so it will require waiting on
  156. // condvar. specialized wait() will make the delayed command available.
  157. delayed_command_queue.push_back(shutdown_cmd);
  158. builder.run();
  159. // There should be one call to wait()
  160. EXPECT_EQ(1, cond.wait_count);
  161. // wait() effectively involves one more set of lock/unlock, so we have
  162. // two in total
  163. EXPECT_EQ(2, queue_mutex.lock_count);
  164. EXPECT_EQ(2, queue_mutex.unlock_count);
  165. }
  166. TEST_F(DataSrcClientsBuilderTest, reconfigure) {
  167. // Full testing of different configurations is not here, but we
  168. // do check a few cases of correct and erroneous input, to verify
  169. // the error handling
  170. // A command structure we'll modify to send different commands
  171. Command reconfig_cmd(RECONFIGURE, ConstElementPtr(), FinishedCallback());
  172. // Initially, no clients should be there
  173. EXPECT_TRUE(clients_map->empty());
  174. // A config that doesn't do much except be accepted
  175. ConstElementPtr good_config = Element::fromJSON(
  176. "{"
  177. "\"IN\": [{"
  178. " \"type\": \"MasterFiles\","
  179. " \"params\": {},"
  180. " \"cache-enable\": true"
  181. "}]"
  182. "}"
  183. );
  184. // A configuration that is 'correct' in the top-level, but contains
  185. // bad data for the type it specifies
  186. ConstElementPtr bad_config = Element::fromJSON(
  187. "{"
  188. "\"IN\": [{"
  189. " \"type\": \"MasterFiles\","
  190. " \"params\": { \"foo\": [ 1, 2, 3, 4 ]},"
  191. " \"cache-enable\": true"
  192. "}]"
  193. "}"
  194. );
  195. reconfig_cmd.params = good_config;
  196. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  197. EXPECT_EQ(1, clients_map->size());
  198. EXPECT_EQ(1, map_mutex.lock_count);
  199. // Store the nonempty clients map we now have
  200. ClientListMapPtr working_config_clients(clients_map);
  201. // If a 'bad' command argument got here, the config validation should
  202. // have failed already, but still, the handler should return true,
  203. // and the clients_map should not be updated.
  204. reconfig_cmd.params = Element::create("{ \"foo\": \"bar\" }");
  205. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  206. EXPECT_EQ(working_config_clients, clients_map);
  207. // Building failed, so map mutex should not have been locked again
  208. EXPECT_EQ(1, map_mutex.lock_count);
  209. // The same for a configuration that has bad data for the type it
  210. // specifies
  211. reconfig_cmd.params = bad_config;
  212. builder.handleCommand(reconfig_cmd);
  213. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  214. EXPECT_EQ(working_config_clients, clients_map);
  215. // Building failed, so map mutex should not have been locked again
  216. EXPECT_EQ(1, map_mutex.lock_count);
  217. // The same goes for an empty parameter (it should at least be
  218. // an empty map)
  219. reconfig_cmd.params = ConstElementPtr();
  220. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  221. EXPECT_EQ(working_config_clients, clients_map);
  222. EXPECT_EQ(1, map_mutex.lock_count);
  223. // Reconfigure again with the same good clients, the result should
  224. // be a different map than the original, but not an empty one.
  225. reconfig_cmd.params = good_config;
  226. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  227. EXPECT_NE(working_config_clients, clients_map);
  228. EXPECT_EQ(1, clients_map->size());
  229. EXPECT_EQ(2, map_mutex.lock_count);
  230. // And finally, try an empty config to disable all datasource clients
  231. reconfig_cmd.params = Element::createMap();
  232. EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
  233. EXPECT_EQ(0, clients_map->size());
  234. EXPECT_EQ(3, map_mutex.lock_count);
  235. // Also check if it has been cleanly unlocked every time
  236. EXPECT_EQ(3, map_mutex.unlock_count);
  237. }
  238. TEST_F(DataSrcClientsBuilderTest, shutdown) {
  239. EXPECT_FALSE(builder.handleCommand(shutdown_cmd));
  240. }
  241. TEST_F(DataSrcClientsBuilderTest, badCommand) {
  242. // out-of-range command ID
  243. EXPECT_THROW(builder.handleCommand(Command(NUM_COMMANDS,
  244. ConstElementPtr(),
  245. FinishedCallback())),
  246. isc::Unexpected);
  247. }
  248. // A helper function commonly used for the "loadzone" command tests.
  249. // It configures the given data source client lists with a memory data source
  250. // containing two zones, and checks the zones are correctly loaded.
  251. void
  252. zoneChecks(ClientListMapPtr clients_map, RRClass rrclass) {
  253. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  254. find(Name("ns.test1.example")).finder_->
  255. find(Name("ns.test1.example"), RRType::A())->code);
  256. EXPECT_EQ(ZoneFinder::NXRRSET, clients_map->find(rrclass)->second->
  257. find(Name("ns.test1.example")).finder_->
  258. find(Name("ns.test1.example"), RRType::AAAA())->code);
  259. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  260. find(Name("ns.test2.example")).finder_->
  261. find(Name("ns.test2.example"), RRType::A())->code);
  262. EXPECT_EQ(ZoneFinder::NXRRSET, clients_map->find(rrclass)->second->
  263. find(Name("ns.test2.example")).finder_->
  264. find(Name("ns.test2.example"), RRType::AAAA())->code);
  265. }
  266. // Another helper that checks after completing loadzone command.
  267. void
  268. newZoneChecks(ClientListMapPtr clients_map, RRClass rrclass) {
  269. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  270. find(Name("ns.test1.example")).finder_->
  271. find(Name("ns.test1.example"), RRType::A())->code);
  272. // now test1.example should have ns/AAAA
  273. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  274. find(Name("ns.test1.example")).finder_->
  275. find(Name("ns.test1.example"), RRType::AAAA())->code);
  276. // test2.example shouldn't change
  277. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  278. find(Name("ns.test2.example")).finder_->
  279. find(Name("ns.test2.example"), RRType::A())->code);
  280. EXPECT_EQ(ZoneFinder::NXRRSET,
  281. clients_map->find(rrclass)->second->
  282. find(Name("ns.test2.example")).finder_->
  283. find(Name("ns.test2.example"), RRType::AAAA())->code);
  284. }
  285. void
  286. DataSrcClientsBuilderTest::configureZones() {
  287. ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR "/test1.zone.in "
  288. TEST_DATA_BUILDDIR "/test1.zone.copied"));
  289. ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
  290. TEST_DATA_BUILDDIR "/test2.zone.copied"));
  291. const ConstElementPtr config(
  292. Element::fromJSON(
  293. "{"
  294. "\"IN\": [{"
  295. " \"type\": \"MasterFiles\","
  296. " \"params\": {"
  297. " \"test1.example\": \"" +
  298. std::string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\","
  299. " \"test2.example\": \"" +
  300. std::string(TEST_DATA_BUILDDIR "/test2.zone.copied") + "\""
  301. " },"
  302. " \"cache-enable\": true"
  303. "}]}"));
  304. clients_map = configureDataSource(config);
  305. zoneChecks(clients_map, rrclass);
  306. }
  307. TEST_F(DataSrcClientsBuilderTest, loadZone) {
  308. // pre test condition checks
  309. EXPECT_EQ(0, map_mutex.lock_count);
  310. EXPECT_EQ(0, map_mutex.unlock_count);
  311. configureZones();
  312. EXPECT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
  313. "/test1-new.zone.in "
  314. TEST_DATA_BUILDDIR "/test1.zone.copied"));
  315. EXPECT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
  316. "/test2-new.zone.in "
  317. TEST_DATA_BUILDDIR "/test2.zone.copied"));
  318. const Command loadzone_cmd(LOADZONE, Element::fromJSON(
  319. "{\"class\": \"IN\","
  320. " \"origin\": \"test1.example\"}"),
  321. FinishedCallback());
  322. EXPECT_TRUE(builder.handleCommand(loadzone_cmd));
  323. // loadZone involves two critical sections: one for getting the zone
  324. // writer, and one for actually updating the zone data. So the lock/unlock
  325. // count should be incremented by 2.
  326. EXPECT_EQ(2, map_mutex.lock_count);
  327. EXPECT_EQ(2, map_mutex.unlock_count);
  328. newZoneChecks(clients_map, rrclass);
  329. }
  330. TEST_F(DataSrcClientsBuilderTest,
  331. #ifdef USE_STATIC_LINK
  332. DISABLED_loadZoneSQLite3
  333. #else
  334. loadZoneSQLite3
  335. #endif
  336. )
  337. {
  338. // Prepare the database first
  339. const std::string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
  340. std::stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n"
  341. "example.org. 3600 IN NS ns1.example.org.\n");
  342. createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
  343. // This describes the data source in the configuration
  344. const ConstElementPtr config(Element::fromJSON("{"
  345. "\"IN\": [{"
  346. " \"type\": \"sqlite3\","
  347. " \"params\": {\"database_file\": \"" + test_db + "\"},"
  348. " \"cache-enable\": true,"
  349. " \"cache-zones\": [\"example.org\"]"
  350. "}]}"));
  351. clients_map = configureDataSource(config);
  352. // Check that the A record at www.example.org does not exist
  353. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  354. clients_map->find(rrclass)->second->
  355. find(Name("example.org")).finder_->
  356. find(Name("www.example.org"), RRType::A())->code);
  357. // Add the record to the underlying sqlite database, by loading
  358. // it as a separate datasource, and updating it
  359. ConstElementPtr sql_cfg = Element::fromJSON("{ \"type\": \"sqlite3\","
  360. "\"database_file\": \""
  361. + test_db + "\"}");
  362. DataSourceClientContainer sql_ds("sqlite3", sql_cfg);
  363. ZoneUpdaterPtr sql_updater =
  364. sql_ds.getInstance().getUpdater(Name("example.org"), false);
  365. sql_updater->addRRset(
  366. *textToRRset("www.example.org. 60 IN A 192.0.2.1"));
  367. sql_updater->commit();
  368. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  369. clients_map->find(rrclass)->second->
  370. find(Name("example.org")).finder_->
  371. find(Name("www.example.org"), RRType::A())->code);
  372. // Now send the command to reload it
  373. const Command loadzone_cmd(LOADZONE, Element::fromJSON(
  374. "{\"class\": \"IN\","
  375. " \"origin\": \"example.org\"}"),
  376. FinishedCallback());
  377. EXPECT_TRUE(builder.handleCommand(loadzone_cmd));
  378. // And now it should be present too.
  379. EXPECT_EQ(ZoneFinder::SUCCESS,
  380. clients_map->find(rrclass)->second->
  381. find(Name("example.org")).finder_->
  382. find(Name("www.example.org"), RRType::A())->code);
  383. // An error case: the zone has no configuration. (note .com here)
  384. const Command nozone_cmd(LOADZONE, Element::fromJSON(
  385. "{\"class\": \"IN\","
  386. " \"origin\": \"example.com\"}"),
  387. FinishedCallback());
  388. EXPECT_THROW(builder.handleCommand(nozone_cmd),
  389. TestDataSrcClientsBuilder::InternalCommandError);
  390. // The previous zone is not hurt in any way
  391. EXPECT_EQ(ZoneFinder::SUCCESS, clients_map->find(rrclass)->second->
  392. find(Name("example.org")).finder_->
  393. find(Name("example.org"), RRType::SOA())->code);
  394. // attempt of reloading a zone but in-memory cache is disabled. In this
  395. // case the command is simply ignored.
  396. const size_t orig_lock_count = map_mutex.lock_count;
  397. const size_t orig_unlock_count = map_mutex.unlock_count;
  398. const ConstElementPtr config2(Element::fromJSON("{"
  399. "\"IN\": [{"
  400. " \"type\": \"sqlite3\","
  401. " \"params\": {\"database_file\": \"" + test_db + "\"},"
  402. " \"cache-enable\": false,"
  403. " \"cache-zones\": [\"example.org\"]"
  404. "}]}"));
  405. clients_map = configureDataSource(config2);
  406. builder.handleCommand(
  407. Command(LOADZONE, Element::fromJSON(
  408. "{\"class\": \"IN\","
  409. " \"origin\": \"example.org\"}"),
  410. FinishedCallback()));
  411. // Only one mutex was needed because there was no actual reload.
  412. EXPECT_EQ(orig_lock_count + 1, map_mutex.lock_count);
  413. EXPECT_EQ(orig_unlock_count + 1, map_mutex.unlock_count);
  414. // zone doesn't exist in the data source
  415. const ConstElementPtr config_nozone(Element::fromJSON("{"
  416. "\"IN\": [{"
  417. " \"type\": \"sqlite3\","
  418. " \"params\": {\"database_file\": \"" + test_db + "\"},"
  419. " \"cache-enable\": true,"
  420. " \"cache-zones\": [\"nosuchzone.example\"]"
  421. "}]}"));
  422. clients_map = configureDataSource(config_nozone);
  423. EXPECT_THROW(
  424. builder.handleCommand(
  425. Command(LOADZONE, Element::fromJSON(
  426. "{\"class\": \"IN\","
  427. " \"origin\": \"nosuchzone.example\"}"),
  428. FinishedCallback())),
  429. TestDataSrcClientsBuilder::InternalCommandError);
  430. // basically impossible case: in-memory cache is completely disabled.
  431. // In this implementation of manager-builder, this should never happen,
  432. // but it catches it like other configuration error and keeps going.
  433. clients_map->clear();
  434. boost::shared_ptr<ConfigurableClientList> nocache_list(
  435. new ConfigurableClientList(rrclass));
  436. nocache_list->configure(
  437. Element::fromJSON(
  438. "[{\"type\": \"sqlite3\","
  439. " \"params\": {\"database_file\": \"" + test_db + "\"},"
  440. " \"cache-enable\": true,"
  441. " \"cache-zones\": [\"example.org\"]"
  442. "}]"), false); // false = disable cache
  443. (*clients_map)[rrclass] = nocache_list;
  444. EXPECT_THROW(builder.handleCommand(
  445. Command(LOADZONE, Element::fromJSON(
  446. "{\"class\": \"IN\","
  447. " \"origin\": \"example.org\"}"),
  448. FinishedCallback())),
  449. TestDataSrcClientsBuilder::InternalCommandError);
  450. }
  451. TEST_F(DataSrcClientsBuilderTest, loadBrokenZone) {
  452. configureZones();
  453. ASSERT_EQ(0, std::system(INSTALL_PROG " -c " TEST_DATA_DIR
  454. "/test1-broken.zone.in "
  455. TEST_DATA_BUILDDIR "/test1.zone.copied"));
  456. // there's an error in the new zone file. reload will be rejected.
  457. const Command loadzone_cmd(LOADZONE, Element::fromJSON(
  458. "{\"class\": \"IN\","
  459. " \"origin\": \"test1.example\"}"),
  460. FinishedCallback());
  461. EXPECT_THROW(builder.handleCommand(loadzone_cmd),
  462. TestDataSrcClientsBuilder::InternalCommandError);
  463. zoneChecks(clients_map, rrclass); // zone shouldn't be replaced
  464. }
  465. TEST_F(DataSrcClientsBuilderTest, loadUnreadableZone) {
  466. configureZones();
  467. // install the zone file as unreadable
  468. ASSERT_EQ(0, std::system(INSTALL_PROG " -c -m 000 " TEST_DATA_DIR
  469. "/test1.zone.in "
  470. TEST_DATA_BUILDDIR "/test1.zone.copied"));
  471. const Command loadzone_cmd(LOADZONE, Element::fromJSON(
  472. "{\"class\": \"IN\","
  473. " \"origin\": \"test1.example\"}"),
  474. FinishedCallback());
  475. EXPECT_THROW(builder.handleCommand(loadzone_cmd),
  476. TestDataSrcClientsBuilder::InternalCommandError);
  477. zoneChecks(clients_map, rrclass); // zone shouldn't be replaced
  478. }
  479. TEST_F(DataSrcClientsBuilderTest, loadZoneWithoutDataSrc) {
  480. // try to execute load command without configuring the zone beforehand.
  481. // it should fail.
  482. EXPECT_THROW(builder.handleCommand(
  483. Command(LOADZONE,
  484. Element::fromJSON(
  485. "{\"class\": \"IN\", "
  486. " \"origin\": \"test1.example\"}"),
  487. FinishedCallback())),
  488. TestDataSrcClientsBuilder::InternalCommandError);
  489. }
  490. TEST_F(DataSrcClientsBuilderTest, loadZoneInvalidParams) {
  491. configureZones();
  492. if (!isc::util::unittests::runningOnValgrind()) {
  493. // null arg: this causes assertion failure
  494. EXPECT_DEATH_IF_SUPPORTED({
  495. builder.handleCommand(Command(LOADZONE, ElementPtr(),
  496. FinishedCallback()));
  497. }, "");
  498. }
  499. // zone class is bogus (note that this shouldn't happen except in tests)
  500. EXPECT_THROW(builder.handleCommand(
  501. Command(LOADZONE,
  502. Element::fromJSON(
  503. "{\"origin\": \"test1.example\","
  504. " \"class\": \"no_such_class\"}"),
  505. FinishedCallback())),
  506. InvalidRRClass);
  507. // not a string
  508. EXPECT_THROW(builder.handleCommand(
  509. Command(LOADZONE,
  510. Element::fromJSON(
  511. "{\"origin\": \"test1.example\","
  512. " \"class\": 1}"),
  513. FinishedCallback())),
  514. isc::data::TypeError);
  515. // class or origin is missing: result in assertion failure
  516. if (!isc::util::unittests::runningOnValgrind()) {
  517. EXPECT_DEATH_IF_SUPPORTED({
  518. builder.handleCommand(Command(LOADZONE,
  519. Element::fromJSON(
  520. "{\"class\": \"IN\"}"),
  521. FinishedCallback()));
  522. }, "");
  523. }
  524. // origin is bogus
  525. EXPECT_THROW(builder.handleCommand(
  526. Command(LOADZONE,
  527. Element::fromJSON(
  528. "{\"class\": \"IN\", \"origin\": \"...\"}"),
  529. FinishedCallback())),
  530. EmptyLabel);
  531. EXPECT_THROW(builder.handleCommand(
  532. Command(LOADZONE,
  533. Element::fromJSON(
  534. "{\"origin\": 10, \"class\": 1}"),
  535. FinishedCallback())),
  536. isc::data::TypeError);
  537. }
  538. // This works only if mapped memory segment is compiled.
  539. // Note also that this test case may fail as we make b10-auth more aware
  540. // of shared-memory cache.
  541. TEST_F(DataSrcClientsBuilderTest,
  542. #ifdef USE_SHARED_MEMORY
  543. loadInNonWritableCache
  544. #else
  545. DISABLED_loadInNonWritableCache
  546. #endif
  547. )
  548. {
  549. const ConstElementPtr config = Element::fromJSON(
  550. "{"
  551. "\"IN\": [{"
  552. " \"type\": \"MasterFiles\","
  553. " \"params\": {"
  554. " \"test1.example\": \"" +
  555. std::string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\"},"
  556. " \"cache-enable\": true,"
  557. " \"cache-type\": \"mapped\""
  558. "}]}");
  559. clients_map = configureDataSource(config);
  560. EXPECT_THROW(builder.handleCommand(
  561. Command(LOADZONE,
  562. Element::fromJSON(
  563. "{\"origin\": \"test1.example\","
  564. " \"class\": \"IN\"}"),
  565. FinishedCallback())),
  566. TestDataSrcClientsBuilder::InternalCommandError);
  567. }
  568. } // unnamed namespace