d_test_stubs.h 15.9 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

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

204 205 206
    /// @brief Instantiates an instance of DStubProcess.
    ///
    /// This implementation will fail if SimFailure is set to
207
    /// ftCreateProcessException OR ftCreateProcessNull.
208
    ///
209 210
    /// @return returns a pointer to the new process instance (DProcessBase*)
    /// or NULL if SimFailure is set to ftCreateProcessNull.
211
    /// @throw throws std::runtime_error if SimFailure is set to
212 213 214
    /// ftCreateProcessException.
    virtual DProcessBase* createProcess();

215 216 217
    /// @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
218 219 220 221
    /// 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
222
    /// command.
223
    /// @return an Element that contains the results of command composed
224
    /// of an integer status value and a string explanation of the outcome.
225
    /// The status value is:
226 227
    /// COMMAND_SUCCESS if the command is recognized and executes successfully.
    /// COMMAND_ERROR if the command is recognized but fails to execute.
228 229 230 231
    /// COMMAND_INVALID if the command is not recognized.
    virtual isc::data::ConstElementPtr customControllerCommand(
            const std::string& command, isc::data::ConstElementPtr args);

232 233 234
    /// @brief Provides a string of the additional command line options
    /// supported by DStubController.  DStubController supports one
    /// addition option, stub_option_x_.
235 236
    ///
    /// @return returns a string containing the option letters.
237
    virtual const std::string getCustomOpts() const;
238 239 240 241 242 243 244 245 246

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

public:
    virtual ~DStubController();
};

247
/// @brief Abstract Test fixture class that wraps a DControllerBase. This class
248
/// is a friend class of DControllerBase which allows it access to class
249 250
/// content to facilitate testing.  It provides numerous wrapper methods for
/// the protected and private methods and member of the base class.
251 252 253
class DControllerTest : public ::testing::Test {
public:

254
    /// @brief Defines a function pointer for controller singleton fetchers.
255 256
    typedef DControllerBasePtr& (*InstanceGetter)();

257 258 259
    /// @brief Static storage of the controller class's singleton fetcher.
    /// We need this this statically available for callbacks.
    static InstanceGetter instanceGetter_;
260

261 262 263 264 265 266 267 268
    /// @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;
269 270 271
        getController();
    }

272 273 274 275
    /// @brief Destructor
    /// Note the controller singleton is destroyed. This is essential to ensure
    /// a clean start between tests.
    virtual ~DControllerTest() {
276 277 278
        getController().reset();
    }

279 280 281
    /// @brief Convenience method that destructs and then recreates the
    /// controller singleton under test.  This is handy for tests within
    /// tests.
282
    void resetController() {
283 284
        getController().reset();
        getController();
285 286
    }

287 288 289
    /// @brief Static method which returns the instance of the controller
    /// under test.
    /// @return returns a reference to the controller instance.
290 291 292 293
    static DControllerBasePtr& getController() {
        return ((*instanceGetter_)());
    }

294 295 296 297 298
    /// @brief Returns true if the Controller's name matches the given value.
    ///
    /// @param should_be is the value to compare against.
    ///
    /// @return returns true if the values are equal.
299 300 301 302
    bool checkName(const std::string& should_be) {
        return (getController()->getName().compare(should_be) == 0);
    }

303 304 305 306 307 308
    /// @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.
309 310 311 312
    bool checkSpecFileName(const std::string& should_be) {
        return (getController()->getSpecFileName().compare(should_be) == 0);
    }

313 314 315
    /// @brief Tests the existence of the Controller's application process.
    ///
    /// @return returns true if the process instance exists.
316 317 318 319
    bool checkProcess() {
        return (getController()->process_);
    }

320 321 322
    /// @brief Tests the existence of the Controller's IOService.
    ///
    /// @return returns true if the IOService exists.
323 324 325 326
    bool checkIOService() {
        return (getController()->io_service_);
    }

327 328 329
    /// @brief Gets the Controller's IOService.
    ///
    /// @return returns a reference to the IOService
330 331 332 333
    IOServicePtr& getIOService() {
        return (getController()->io_service_);
    }

334 335 336 337 338 339
    /// @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.
340 341 342 343
    bool checkStandAlone(bool value) {
        return (getController()->isStandAlone() == value);
    }

344 345 346 347
    /// @brief Sets the controller's stand alone flag to the given value.
    ///
    /// @param value is the new value to assign.
    ///
348 349 350 351
    void setStandAlone(bool value) {
        getController()->setStandAlone(value);
    }

352 353 354 355 356
    /// @brief Compares verbose flag with the given value.
    ///
    /// @param value
    ///
    /// @return returns true if the verbose flag is equal to the given value.
357 358 359 360
    bool checkVerbose(bool value) {
        return (getController()->isVerbose() == value);
    }

361 362
    /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
    /// DControllerBase::parseArgs for details.
363 364 365 366
    void parseArgs(int argc, char* argv[]) {
        getController()->parseArgs(argc, argv);
    }

367 368
    /// @Wrapper to invoke the Controller's init method.  Please refer to
    /// DControllerBase::init for details.
369 370 371 372
    void initProcess() {
        getController()->initProcess();
    }

373 374
    /// @Wrapper to invoke the Controller's establishSession method.  Please
    /// refer to DControllerBase::establishSession for details.
375 376 377 378
    void establishSession() {
        getController()->establishSession();
    }

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

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

392 393 394
    /// @Wrapper to invoke the Controller's updateConfig method.  Please
    /// refer to DControllerBase::updateConfig for details.
    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
395 396 397 398
                                            new_config) {
        return (getController()->updateConfig(new_config));
    }

399 400 401
    /// @Wrapper to invoke the Controller's executeCommand method.  Please
    /// refer to DControllerBase::executeCommand for details.
    isc::data::ConstElementPtr executeCommand(const std::string& command,
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
                                       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");
    }
};

419
}; // namespace isc::d2
420 421 422
}; // namespace isc

#endif