d_test_stubs.cc 10.6 KB
Newer Older
1
// Copyright (C) 2013-2017 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 <cc/command_interpreter.h>
12

13
using namespace boost::asio;
14
15

namespace isc {
16
namespace process {
17

18
// Initialize the static failure flag.
19
20
SimFailure::FailureType SimFailure::failure_type_ = SimFailure::ftNoFailure;

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

25

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

34
void
35
36
37
38
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.
39
    // To use run(), the "managing" layer must issue an io_service::stop
40
41
    // or the call to run will continue to block, and shutdown will not
    // occur.
42
    asiolink::IOServicePtr& io_service = getIoService();
43
44
45
46
    while (!shouldShutdown()) {
        try {
            io_service->run_one();
        } catch (const std::exception& ex) {
47
48
            isc_throw (DProcessBaseError,
                std::string("Process run method failed:") + ex.what());
49
50
51
52
        }
    }
};

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

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

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

73
    return (getCfgMgr()->parseConfig(config_set, check_only));
74
75
76
77
78
79
80
}

DStubProcess::~DStubProcess() {
};

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

81
82
// Define custom command line option command supported by DStubController.
const char* DStubController::stub_option_x_ = "x";
83

84
85
86
87
88
89
/// @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";

90

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

    return (getController());
}

DStubController::DStubController()
103
    : DControllerBase(stub_app_name_, stub_bin_name_),
104
      processed_signals_(), record_signal_only_(false), use_alternate_parser_(false) {
105
106
107
108
109
}

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

115
116
117
118
119
    return (false);
}

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

    if (SimFailure::shouldFailOn(SimFailure::ftCreateProcessNull)) {
125
        // Simulates a failure to instantiate the process.
126
127
128
129
        return (NULL);
    }

    // This should be a successful instantiation.
130
    return (new DStubProcess(getAppName().c_str(), getIOService()));
131
132
}

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

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

    DControllerBase::processSignal(signum);
}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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);
}

164
165
166
DStubController::~DStubController() {
}

167
168
169
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//************************** 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()));
    write_timer_->setup(boost::bind(&DControllerTest::timedWriteCallback, this),
                        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  {
212
213
214
215
        // Set up valid command line arguments
        char* argv[] = { const_cast<char*>("progName"),
                         const_cast<char*>("-c"),
                         const_cast<char*>(DControllerTest::CFG_TEST_FILE),
216
                         const_cast<char*>("-d") };
217
        launch(4, argv);
218
    } catch (...) {
Andrei Pavel's avatar
Andrei Pavel committed
219
        // calculate elapsed time, then rethrow it
220
221
222
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
249
250
251
252
253
254
255
        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);
}

DCfgContextBasePtr
DControllerTest::getContext() {
    DCfgContextBasePtr p;
    if (getCfgMgr()) {
        p = getCfgMgr()->getContext();
    }

    return (p);
}

256
// Initialize controller wrapper's static instance getter member.
257
258
DControllerTest::InstanceGetter DControllerTest::instanceGetter_ = NULL;

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

262
263
//************************** DStubContext *************************

264
DStubContext::DStubContext(): object_values_(new ObjectStorage()) {
265
266
267
268
269
270
}

DStubContext::~DStubContext() {
}

void
271
272
273
DStubContext::getObjectParam(const std::string& name,
                             isc::data::ConstElementPtr& value) {
    value = object_values_->getParam(name);
274
275
}

276
277
278
ObjectStoragePtr&
DStubContext::getObjectStorage() {
    return (object_values_);
279
280
}

281
DCfgContextBasePtr
282
DStubContext::clone() {
283
    return (DCfgContextBasePtr(new DStubContext(*this)));
284
285
286
}

DStubContext::DStubContext(const DStubContext& rhs): DCfgContextBase(rhs),
287
    object_values_(new ObjectStorage(*(rhs.object_values_))) {
288
289
}

290
291
292
293
294
isc::data::ElementPtr
DStubContext::toElement() const {
    return (isc::data::Element::createMap());
}

295
296
297
298
299
300
301
302
303
//************************** DStubCfgMgr *************************

DStubCfgMgr::DStubCfgMgr()
    : DCfgMgrBase(DCfgContextBasePtr(new DStubContext())) {
}

DStubCfgMgr::~DStubCfgMgr() {
}

304
DCfgContextBasePtr
305
306
307
308
DStubCfgMgr::createNewContext() {
    return (DCfgContextBasePtr (new DStubContext()));
}

309
310
311
void
DStubCfgMgr::parseElement(const std::string& element_id,
                          isc::data::ConstElementPtr element) {
312
313
    DStubContextPtr context
        = boost::dynamic_pointer_cast<DStubContext>(getContext());
314

315
    if (element_id == "bool_test") {
316
317
318
        bool value = element->boolValue();
        context->getBooleanStorage()->setParam(element_id, value,
                                               element->getPosition()); 
319
    } else if (element_id == "uint32_test") {
320
321
322
323
        uint32_t value = element->intValue();
        context->getUint32Storage()->setParam(element_id, value,
                                              element->getPosition()); 

324
    } else if (element_id == "string_test") {
325
326
327
        std::string value = element->stringValue();
        context->getStringStorage()->setParam(element_id, value,
                                              element->getPosition()); 
328
329
330
331
332
    } else {
        // Fail only if SimFailure dictates we should.  This makes it easier
        // to test parse ordering, by permitting a wide range of element ids
        // to "succeed" without specifically supporting them.
        if (SimFailure::shouldFailOn(SimFailure::ftElementUnknown)) {
333
            isc_throw(DCfgMgrBaseError,
334
                      "Configuration parameter not supported: " << element_id
335
                      << element->getPosition());
336
337
        }

338
        // Going to assume anything else is an object element.
339
340
        context->getObjectStorage()->setParam(element_id, element,
                                              element->getPosition()); 
341
342
    }

343
    parsed_order_.push_back(element_id);
344
345
}

346
347
348
349
350
isc::data::ConstElementPtr
DStubCfgMgr::parse(isc::data::ConstElementPtr /*config*/, bool /*check_only*/) {
    return (isc::config::createAnswer(0, "It all went fine. I promise"));
}

351
}; // namespace isc::process
352
}; // namespace isc