d_test_stubs.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. // Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/io_service.h>
  8. #include <d2/d2_log.h>
  9. #include <d2/spec_config.h>
  10. #include <d2/tests/d_test_stubs.h>
  11. using namespace boost::asio;
  12. namespace isc {
  13. namespace d2 {
  14. const char* valid_d2_config = "{ "
  15. "\"ip-address\" : \"127.0.0.1\" , "
  16. "\"port\" : 5031, "
  17. "\"tsig-keys\": ["
  18. "{ \"name\": \"d2_key.tmark.org\" , "
  19. " \"algorithm\": \"HMAC-MD5\" ,"
  20. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  21. "} ],"
  22. "\"forward-ddns\" : {"
  23. "\"ddns-domains\": [ "
  24. "{ \"name\": \"tmark.org.\" , "
  25. " \"key-name\": \"d2_key.tmark.org\" , "
  26. " \"dns-servers\" : [ "
  27. " { \"ip-address\": \"127.0.0.101\" } "
  28. "] } ] }, "
  29. "\"reverse-ddns\" : {"
  30. "\"ddns-domains\": [ "
  31. "{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
  32. " \"key-name\": \"d2_key.tmark.org\" , "
  33. " \"dns-servers\" : [ "
  34. " { \"ip-address\": \"127.0.0.101\" , "
  35. " \"port\": 100 } ] } "
  36. "] } }";
  37. // Initialize the static failure flag.
  38. SimFailure::FailureType SimFailure::failure_type_ = SimFailure::ftNoFailure;
  39. // Define custom process command supported by DStubProcess.
  40. const char* DStubProcess::stub_proc_command_("cool_proc_cmd");
  41. DStubProcess::DStubProcess(const char* name, asiolink::IOServicePtr io_service)
  42. : DProcessBase(name, io_service, DCfgMgrBasePtr(new DStubCfgMgr())) {
  43. };
  44. void
  45. DStubProcess::init() {
  46. if (SimFailure::shouldFailOn(SimFailure::ftProcessInit)) {
  47. // Simulates a failure to instantiate the process.
  48. isc_throw(DProcessBaseError, "DStubProcess simulated init() failure");
  49. }
  50. };
  51. void
  52. DStubProcess::run() {
  53. // Until shut down or an fatal error occurs, wait for and
  54. // execute a single callback. This is a preliminary implementation
  55. // that is likely to evolve as development progresses.
  56. // To use run(), the "managing" layer must issue an io_service::stop
  57. // or the call to run will continue to block, and shutdown will not
  58. // occur.
  59. asiolink::IOServicePtr& io_service = getIoService();
  60. while (!shouldShutdown()) {
  61. try {
  62. io_service->run_one();
  63. } catch (const std::exception& ex) {
  64. isc_throw (DProcessBaseError,
  65. std::string("Process run method failed:") + ex.what());
  66. }
  67. }
  68. };
  69. isc::data::ConstElementPtr
  70. DStubProcess::shutdown(isc::data::ConstElementPtr /* args */) {
  71. if (SimFailure::shouldFailOn(SimFailure::ftProcessShutdown)) {
  72. // Simulates a failure during shutdown process.
  73. isc_throw(DProcessBaseError, "DStubProcess simulated shutdown failure");
  74. }
  75. setShutdownFlag(true);
  76. stopIOService();
  77. return (isc::config::createAnswer(0, "Shutdown inititiated."));
  78. }
  79. isc::data::ConstElementPtr
  80. DStubProcess::configure(isc::data::ConstElementPtr config_set) {
  81. if (SimFailure::shouldFailOn(SimFailure::ftProcessConfigure)) {
  82. // Simulates a process configure failure.
  83. return (isc::config::createAnswer(1,
  84. "Simulated process configuration error."));
  85. }
  86. return (getCfgMgr()->parseConfig(config_set));
  87. }
  88. isc::data::ConstElementPtr
  89. DStubProcess::command(const std::string& command,
  90. isc::data::ConstElementPtr /* args */) {
  91. isc::data::ConstElementPtr answer;
  92. if (SimFailure::shouldFailOn(SimFailure::ftProcessCommand)) {
  93. // Simulates a process command execution failure.
  94. answer = isc::config::createAnswer(COMMAND_ERROR,
  95. "SimFailure::ftProcessCommand");
  96. } else if (command.compare(stub_proc_command_) == 0) {
  97. answer = isc::config::createAnswer(COMMAND_SUCCESS, "Command accepted");
  98. } else {
  99. answer = isc::config::createAnswer(COMMAND_INVALID,
  100. "Unrecognized command:" + command);
  101. }
  102. return (answer);
  103. }
  104. DStubProcess::~DStubProcess() {
  105. };
  106. //************************** DStubController *************************
  107. // Define custom controller command supported by DStubController.
  108. const char* DStubController::stub_ctl_command_("spiffy");
  109. // Define custom command line option command supported by DStubController.
  110. const char* DStubController::stub_option_x_ = "x";
  111. /// @brief Defines the app name used to construct the controller
  112. const char* DStubController::stub_app_name_ = "TestService";
  113. /// @brief Defines the bin name used to construct the controller
  114. const char* DStubController::stub_bin_name_ = "TestBin";
  115. DControllerBasePtr&
  116. DStubController::instance() {
  117. // If the singleton hasn't been created, do it now.
  118. if (!getController()) {
  119. DControllerBasePtr p(new DStubController());
  120. setController(p);
  121. }
  122. return (getController());
  123. }
  124. DStubController::DStubController()
  125. : DControllerBase(stub_app_name_, stub_bin_name_),
  126. processed_signals_(), record_signal_only_(false) {
  127. if (getenv("KEA_FROM_BUILD")) {
  128. setSpecFileName(std::string(getenv("KEA_FROM_BUILD")) +
  129. "/src/bin/d2/dhcp-ddns.spec");
  130. } else {
  131. setSpecFileName(D2_SPECFILE_LOCATION);
  132. }
  133. }
  134. bool
  135. DStubController::customOption(int option, char* /* optarg */)
  136. {
  137. // Check for the custom option supported by DStubController.
  138. if (static_cast<char>(option) == *stub_option_x_) {
  139. return (true);
  140. }
  141. return (false);
  142. }
  143. DProcessBase* DStubController::createProcess() {
  144. if (SimFailure::shouldFailOn(SimFailure::ftCreateProcessException)) {
  145. // Simulates a failure to instantiate the process due to exception.
  146. throw std::runtime_error("SimFailure::ftCreateProcess");
  147. }
  148. if (SimFailure::shouldFailOn(SimFailure::ftCreateProcessNull)) {
  149. // Simulates a failure to instantiate the process.
  150. return (NULL);
  151. }
  152. // This should be a successful instantiation.
  153. return (new DStubProcess(getAppName().c_str(), getIOService()));
  154. }
  155. isc::data::ConstElementPtr
  156. DStubController::customControllerCommand(const std::string& command,
  157. isc::data::ConstElementPtr /* args */) {
  158. isc::data::ConstElementPtr answer;
  159. if (SimFailure::shouldFailOn(SimFailure::ftControllerCommand)) {
  160. // Simulates command failing to execute.
  161. answer = isc::config::createAnswer(COMMAND_ERROR,
  162. "SimFailure::ftControllerCommand");
  163. } else if (command.compare(stub_ctl_command_) == 0) {
  164. answer = isc::config::createAnswer(COMMAND_SUCCESS, "Command accepted");
  165. } else {
  166. answer = isc::config::createAnswer(COMMAND_INVALID,
  167. "Unrecognized command:" + command);
  168. }
  169. return (answer);
  170. }
  171. const std::string DStubController::getCustomOpts() const {
  172. // Return the "list" of custom options supported by DStubController.
  173. return (std::string(stub_option_x_));
  174. }
  175. void
  176. DStubController::processSignal(int signum){
  177. processed_signals_.push_back(signum);
  178. if (record_signal_only_) {
  179. return;
  180. }
  181. DControllerBase::processSignal(signum);
  182. }
  183. DStubController::~DStubController() {
  184. }
  185. //************************** DControllerTest *************************
  186. void
  187. DControllerTest::writeFile(const std::string& content,
  188. const std::string& module_name) {
  189. std::ofstream out(CFG_TEST_FILE, std::ios::trunc);
  190. ASSERT_TRUE(out.is_open());
  191. out << "{ \"" << (!module_name.empty() ? module_name
  192. : getController()->getAppName())
  193. << "\": " << std::endl;
  194. out << content;
  195. out << " } " << std::endl;
  196. out.close();
  197. }
  198. void
  199. DControllerTest::timedWriteCallback() {
  200. writeFile(new_cfg_content_);
  201. }
  202. void
  203. DControllerTest::scheduleTimedWrite(const std::string& config,
  204. int write_time_ms) {
  205. new_cfg_content_ = config;
  206. write_timer_.reset(new asiolink::IntervalTimer(*getIOService()));
  207. write_timer_->setup(boost::bind(&DControllerTest::timedWriteCallback, this),
  208. write_time_ms, asiolink::IntervalTimer::ONE_SHOT);
  209. }
  210. void
  211. DControllerTest::runWithConfig(const std::string& config, int run_time_ms,
  212. time_duration& elapsed_time) {
  213. // Create the config file.
  214. writeFile(config);
  215. // Shutdown (without error) after runtime.
  216. isc::asiolink::IntervalTimer timer(*getIOService());
  217. timer.setup(genShutdownCallback, run_time_ms);
  218. // Record start time, and invoke launch().
  219. // We catch and rethrow to allow testing error scenarios.
  220. ptime start = microsec_clock::universal_time();
  221. try {
  222. // Set up valid command line arguments
  223. char* argv[] = { const_cast<char*>("progName"),
  224. const_cast<char*>("-c"),
  225. const_cast<char*>(DControllerTest::CFG_TEST_FILE),
  226. const_cast<char*>("-d") };
  227. launch(4, argv);
  228. } catch (...) {
  229. // calculate elasped time, then rethrow it
  230. elapsed_time = microsec_clock::universal_time() - start;
  231. throw;
  232. }
  233. elapsed_time = microsec_clock::universal_time() - start;
  234. }
  235. DProcessBasePtr
  236. DControllerTest:: getProcess() {
  237. DProcessBasePtr p;
  238. if (getController()) {
  239. p = getController()->getProcess();
  240. }
  241. return (p);
  242. }
  243. DCfgMgrBasePtr
  244. DControllerTest::getCfgMgr() {
  245. DCfgMgrBasePtr p;
  246. if (getProcess()) {
  247. p = getProcess()->getCfgMgr();
  248. }
  249. return (p);
  250. }
  251. DCfgContextBasePtr
  252. DControllerTest::getContext() {
  253. DCfgContextBasePtr p;
  254. if (getCfgMgr()) {
  255. p = getCfgMgr()->getContext();
  256. }
  257. return (p);
  258. }
  259. // Initialize controller wrapper's static instance getter member.
  260. DControllerTest::InstanceGetter DControllerTest::instanceGetter_ = NULL;
  261. /// @brief Defines the name of the configuration file to use
  262. const char* DControllerTest::CFG_TEST_FILE = "d2-test-config.json";
  263. //************************** ObjectParser *************************
  264. ObjectParser::ObjectParser(const std::string& param_name,
  265. ObjectStoragePtr& object_values)
  266. : param_name_(param_name), object_values_(object_values) {
  267. }
  268. ObjectParser::~ObjectParser(){
  269. }
  270. void
  271. ObjectParser::build(isc::data::ConstElementPtr new_config) {
  272. if (SimFailure::shouldFailOn(SimFailure::ftElementBuild)) {
  273. // Simulates an error during element data parsing.
  274. isc_throw (DCfgMgrBaseError, "Simulated build exception");
  275. }
  276. value_ = new_config;
  277. }
  278. void
  279. ObjectParser::commit() {
  280. if (SimFailure::shouldFailOn(SimFailure::ftElementCommit)) {
  281. // Simulates an error while committing the parsed element data.
  282. throw std::runtime_error("Simulated commit exception");
  283. }
  284. object_values_->setParam(param_name_, value_,
  285. isc::data::Element::Position());
  286. }
  287. //************************** DStubContext *************************
  288. DStubContext::DStubContext(): object_values_(new ObjectStorage()) {
  289. }
  290. DStubContext::~DStubContext() {
  291. }
  292. void
  293. DStubContext::getObjectParam(const std::string& name,
  294. isc::data::ConstElementPtr& value) {
  295. value = object_values_->getParam(name);
  296. }
  297. ObjectStoragePtr&
  298. DStubContext::getObjectStorage() {
  299. return (object_values_);
  300. }
  301. DCfgContextBasePtr
  302. DStubContext::clone() {
  303. return (DCfgContextBasePtr(new DStubContext(*this)));
  304. }
  305. DStubContext::DStubContext(const DStubContext& rhs): DCfgContextBase(rhs),
  306. object_values_(new ObjectStorage(*(rhs.object_values_))) {
  307. }
  308. //************************** DStubCfgMgr *************************
  309. DStubCfgMgr::DStubCfgMgr()
  310. : DCfgMgrBase(DCfgContextBasePtr(new DStubContext())) {
  311. }
  312. DStubCfgMgr::~DStubCfgMgr() {
  313. }
  314. DCfgContextBasePtr
  315. DStubCfgMgr::createNewContext() {
  316. return (DCfgContextBasePtr (new DStubContext()));
  317. }
  318. isc::dhcp::ParserPtr
  319. DStubCfgMgr::createConfigParser(const std::string& element_id,
  320. const isc::data::Element::Position& pos) {
  321. isc::dhcp::ParserPtr parser;
  322. DStubContextPtr context
  323. = boost::dynamic_pointer_cast<DStubContext>(getContext());
  324. if (element_id == "bool_test") {
  325. parser.reset(new isc::dhcp::
  326. BooleanParser(element_id,
  327. context->getBooleanStorage()));
  328. } else if (element_id == "uint32_test") {
  329. parser.reset(new isc::dhcp::Uint32Parser(element_id,
  330. context->getUint32Storage()));
  331. } else if (element_id == "string_test") {
  332. parser.reset(new isc::dhcp::StringParser(element_id,
  333. context->getStringStorage()));
  334. } else {
  335. // Fail only if SimFailure dictates we should. This makes it easier
  336. // to test parse ordering, by permitting a wide range of element ids
  337. // to "succeed" without specifically supporting them.
  338. if (SimFailure::shouldFailOn(SimFailure::ftElementUnknown)) {
  339. isc_throw(DCfgMgrBaseError,
  340. "Configuration parameter not supported: " << element_id
  341. << pos);
  342. }
  343. // Going to assume anything else is an object element.
  344. parser.reset(new ObjectParser(element_id, context->getObjectStorage()));
  345. }
  346. parsed_order_.push_back(element_id);
  347. return (parser);
  348. }
  349. }; // namespace isc::d2
  350. }; // namespace isc