d_test_stubs.h 31.7 KB
Newer Older
1
// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 7 8 9

#ifndef D_TEST_STUBS_H
#define D_TEST_STUBS_H

10 11
#include <asiolink/io_service.h>

12
#include <cc/data.h>
13
#include <cc/command_interpreter.h>
14

15 16
#include <log/logger_support.h>

17 18 19
#include <process/d_controller.h>
#include <process/d_cfg_mgr.h>

20 21 22 23
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace boost::posix_time;

24 25
#include <gtest/gtest.h>

26 27 28 29
#include <fstream>
#include <iostream>
#include <sstream>

30
namespace isc {
31
namespace process {
32

33
/// @brief Provides a valid DHCP-DDNS configuration for testing basic
34 35 36 37
/// parsing fundamentals.
extern const char* valid_d2_config;


38
/// @brief Class is used to set a globally accessible value that indicates
39
/// a specific type of failure to simulate.  Test derivations of base classes
40
/// can exercise error handling code paths by testing for specific SimFailure
41 42 43 44
/// values at the appropriate places and then causing the error to "occur".
/// The class consists of an enumerated set of failures, and static methods
/// for getting, setting, and testing the current value.
class SimFailure {
45
public:
46
    enum FailureType {
47
        ftUnknown = -1,
48
        ftNoFailure = 0,
49
        ftCreateProcessException,
50 51 52 53
        ftCreateProcessNull,
        ftProcessInit,
        ftProcessConfigure,
        ftControllerCommand,
54
        ftProcessCommand,
55 56 57 58
        ftProcessShutdown,
        ftElementBuild,
        ftElementCommit,
        ftElementUnknown
59 60 61 62 63 64 65 66 67
    };

    /// @brief Sets the SimFailure value to the given value.
    ///
    /// @param value is the new value to assign to the global value.
    static void set(enum FailureType value) {
       failure_type_ = value;
    }

68
    /// @brief Gets the current global SimFailure value
69
    ///
70
    /// @return returns the current SimFailure value
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    static enum FailureType get() {
       return (failure_type_);
    }

    /// @brief One-shot test of the SimFailure value. If the global
    /// SimFailure value is equal to the given value, clear the global
    /// value and return true.  This makes it convenient for code to
    /// test and react without having to explicitly clear the global
    /// value.
    ///
    /// @param value is the value against which the global value is
    /// to be compared.
    ///
    /// @return returns true if current SimFailure value matches the
    /// given value.
    static bool shouldFailOn(enum FailureType value) {
        if (failure_type_ == value) {
            clear();
            return (true);
        }

        return (false);
    }

95
    /// @brief Resets the failure type to none.
96 97 98 99
    static void clear() {
       failure_type_ = ftNoFailure;
    }

100
    /// @brief Static value for holding the failure type to simulate.
101 102 103 104 105 106 107 108 109 110 111 112
    static enum FailureType failure_type_;
};

/// @brief Test Derivation of the DProcessBase class.
///
/// This class is used primarily to server as a test process class for testing
/// DControllerBase.  It provides minimal, but sufficient implementation to
/// test the majority of DControllerBase functionality.
class DStubProcess : public DProcessBase {
public:

    /// @brief Static constant that defines a custom process command string.
113
    static const char* stub_proc_command_;
114 115 116 117

