d_test_stubs.h 32 KB

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