d_test_stubs.cc 14 KB

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