    /// @brief Constructor
    ///
    /// @param name name is a text label for the process. Generally used
118
    /// in log statements, but otherwise arbitrary.
119 120 121
    /// @param io_service is the io_service used by the caller for
    /// asynchronous event handling.
    ///
122
    /// @throw DProcessBaseError is io_service is NULL.
123
    DStubProcess(const char* name, asiolink::IOServicePtr io_service);
124

125 126 127 128
    /// @brief Invoked after process instantiation to perform initialization.
    /// This implementation supports simulating an error initializing the
    /// process by throwing a DProcessBaseError if SimFailure is set to
    /// ftProcessInit.
129 130
    virtual void init();

131 132 133 134
    /// @brief Implements the process's event loop.
    /// This implementation is quite basic, surrounding calls to
    /// io_service->runOne() with a test of the shutdown flag. Once invoked,
    /// the method will continue until the process itself is exiting due to a
135 136
    /// request to shutdown or some anomaly forces an exit.
    /// @return  returns 0 upon a successful, "normal" termination, non-zero to
137 138
    /// indicate an abnormal termination.
    virtual void run();
139

140
    /// @brief Implements the process shutdown procedure.
141
    ///
142
    /// This sets the instance shutdown flag monitored by run()  and stops
143 144
    /// the IO service.
    virtual isc::data::ConstElementPtr shutdown(isc::data::ConstElementPtr);
145

146 147
    /// @brief Processes the given configuration.
    ///
148 149 150 151 152 153 154
    /// This implementation fails if SimFailure is set to ftProcessConfigure.
    /// Otherwise it will complete successfully.  It does not check the content
    /// of the inbound configuration.
    ///
    /// @param config_set a new configuration (JSON) for the process
    /// @return an Element that contains the results of configuration composed
    /// of an integer status value (0 means successful, non-zero means failure),
155
    /// and a string explanation of the outcome.
156 157 158
    virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr
                                                 config_set);

159 160
    /// @brief Executes the given command.
    ///
161
    /// This implementation will recognizes one "custom" process command,
162 163
    /// stub_proc_command_.  It will fail if SimFailure is set to
    /// ftProcessCommand.
164 165 166
    ///
    /// @param command is a string label representing the command to execute.
    /// @param args is a set of arguments (if any) required for the given
167
    /// command.
168
    /// @return an Element that contains the results of command composed
169
    /// of an integer status value and a string explanation of the outcome.
170
    /// The status value is:
171 172
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
173
    /// COMMAND_INVALID if the command is not recognized.
174
    virtual isc::data::ConstElementPtr command(const std::string& command,
175 176
                                               isc::data::ConstElementPtr args);

177 178 179
    /// @brief Returns configuration summary in the textual format.
    ///
    /// @return Always an empty string.
180
    virtual std::string getConfigSummary(const uint32_t) {
181 182 183
        return ("");
    }

184 185 186 187 188 189 190 191
    // @brief Destructor
    virtual ~DStubProcess();
};


/// @brief Test Derivation of the DControllerBase class.
///
/// DControllerBase is an abstract class and therefore requires a derivation
192 193 194 195
/// for testing.  It allows testing the majority of the base class code
/// without polluting production derivations (e.g. D2Process).  It uses
/// DStubProcess as its application process class.  It is a full enough
/// implementation to support running both stand alone and integrated.
196 197 198
class DStubController : public DControllerBase {
public:
    /// @brief Static singleton instance method. This method returns the
199 200
    /// base class singleton instance member.  It instantiates the singleton
    /// and sets the base class instance member upon first invocation.
201
    ///
202
    /// @return returns a pointer reference to the singleton instance.
203 204
    static DControllerBasePtr& instance();

205
    /// @brief Defines a custom controller command string. This is a
206
    /// custom command supported by DStubController.
207
    static const char* stub_ctl_command_;
208 209 210 211

    /// @brief Defines a custom command line option supported by
    /// DStubController.
    static const char* stub_option_x_;
212

213 214 215 216 217 218
    /// @brief Defines the app name used to construct the controller
    static const char* stub_app_name_;

    /// @brief Defines the executable name used to construct the controller
    static const char* stub_bin_name_;

219 220 221 222 223 224 225 226 227 228 229 230 231
    /// @brief Gets the list of signals that have been caught and processed.
    std::vector<int>& getProcessedSignals() {
        return (processed_signals_);
    }

