d_test_stubs.h 32 KB

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