d_test_stubs.h 16.5 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 24 25 26 27 28
// 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>
#include <gtest/gtest.h>

namespace isc {
namespace d2 {

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

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

56
    /// @brief Gets the current global SimFailure value
57
    ///
58
    /// @return returns the current SimFailure value
59 60 61 62 63 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
    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.
99
    static const char* stub_proc_command_;
100 101 102 103

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

111 112 113 114
    /// @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.
115 116
    virtual void init();

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

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

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

144 145
    /// @brief Executes the given command.
    ///
146
    /// This implementation will recognizes one "custom" process command,
147 148
    /// stub_proc_command_.  It will fail if SimFailure is set to
    /// ftProcessCommand.
149 150 151
    ///
    /// @param command is a string label representing the command to execute.
    /// @param args is a set of arguments (if any) required for the given
152
    /// command.
153
    /// @return an Element that contains the results of command composed
154
    /// of an integer status value and a string explanation of the outcome.
155
    /// The status value is:
156 157
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
158
    /// COMMAND_INVALID if the command is not recognized.
159
    virtual isc::data::ConstElementPtr command(const std::string& command,
160 161 162 163 164 165 166 167 168 169
                                               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
170 171 172 173
/// 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.
174 175 176 177 178
/// 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
179 180
    /// base class singleton instance member.  It instantiates the singleton
    /// and sets the base class instance member upon first invocation.
181
    ///
182
    /// @return returns a pointer reference to the singleton instance.
183 184
    static DControllerBasePtr& instance();

185
    /// @brief Defines a custom controller command string. This is a
186
    /// custom command supported by DStubController.
187
    static const char* stub_ctl_command_;
188 189 190 191

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

193 194 195 196 197 198
    /// @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_;

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

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

221 222 223
    /// @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
224 225 226 227
    /// 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
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 233
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
234 235 236 237
    /// COMMAND_INVALID if the command is not recognized.
    virtual isc::data::ConstElementPtr customControllerCommand(
            const std::string& command, isc::data::ConstElementPtr args);

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

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

public:
    virtual ~DStubController();
};

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

260
    /// @brief Defines a function pointer for controller singleton fetchers.
261 262
    typedef DControllerBasePtr& (*InstanceGetter)();

263 264 265
    /// @brief Static storage of the controller class's singleton fetcher.
    /// We need this this statically available for callbacks.
    static InstanceGetter instanceGetter_;
266

267 268 269 270 271 272 273 274
    /// @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;
275 276 277
        getController();
    }

278 279 280 281
    /// @brief Destructor
    /// Note the controller singleton is destroyed. This is essential to ensure
    /// a clean start between tests.
    virtual ~DControllerTest() {
282 283 284
        getController().reset();
    }

285 286 287
    /// @brief Convenience method that destructs and then recreates the
    /// controller singleton under test.  This is handy for tests within
    /// tests.
288
    void resetController() {
289 290
        getController().reset();
        getController();
291 292
    }

293 294 295
    /// @brief Static method which returns the instance of the controller
    /// under test.
    /// @return returns a reference to the controller instance.
296 297 298 299
    static DControllerBasePtr& getController() {
        return ((*instanceGetter_)());
    }

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

320 321 322 323 324 325
    /// @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.
326 327 328 329
    bool checkSpecFileName(const std::string& should_be) {
        return (getController()->getSpecFileName().compare(should_be) == 0);
    }

330 331 332
    /// @brief Tests the existence of the Controller's application process.
    ///
    /// @return returns true if the process instance exists.
333 334 335 336
    bool checkProcess() {
        return (getController()->process_);
    }

337 338 339
    /// @brief Tests the existence of the Controller's IOService.
    ///
    /// @return returns true if the IOService exists.
340 341 342 343
    bool checkIOService() {
        return (getController()->io_service_);
    }

344 345 346
    /// @brief Gets the Controller's IOService.
    ///
    /// @return returns a reference to the IOService
347 348 349 350
    IOServicePtr& getIOService() {
        return (getController()->io_service_);
    }

351 352 353 354 355 356
    /// @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.
357 358 359 360
    bool checkStandAlone(bool value) {
        return (getController()->isStandAlone() == value);
    }

361 362 363 364
    /// @brief Sets the controller's stand alone flag to the given value.
    ///
    /// @param value is the new value to assign.
    ///
365 366 367 368
    void setStandAlone(bool value) {
        getController()->setStandAlone(value);
    }

369 370 371 372 373
    /// @brief Compares verbose flag with the given value.
    ///
    /// @param value
    ///
    /// @return returns true if the verbose flag is equal to the given value.
374 375 376 377
    bool checkVerbose(bool value) {
        return (getController()->isVerbose() == value);
    }

378 379
    /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
    /// DControllerBase::parseArgs for details.
380 381 382 383
    void parseArgs(int argc, char* argv[]) {
        getController()->parseArgs(argc, argv);
    }

384 385
    /// @Wrapper to invoke the Controller's init method.  Please refer to
    /// DControllerBase::init for details.
386 387 388 389
    void initProcess() {
        getController()->initProcess();
    }

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

396 397
    /// @Wrapper to invoke the Controller's launch method.  Please refer to
    /// DControllerBase::launch for details.
398
    void launch(int argc, char* argv[]) {
399
        optind = 1;
400
        getController()->launch(argc, argv, true);
401 402
    }

403 404
    /// @Wrapper to invoke the Controller's disconnectSession method.  Please
    /// refer to DControllerBase::disconnectSession for details.
405 406 407 408
    void disconnectSession() {
        getController()->disconnectSession();
    }

409 410 411
    /// @Wrapper to invoke the Controller's updateConfig method.  Please
    /// refer to DControllerBase::updateConfig for details.
    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
412 413 414 415
                                            new_config) {
        return (getController()->updateConfig(new_config));
    }

416 417 418
    /// @Wrapper to invoke the Controller's executeCommand method.  Please
    /// refer to DControllerBase::executeCommand for details.
    isc::data::ConstElementPtr executeCommand(const std::string& command,
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
                                       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");
    }
};

436
}; // namespace isc::d2
437 438 439
}; // namespace isc

#endif