    /// @brief Controls whether signals are processed in full or merely
    /// recorded.
    ///
    /// If true, signal handling will stop after recording the signal.
    /// Otherwise the base class signal handler,
    /// DControllerBase::processSignals will also be invoked. This switch is
    /// useful for ensuring that IOSignals are delivered as expected without
    /// incurring the full impact such as reconfiguring or shutting down.
232 233
    ///
    /// @param value boolean which if true enables record-only behavior
234 235 236 237
    void recordSignalOnly(bool value) {
       record_signal_only_ = value;
    }

238 239 240 241 242
protected:
    /// @brief Handles additional command line options that are supported
    /// by DStubController.  This implementation supports an option "-x".
    ///
    /// @param option is the option "character" from the command line, without
243
    /// any prefixing hyphen(s)
244 245
    /// @optarg optarg is the argument value (if one) associated with the option
    ///
246
    /// @return returns true if the option is "x", otherwise ti returns false.
247 248
    virtual bool customOption(int option, char *optarg);

249 250 251
    /// @brief Instantiates an instance of DStubProcess.
    ///
    /// This implementation will fail if SimFailure is set to
252
    /// ftCreateProcessException OR ftCreateProcessNull.
253
    ///
254 255
    /// @return returns a pointer to the new process instance (DProcessBase*)
    /// or NULL if SimFailure is set to ftCreateProcessNull.
256
    /// @throw throws std::runtime_error if SimFailure is set to
257 258 259
    /// ftCreateProcessException.
    virtual DProcessBase* createProcess();

260 261 262
    /// @brief Executes custom controller commands are supported by
    /// DStubController. This implementation supports one custom controller
    /// command, stub_ctl_command_.  It will fail if SimFailure is set
263 264 265 266
    /// to ftControllerCommand.
    ///
    /// @param command is a string label representing the command to execute.
    /// @param args is a set of arguments (if any) required for the given
267
    /// command.
268
    /// @return an Element that contains the results of command composed
269
    /// of an integer status value and a string explanation of the outcome.
270
    /// The status value is:
271 272
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
273 274 275 276
    /// COMMAND_INVALID if the command is not recognized.
    virtual isc::data::ConstElementPtr customControllerCommand(
            const std::string& command, isc::data::ConstElementPtr args);

277 278 279
    /// @brief Provides a string of the additional command line options
    /// supported by DStubController.  DStubController supports one
    /// addition option, stub_option_x_.
280 281
    ///
    /// @return returns a string containing the option letters.
282
    virtual const std::string getCustomOpts() const;
283

284 285 286 287 288 289 290 291
    /// @brief Application-level "signal handler"
    ///
    /// Overrides the base class implementation such that this method
    /// is invoked each time an IOSignal is processed.  It records the
    /// signal received and unless we are in record-only behavior, it
    /// in invokes the base class implementation.
    ///
    /// @param signum OS signal value received
292 293
    virtual void processSignal(int signum);

294 295 296 297
private:
    /// @brief Constructor is private to protect singleton integrity.
    DStubController();

298 299 300 301 302 303
    /// @brief Vector to record the signal values received.
    std::vector<int> processed_signals_;

    /// @brief Boolean for controlling if signals are merely recorded.
    bool record_signal_only_;

304 305 306 307
public:
    virtual ~DStubController();
};

308 309 310
/// @brief Defines a pointer to a DStubController.
typedef boost::shared_ptr<DStubController> DStubControllerPtr;

311
/// @brief Abstract Test fixture class that wraps a DControllerBase. This class
312
/// is a friend class of DControllerBase which allows it access to class
313 314
/// content to facilitate testing.  It provides numerous wrapper methods for
/// the protected and private methods and member of the base class.
315 316 317
class DControllerTest : public ::testing::Test {
public:

318
    /// @brief Defines a function pointer for controller singleton fetchers.
319 320
    typedef DControllerBasePtr& (*InstanceGetter)();

321 322 323
    /// @brief Static storage of the controller class's singleton fetcher.
    /// We need this this statically available for callbacks.
    static InstanceGetter instanceGetter_;
324

325 326 327 328
    /// @brief Constructor
    ///
    /// @param instance_getter is a function pointer to the static instance
    /// method of the DControllerBase derivation under test.
329 330
    DControllerTest(InstanceGetter instance_getter)
         : write_timer_(), new_cfg_content_() {
331 332 333
        // Set the static fetcher member, then invoke it via getController.
        // This ensures the singleton is instantiated.
        instanceGetter_ = instance_getter;
334 335 336
        getController();
    }

337 338 339 340
    /// @brief Destructor
    /// Note the controller singleton is destroyed. This is essential to ensure
    /// a clean start between tests.
    virtual ~DControllerTest() {
341 342 343 344 345
        // Some unit tests update the logging configuration which has a side
        // effect that all subsequent tests print the output to stdout. This
        // is to ensure that the logging settings are back to default.
        isc::log::setDefaultLoggingOutput();

346 347 348 349
        if (write_timer_) {
            write_timer_->cancel();
        }

350
        getController().reset();
351
        static_cast<void>(remove(CFG_TEST_FILE));
352 353
    }

354 355 356
    /// @brief Convenience method that destructs and then recreates the
    /// controller singleton under test.  This is handy for tests within
    /// tests.
357
    void resetController() {
358 359
        getController().reset();
        getController();
360 361
    }

362 363 364
    /// @brief Static method which returns the instance of the controller
    /// under test.
    /// @return returns a reference to the controller instance.
365 366 367 368
    static DControllerBasePtr& getController() {
        return ((*instanceGetter_)());
    }

369 370 371 372 373 374 375 376 377 378 379 380
    /// @brief Returns true if the Controller's app name matches the
    /// given value.
    ///
    /// @param should_be is the value to compare against.
    ///
    /// @return returns true if the values are equal.
    bool checkAppName(const std::string& should_be) {
        return (getController()->getAppName().compare(should_be) == 0);
    }

