d_test_stubs.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  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
  422. updateConfig(isc::data::ConstElementPtr new_config,
  423. bool check_only) {
  424. return (getController()->updateConfig(new_config, check_only));
  425. }
  426. /// @Wrapper to invoke the Controller's executeCommand method. Please
  427. /// refer to DControllerBase::executeCommand for details.
  428. isc::data::ConstElementPtr executeCommand(const std::string& command,
  429. isc::data::ConstElementPtr args){
  430. return (getController()->executeCommand(command, args));
  431. }
  432. /// @brief Callback that will generate shutdown command via the
  433. /// command callback function.
  434. static void genShutdownCallback() {
  435. isc::data::ElementPtr arg_set;
  436. getController()->executeCommand(SHUT_DOWN_COMMAND, arg_set);
  437. }
  438. /// @brief Callback that throws an exception.
  439. static void genFatalErrorCallback() {
  440. isc_throw (DProcessBaseError, "simulated fatal error");
  441. }
  442. /// @brief writes specified content to a well known file
  443. ///
  444. /// Writes given JSON content to CFG_TEST_FILE. It will wrap the
  445. /// content within a JSON element whose name is equal to the controller's
  446. /// app name or the given module name if not blank:
  447. ///
  448. /// @code
  449. /// { "<app_name>" : <content> }
  450. /// @endcode
  451. ///
  452. /// suffix the content within a JSON element with the given module
  453. /// name or wrapped by a JSON
  454. /// element . Tests will
  455. /// attempt to read that file.
  456. ///
  457. /// @param content JSON text to be written to file
  458. /// @param module_name content content to be written to file
  459. void writeFile(const std::string& content,
  460. const std::string& module_name = "");
  461. /// @brief Method used as timer callback to invoke writeFile.
  462. ///
  463. /// Wraps a call to writeFile passing in new_cfg_content_. This allows
  464. /// the method to be bound as an IntervalTimer callback.
  465. virtual void timedWriteCallback();
  466. /// @brief Schedules the given content to overwrite the config file.
  467. ///
  468. /// Creates a one-shot IntervalTimer whose callback will overwrite the
  469. /// configuration with the given content. This allows the configuration
  470. /// file to replaced write_time_ms after DControllerBase::launch() has
  471. /// invoked runProcess().
  472. ///
  473. /// @param config JSON string containing the desired content for the config
  474. /// file.
  475. /// @param write_time_ms time in milliseconds to delay before writing the
  476. /// file.
  477. void scheduleTimedWrite(const std::string& config, int write_time_ms);
  478. /// @brief Convenience method for invoking standard, valid launch
  479. ///
  480. /// This method sets up a timed run of the DController::launch. It does
  481. /// the following:
  482. /// - It creates command line argument variables argc/argv
  483. /// - Invokes writeFile to create the config file with the given content
  484. /// - Schedules a shutdown time timer to call DController::executeShutdown
  485. /// after the interval
  486. /// - Records the start time
  487. /// - Invokes DController::launch() with the command line arguments
  488. /// - After launch returns, it calculates the elapsed time and returns it
  489. ///
  490. /// @param config configuration file content to write before calling launch
  491. /// @param run_time_ms maximum amount of time to allow runProcess() to
  492. /// continue.
  493. /// @param[out] elapsed_time the actual time in ms spent in launch().
  494. void runWithConfig(const std::string& config, int run_time_ms,
  495. time_duration& elapsed_time);
  496. /// @brief Fetches the controller's process
  497. ///
  498. /// @return A pointer to the process which may be null if it has not yet
  499. /// been instantiated.
  500. DProcessBasePtr getProcess();
  501. /// @brief Fetches the process's configuration manager
  502. ///
  503. /// @return A pointer to the manager which may be null if it has not yet
  504. /// been instantiated.
  505. DCfgMgrBasePtr getCfgMgr();
  506. /// @brief Fetches the configuration manager's context
  507. ///
  508. /// @return A pointer to the context which may be null if it has not yet
  509. /// been instantiated.
  510. DCfgContextBasePtr getContext();
  511. /// @brief Timer used for delayed configuration file writing.
  512. asiolink::IntervalTimerPtr write_timer_;
  513. /// @brief String which contains the content delayed file writing will use.
  514. std::string new_cfg_content_;
  515. /// @brief Name of a config file used during tests
  516. static const char* CFG_TEST_FILE;
  517. };
  518. /// @brief a collection of elements that store uint32 values
  519. typedef isc::dhcp::ValueStorage<isc::data::ConstElementPtr> ObjectStorage;
  520. typedef boost::shared_ptr<ObjectStorage> ObjectStoragePtr;
  521. /// @brief Test Derivation of the DCfgContextBase class.
  522. ///
  523. /// This class is used to test basic functionality of configuration context.
  524. /// It adds an additional storage container "extra values" to mimic an
  525. /// application extension of configuration storage. This permits testing that
  526. /// both the base class content as well as the application content is
  527. /// correctly copied during cloning. This is vital to configuration backup
  528. /// and rollback during configuration parsing.
  529. class DStubContext : public DCfgContextBase {
  530. public:
  531. /// @brief Constructor
  532. DStubContext();
  533. /// @brief Destructor
  534. virtual ~DStubContext();
  535. /// @brief Creates a clone of a DStubContext.
  536. ///
  537. /// @return returns a pointer to the new clone.
  538. virtual DCfgContextBasePtr clone();
  539. /// @brief Fetches the value for a given "extra" configuration parameter
  540. /// from the context.
  541. ///
  542. /// @param name is the name of the parameter to retrieve.
  543. /// @param value is an output parameter in which to return the retrieved
  544. /// value.
  545. /// @throw throws DhcpConfigError if the context does not contain the
  546. /// parameter.
  547. void getObjectParam(const std::string& name,
  548. isc::data::ConstElementPtr& value);
  549. ObjectStoragePtr& getObjectStorage();
  550. protected:
  551. /// @brief Copy constructor
  552. DStubContext(const DStubContext& rhs);
  553. private:
  554. /// @brief Private assignment operator, not implemented.
  555. DStubContext& operator=(const DStubContext& rhs);
  556. /// @brief Stores non-scalar configuration elements
  557. ObjectStoragePtr object_values_;
  558. /// @brief Unparse a configuration object
  559. ///
  560. /// @return a pointer to a configuration
  561. virtual isc::data::ElementPtr toElement() const;
  562. };
  563. /// @brief Defines a pointer to DStubContext.
  564. typedef boost::shared_ptr<DStubContext> DStubContextPtr;
  565. /// @brief Test Derivation of the DCfgMgrBase class.
  566. ///
  567. /// This class is used to test basic functionality of configuration management.
  568. /// It supports the following configuration elements:
  569. ///
  570. /// "bool_test" - Boolean element, tests parsing and committing a boolean
  571. /// configuration parameter.
  572. /// "uint32_test" - Uint32 element, tests parsing and committing a uint32_t
  573. /// configuration parameter.
  574. /// "string_test" - String element, tests parsing and committing a string
  575. /// configuration parameter.
  576. /// "extra_test" - "Extra" element, tests parsing and committing an extra
  577. /// configuration parameter. (This is used to demonstrate
  578. /// derivation's addition of storage to configuration context.
  579. ///
  580. /// It also keeps track of the element ids that are parsed in the order they
  581. /// are parsed. This is used to test ordered and non-ordered parsing.
  582. class DStubCfgMgr : public DCfgMgrBase {
  583. public:
  584. /// @brief Constructor
  585. DStubCfgMgr();
  586. /// @brief Destructor
  587. virtual ~DStubCfgMgr();
  588. /// @brief Parses the given element into the appropriate object
  589. ///
  590. /// The method supports three named elements:
  591. ///
  592. /// -# "bool_test"
  593. /// -# "uint32_test"
  594. /// -# "string_test"
  595. ///
  596. /// which are parsed and whose value is then stored in the
  597. /// the appropriate context value store.
  598. ///
  599. /// Any other element_id is treated generically and stored
  600. /// in the context's object store, unless the simulated
  601. /// error has been set to SimFailure::ftElementUnknown.
  602. ///
  603. /// @param element_id name of the element to parse
  604. /// @param element Element to parse
  605. ///
  606. /// @throw DCfgMgrBaseError if simulated error is set
  607. /// to ftElementUnknown and element_id is not one of
  608. /// the named elements.
  609. virtual void parseElement(const std::string& element_id,
  610. isc::data::ConstElementPtr element);
  611. /// @brief Pretends to parse the config
  612. ///
  613. /// This method pretends to parse the configuration specified on input
  614. /// and returns a positive answer. The check_only flag is currently ignored.
  615. ///
  616. /// @param config configuration specified
  617. /// @param check_only whether it's real configuration (false) or just
  618. /// configuration check (true)
  619. /// @return always positive answer
  620. ///
  621. isc::data::ConstElementPtr
  622. parse(isc::data::ConstElementPtr config, bool check_only);
  623. /// @brief Returns a summary of the configuration in the textual format.
  624. ///
  625. /// @return Always an empty string.
  626. virtual std::string getConfigSummary(const uint32_t) {
  627. return ("");
  628. }
  629. /// @brief A list for remembering the element ids in the order they were
  630. /// parsed.
  631. ElementIdList parsed_order_;
  632. /// @todo
  633. virtual DCfgContextBasePtr createNewContext();
  634. };
  635. /// @brief Defines a pointer to DStubCfgMgr.
  636. typedef boost::shared_ptr<DStubCfgMgr> DStubCfgMgrPtr;
  637. /// @brief Test fixture base class for any fixtures which test parsing.
  638. /// It provides methods for converting JSON strings to configuration element
  639. /// sets and checking parse results
  640. class ConfigParseTest : public ::testing::Test {
  641. public:
  642. /// @brief Constructor
  643. ConfigParseTest(){
  644. }
  645. /// @brief Destructor
  646. ~ConfigParseTest() {
  647. }
  648. /// @brief Converts a given JSON string into an Element set and stores the
  649. /// result the member variable, config_set_.
  650. ///
  651. /// @param json_text contains the configuration text in JSON format to
  652. /// convert.
  653. /// @return returns AssertionSuccess if there were no parsing errors,
  654. /// AssertionFailure otherwise.
  655. ::testing::AssertionResult fromJSON(const std::string& json_text) {
  656. try {
  657. config_set_ = isc::data::Element::fromJSON(json_text);
  658. } catch (const isc::Exception &ex) {
  659. return (::testing::AssertionFailure(::testing::Message() <<
  660. "JSON text failed to parse:"
  661. << ex.what()));
  662. }
  663. return (::testing::AssertionSuccess());
  664. }
  665. /// @brief Compares the status in the parse result stored in member
  666. /// variable answer_ to a given value.
  667. ///
  668. /// @param should_be is an integer against which to compare the status.
  669. ///
  670. /// @return returns AssertionSuccess if there were no parsing errors,
  671. /// AssertionFailure otherwise.
  672. ::testing::AssertionResult checkAnswer(int should_be) {
  673. return (checkAnswer(answer_, should_be));
  674. }
  675. /// @brief Compares the status in the given parse result to a given value.
  676. ///
  677. /// @param answer Element set containing an integer response and string
  678. /// comment.
  679. /// @param should_be is an integer against which to compare the status.
  680. ///
  681. /// @return returns AssertionSuccess if there were no parsing errors,
  682. /// AssertionFailure otherwise.
  683. ::testing::AssertionResult checkAnswer(isc::data::ConstElementPtr answer,
  684. int should_be) {
  685. int rcode = 0;
  686. isc::data::ConstElementPtr comment;
  687. comment = isc::config::parseAnswer(rcode, answer);
  688. if (rcode == should_be) {
  689. return (testing::AssertionSuccess());
  690. }
  691. return (::testing::AssertionFailure(::testing::Message() <<
  692. "checkAnswer rcode:" << rcode
  693. << " comment: " << *comment));
  694. }
  695. /// @brief Configuration set being tested.
  696. isc::data::ElementPtr config_set_;
  697. /// @brief Results of most recent element parsing.
  698. isc::data::ConstElementPtr answer_;
  699. };
  700. /// @brief Implements a time-delayed signal
  701. ///
  702. /// Given an IOService, a signal number, and a time period, this class will
  703. /// send (raise) the signal to the current process.
  704. class TimedSignal {
  705. public:
  706. /// @brief Constructor
  707. ///
  708. /// @param io_service IOService to run the timer
  709. /// @param signum OS signal value (e.g. SIGHUP, SIGUSR1 ...)
  710. /// @param milliseconds time in milliseconds to wait until the signal is
  711. /// raised.
  712. /// @param mode selects between a one-shot signal or a signal which repeats
  713. /// at "milliseconds" interval.
  714. TimedSignal(asiolink::IOService& io_service, int signum, int milliseconds,
  715. const asiolink::IntervalTimer::Mode& mode =
  716. asiolink::IntervalTimer::ONE_SHOT)
  717. : timer_(new asiolink::IntervalTimer(io_service)) {
  718. timer_->setup(SendSignalCallback(signum), milliseconds, mode);
  719. }
  720. /// @brief Cancels the given timer.
  721. void cancel() {
  722. if (timer_) {
  723. timer_->cancel();
  724. }
  725. }
  726. /// @brief Destructor.
  727. ~TimedSignal() {
  728. cancel();
  729. }
  730. /// @brief Callback for the TimeSignal's internal timer.
  731. class SendSignalCallback: public std::unary_function<void, void> {
  732. public:
  733. /// @brief Constructor
  734. ///
  735. /// @param signum OS signal value of the signal to send
  736. SendSignalCallback(int signum) : signum_(signum) {
  737. }
  738. /// @brief Callback method invoked when the timer expires
  739. ///
  740. /// Calls raise with the given signal which should generate that
  741. /// signal to the given process.
  742. void operator()() {
  743. ASSERT_EQ(0, raise(signum_));
  744. return;
  745. }
  746. private:
  747. /// @brief Stores the OS signal value to send.
  748. int signum_;
  749. };
  750. private:
  751. /// @brief Timer which controls when the signal is sent.
  752. asiolink::IntervalTimerPtr timer_;
  753. };
  754. }; // namespace isc::process
  755. }; // namespace isc
  756. #endif