d_test_stubs.h 21.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef D_TEST_STUBS_H
#define D_TEST_STUBS_H

#include <asiolink/asiolink.h>
#include <cc/data.h>
#include <cc/session.h>
#include <config/ccsession.h>

#include <d2/d_controller.h>
24 25
#include <d2/d_cfg_mgr.h>

26 27 28 29 30
#include <gtest/gtest.h>

namespace isc {
namespace d2 {

31
/// @brief Class is used to set a globally accessible value that indicates
32
/// a specific type of failure to simulate.  Test derivations of base classes
33
/// can exercise error handling code paths by testing for specific SimFailure
34 35 36 37
/// 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 {
38
public:
39
    enum FailureType {
40
        ftUnknown = -1,
41
        ftNoFailure = 0,
42
        ftCreateProcessException,
43 44 45 46
        ftCreateProcessNull,
        ftProcessInit,
        ftProcessConfigure,
        ftControllerCommand,
47
        ftProcessCommand,
48 49 50 51
        ftProcessShutdown,
        ftElementBuild,
        ftElementCommit,
        ftElementUnknown
52 53 54 55 56 57 58 59 60
    };

    /// @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;
    }

61
    /// @brief Gets the current global SimFailure value
62
    ///
63
    /// @return returns the current SimFailure value
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    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);
    }

    static void clear() {
       failure_type_ = ftNoFailure;
    }

    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.
104
    static const char* stub_proc_command_;
105 106 107 108

    /// @brief Constructor
    ///
    /// @param name name is a text label for the process. Generally used
109
    /// in log statements, but otherwise arbitrary.
110 111 112
    /// @param io_service is the io_service used by the caller for
    /// asynchronous event handling.
    ///
113
    /// @throw DProcessBaseError is io_service is NULL.
114 115
    DStubProcess(const char* name, IOServicePtr io_service);

116 117 118 119
    /// @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.
120 121
    virtual void init();

122 123 124 125
    /// @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
126 127
    /// request to shutdown or some anomaly forces an exit.
    /// @return  returns 0 upon a successful, "normal" termination, non-zero to
128 129
    /// indicate an abnormal termination.
    virtual void run();
130 131 132 133

    /// @brief Implements the process shutdown procedure. Currently this is
    /// limited to setting the instance shutdown flag, which is monitored in
    /// run().
134
    virtual void shutdown();
135

136 137
    /// @brief Processes the given configuration.
    ///
138 139 140 141 142 143 144
    /// 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),
145
    /// and a string explanation of the outcome.
146 147 148
    virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr
                                                 config_set);

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

    // @brief Destructor
    virtual ~DStubProcess();
};


/// @brief Test Derivation of the DControllerBase class.
///
/// DControllerBase is an abstract class and therefore requires a derivation
175 176 177 178
/// 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.
179 180 181 182 183
/// Obviously BIND10 connectivity is not available under unit tests, so
/// testing here is limited to "failures" to communicate with BIND10.
class DStubController : public DControllerBase {
public:
    /// @brief Static singleton instance method. This method returns the
184 185
    /// base class singleton instance member.  It instantiates the singleton
    /// and sets the base class instance member upon first invocation.
186
    ///
187
    /// @return returns a pointer reference to the singleton instance.
188 189
    static DControllerBasePtr& instance();

190
    /// @brief Defines a custom controller command string. This is a
191
    /// custom command supported by DStubController.
192
    static const char* stub_ctl_command_;
193 194 195 196

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

198 199 200 201 202 203
    /// @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_;

204 205 206 207 208
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
209
    /// any prefixing hyphen(s)
210 211
    /// @optarg optarg is the argument value (if one) associated with the option
    ///
212
    /// @return returns true if the option is "x", otherwise ti returns false.
213 214
    virtual bool customOption(int option, char *optarg);

215 216 217
    /// @brief Instantiates an instance of DStubProcess.
    ///
    /// This implementation will fail if SimFailure is set to
218
    /// ftCreateProcessException OR ftCreateProcessNull.
219
    ///
220 221
    /// @return returns a pointer to the new process instance (DProcessBase*)
    /// or NULL if SimFailure is set to ftCreateProcessNull.
222
    /// @throw throws std::runtime_error if SimFailure is set to
223 224 225
    /// ftCreateProcessException.
    virtual DProcessBase* createProcess();

226 227 228
    /// @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
229 230 231 232
    /// 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
233
    /// command.
234
    /// @return an Element that contains the results of command composed
235
    /// of an integer status value and a string explanation of the outcome.
236
    /// The status value is:
237 238
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
239 240 241 242
    /// COMMAND_INVALID if the command is not recognized.
    virtual isc::data::ConstElementPtr customControllerCommand(
            const std::string& command, isc::data::ConstElementPtr args);

243 244 245
    /// @brief Provides a string of the additional command line options
    /// supported by DStubController.  DStubController supports one
    /// addition option, stub_option_x_.
246 247
    ///
    /// @return returns a string containing the option letters.
248
    virtual const std::string getCustomOpts() const;
249 250 251 252 253 254 255 256 257

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

public:
    virtual ~DStubController();
};