    /// @brief Returns true if the Controller's service name matches the
    /// given value.
381 382 383 384
    ///
    /// @param should_be is the value to compare against.
    ///
    /// @return returns true if the values are equal.
385 386
    bool checkBinName(const std::string& should_be) {
        return (getController()->getBinName().compare(should_be) == 0);
387 388
    }

389 390 391 392 393 394
    /// @brief Returns true if the Controller's spec file name matches the
    /// given value.
    ///
    /// @param should_be is the value to compare against.
    ///
    /// @return returns true if the values are equal.
395 396 397 398
    bool checkSpecFileName(const std::string& should_be) {
        return (getController()->getSpecFileName().compare(should_be) == 0);
    }

399 400 401
    /// @brief Tests the existence of the Controller's application process.
    ///
    /// @return returns true if the process instance exists.
402
    bool checkProcess() {
403
        return (getController()->process_.get() != 0);
404 405
    }

406 407 408
    /// @brief Tests the existence of the Controller's IOService.
    ///
    /// @return returns true if the IOService exists.
409
    bool checkIOService() {
410
        return (getController()->io_service_.get() != 0);
411 412
    }

413 414 415
    /// @brief Gets the Controller's IOService.
    ///
    /// @return returns a reference to the IOService
416
    asiolink::IOServicePtr& getIOService() {
417 418 419
        return (getController()->io_service_);
    }

420
    /// @brief Compares verbose flag with the given value.
421 422 423
    ///
    /// @param value
    ///
424 425 426
    /// @return returns true if the verbose flag is equal to the given value.
    bool checkVerbose(bool value) {
        return (getController()->isVerbose() == value);
427 428
    }

429
    /// @brief Compares configuration file name with the given value.
430
    ///
431
    /// @param value file name to compare against
432 433
    ///
    /// @return returns true if the verbose flag is equal to the given value.
434
    bool checkConfigFileName(const std::string& value) {
435
        return (getController()->getConfigFile() == value);
436 437
    }

438 439
    /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
    /// DControllerBase::parseArgs for details.
440 441 442 443
    void parseArgs(int argc, char* argv[]) {
        getController()->parseArgs(argc, argv);
    }

444 445
    /// @Wrapper to invoke the Controller's init method.  Please refer to
    /// DControllerBase::init for details.
446 447 448 449
    void initProcess() {
        getController()->initProcess();
    }

450 451
    /// @Wrapper to invoke the Controller's launch method.  Please refer to
    /// DControllerBase::launch for details.
452
    void launch(int argc, char* argv[]) {
453
        optind = 1;
454
        getController()->launch(argc, argv, true);
455 456
    }

457 458 459
    /// @Wrapper to invoke the Controller's updateConfig method.  Please
    /// refer to DControllerBase::updateConfig for details.
    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
460 461 462 463
                                            new_config) {
        return (getController()->updateConfig(new_config));
    }

464 465 466
    /// @Wrapper to invoke the Controller's executeCommand method.  Please
    /// refer to DControllerBase::executeCommand for details.
    isc::data::ConstElementPtr executeCommand(const std::string& command,
467 468 469 470 471 472 473 474
                                       isc::data::ConstElementPtr args){
        return (getController()->executeCommand(command, args));
    }

    /// @brief Callback that will generate shutdown command via the
    /// command callback function.
    static void genShutdownCallback() {
        isc::data::ElementPtr arg_set;
475
        getController()->executeCommand(SHUT_DOWN_COMMAND, arg_set);
476 477 478 479 480 481
    }

    /// @brief Callback that throws an exception.
    static void genFatalErrorCallback() {
        isc_throw (DProcessBaseError, "simulated fatal error");
    }
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500

