d_test_stubs.cc 12 KB

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