258
/// @brief Abstract Test fixture class that wraps a DControllerBase. This class
259
/// is a friend class of DControllerBase which allows it access to class
260 261
/// content to facilitate testing.  It provides numerous wrapper methods for
/// the protected and private methods and member of the base class.
262 263 264
class DControllerTest : public ::testing::Test {
public:

265
    /// @brief Defines a function pointer for controller singleton fetchers.
266 267
    typedef DControllerBasePtr& (*InstanceGetter)();

268 269 270
    /// @brief Static storage of the controller class's singleton fetcher.
    /// We need this this statically available for callbacks.
    static InstanceGetter instanceGetter_;
271

272 273 274 275 276 277 278 279
    /// @brief Constructor
    ///
    /// @param instance_getter is a function pointer to the static instance
    /// method of the DControllerBase derivation under test.
    DControllerTest(InstanceGetter instance_getter) {
        // Set the static fetcher member, then invoke it via getController.
        // This ensures the singleton is instantiated.
        instanceGetter_ = instance_getter;
280 281 282
        getController();
    }

283 284 285 286
    /// @brief Destructor
    /// Note the controller singleton is destroyed. This is essential to ensure
    /// a clean start between tests.
    virtual ~DControllerTest() {
287 288 289
        getController().reset();
    }

290 291 292
    /// @brief Convenience method that destructs and then recreates the
    /// controller singleton under test.  This is handy for tests within
    /// tests.
293
    void resetController() {
294 295
        getController().reset();
        getController();
296 297
    }

298 299 300
    /// @brief Static method which returns the instance of the controller
    /// under test.
    /// @return returns a reference to the controller instance.
301 302 303 304
    static DControllerBasePtr& getController() {
        return ((*instanceGetter_)());
    }

305 306 307 308 309 310 311 312 313 314 315 316
    /// @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.
317 318 319 320
    ///
    /// @param should_be is the value to compare against.
    ///
    /// @return returns true if the values are equal.
321 322
    bool checkBinName(const std::string& should_be) {
        return (getController()->getBinName().compare(should_be) == 0);
323 324
    }

325 326 327 328 329 330
    /// @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.
331 332 333 334
    bool checkSpecFileName(const std::string& should_be) {
        return (getController()->getSpecFileName().compare(should_be) == 0);
    }

335 336 337
    /// @brief Tests the existence of the Controller's application process.
    ///
    /// @return returns true if the process instance exists.
338 339 340 341
    bool checkProcess() {
        return (getController()->process_);
    }

342 343 344
    /// @brief Tests the existence of the Controller's IOService.
    ///
    /// @return returns true if the IOService exists.
345 346 347 348
    bool checkIOService() {
        return (getController()->io_service_);
    }

349 350 351
    /// @brief Gets the Controller's IOService.
    ///
    /// @return returns a reference to the IOService
352 353 354 355
    IOServicePtr& getIOService() {
        return (getController()->io_service_);
    }

356 357 358 359 360 361
    /// @brief Compares stand alone flag with the given value.
    ///
    /// @param value
    ///
    /// @return returns true if the stand alone flag is equal to the given
    /// value.
362 363 364 365
    bool checkStandAlone(bool value) {
        return (getController()->isStandAlone() == value);
    }

366 367 368 369
    /// @brief Sets the controller's stand alone flag to the given value.
    ///
    /// @param value is the new value to assign.
    ///
370 371 372 373
    void setStandAlone(bool value) {
        getController()->setStandAlone(value);
    }

374 375 376 377 378
    /// @brief Compares verbose flag with the given value.
    ///
    /// @param value
    ///
    /// @return returns true if the verbose flag is equal to the given value.
379 380 381 382
    bool checkVerbose(bool value) {
        return (getController()->isVerbose() == value);
    }

383 384
    /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
    /// DControllerBase::parseArgs for details.
385 386 387 388
    void parseArgs(int argc, char* argv[]) {
        getController()->parseArgs(argc, argv);
    }

389 390
    /// @Wrapper to invoke the Controller's init method.  Please refer to
    /// DControllerBase::init for details.
391 392 393 394
    void initProcess() {
        getController()->initProcess();
    }

395 396
    /// @Wrapper to invoke the Controller's establishSession method.  Please
    /// refer to DControllerBase::establishSession for details.
397 398 399 400
    void establishSession() {
        getController()->establishSession();
    }

401 402
    /// @Wrapper to invoke the Controller's launch method.  Please refer to
    /// DControllerBase::launch for details.
403
    void launch(int argc, char* argv[]) {
404
        optind = 1;
405
        getController()->launch(argc, argv);
406 407
    }

408 409
    /// @Wrapper to invoke the Controller's disconnectSession method.  Please
    /// refer to DControllerBase::disconnectSession for details.
410 411 412 413
    void disconnectSession() {
        getController()->disconnectSession();
    }

414 415 416
    /// @Wrapper to invoke the Controller's updateConfig method.  Please
    /// refer to DControllerBase::updateConfig for details.
    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
417 418 419 420
                                            new_config) {
        return (getController()->updateConfig(new_config));
    }