    /// @brief writes specified content to a well known file
    ///
    /// Writes given JSON content to CFG_TEST_FILE. It will wrap the
    /// content within a JSON element whose name is equal to the controller's
    /// app name or the given module name if not blank:
    ///
    /// @code
    ///    { "<app_name>" : <content> }
    /// @endcod
    ///
    /// suffix the content within a JSON element with the given module
    /// name or  wrapped by a JSON
    /// element  . Tests will
    /// attempt to read that file.
    ///
    /// @param content JSON text to be written to file
    /// @param module_name  content content to be written to file
    void writeFile(const std::string& content,
501
                   const std::string& module_name = "");
502

503 504 505 506 507
    /// @brief Method used as timer callback to invoke writeFile.
    ///
    /// Wraps a call to writeFile passing in new_cfg_content_.  This allows
    /// the method to be bound as an IntervalTimer callback.
    virtual void timedWriteCallback();
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
    /// @brief Schedules the given content to overwrite the config file.
    ///
    /// Creates a one-shot IntervalTimer whose callback will overwrite the
    /// configuration with the given content.  This allows the configuration
    /// file to replaced write_time_ms after DControllerBase::launch() has
    /// invoked runProcess().
    ///
    /// @param config JSON string containing the deisred content for the config
    /// file.
    /// @param write_time_ms time in milliseconds to delay before writing the
    /// file.
    void scheduleTimedWrite(const std::string& config, int write_time_ms);

    /// @brief Convenience method for invoking standard, valid launch
    ///
    /// This method sets up a timed run of the DController::launch.  It does
    /// the following:
    /// - It creates command line argument variables argc/argv
    /// - Invokes writeFile to create the config file with the given content
    /// - Schedules a shutdown time timer to call DController::executeShutdown
    /// after the interval
    /// - Records the start time
    /// - Invokes DController::launch() with the command line arguments
    /// - After launch returns, it calculates the elapsed time and returns it
    ///
    /// @param config configuration file content to write before calling launch
    /// @param run_time_ms  maximum amount of time to allow runProcess() to
    /// continue.
    /// @param[out] elapsed_time the actual time in ms spent in launch().
    void runWithConfig(const std::string& config, int run_time_ms,
                       time_duration& elapsed_time);

    /// @brief Fetches the controller's process
    ///
    /// @return A pointer to the process which may be null if it has not yet
    /// been instantiated.
    DProcessBasePtr getProcess();

    /// @brief Fetches the process's configuration manager
    ///
    /// @return A pointer to the manager which may be null if it has not yet
    /// been instantiated.
    DCfgMgrBasePtr getCfgMgr();

    /// @brief Fetches the configuration manager's context
    ///
    /// @return A pointer to the context which may be null if it has not yet
    /// been instantiated.
    DCfgContextBasePtr getContext();

    /// @brief Timer used for delayed configuration file writing.
    asiolink::IntervalTimerPtr write_timer_;

    /// @brief String which contains the content delayed file writing will use.
    std::string new_cfg_content_;
564

565
    /// @brief Name of a config file used during tests
566
    static const char* CFG_TEST_FILE;
567 568
};

569 570 571 572 573 574
/// @brief a collection of elements that store uint32 values
typedef isc::dhcp::ValueStorage<isc::data::ConstElementPtr> ObjectStorage;
typedef boost::shared_ptr<ObjectStorage> ObjectStoragePtr;

/// @brief Simple parser derivation for parsing object elements.
class ObjectParser : public isc::dhcp::DhcpConfigParser {
575 576 577 578 579 580 581
public:

    /// @brief Constructor
    ///
    /// See @ref DhcpConfigParser class for details.
    ///
    /// @param param_name name of the parsed parameter
582
    ObjectParser(const std::string& param_name, ObjectStoragePtr& object_values);
583 584

    /// @brief Destructor
585
    virtual ~ObjectParser();
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611

    /// @brief Builds parameter value.
    ///
    /// See @ref DhcpConfigParser class for details.
    ///
    /// @param new_config pointer to the new configuration
    /// @throw throws DCfgMgrBaseError if the SimFailure is set to
    /// ftElementBuild. This allows for the simulation of an
    /// exception during the build portion of parsing an element.
    virtual void build(isc::data::ConstElementPtr new_config);

    /// @brief Commits the parsed value to storage.
    ///
    /// See @ref DhcpConfigParser class for details.
    ///
    /// @throw throws DCfgMgrBaseError if SimFailure is set to ftElementCommit.
    /// This allows for the simulation of an exception during the commit
    /// portion of parsing an element.
    virtual void commit();

private:
    /// name of the parsed parameter
    std::string param_name_;

    /// pointer to the parsed value of the parameter
    isc::data::ConstElementPtr value_;
612 613 614

