d_test_stubs.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  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. #ifndef D_TEST_STUBS_H
  7. #define D_TEST_STUBS_H
  8. #include <asiolink/io_service.h>
  9. #include <cc/data.h>
  10. #include <cc/command_interpreter.h>
  11. #include <log/logger_support.h>
  12. #include <process/d_controller.h>
  13. #include <process/d_cfg_mgr.h>
  14. #include <boost/date_time/posix_time/posix_time.hpp>
  15. using namespace boost::posix_time;
  16. #include <gtest/gtest.h>
  17. #include <fstream>
  18. #include <iostream>
  19. #include <sstream>
  20. namespace isc {
  21. namespace process {
  22. /// @brief Class is used to set a globally accessible value that indicates
  23. /// a specific type of failure to simulate. Test derivations of base classes
  24. /// can exercise error handling code paths by testing for specific SimFailure
  25. /// values at the appropriate places and then causing the error to "occur".
  26. /// The class consists of an enumerated set of failures, and static methods
  27. /// for getting, setting, and testing the current value.
  28. class SimFailure {
  29. public:
  30. enum FailureType {
  31. ftUnknown = -1,
  32. ftNoFailure = 0,
  33. ftCreateProcessException,
  34. ftCreateProcessNull,
  35. ftProcessInit,
  36. ftProcessConfigure,
  37. ftControllerCommand,
  38. ftProcessCommand,
  39. ftProcessShutdown,
  40. ftElementBuild,
  41. ftElementCommit,
  42. ftElementUnknown
  43. };
  44. /// @brief Sets the SimFailure value to the given value.
  45. ///
  46. /// @param value is the new value to assign to the global value.
  47. static void set(enum FailureType value) {
  48. failure_type_ = value;
  49. }
  50. /// @brief Gets the current global SimFailure value
  51. ///
  52. /// @return returns the current SimFailure value
  53. static enum FailureType get() {
  54. return (failure_type_);
  55. }
  56. /// @brief One-shot test of the SimFailure value. If the global
  57. /// SimFailure value is equal to the given value, clear the global
  58. /// value and return true. This makes it convenient for code to
  59. /// test and react without having to explicitly clear the global
  60. /// value.
  61. ///
  62. /// @param value is the value against which the global value is
  63. /// to be compared.
  64. ///
  65. /// @return returns true if current SimFailure value matches the
  66. /// given value.
  67. static bool shouldFailOn(enum FailureType value) {
  68. if (failure_type_ == value) {
  69. clear();
  70. return (true);
  71. }
  72. return (false);
  73. }
  74. /// @brief Resets the failure type to none.
  75. static void clear() {
  76. failure_type_ = ftNoFailure;
  77. }
  78. /// @brief Static value for holding the failure type to simulate.
  79. static enum FailureType failure_type_;
  80. };
  81. /// @brief Test Derivation of the DProcessBase class.
  82. ///
  83. /// This class is used primarily to server as a test process class for testing
  84. /// DControllerBase. It provides minimal, but sufficient implementation to
  85. /// test the majority of DControllerBase functionality.
  86. class DStubProcess : public DProcessBase {
  87. public:
  88. /// @brief Static constant that defines a custom process command string.
  89. static const char* stub_proc_command_;
  90. /// @brief Constructor
  91. ///
  92. /// @param name name is a text label for the process. Generally used
  93. /// in log statements, but otherwise arbitrary.
  94. /// @param io_service is the io_service used by the caller for
  95. /// asynchronous event handling.
  96. ///
  97. /// @throw DProcessBaseError is io_service is NULL.
  98. DStubProcess(const char* name, asiolink::IOServicePtr io_service);
  99. /// @brief Invoked after process instantiation to perform initialization.
  100. /// This implementation supports simulating an error initializing the
  101. /// process by throwing a DProcessBaseError if SimFailure is set to
  102. /// ftProcessInit.
  103. virtual void init();
  104. /// @brief Implements the process's event loop.
  105. /// This implementation is quite basic, surrounding calls to
  106. /// io_service->runOne() with a test of the shutdown flag. Once invoked,
  107. /// the method will continue until the process itself is exiting due to a
  108. /// request to shutdown or some anomaly forces an exit.
  109. /// @return returns 0 upon a successful, "normal" termination, non-zero to
  110. /// indicate an abnormal termination.
  111. virtual void run();
  112. /// @brief Implements the process shutdown procedure.
  113. ///
  114. /// This sets the instance shutdown flag monitored by run() and stops
  115. /// the IO service.
  116. virtual isc::data::ConstElementPtr shutdown(isc::data::ConstElementPtr);
  117. /// @brief Processes the given configuration.
  118. ///
  119. /// This implementation fails if SimFailure is set to ftProcessConfigure.
  120. /// Otherwise it will complete successfully. It does not check the content
  121. /// of the inbound configuration.
  122. ///
  123. /// @param config_set a new configuration (JSON) for the process
  124. /// @param check_only true if configuration is to be verified only, not applied
  125. /// @return an Element that contains the results of configuration composed
  126. /// of an integer status value (0 means successful, non-zero means failure),
  127. /// and a string explanation of the outcome.
  128. virtual isc::data::ConstElementPtr
  129. configure(isc::data::ConstElementPtr config_set, bool check_only);
  130. /// @brief Executes the given command.
  131. ///
  132. /// This implementation will recognizes one "custom" process command,
  133. /// stub_proc_command_. It will fail if SimFailure is set to
  134. /// ftProcessCommand.
  135. ///
  136. /// @param command is a string label representing the command to execute.
  137. /// @param args is a set of arguments (if any) required for the given
  138. /// command.
  139. /// @return an Element that contains the results of command composed
  140. /// of an integer status value and a string explanation of the outcome.
  141. /// The status value is:
  142. /// COMMAND_SUCCESS if the command is recognized and executes successfully.
  143. /// COMMAND_ERROR if the command is recognized but fails to execute.
  144. /// COMMAND_INVALID if the command is not recognized.
  145. virtual isc::data::ConstElementPtr command(const std::string& command,
  146. isc::data::ConstElementPtr args);
  147. /// @brief Returns configuration summary in the textual format.
  148. ///
  149. /// @return Always an empty string.
  150. virtual std::string getConfigSummary(const uint32_t) {
  151. return ("");
  152. }
  153. // @brief Destructor
  154. virtual ~DStubProcess();
  155. };
  156. /// @brief Test Derivation of the DControllerBase class.
  157. ///
  158. /// DControllerBase is an abstract class and therefore requires a derivation
  159. /// for testing. It allows testing the majority of the base class code
  160. /// without polluting production derivations (e.g. D2Process). It uses
  161. /// DStubProcess as its application process class. It is a full enough
  162. /// implementation to support running both stand alone and integrated.
  163. class DStubController : public DControllerBase {
  164. public:
  165. /// @brief Static singleton instance method. This method returns the
  166. /// base class singleton instance member. It instantiates the singleton
  167. /// and sets the base class instance member upon first invocation.
  168. ///
  169. /// @return returns a pointer reference to the singleton instance.
  170. static DControllerBasePtr& instance();
  171. /// @brief Defines a custom controller command string. This is a
  172. /// custom command supported by DStubController.
  173. static const char* stub_ctl_command_;
  174. /// @brief Defines a custom command line option supported by
  175. /// DStubController.
  176. static const char* stub_option_x_;
  177. /// @brief Defines the app name used to construct the controller
  178. static const char* stub_app_name_;
  179. /// @brief Defines the executable name used to construct the controller
  180. static const char* stub_bin_name_;
  181. /// @brief Gets the list of signals that have been caught and processed.
  182. std::vector<int>& getProcessedSignals() {
  183. return (processed_signals_);
  184. }
  185. /// @brief Controls whether signals are processed in full or merely
  186. /// recorded.
  187. ///
  188. /// If true, signal handling will stop after recording the signal.
  189. /// Otherwise the base class signal handler,
  190. /// DControllerBase::processSignals will also be invoked. This switch is
  191. /// useful for ensuring that IOSignals are delivered as expected without
  192. /// incurring the full impact such as reconfiguring or shutting down.
  193. ///
  194. /// @param value boolean which if true enables record-only behavior
  195. void recordSignalOnly(bool value) {
  196. record_signal_only_ = value;
  197. }
  198. /// @brief Determines if parseFile() implementation is used
  199. ///
  200. /// If true, parseFile() will return a Map of elements with fixed content,
  201. /// mimicking a controller which is using alternate JSON parsing.
  202. /// If false, parseFile() will return an empty pointer mimicking a
  203. /// controller which is using original JSON parsing supplied by the
  204. /// Element class.
  205. ///
  206. /// @param value boolean which if true enables record-only behavior
  207. void useAlternateParser(bool value) {
  208. use_alternate_parser_ = value;
  209. }
  210. protected:
  211. /// @brief Handles additional command line options that are supported
  212. /// by DStubController. This implementation supports an option "-x".
  213. ///
  214. /// @param option is the option "character" from the command line, without
  215. /// any prefixing hyphen(s)
  216. /// @optarg optarg is the argument value (if one) associated with the option
  217. ///
  218. /// @return returns true if the option is "x", otherwise ti returns false.
  219. virtual bool customOption(int option, char *optarg);
  220. /// @brief Instantiates an instance of DStubProcess.
  221. ///
  222. /// This implementation will fail if SimFailure is set to
  223. /// ftCreateProcessException OR ftCreateProcessNull.
  224. ///
  225. /// @return returns a pointer to the new process instance (DProcessBase*)
  226. /// or NULL if SimFailure is set to ftCreateProcessNull.
  227. /// @throw throws std::runtime_error if SimFailure is set to
  228. /// ftCreateProcessException.
  229. virtual DProcessBase* createProcess();
  230. /// @brief Executes custom controller commands are supported by
  231. /// DStubController. This implementation supports one custom controller
  232. /// command, stub_ctl_command_. It will fail if SimFailure is set
  233. /// to ftControllerCommand.
  234. ///
  235. /// @param command is a string label representing the command to execute.
  236. /// @param args is a set of arguments (if any) required for the given
  237. /// command.
  238. /// @return an Element that contains the results of command composed
  239. /// of an integer status value and a string explanation of the outcome.
  240. /// The status value is:
  241. /// COMMAND_SUCCESS if the command is recognized and executes successfully.
  242. /// COMMAND_ERROR if the command is recognized but fails to execute.
  243. /// COMMAND_INVALID if the command is not recognized.
  244. virtual isc::data::ConstElementPtr customControllerCommand(
  245. const std::string& command, isc::data::ConstElementPtr args);
  246. /// @brief Provides a string of the additional command line options
  247. /// supported by DStubController. DStubController supports one
  248. /// addition option, stub_option_x_.
  249. ///
  250. /// @return returns a string containing the option letters.
  251. virtual const std::string getCustomOpts() const;
  252. /// @brief Application-level "signal handler"
  253. ///
  254. /// Overrides the base class implementation such that this method
  255. /// is invoked each time an IOSignal is processed. It records the
  256. /// signal received and unless we are in record-only behavior, it
  257. /// in invokes the base class implementation.
  258. ///
  259. /// @param signum OS signal value received
  260. virtual void processSignal(int signum);
  261. /// @brief Provides alternate parse file implementation
  262. ///
  263. /// Overrides the base class implementation to mimick controllers which
  264. /// implement alternate file parsing. If enabled via useAlternateParser()
  265. /// the method will return a fixed map of elements reflecting the following
  266. /// JSON:
  267. ///
  268. /// @code
  269. /// { "<name>getController()->getAppName()" :
  270. /// { "string_test": "alt value" };
  271. /// }
  272. ///
  273. /// @endcode
  274. ///
  275. /// where <name> is getController()->getAppName()
  276. ///
  277. /// otherwise it return an empty pointer.
  278. virtual isc::data::ConstElementPtr parseFile(const std::string&);
  279. private:
  280. /// @brief Constructor is private to protect singleton integrity.
  281. DStubController();
  282. /// @brief Vector to record the signal values received.
  283. std::vector<int> processed_signals_;
  284. /// @brief Boolean for controlling if signals are merely recorded.
  285. bool record_signal_only_;
  286. /// @brief Boolean for controlling if parseFile is "implemented"
  287. bool use_alternate_parser_;
  288. public:
  289. virtual ~DStubController();
  290. };
  291. /// @brief Defines a pointer to a DStubController.
  292. typedef boost::shared_ptr<DStubController> DStubControllerPtr;
  293. /// @brief Abstract Test fixture class that wraps a DControllerBase. This class
  294. /// is a friend class of DControllerBase which allows it access to class
  295. /// content to facilitate testing. It provides numerous wrapper methods for
  296. /// the protected and private methods and member of the base class.
  297. class DControllerTest : public ::testing::Test {
  298. public:
  299. /// @brief Defines a function pointer for controller singleton fetchers.
  300. typedef DControllerBasePtr& (*InstanceGetter)();
  301. /// @brief Static storage of the controller class's singleton fetcher.
  302. /// We need this this statically available for callbacks.
  303. static InstanceGetter instanceGetter_;
  304. /// @brief Constructor
  305. ///
  306. /// @param instance_getter is a function pointer to the static instance
  307. /// method of the DControllerBase derivation under test.
  308. DControllerTest(InstanceGetter instance_getter)
  309. : write_timer_(), new_cfg_content_() {
  310. // Set the static fetcher member, then invoke it via getController.
  311. // This ensures the singleton is instantiated.
  312. instanceGetter_ = instance_getter;
  313. getController();
  314. }
  315. /// @brief Destructor
  316. /// Note the controller singleton is destroyed. This is essential to ensure
  317. /// a clean start between tests.
  318. virtual ~DControllerTest() {
  319. // Some unit tests update the logging configuration which has a side
  320. // effect that all subsequent tests print the output to stdout. This
  321. // is to ensure that the logging settings are back to default.
  322. isc::log::setDefaultLoggingOutput();
  323. if (write_timer_) {
  324. write_timer_->cancel();
  325. }
  326. getController().reset();
  327. static_cast<void>(remove(CFG_TEST_FILE));
  328. }
  329. /// @brief Convenience method that destructs and then recreates the
  330. /// controller singleton under test. This is handy for tests within
  331. /// tests.
  332. void resetController() {
  333. getController().reset();
  334. getController();
  335. }
  336. /// @brief Static method which returns the instance of the controller
  337. /// under test.
  338. /// @return returns a reference to the controller instance.
  339. static DControllerBasePtr& getController() {
  340. return ((*instanceGetter_)());
  341. }
  342. /// @brief Returns true if the Controller's app name matches the
  343. /// given value.
  344. ///
  345. /// @param should_be is the value to compare against.
  346. ///
  347. /// @return returns true if the values are equal.
  348. bool checkAppName(const std::string& should_be) {
  349. return (getController()->getAppName().compare(should_be) == 0);
  350. }
  351. /// @brief Returns true if the Controller's service name matches the
  352. /// given value.
  353. ///
  354. /// @param should_be is the value to compare against.
  355. ///
  356. /// @return returns true if the values are equal.
  357. bool checkBinName(const std::string& should_be) {
  358. return (getController()->getBinName().compare(should_be) == 0);
  359. }
  360. /// @brief Returns true if the Controller's spec file name matches the
  361. /// given value.
  362. ///
  363. /// @param should_be is the value to compare against.
  364. ///
  365. /// @return returns true if the values are equal.
  366. bool checkSpecFileName(const std::string& should_be) {
  367. return (getController()->getSpecFileName().compare(should_be) == 0);
  368. }
  369. /// @brief Tests the existence of the Controller's application process.
  370. ///
  371. /// @return returns true if the process instance exists.
  372. bool checkProcess() {
  373. return (getController()->process_.get() != 0);
  374. }
  375. /// @brief Tests the existence of the Controller's IOService.
  376. ///
  377. /// @return returns true if the IOService exists.
  378. bool checkIOService() {
  379. return (getController()->io_service_.get() != 0);
  380. }
  381. /// @brief Gets the Controller's IOService.
  382. ///
  383. /// @return returns a reference to the IOService
  384. asiolink::IOServicePtr& getIOService() {
  385. return (getController()->io_service_);
  386. }
  387. /// @brief Compares verbose flag with the given value.
  388. ///
  389. /// @param value
  390. ///
  391. /// @return returns true if the verbose flag is equal to the given value.
  392. bool checkVerbose(bool value) {
  393. return (getController()->isVerbose() == value);
  394. }
  395. /// @brief Compares configuration file name with the given value.
  396. ///
  397. /// @param value file name to compare against
  398. ///
  399. /// @return returns true if the verbose flag is equal to the given value.
  400. bool checkConfigFileName(const std::string& value) {
  401. return (getController()->getConfigFile() == value);
  402. }
  403. /// @Wrapper to invoke the Controller's parseArgs method. Please refer to
  404. /// DControllerBase::parseArgs for details.
  405. void parseArgs(int argc, char* argv[]) {
  406. getController()->parseArgs(argc, argv);
  407. }
  408. /// @Wrapper to invoke the Controller's init method. Please refer to
  409. /// DControllerBase::init for details.
  410. void initProcess() {
  411. getController()->initProcess();
  412. }
  413. /// @Wrapper to invoke the Controller's launch method. Please refer to
  414. /// DControllerBase::launch for details.
  415. void launch(int argc, char* argv[]) {
  416. optind = 1;
  417. getController()->launch(argc, argv, true);
  418. }
  419. /// @Wrapper to invoke the Controller's updateConfig method. Please
  420. /// refer to DControllerBase::updateConfig for details.
  421. isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
  422. new_config) {
  423. return (getController()->updateConfig(new_config));
  424. }
  425. /// @Wrapper to invoke the Controller's checkConfig method. Please
  426. /// refer to DControllerBase::checkConfig for details.
  427. isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr
  428. new_config) {
  429. return (getController()->checkConfig(new_config));
  430. }
  431. /// @Wrapper to invoke the Controller's executeCommand method. Please
  432. /// refer to DControllerBase::executeCommand for details.
  433. isc::data::ConstElementPtr executeCommand(const std::string& command,
  434. isc::data::ConstElementPtr args){
  435. return (getController()->executeCommand(command, args));
  436. }
  437. /// @brief Callback that will generate shutdown command via the
  438. /// command callback function.
  439. static void genShutdownCallback() {
  440. isc::data::ElementPtr arg_set;
  441. getController()->executeCommand(SHUT_DOWN_COMMAND, arg_set);
  442. }
  443. /// @brief Callback that throws an exception.
  444. static void genFatalErrorCallback() {
  445. isc_throw (DProcessBaseError, "simulated fatal error");
  446. }
  447. /// @brief writes specified content to a well known file
  448. ///
  449. /// Writes given JSON content to CFG_TEST_FILE. It will wrap the
  450. /// content within a JSON element whose name is equal to the controller's
  451. /// app name or the given module name if not blank:
  452. ///
  453. /// @code
  454. /// { "<app_name>" : <content> }
  455. /// @endcode
  456. ///
  457. /// suffix the content within a JSON element with the given module
  458. /// name or wrapped by a JSON
  459. /// element . Tests will
  460. /// attempt to read that file.
  461. ///
  462. /// @param content JSON text to be written to file
  463. /// @param module_name content content to be written to file
  464. void writeFile(const std::string& content,
  465. const std::string& module_name = "");
  466. /// @brief Method used as timer callback to invoke writeFile.
  467. ///
  468. /// Wraps a call to writeFile passing in new_cfg_content_. This allows
  469. /// the method to be bound as an IntervalTimer callback.
  470. virtual void timedWriteCallback();
  471. /// @brief Schedules the given content to overwrite the config file.
  472. ///
  473. /// Creates a one-shot IntervalTimer whose callback will overwrite the
  474. /// configuration with the given content. This allows the configuration
  475. /// file to replaced write_time_ms after DControllerBase::launch() has
  476. /// invoked runProcess().
  477. ///
  478. /// @param config JSON string containing the desired content for the config
  479. /// file.
  480. /// @param write_time_ms time in milliseconds to delay before writing the
  481. /// file.
  482. void scheduleTimedWrite(const std::string& config, int write_time_ms);
  483. /// @brief Convenience method for invoking standard, valid launch
  484. ///
  485. /// This method sets up a timed run of the DController::launch. It does
  486. /// the following:
  487. /// - It creates command line argument variables argc/argv
  488. /// - Invokes writeFile to create the config file with the given content
  489. /// - Schedules a shutdown time timer to call DController::executeShutdown
  490. /// after the interval
  491. /// - Records the start time
  492. /// - Invokes DController::launch() with the command line arguments
  493. /// - After launch returns, it calculates the elapsed time and returns it
  494. ///
  495. /// @param config configuration file content to write before calling launch
  496. /// @param run_time_ms maximum amount of time to allow runProcess() to
  497. /// continue.
  498. /// @param[out] elapsed_time the actual time in ms spent in launch().
  499. void runWithConfig(const std::string& config, int run_time_ms,
  500. time_duration& elapsed_time);
  501. /// @brief Fetches the controller's process
  502. ///
  503. /// @return A pointer to the process which may be null if it has not yet
  504. /// been instantiated.
  505. DProcessBasePtr getProcess();
  506. /// @brief Fetches the process's configuration manager
  507. ///
  508. /// @return A pointer to the manager which may be null if it has not yet
  509. /// been instantiated.
  510. DCfgMgrBasePtr getCfgMgr();
  511. /// @brief Fetches the configuration manager's context
  512. ///
  513. /// @return A pointer to the context which may be null if it has not yet
  514. /// been instantiated.
  515. DCfgContextBasePtr getContext();
  516. /// @brief Timer used for delayed configuration file writing.
  517. asiolink::IntervalTimerPtr write_timer_;
  518. /// @brief String which contains the content delayed file writing will use.
  519. std::string new_cfg_content_;
  520. /// @brief Name of a config file used during tests
  521. static const char* CFG_TEST_FILE;
  522. };
  523. /// @brief a collection of elements that store uint32 values
  524. typedef isc::dhcp::ValueStorage<isc::data::ConstElementPtr> ObjectStorage;
  525. typedef boost::shared_ptr<ObjectStorage> ObjectStoragePtr;
  526. /// @brief Test Derivation of the DCfgContextBase class.
  527. ///
  528. /// This class is used to test basic functionality of configuration context.
  529. /// It adds an additional storage container "extra values" to mimic an
  530. /// application extension of configuration storage. This permits testing that
  531. /// both the base class content as well as the application content is
  532. /// correctly copied during cloning. This is vital to configuration backup
  533. /// and rollback during configuration parsing.
  534. class DStubContext : public DCfgContextBase {
  535. public:
  536. /// @brief Constructor
  537. DStubContext();
  538. /// @brief Destructor
  539. virtual ~DStubContext();
  540. /// @brief Creates a clone of a DStubContext.
  541. ///
  542. /// @return returns a pointer to the new clone.
  543. virtual DCfgContextBasePtr clone();
  544. /// @brief Fetches the value for a given "extra" configuration parameter
  545. /// from the context.
  546. ///
  547. /// @param name is the name of the parameter to retrieve.
  548. /// @param value is an output parameter in which to return the retrieved
  549. /// value.
  550. /// @throw throws DhcpConfigError if the context does not contain the
  551. /// parameter.
  552. void getObjectParam(const std::string& name,
  553. isc::data::ConstElementPtr& value);
  554. ObjectStoragePtr& getObjectStorage();
  555. protected:
  556. /// @brief Copy constructor
  557. DStubContext(const DStubContext& rhs);
  558. private:
  559. /// @brief Private assignment operator, not implemented.
  560. DStubContext& operator=(const DStubContext& rhs);
  561. /// @brief Stores non-scalar configuration elements
  562. ObjectStoragePtr object_values_;
  563. /// @brief Unparse a configuration object
  564. ///
  565. /// @return a pointer to a configuration
  566. virtual isc::data::ElementPtr toElement() const;
  567. };
  568. /// @brief Defines a pointer to DStubContext.
  569. typedef boost::shared_ptr<DStubContext> DStubContextPtr;
  570. /// @brief Test Derivation of the DCfgMgrBase class.
  571. ///
  572. /// This class is used to test basic functionality of configuration management.
  573. /// It supports the following configuration elements:
  574. ///
  575. /// "bool_test" - Boolean element, tests parsing and committing a boolean
  576. /// configuration parameter.
  577. /// "uint32_test" - Uint32 element, tests parsing and committing a uint32_t
  578. /// configuration parameter.
  579. /// "string_test" - String element, tests parsing and committing a string
  580. /// configuration parameter.
  581. /// "extra_test" - "Extra" element, tests parsing and committing an extra
  582. /// configuration parameter. (This is used to demonstrate
  583. /// derivation's addition of storage to configuration context.
  584. ///
  585. /// It also keeps track of the element ids that are parsed in the order they
  586. /// are parsed. This is used to test ordered and non-ordered parsing.
  587. class DStubCfgMgr : public DCfgMgrBase {
  588. public:
  589. /// @brief Constructor
  590. DStubCfgMgr();
  591. /// @brief Destructor
  592. virtual ~DStubCfgMgr();
  593. /// @brief Parses the given element into the appropriate object
  594. ///
  595. /// The method supports three named elements:
  596. ///
  597. /// -# "bool_test"
  598. /// -# "uint32_test"
  599. /// -# "string_test"
  600. ///
  601. /// which are parsed and whose value is then stored in the
  602. /// the appropriate context value store.
  603. ///
  604. /// Any other element_id is treated generically and stored
  605. /// in the context's object store, unless the simulated
  606. /// error has been set to SimFailure::ftElementUnknown.
  607. ///
  608. /// @param element_id name of the element to parse
  609. /// @param element Element to parse
  610. ///
  611. /// @throw DCfgMgrBaseError if simulated error is set
  612. /// to ftElementUnknown and element_id is not one of
  613. /// the named elements.
  614. virtual void parseElement(const std::string& element_id,
  615. isc::data::ConstElementPtr element);
  616. /// @brief Pretends to parse the config
  617. ///
  618. /// This method pretends to parse the configuration specified on input
  619. /// and returns a positive answer. The check_only flag is currently ignored.
  620. ///
  621. /// @param config configuration specified
  622. /// @param check_only whether it's real configuration (false) or just
  623. /// configuration check (true)
  624. /// @return always positive answer
  625. ///
  626. isc::data::ConstElementPtr
  627. parse(isc::data::ConstElementPtr config, bool check_only);
  628. /// @brief Returns a summary of the configuration in the textual format.
  629. ///
  630. /// @return Always an empty string.
  631. virtual std::string getConfigSummary(const uint32_t) {
  632. return ("");
  633. }
  634. /// @brief A list for remembering the element ids in the order they were
  635. /// parsed.
  636. ElementIdList parsed_order_;
  637. /// @todo
  638. virtual DCfgContextBasePtr createNewContext();
  639. };
  640. /// @brief Defines a pointer to DStubCfgMgr.
  641. typedef boost::shared_ptr<DStubCfgMgr> DStubCfgMgrPtr;
  642. /// @brief Test fixture base class for any fixtures which test parsing.
  643. /// It provides methods for converting JSON strings to configuration element
  644. /// sets and checking parse results
  645. class ConfigParseTest : public ::testing::Test {
  646. public:
  647. /// @brief Constructor
  648. ConfigParseTest(){
  649. }
  650. /// @brief Destructor
  651. ~ConfigParseTest() {
  652. }
  653. /// @brief Converts a given JSON string into an Element set and stores the
  654. /// result the member variable, config_set_.
  655. ///
  656. /// @param json_text contains the configuration text in JSON format to
  657. /// convert.
  658. /// @return returns AssertionSuccess if there were no parsing errors,
  659. /// AssertionFailure otherwise.
  660. ::testing::AssertionResult fromJSON(const std::string& json_text) {
  661. try {
  662. config_set_ = isc::data::Element::fromJSON(json_text);
  663. } catch (const isc::Exception &ex) {
  664. return (::testing::AssertionFailure(::testing::Message() <<
  665. "JSON text failed to parse:"
  666. << ex.what()));
  667. }
  668. return (::testing::AssertionSuccess());
  669. }
  670. /// @brief Compares the status in the parse result stored in member
  671. /// variable answer_ to a given value.
  672. ///
  673. /// @param should_be is an integer against which to compare the status.
  674. ///
  675. /// @return returns AssertionSuccess if there were no parsing errors,
  676. /// AssertionFailure otherwise.
  677. ::testing::AssertionResult checkAnswer(int should_be) {
  678. return (checkAnswer(answer_, should_be));
  679. }
  680. /// @brief Compares the status in the given parse result to a given value.
  681. ///
  682. /// @param answer Element set containing an integer response and string
  683. /// comment.
  684. /// @param should_be is an integer against which to compare the status.
  685. ///
  686. /// @return returns AssertionSuccess if there were no parsing errors,
  687. /// AssertionFailure otherwise.
  688. ::testing::AssertionResult checkAnswer(isc::data::ConstElementPtr answer,
  689. int should_be) {
  690. int rcode = 0;
  691. isc::data::ConstElementPtr comment;
  692. comment = isc::config::parseAnswer(rcode, answer);
  693. if (rcode == should_be) {
  694. return (testing::AssertionSuccess());
  695. }
  696. return (::testing::AssertionFailure(::testing::Message() <<
  697. "checkAnswer rcode:" << rcode
  698. << " comment: " << *comment));
  699. }
  700. /// @brief Configuration set being tested.
  701. isc::data::ElementPtr config_set_;
  702. /// @brief Results of most recent element parsing.
  703. isc::data::ConstElementPtr answer_;
  704. };
  705. /// @brief Implements a time-delayed signal
  706. ///
  707. /// Given an IOService, a signal number, and a time period, this class will
  708. /// send (raise) the signal to the current process.
  709. class TimedSignal {
  710. public:
  711. /// @brief Constructor
  712. ///
  713. /// @param io_service IOService to run the timer
  714. /// @param signum OS signal value (e.g. SIGHUP, SIGUSR1 ...)
  715. /// @param milliseconds time in milliseconds to wait until the signal is
  716. /// raised.
  717. /// @param mode selects between a one-shot signal or a signal which repeats
  718. /// at "milliseconds" interval.
  719. TimedSignal(asiolink::IOService& io_service, int signum, int milliseconds,
  720. const asiolink::IntervalTimer::Mode& mode =
  721. asiolink::IntervalTimer::ONE_SHOT)
  722. : timer_(new asiolink::IntervalTimer(io_service)) {
  723. timer_->setup(SendSignalCallback(signum), milliseconds, mode);
  724. }
  725. /// @brief Cancels the given timer.
  726. void cancel() {
  727. if (timer_) {
  728. timer_->cancel();
  729. }
  730. }
  731. /// @brief Destructor.
  732. ~TimedSignal() {
  733. cancel();
  734. }
  735. /// @brief Callback for the TimeSignal's internal timer.
  736. class SendSignalCallback: public std::unary_function<void, void> {
  737. public:
  738. /// @brief Constructor
  739. ///
  740. /// @param signum OS signal value of the signal to send
  741. SendSignalCallback(int signum) : signum_(signum) {
  742. }
  743. /// @brief Callback method invoked when the timer expires
  744. ///
  745. /// Calls raise with the given signal which should generate that
  746. /// signal to the given process.
  747. void operator()() {
  748. ASSERT_EQ(0, raise(signum_));
  749. return;
  750. }
  751. private:
  752. /// @brief Stores the OS signal value to send.
  753. int signum_;
  754. };
  755. private:
  756. /// @brief Timer which controls when the signal is sent.
  757. asiolink::IntervalTimerPtr timer_;
  758. };
  759. }; // namespace isc::process
  760. }; // namespace isc
  761. #endif