d2_controller_unittests.cc 8.87 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// 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.

#include <config/ccsession.h>
#include <d_test_stubs.h>
#include <d2/d2_controller.h>
#include <d2/spec_config.h>

20
#include <boost/pointer_cast.hpp>
21 22 23 24 25 26 27 28 29 30 31
#include <boost/date_time/posix_time/posix_time.hpp>
#include <gtest/gtest.h>

#include <config.h>
#include <sstream>

using namespace boost::posix_time;

namespace isc {
namespace d2 {

32 33 34 35 36 37 38 39 40 41 42
/// @brief Test fixture class for testing D2Controller class. This class
/// derives from DControllerTest and wraps a D2Controller.  Much of the
/// underlying functionality is in the DControllerBase class which has an
/// extensive set of unit tests that are independent of DHCP-DDNS.
/// @TODO Currently These tests are relatively light and duplicate some of
/// the testing done on the base class.  These tests are sufficient to ensure
/// that D2Controller properly derives from its base class and to test the
/// logic that is unique to D2Controller. These tests will be augmented and
/// or new tests added as additional functionality evolves.
/// Unlike the stub testing, there is no use of SimFailure to induce error
/// conditions as this is production code.
43 44 45
class D2ControllerTest : public DControllerTest {
public:
    /// @brief Constructor
46 47
    /// Note the constructor passes in the static D2Controller instance
    /// method.
48 49 50
    D2ControllerTest() : DControllerTest(D2Controller::instance) {
    }

51
    /// @brief Destructor
52 53 54 55
    ~D2ControllerTest() {
    }
};

56
/// @brief Basic Controller instantiation testing.
57
/// Verifies that the controller singleton gets created and that the
58
/// basic derivation from the base class is intact.
59
TEST_F(D2ControllerTest, basicInstanceTesting) {
60 61
    // Verify the we can the singleton instance can be fetched and that
    // it is the correct type.
62 63
    DControllerBasePtr& controller = DControllerTest::getController();
    ASSERT_TRUE(controller);
64 65
    ASSERT_NO_THROW(boost::dynamic_pointer_cast<D2Controller>(controller));

66 67 68 69 70
    // Verify that controller's app name is correct.
    EXPECT_TRUE(checkAppName(D2Controller::d2_app_name_));

    // Verify that controller's bin name is correct.
    EXPECT_TRUE(checkBinName(D2Controller::d2_bin_name_));
71 72

    // Verify that controller's spec file name is correct.
73
    EXPECT_TRUE(checkSpecFileName(D2_SPECFILE_LOCATION));
74 75

    // Verify that controller's IOService exists.
76 77
    EXPECT_TRUE(checkIOService());

78
    // Verify that the Process does NOT exist.
79 80 81
    EXPECT_FALSE(checkProcess());
}

82
/// @brief Tests basic command line processing.
83
/// Verifies that:
84 85
/// 1. Standard command line options are supported.
/// 2. Invalid options are detected.
86
TEST_F(D2ControllerTest, commandLineArgs) {
87 88
    char* argv[] = { const_cast<char*>("progName"),
                     const_cast<char*>("-s"),
89
                     const_cast<char*>("-v") };
90 91
    int argc = 3;

92
    // Verify that both flags are false initially.
93 94 95
    EXPECT_TRUE(checkStandAlone(false));
    EXPECT_TRUE(checkVerbose(false));

96
    // Verify that standard options can be parsed without error.
97 98
    EXPECT_NO_THROW(parseArgs(argc, argv));

99
    // Verify that flags are now true.
100 101 102
    EXPECT_TRUE(checkStandAlone(true));
    EXPECT_TRUE(checkVerbose(true));

103
    // Verify that an unknown option is detected.
104
    char* argv2[] = { const_cast<char*>("progName"),
105
                      const_cast<char*>("-x") };
106
    argc = 2;
107
    EXPECT_THROW(parseArgs(argc, argv2), InvalidUsage);
108 109
}

110 111
/// @brief Tests application process creation and initialization.
/// Verifies that the process can be successfully created and initialized.
112 113 114 115 116
TEST_F(D2ControllerTest, initProcessTesting) {
    ASSERT_NO_THROW(initProcess());
    EXPECT_TRUE(checkProcess());
}

117 118 119 120 121
/// @brief Tests launch and normal shutdown (stand alone mode).
/// This creates an interval timer to generate a normal shutdown and then
/// launches with a valid, stand-alone command line and no simulated errors.
TEST_F(D2ControllerTest, launchNormalShutdown) {
    // command line to run standalone
122 123
    char* argv[] = { const_cast<char*>("progName"),
                     const_cast<char*>("-s"),
124
                     const_cast<char*>("-v") };
125 126 127 128 129 130 131 132 133
    int argc = 3;

    // Use an asiolink IntervalTimer and callback to generate the
    // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
    isc::asiolink::IntervalTimer timer(*getIOService());
    timer.setup(genShutdownCallback, 2 * 1000);

    // Record start time, and invoke launch().
    ptime start = microsec_clock::universal_time();
134
    EXPECT_NO_THROW(launch(argc, argv));
135 136 137 138 139 140 141 142 143 144 145 146

    // Record stop time.
    ptime stop = microsec_clock::universal_time();

    // Verify that duration of the run invocation is the same as the
    // timer duration.  This demonstrates that the shutdown was driven
    // by an io_service event and callback.
    time_duration elapsed = stop - start;
    EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
                elapsed.total_milliseconds() <= 2100);
}

147
/// @brief Configuration update event testing.
148
/// This really tests just the ability of the handlers to invoke the necessary
149 150 151 152 153 154 155 156 157 158 159
/// chain of methods and handle error conditions. Configuration parsing and
/// retrieval should be tested as part of the d2 configuration management
/// implementation.  Note that this testing calls the configuration update event
/// callback, configHandler, directly.
/// This test verifies that:
/// 1. Configuration will be rejected in integrated mode when there is no
/// session established. (This is a very contrived situation).
/// 2. In stand-alone mode a configuration update results in successful
/// status return.
/// 3. That an application process error in configuration updating is handled
/// properly.
160 161 162 163
TEST_F(D2ControllerTest, configUpdateTests) {
    int rcode = -1;
    isc::data::ConstElementPtr answer;

164
    // Initialize the application process.
165 166 167
    ASSERT_NO_THROW(initProcess());
    EXPECT_TRUE(checkProcess());

168 169 170
    // Create a configuration set using a small, valid D2 configuration.
    isc::data::ElementPtr config_set =
                                isc::data::Element::fromJSON(valid_d2_config);
171 172

    // We are not stand-alone, so configuration should be rejected as there is
173
    // no session.  This is a pretty contrived situation that shouldn't be
174 175 176 177 178 179 180 181 182 183
    // possible other than the handler being called directly (like this does).
    answer = DControllerBase::configHandler(config_set);
    isc::config::parseAnswer(rcode, answer);
    EXPECT_EQ(1, rcode);

    // Verify that in stand alone we get a successful update result.
    setStandAlone(true);
    answer = DControllerBase::configHandler(config_set);
    isc::config::parseAnswer(rcode, answer);
    EXPECT_EQ(0, rcode);
184 185 186 187 188 189 190

    // Use an invalid configuration to verify parsing error return.
    std::string config = "{ \"bogus\": 1000 } ";
    config_set = isc::data::Element::fromJSON(config);
    answer = DControllerBase::configHandler(config_set);
    isc::config::parseAnswer(rcode, answer);
    EXPECT_EQ(1, rcode);
191 192
}

193 194 195 196 197 198 199 200
/// @brief Command execution tests.
/// This really tests just the ability of the handler to invoke the necessary
/// chain of methods and to handle error conditions. Note that this testing
/// calls the command callback, commandHandler, directly.
/// This test verifies that:
/// 1. That an unrecognized command is detected and returns a status of
/// d2::COMMAND_INVALID.
/// 2. Shutdown command is recognized and returns a d2::COMMAND_SUCCESS status.
201 202 203 204 205
TEST_F(D2ControllerTest, executeCommandTests) {
    int rcode = -1;
    isc::data::ConstElementPtr answer;
    isc::data::ElementPtr arg_set;

206
    // Initialize the application process.
207 208 209
    ASSERT_NO_THROW(initProcess());
    EXPECT_TRUE(checkProcess());

210
    // Verify that an unknown command returns an COMMAND_INVALID response.
211 212 213 214
    std::string bogus_command("bogus");
    answer = DControllerBase::commandHandler(bogus_command, arg_set);
    isc::config::parseAnswer(rcode, answer);
    EXPECT_EQ(COMMAND_INVALID, rcode);
215 216 217 218 219 220 221

    // Verify that shutdown command returns COMMAND_SUCCESS response.
    //answer = executeCommand(SHUT_DOWN_COMMAND, isc::data::ElementPtr());
    answer = DControllerBase::commandHandler(SHUT_DOWN_COMMAND, arg_set);
    isc::config::parseAnswer(rcode, answer);
    EXPECT_EQ(COMMAND_SUCCESS, rcode);

222 223 224 225
}

}; // end of isc::d2 namespace
}; // end of isc namespace