    /// Pointer to the storage where committed value is stored.
    ObjectStoragePtr object_values_;
615 616
};

617

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
/// @brief Test Derivation of the DCfgContextBase class.
///
/// This class is used to test basic functionality of configuration context.
/// It adds an additional storage container "extra values" to mimic an
/// application extension of configuration storage.  This permits testing that
/// both the base class content as well as the application content is
/// correctly copied during cloning.  This is vital to configuration backup
/// and rollback during configuration parsing.
class DStubContext : public DCfgContextBase {
public:

    /// @brief Constructor
    DStubContext();

    /// @brief Destructor
    virtual ~DStubContext();

635 636 637 638 639
    /// @brief Creates a clone of a DStubContext.
    ///
    /// @return returns a pointer to the new clone.
    virtual DCfgContextBasePtr clone();

640 641 642 643 644 645 646 647
    /// @brief Fetches the value for a given "extra" configuration parameter
    /// from the context.
    ///
    /// @param name is the name of the parameter to retrieve.
    /// @param value is an output parameter in which to return the retrieved
    /// value.
    /// @throw throws DhcpConfigError if the context does not contain the
    /// parameter.
648 649
    void getObjectParam(const std::string& name,
                        isc::data::ConstElementPtr& value);
650

651
    ObjectStoragePtr& getObjectStorage();
652 653 654 655 656 657 658 659 660

protected:
    /// @brief Copy constructor
    DStubContext(const DStubContext& rhs);

private:
    /// @brief Private assignment operator, not implemented.
    DStubContext& operator=(const DStubContext& rhs);

661 662
    /// @brief Stores non-scalar configuration elements
    ObjectStoragePtr object_values_;
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
};

/// @brief Defines a pointer to DStubContext.
typedef boost::shared_ptr<DStubContext> DStubContextPtr;

/// @brief Test Derivation of the DCfgMgrBase class.
///
/// This class is used to test basic functionality of configuration management.
/// It supports the following configuration elements:
///
/// "bool_test" - Boolean element, tests parsing and committing a boolean
///               configuration parameter.
/// "uint32_test" - Uint32 element, tests parsing and committing a uint32_t
///               configuration parameter.
/// "string_test" - String element, tests parsing and committing a string
///               configuration parameter.
/// "extra_test" - "Extra" element, tests parsing and committing an extra
///               configuration parameter. (This is used to demonstrate
///               derivation's addition of storage to configuration context.
///
/// It also keeps track of the element ids that are parsed in the order they
/// are parsed.  This is used to test ordered and non-ordered parsing.
class DStubCfgMgr : public DCfgMgrBase {
public:
    /// @brief Constructor
    DStubCfgMgr();

    /// @brief Destructor
    virtual ~DStubCfgMgr();

    /// @brief Given an element_id returns an instance of the appropriate
    /// parser. It supports the element ids as described in the class brief.
    ///
    /// @param element_id is the string name of the element as it will appear
    /// in the configuration set.
698 699
    /// @param pos position within the configuration text (or file) of element
    /// to be parsed.  This is passed for error messaging.
700 701 702 703
    ///
    /// @return returns a ParserPtr to the parser instance.
    /// @throw throws DCfgMgrBaseError if SimFailure is ftElementUnknown.
    virtual isc::dhcp::ParserPtr
704 705 706
    createConfigParser(const std::string& element_id,
                       const isc::data::Element::Position& pos
                       = isc::data::Element::Position());
707

708 709 710
    /// @brief Returns a summary of the configuration in the textual format.
    ///
    /// @return Always an empty string.
711
    virtual std::string getConfigSummary(const uint32_t) {
712 713 714
        return ("");
    }

715 716 717
    /// @brief A list for remembering the element ids in the order they were
    /// parsed.
    ElementIdList parsed_order_;
718 719 720

    /// @todo
    virtual DCfgContextBasePtr createNewContext();
721 722 723 724 725
};

/// @brief Defines a pointer to DStubCfgMgr.
typedef boost::shared_ptr<DStubCfgMgr> DStubCfgMgrPtr;

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
/// @brief Test fixture base class for any fixtures which test parsing.
/// It provides methods for converting JSON strings to configuration element
/// sets and checking parse results
class ConfigParseTest : public ::testing::Test {
public:

    /// @brief Constructor
    ConfigParseTest(){
    }

    /// @brief Destructor
    ~ConfigParseTest() {
    }