421 422 423
    /// @Wrapper to invoke the Controller's executeCommand method.  Please
    /// refer to DControllerBase::executeCommand for details.
    isc::data::ConstElementPtr executeCommand(const std::string& command,
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
                                       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;
        DControllerBase::commandHandler(SHUT_DOWN_COMMAND, arg_set);
    }

    /// @brief Callback that throws an exception.
    static void genFatalErrorCallback() {
        isc_throw (DProcessBaseError, "simulated fatal error");
    }
};

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 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 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
/// @brief Simple parser derivation for testing the basics of configuration
/// parsing.
class TestParser : public isc::dhcp::DhcpConfigParser {
public:

    /// @brief Constructor
    ///
    /// See @ref DhcpConfigParser class for details.
    ///
    /// @param param_name name of the parsed parameter
    TestParser(const std::string& param_name);

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

    /// @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_;
};

/// @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();

    /// @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.
    void getExtraParam(const std::string& name, uint32_t& value);

    /// @brief Fetches the extra storage.
    ///
    /// @return returns a pointer to the extra storage.
    isc::dhcp::Uint32StoragePtr getExtraStorage();

    /// @brief Creates a clone of a DStubContext.
    ///
    /// @return returns a raw pointer to the new clone.
    virtual DStubContext* clone();

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

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

    /// @brief Extra storage for uint32 parameters.
    isc::dhcp::Uint32StoragePtr extra_values_;
};

/// @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.
    ///
    /// @return returns a ParserPtr to the parser instance.
    /// @throw throws DCfgMgrBaseError if SimFailure is ftElementUnknown.
    virtual isc::dhcp::ParserPtr
    createConfigParser(const std::string& element_id);

    /// @brief A list for remembering the element ids in the order they were
    /// parsed.
    ElementIdList parsed_order_;
};

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

579
}; // namespace isc::d2
580 581 582
}; // namespace isc

#endif