d_test_stubs.cc 8.67 KB
Newer Older
1
// Copyright (C) 2013-2020 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
#include <config.h>
8
#include <asiolink/io_service.h>
9
#include <process/d_log.h>
10
#include <process/testutils/d_test_stubs.h>
11
#include <process/daemon.h>
12
#include <cc/command_interpreter.h>
13
#include <functional>
14

15
using namespace boost::asio;
16 17

namespace isc {
18
namespace process {
19

20
// Initialize the static failure flag.
21 22
SimFailure::FailureType SimFailure::failure_type_ = SimFailure::ftNoFailure;

23
DStubProcess::DStubProcess(const char* name, asiolink::IOServicePtr io_service)
24
    : DProcessBase(name, io_service, DCfgMgrBasePtr(new DStubCfgMgr())) {
25 26
};

27

28 29 30
void
DStubProcess::init() {
    if (SimFailure::shouldFailOn(SimFailure::ftProcessInit)) {
31 32
        // Simulates a failure to instantiate the process.
        isc_throw(DProcessBaseError, "DStubProcess simulated init() failure");
33 34 35
    }
};

36
void
37 38 39 40
DStubProcess::run() {
    // Until shut down or an fatal error occurs, wait for and
    // execute a single callback. This is a preliminary implementation
    // that is likely to evolve as development progresses.
41
    // To use run(), the "managing" layer must issue an io_service::stop
42 43
    // or the call to run will continue to block, and shutdown will not
    // occur.
44
    asiolink::IOServicePtr& io_service = getIoService();
45 46 47 48
    while (!shouldShutdown()) {
        try {
            io_service->run_one();
        } catch (const std::exception& ex) {
49
            isc_throw (DProcessBaseError,
50
                std::string("Process run method failed: ") + ex.what());
51 52 53 54
        }
    }
};

55 56
isc::data::ConstElementPtr
DStubProcess::shutdown(isc::data::ConstElementPtr /* args */) {
57 58 59 60
    if (SimFailure::shouldFailOn(SimFailure::ftProcessShutdown)) {
        // Simulates a failure during shutdown process.
        isc_throw(DProcessBaseError, "DStubProcess simulated shutdown failure");
    }
61

62 63
    setShutdownFlag(true);
    stopIOService();
Josh Soref's avatar
Josh Soref committed
64
    return (isc::config::createAnswer(0, "Shutdown initiated."));
65
}
66

67
isc::data::ConstElementPtr
68
DStubProcess::configure(isc::data::ConstElementPtr config_set, bool check_only) {
69
    if (SimFailure::shouldFailOn(SimFailure::ftProcessConfigure)) {
70
        // Simulates a process configure failure.
71 72 73 74
        return (isc::config::createAnswer(1,
                "Simulated process configuration error."));
    }

75
    return (getCfgMgr()->simpleParseConfig(config_set, check_only));
76 77 78
}

DStubProcess::~DStubProcess() {
79
    Daemon::setVerbose(false);
80 81 82 83
};

//************************** DStubController *************************

84 85
// Define custom command line option command supported by DStubController.
const char* DStubController::stub_option_x_ = "x";
86

87 88 89 90 91 92
/// @brief Defines the app name used to construct the controller
const char* DStubController::stub_app_name_ = "TestService";

/// @brief Defines the bin name used to construct the controller
const char* DStubController::stub_bin_name_ = "TestBin";

93

94 95
DControllerBasePtr&
DStubController::instance() {
96
    // If the singleton hasn't been created, do it now.
97
    if (!getController()) {
98 99
        DControllerBasePtr p(new DStubController());
        setController(p);
100 101 102 103 104 105
    }

    return (getController());
}

DStubController::DStubController()
106
    : DControllerBase(stub_app_name_, stub_bin_name_),
107
      processed_signals_(), record_signal_only_(false), use_alternate_parser_(false) {
108 109 110 111 112
}

bool
DStubController::customOption(int option, char* /* optarg */)
{
113
    // Check for the custom option supported by DStubController.
114
    if (static_cast<char>(option) == *stub_option_x_) {
115
        return (true);
116
    }
117

118 119 120 121 122
    return (false);
}

DProcessBase* DStubController::createProcess() {
    if (SimFailure::shouldFailOn(SimFailure::ftCreateProcessException)) {
123
        // Simulates a failure to instantiate the process due to exception.
124 125 126 127
        throw std::runtime_error("SimFailure::ftCreateProcess");
    }

    if (SimFailure::shouldFailOn(SimFailure::ftCreateProcessNull)) {
128
        // Simulates a failure to instantiate the process.
129 130 131 132
        return (NULL);
    }

    // This should be a successful instantiation.
133
    return (new DStubProcess(getAppName().c_str(), getIOService()));
134 135
}

136
const std::string DStubController::getCustomOpts() const {
137 138
    // Return the "list" of custom options supported by DStubController.
    return (std::string(stub_option_x_));
139 140
}

141 142 143 144 145 146 147 148 149 150
void
DStubController::processSignal(int signum){
    processed_signals_.push_back(signum);
    if (record_signal_only_) {
        return;
    }

    DControllerBase::processSignal(signum);
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
isc::data::ConstElementPtr
DStubController::parseFile(const std::string& /*file_name*/) {
    isc::data::ConstElementPtr elements;
    if (use_alternate_parser_) {
        std::ostringstream os;

        os << "{ \"" << getController()->getAppName()
            << "\": " << std::endl;
        os <<  "{ \"string_test\": \"alt value\" } ";
        os << " } " << std::endl;
        elements = isc::data::Element::fromJSON(os.str());
    }

    return (elements);
}

167 168 169
DStubController::~DStubController() {
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
//************************** DControllerTest *************************

void
DControllerTest::writeFile(const std::string& content,
                           const std::string& module_name) {
    std::ofstream out(CFG_TEST_FILE, std::ios::trunc);
    ASSERT_TRUE(out.is_open());

    out << "{ \"" << (!module_name.empty() ? module_name
                      : getController()->getAppName())
        << "\": " << std::endl;

    out << content;
    out << " } " << std::endl;
    out.close();
}

void
DControllerTest::timedWriteCallback() {
    writeFile(new_cfg_content_);
}

void
DControllerTest::scheduleTimedWrite(const std::string& config,
                                    int write_time_ms) {
    new_cfg_content_ = config;
    write_timer_.reset(new asiolink::IntervalTimer(*getIOService()));
197
    write_timer_->setup(std::bind(&DControllerTest::timedWriteCallback, this),
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
                        write_time_ms, asiolink::IntervalTimer::ONE_SHOT);
}

void
DControllerTest::runWithConfig(const std::string& config, int run_time_ms,
                               time_duration& elapsed_time) {
    // Create the config file.
    writeFile(config);

    // Shutdown (without error) after runtime.
    isc::asiolink::IntervalTimer timer(*getIOService());
    timer.setup(genShutdownCallback, run_time_ms);

    // Record start time, and invoke launch().
    // We catch and rethrow to allow testing error scenarios.
    ptime start = microsec_clock::universal_time();
    try  {
215 216 217 218
        // Set up valid command line arguments
        char* argv[] = { const_cast<char*>("progName"),
                         const_cast<char*>("-c"),
                         const_cast<char*>(DControllerTest::CFG_TEST_FILE),
219
                         const_cast<char*>("-d") };
220
        launch(4, argv);
221
    } catch (...) {
Andrei Pavel's avatar
Andrei Pavel committed
222
        // calculate elapsed time, then rethrow it
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        elapsed_time = microsec_clock::universal_time() - start;
        throw;
    }

    elapsed_time = microsec_clock::universal_time() - start;
}

DProcessBasePtr
DControllerTest:: getProcess() {
    DProcessBasePtr p;
    if (getController()) {
        p = getController()->getProcess();
    }
    return (p);
}

DCfgMgrBasePtr
DControllerTest::getCfgMgr() {
    DCfgMgrBasePtr p;
    if (getProcess()) {
        p = getProcess()->getCfgMgr();
    }

    return (p);
}

249
ConfigPtr
250
DControllerTest::getContext() {
251
    ConfigPtr p;
252 253 254 255 256 257 258
    if (getCfgMgr()) {
        p = getCfgMgr()->getContext();
    }

    return (p);
}

259
// Initialize controller wrapper's static instance getter member.
260 261
DControllerTest::InstanceGetter DControllerTest::instanceGetter_ = NULL;

262 263 264
/// @brief Defines the name of the configuration file to use
const char* DControllerTest::CFG_TEST_FILE = "d2-test-config.json";

265 266
//************************** DStubContext *************************

267
DStubContext::DStubContext() {
268 269 270 271 272
}

DStubContext::~DStubContext() {
}

273
ConfigPtr
274
DStubContext::clone() {
275
    return (ConfigPtr(new DStubContext(*this)));
276 277
}

278
DStubContext::DStubContext(const DStubContext& rhs): ConfigBase(rhs) {
279 280
}

281 282 283 284 285
isc::data::ElementPtr
DStubContext::toElement() const {
    return (isc::data::Element::createMap());
}

286 287 288
//************************** DStubCfgMgr *************************

DStubCfgMgr::DStubCfgMgr()
289
    : DCfgMgrBase(ConfigPtr(new DStubContext())) {
290 291 292 293 294
}

DStubCfgMgr::~DStubCfgMgr() {
}

295
ConfigPtr
296
DStubCfgMgr::createNewContext() {
297
    return (ConfigPtr (new DStubContext()));
298 299
}

300 301 302 303 304
isc::data::ConstElementPtr
DStubCfgMgr::parse(isc::data::ConstElementPtr /*config*/, bool /*check_only*/) {
    return (isc::config::createAnswer(0, "It all went fine. I promise"));
}

305
}; // namespace isc::process
306
}; // namespace isc