    /// @brief Converts a given JSON string into an Element set and stores the
    /// result the member variable, config_set_.
    ///
    /// @param json_text contains the configuration text in JSON format to
    /// convert.
745 746
    /// @return returns AssertionSuccess if there were no parsing errors,
    /// AssertionFailure otherwise.
747
    ::testing::AssertionResult fromJSON(const std::string& json_text) {
748 749
        try  {
            config_set_ = isc::data::Element::fromJSON(json_text);
750
        } catch (const isc::Exception &ex) {
751 752 753
            return (::testing::AssertionFailure(::testing::Message() <<
                                                "JSON text failed to parse:"
                                                << ex.what()));
754 755
        }

756
        return (::testing::AssertionSuccess());
757 758 759 760 761 762 763
    }

    /// @brief Compares the status in the  parse result stored in member
    /// variable answer_ to a given value.
    ///
    /// @param should_be is an integer against which to compare the status.
    ///
764 765 766
    /// @return returns AssertionSuccess if there were no parsing errors,
    /// AssertionFailure otherwise.
    ::testing::AssertionResult checkAnswer(int should_be) {
767 768 769 770 771 772
        return (checkAnswer(answer_, should_be));
    }

    /// @brief Compares the status in the given parse result to a given value.
    ///
    /// @param answer Element set containing an integer response and string
773
    /// comment.
774 775 776 777 778 779
    /// @param should_be is an integer against which to compare the status.
    ///
    /// @return returns AssertionSuccess if there were no parsing errors,
    /// AssertionFailure otherwise.
    ::testing::AssertionResult checkAnswer(isc::data::ConstElementPtr answer,
                                           int should_be) {
780 781
        int rcode = 0;
        isc::data::ConstElementPtr comment;
782
        comment = isc::config::parseAnswer(rcode, answer);
783
        if (rcode == should_be) {
784
            return (testing::AssertionSuccess());
785
        }
786

787 788
        return (::testing::AssertionFailure(::testing::Message() <<
                                            "checkAnswer rcode:" << rcode
789
                                            << " comment: " << *comment));
790 791 792 793 794 795 796 797 798
    }

    /// @brief Configuration set being tested.
    isc::data::ElementPtr config_set_;

    /// @brief Results of most recent element parsing.
    isc::data::ConstElementPtr answer_;
};

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
/// @brief Implements a time-delayed signal
///
/// Given an IOService, a signal number, and a time period, this class will
/// send (raise) the signal to the current process.
class TimedSignal {
public:
    /// @brief Constructor
    ///
    /// @param io_service  IOService to run the timer
    /// @param signum OS signal value (e.g. SIGHUP, SIGUSR1 ...)
    /// @param milliseconds time in milliseconds to wait until the signal is
    /// raised.
    /// @param mode selects between a one-shot signal or a signal which repeats
    /// at "milliseconds" interval.
    TimedSignal(asiolink::IOService& io_service, int signum, int milliseconds,
                const asiolink::IntervalTimer::Mode& mode =
                asiolink::IntervalTimer::ONE_SHOT)
        : timer_(new asiolink::IntervalTimer(io_service)) {
        timer_->setup(SendSignalCallback(signum), milliseconds, mode);
    }

    /// @brief Cancels the given timer.
    void cancel() {
        if (timer_) {
            timer_->cancel();
        }
    }

    /// @brief Destructor.
    ~TimedSignal() {
        cancel();
    }

    /// @brief Callback for the TimeSignal's internal timer.
    class SendSignalCallback: public std::unary_function<void, void> {
    public:

        /// @brief Constructor
        ///
        /// @param signum OS signal value of the signal to send
        SendSignalCallback(int signum) : signum_(signum) {
        }

        /// @brief Callback method invoked when the timer expires
        ///
        /// Calls raise with the given signal which should generate that
        /// signal to the given process.
        void operator()() {
            ASSERT_EQ(0, raise(signum_));
            return;
        }

    private:
        /// @brief Stores the OS signal value to send.
        int signum_;
    };

private:
    /// @brief Timer which controls when the signal is sent.
    asiolink::IntervalTimerPtr timer_;
};

861 862 863 864
/// @brief Defines a small but valid DHCP-DDNS compliant configuration for
/// testing configuration parsing fundamentals.
extern const char* valid_d2_config;

865
}; // namespace isc::process
866 867 868
}; // namespace isc

#endif