1 // Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <exceptions/exceptions.h>
10 #include <dhcp/dhcp6.h>
11 #include <dhcp/tests/iface_mgr_test_config.h>
12 #include <dhcpsrv/cfgmgr.h>
13 #include <dhcpsrv/lease_mgr_factory.h>
14 #include <dhcpsrv/subnet_id.h>
15 #include <dhcpsrv/parsers/dhcp_parsers.h>
16 #include <process/logging_info.h>
17 #include <stats/stats_mgr.h>
18 #include <util/chrono_time_utils.h>
19
20 #include <boost/scoped_ptr.hpp>
21
22 #include <gtest/gtest.h>
23
24 #include <iostream>
25 #include <sstream>
26
27 #include <arpa/inet.h>
28
29 using namespace std;
30 using namespace isc::asiolink;
31 using namespace isc::data;
32 using namespace isc::dhcp;
33 using namespace isc::dhcp::test;
34 using namespace isc::util;
35 using namespace isc::stats;
36 using namespace isc::process;
37 using namespace isc;
38
39 // don't import the entire boost namespace. It will unexpectedly hide uint8_t
40 // for some systems.
41 using boost::scoped_ptr;
42
43 namespace {
44
45 template <typename Storage>
isZeroPosition(const Storage & storage,const std::string & param_name)46 bool isZeroPosition(const Storage& storage, const std::string& param_name) {
47 Element::Position position = storage.getPosition(param_name);
48 return ((position.line_ == 0) && (position.pos_ == 0) &&
49 (position.file_.empty()));
50 }
51
52 // This test verifies that BooleanStorage functions properly.
TEST(ValueStorageTest,BooleanTesting)53 TEST(ValueStorageTest, BooleanTesting) {
54 BooleanStorage testStore;
55
56 // Verify that we can add and retrieve parameters.
57 testStore.setParam("firstBool", false, Element::Position("kea.conf", 123, 234));
58 testStore.setParam("secondBool", true, Element::Position("keax.conf", 10, 20));
59
60 EXPECT_FALSE(testStore.getParam("firstBool"));
61 EXPECT_TRUE(testStore.getParam("secondBool"));
62
63 EXPECT_EQ(123, testStore.getPosition("firstBool").line_);
64 EXPECT_EQ(234, testStore.getPosition("firstBool").pos_);
65 EXPECT_EQ("kea.conf", testStore.getPosition("firstBool").file_);
66
67 EXPECT_EQ(10, testStore.getPosition("secondBool").line_);
68 EXPECT_EQ(20, testStore.getPosition("secondBool").pos_);
69 EXPECT_EQ("keax.conf", testStore.getPosition("secondBool").file_);
70
71 // Verify that we can update parameters.
72 testStore.setParam("firstBool", true, Element::Position("keax.conf", 555, 111));
73 testStore.setParam("secondBool", false, Element::Position("kea.conf", 1, 3));
74
75 EXPECT_TRUE(testStore.getParam("firstBool"));
76 EXPECT_FALSE(testStore.getParam("secondBool"));
77
78 EXPECT_EQ(555, testStore.getPosition("firstBool").line_);
79 EXPECT_EQ(111, testStore.getPosition("firstBool").pos_);
80 EXPECT_EQ("keax.conf", testStore.getPosition("firstBool").file_);
81
82 EXPECT_EQ(1, testStore.getPosition("secondBool").line_);
83 EXPECT_EQ(3, testStore.getPosition("secondBool").pos_);
84 EXPECT_EQ("kea.conf", testStore.getPosition("secondBool").file_);
85
86 // Verify that we can delete a parameter and it will no longer be found.
87 testStore.delParam("firstBool");
88 EXPECT_THROW(testStore.getParam("firstBool"), isc::dhcp::DhcpConfigError);
89
90 // Verify that the "zero" position is returned when parameter doesn't exist.
91 EXPECT_TRUE(isZeroPosition(testStore, "firstBool"));
92
93 // Verify that the delete was safe and the store still operates.
94 EXPECT_FALSE(testStore.getParam("secondBool"));
95
96 EXPECT_EQ(1, testStore.getPosition("secondBool").line_);
97 EXPECT_EQ(3, testStore.getPosition("secondBool").pos_);
98 EXPECT_EQ("kea.conf", testStore.getPosition("secondBool").file_);
99
100 // Verify that looking for a parameter that never existed throws.
101 ASSERT_THROW(testStore.getParam("bogusBool"), isc::dhcp::DhcpConfigError);
102
103 // Verify that the "zero" position is returned when parameter doesn't exist.
104 EXPECT_TRUE(isZeroPosition(testStore, "bogusBool"));
105
106 // Verify that attempting to delete a parameter that never existed does not throw.
107 EXPECT_NO_THROW(testStore.delParam("bogusBool"));
108
109 // Verify that we can empty the list.
110 testStore.clear();
111 EXPECT_THROW(testStore.getParam("secondBool"), isc::dhcp::DhcpConfigError);
112
113 // Verify that the "zero" position is returned when parameter doesn't exist.
114 EXPECT_TRUE(isZeroPosition(testStore, "secondBool"));
115 }
116
117 // This test verifies that Uint32Storage functions properly.
TEST(ValueStorageTest,Uint32Testing)118 TEST(ValueStorageTest, Uint32Testing) {
119 Uint32Storage testStore;
120
121 uint32_t int_one = 77;
122 uint32_t int_two = 33;
123
124 // Verify that we can add and retrieve parameters.
125 testStore.setParam("firstInt", int_one, Element::Position("kea.conf", 123, 234));
126 testStore.setParam("secondInt", int_two, Element::Position("keax.conf", 10, 20));
127
128 EXPECT_EQ(testStore.getParam("firstInt"), int_one);
129 EXPECT_EQ(testStore.getParam("secondInt"), int_two);
130
131 EXPECT_EQ(123, testStore.getPosition("firstInt").line_);
132 EXPECT_EQ(234, testStore.getPosition("firstInt").pos_);
133 EXPECT_EQ("kea.conf", testStore.getPosition("firstInt").file_);
134
135 EXPECT_EQ(10, testStore.getPosition("secondInt").line_);
136 EXPECT_EQ(20, testStore.getPosition("secondInt").pos_);
137 EXPECT_EQ("keax.conf", testStore.getPosition("secondInt").file_);
138
139 // Verify that we can update parameters.
140 testStore.setParam("firstInt", --int_one, Element::Position("keax.conf", 555, 111));
141 testStore.setParam("secondInt", ++int_two, Element::Position("kea.conf", 1, 3));
142
143 EXPECT_EQ(testStore.getParam("firstInt"), int_one);
144 EXPECT_EQ(testStore.getParam("secondInt"), int_two);
145
146 EXPECT_EQ(555, testStore.getPosition("firstInt").line_);
147 EXPECT_EQ(111, testStore.getPosition("firstInt").pos_);
148 EXPECT_EQ("keax.conf", testStore.getPosition("firstInt").file_);
149
150 EXPECT_EQ(1, testStore.getPosition("secondInt").line_);
151 EXPECT_EQ(3, testStore.getPosition("secondInt").pos_);
152 EXPECT_EQ("kea.conf", testStore.getPosition("secondInt").file_);
153
154 // Verify that we can delete a parameter and it will no longer be found.
155 testStore.delParam("firstInt");
156 EXPECT_THROW(testStore.getParam("firstInt"), isc::dhcp::DhcpConfigError);
157
158 // Verify that the "zero" position is returned when parameter doesn't exist.
159 EXPECT_TRUE(isZeroPosition(testStore, "firstInt"));
160
161 // Verify that the delete was safe and the store still operates.
162 EXPECT_EQ(testStore.getParam("secondInt"), int_two);
163
164 EXPECT_EQ(1, testStore.getPosition("secondInt").line_);
165 EXPECT_EQ(3, testStore.getPosition("secondInt").pos_);
166 EXPECT_EQ("kea.conf", testStore.getPosition("secondInt").file_);
167
168 // Verify that looking for a parameter that never existed throws.
169 ASSERT_THROW(testStore.getParam("bogusInt"), isc::dhcp::DhcpConfigError);
170
171 // Verify that attempting to delete a parameter that never existed does not throw.
172 EXPECT_NO_THROW(testStore.delParam("bogusInt"));
173
174 // Verify that the "zero" position is returned when parameter doesn't exist.
175 EXPECT_TRUE(isZeroPosition(testStore, "bogusInt"));
176
177 // Verify that we can empty the list.
178 testStore.clear();
179 EXPECT_THROW(testStore.getParam("secondInt"), isc::dhcp::DhcpConfigError);
180
181 // Verify that the "zero" position is returned when parameter doesn't exist.
182 EXPECT_TRUE(isZeroPosition(testStore, "secondInt"));
183 }
184
185 // This test verifies that StringStorage functions properly.
TEST(ValueStorageTest,StringTesting)186 TEST(ValueStorageTest, StringTesting) {
187 StringStorage testStore;
188
189 std::string string_one = "seventy-seven";
190 std::string string_two = "thirty-three";
191
192 // Verify that we can add and retrieve parameters.
193 testStore.setParam("firstString", string_one,
194 Element::Position("kea.conf", 123, 234));
195 testStore.setParam("secondString", string_two,
196 Element::Position("keax.conf", 10, 20));
197
198 EXPECT_EQ(testStore.getParam("firstString"), string_one);
199 EXPECT_EQ(testStore.getParam("secondString"), string_two);
200
201 EXPECT_EQ(123, testStore.getPosition("firstString").line_);
202 EXPECT_EQ(234, testStore.getPosition("firstString").pos_);
203 EXPECT_EQ("kea.conf", testStore.getPosition("firstString").file_);
204
205 EXPECT_EQ(10, testStore.getPosition("secondString").line_);
206 EXPECT_EQ(20, testStore.getPosition("secondString").pos_);
207 EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
208
209 // Verify that we can update parameters.
210 string_one.append("-boo");
211 string_two.append("-boo");
212
213 testStore.setParam("firstString", string_one,
214 Element::Position("kea.conf", 555, 111));
215 testStore.setParam("secondString", string_two,
216 Element::Position("keax.conf", 1, 3));
217
218 EXPECT_EQ(testStore.getParam("firstString"), string_one);
219 EXPECT_EQ(testStore.getParam("secondString"), string_two);
220
221 EXPECT_EQ(555, testStore.getPosition("firstString").line_);
222 EXPECT_EQ(111, testStore.getPosition("firstString").pos_);
223 EXPECT_EQ("kea.conf", testStore.getPosition("firstString").file_);
224
225 EXPECT_EQ(1, testStore.getPosition("secondString").line_);
226 EXPECT_EQ(3, testStore.getPosition("secondString").pos_);
227 EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
228
229 // Verify that we can delete a parameter and it will no longer be found.
230 testStore.delParam("firstString");
231 EXPECT_THROW(testStore.getParam("firstString"), isc::dhcp::DhcpConfigError);
232
233 // Verify that the "zero" position is returned when parameter doesn't exist.
234 EXPECT_TRUE(isZeroPosition(testStore, "firstString"));
235
236 // Verify that the delete was safe and the store still operates.
237 EXPECT_EQ(testStore.getParam("secondString"), string_two);
238
239 EXPECT_EQ(1, testStore.getPosition("secondString").line_);
240 EXPECT_EQ(3, testStore.getPosition("secondString").pos_);
241 EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
242
243 // Verify that looking for a parameter that never existed throws.
244 ASSERT_THROW(testStore.getParam("bogusString"), isc::dhcp::DhcpConfigError);
245
246 // Verify that attempting to delete a parameter that never existed does not throw.
247 EXPECT_NO_THROW(testStore.delParam("bogusString"));
248
249 // Verify that the "zero" position is returned when parameter doesn't exist.
250 EXPECT_TRUE(isZeroPosition(testStore, "bogusString"));
251
252 // Verify that we can empty the list.
253 testStore.clear();
254 EXPECT_THROW(testStore.getParam("secondString"), isc::dhcp::DhcpConfigError);
255
256 // Verify that the "zero" position is returned when parameter doesn't exist.
257 EXPECT_TRUE(isZeroPosition(testStore, "secondString"));
258 }
259
260
261
262 class CfgMgrTest : public ::testing::Test {
263 public:
CfgMgrTest()264 CfgMgrTest() {
265 // make sure we start with a clean configuration
266 original_datadir_ = CfgMgr::instance().getDataDir();
267 clear();
268 }
269
270 /// @brief generates interface-id option based on provided text
271 ///
272 /// @param text content of the option to be created
273 ///
274 /// @return pointer to the option object created
generateInterfaceId(const string & text)275 OptionPtr generateInterfaceId(const string& text) {
276 OptionBuffer buffer(text.begin(), text.end());
277 return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, buffer));
278 }
279
~CfgMgrTest()280 ~CfgMgrTest() {
281 // clean up after the test
282 clear();
283 }
284
clear()285 void clear() {
286 CfgMgr::instance().setFamily(AF_INET);
287 CfgMgr::instance().setDataDir(original_datadir_);
288 CfgMgr::instance().clear();
289 LeaseMgrFactory::destroy();
290 }
291
292 /// @brief Creates instance of the backend.
293 ///
294 /// @param family AF_INET for v4, AF_INET6 for v6
startBackend(int family=AF_INET)295 void startBackend(int family = AF_INET) {
296 try {
297 std::ostringstream s;
298 s << "type=memfile persist=false " << (family == AF_INET6 ?
299 "universe=6" : "universe=4");
300 LeaseMgrFactory::create(s.str());
301 } catch (const std::exception& ex) {
302 std::cerr << "*** ERROR: unable to create instance of the Memfile\n"
303 " lease database backend: " << ex.what() << std::endl;
304 throw;
305 }
306 }
307
308 /// used in client classification (or just empty container for other tests)
309 isc::dhcp::ClientClasses classify_;
310
311 private:
312 /// to restore it in destructor.
313 string original_datadir_;
314 };
315
316 // Checks that there is a configuration structure available and that
317 // it is empty by default.
TEST_F(CfgMgrTest,configuration)318 TEST_F(CfgMgrTest, configuration) {
319
320 ConstSrvConfigPtr configuration = CfgMgr::instance().getCurrentCfg();
321 ASSERT_TRUE(configuration);
322 EXPECT_TRUE(configuration->getLoggingInfo().empty());
323
324 configuration = CfgMgr::instance().getStagingCfg();
325 ASSERT_TRUE(configuration);
326 EXPECT_TRUE(configuration->getLoggingInfo().empty());
327 }
328
329 // This test checks the data directory handling.
TEST_F(CfgMgrTest,dataDir)330 TEST_F(CfgMgrTest, dataDir) {
331 // It is only in DHCPv6 syntax so switch to IPv6.
332 CfgMgr::instance().setFamily(AF_INET6);
333
334 // Default.
335 EXPECT_TRUE(CfgMgr::instance().getDataDir().unspecified());
336 ConstElementPtr json = CfgMgr::instance().getCurrentCfg()->toElement();
337 ASSERT_TRUE(json);
338 ASSERT_EQ(Element::map, json->getType());
339 ConstElementPtr dhcp = json->get("Dhcp6");
340 ASSERT_TRUE(dhcp);
341 ASSERT_EQ(Element::map, dhcp->getType());
342 ConstElementPtr datadir = dhcp->get("data-directory");
343 EXPECT_FALSE(datadir);
344
345 // Set but not specified.
346 CfgMgr::instance().setDataDir("/tmp");
347 EXPECT_TRUE(CfgMgr::instance().getDataDir().unspecified());
348 EXPECT_EQ("/tmp", string(CfgMgr::instance().getDataDir()));
349 json = CfgMgr::instance().getCurrentCfg()->toElement();
350 ASSERT_TRUE(json);
351 ASSERT_EQ(Element::map, json->getType());
352 dhcp = json->get("Dhcp6");
353 ASSERT_TRUE(dhcp);
354 ASSERT_EQ(Element::map, dhcp->getType());
355 datadir = dhcp->get("data-directory");
356 EXPECT_FALSE(datadir);
357
358 // Set and specified.
359 CfgMgr::instance().setDataDir("/tmp", false);
360 EXPECT_FALSE(CfgMgr::instance().getDataDir().unspecified());
361 EXPECT_EQ("/tmp", string(CfgMgr::instance().getDataDir()));
362 json = CfgMgr::instance().getCurrentCfg()->toElement();
363 ASSERT_TRUE(json);
364 ASSERT_EQ(Element::map, json->getType());
365 dhcp = json->get("Dhcp6");
366 ASSERT_TRUE(dhcp);
367 ASSERT_EQ(Element::map, dhcp->getType());
368 datadir = dhcp->get("data-directory");
369 ASSERT_TRUE(datadir);
370 ASSERT_EQ(Element::string, datadir->getType());
371 EXPECT_EQ("/tmp", datadir->stringValue());
372
373 // Still IPv6 only.
374 CfgMgr::instance().setFamily(AF_INET);
375 EXPECT_FALSE(CfgMgr::instance().getDataDir().unspecified());
376 EXPECT_EQ("/tmp", string(CfgMgr::instance().getDataDir()));
377 json = CfgMgr::instance().getCurrentCfg()->toElement();
378 ASSERT_TRUE(json);
379 ASSERT_EQ(Element::map, json->getType());
380 dhcp = json->get("Dhcp4");
381 ASSERT_TRUE(dhcp);
382 ASSERT_EQ(Element::map, dhcp->getType());
383 datadir = dhcp->get("data-directory");
384 EXPECT_FALSE(datadir);
385 }
386
387 // This test checks the D2ClientMgr wrapper methods.
TEST_F(CfgMgrTest,d2ClientConfig)388 TEST_F(CfgMgrTest, d2ClientConfig) {
389 // After CfgMgr construction, D2ClientMgr member should be initialized
390 // with a D2 configuration that is disabled.
391 // Verify we can Fetch the mgr.
392 D2ClientMgr& d2_mgr = CfgMgr::instance().getD2ClientMgr();
393 EXPECT_FALSE(d2_mgr.ddnsEnabled());
394
395 // Make sure the convenience method fetches the config correctly.
396 D2ClientConfigPtr original_config = CfgMgr::instance().getD2ClientConfig();
397 ASSERT_TRUE(original_config);
398 EXPECT_FALSE(original_config->getEnableUpdates());
399
400 // Verify that we cannot set the configuration to an empty pointer.
401 D2ClientConfigPtr new_cfg;
402 ASSERT_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg), D2ClientError);
403
404 // Create a new, enabled configuration.
405 ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
406 isc::asiolink::IOAddress("127.0.0.1"), 477,
407 isc::asiolink::IOAddress("127.0.0.1"), 478,
408 1024,
409 dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON)));
410
411 // Verify that we can assign a new, non-empty configuration.
412 ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg));
413
414 // Verify that we can fetch the newly assigned configuration.
415 D2ClientConfigPtr updated_config = CfgMgr::instance().getD2ClientConfig();
416 ASSERT_TRUE(updated_config);
417 EXPECT_TRUE(updated_config->getEnableUpdates());
418
419 // Make sure convenience method agrees with updated configuration.
420 EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
421
422 // Make sure the configuration we fetched is the one we assigned,
423 // and not the original configuration.
424 EXPECT_EQ(*new_cfg, *updated_config);
425 EXPECT_NE(*original_config, *updated_config);
426
427 // Revert to default configuration.
428 ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(original_config));
429 }
430
431 // This test verifies that the configuration staging, commit and rollback works
432 // as expected.
TEST_F(CfgMgrTest,staging)433 TEST_F(CfgMgrTest, staging) {
434 CfgMgr& cfg_mgr = CfgMgr::instance();
435 // Initially, the current configuration is a default one. We are going
436 // to get the current configuration a couple of times and make sure
437 // that always the same instance is returned.
438 ConstSrvConfigPtr const_config;
439 for (int i = 0; i < 5; ++i) {
440 const_config = cfg_mgr.getCurrentCfg();
441 ASSERT_TRUE(const_config) << "Returned NULL current configuration"
442 " for iteration " << i;
443 EXPECT_EQ(0, const_config->getSequence())
444 << "Returned invalid sequence number "
445 << const_config->getSequence() << " for iteration " << i;
446 }
447
448 // Try to get the new staging configuration. When getStagingCfg() is called
449 // for the first time the new instance of the staging configuration is
450 // returned. This instance is returned for every call to getStagingCfg()
451 // until commit is called.
452 SrvConfigPtr config;
453 for (int i = 0; i < 5; ++i) {
454 config = cfg_mgr.getStagingCfg();
455 ASSERT_TRUE(config) << "Returned NULL staging configuration for"
456 " iteration " << i;
457 // The sequence id is 1 for staging because it is ahead of current
458 // configuration having sequence number 0.
459 EXPECT_EQ(1, config->getSequence()) << "Returned invalid sequence"
460 " number " << config->getSequence() << " for iteration " << i;
461 }
462
463 // This should change the staging configuration so as it becomes a current
464 // one.
465 auto before = boost::posix_time::second_clock::universal_time();
466 cfg_mgr.commit();
467 auto after = boost::posix_time::second_clock::universal_time();
468 const_config = cfg_mgr.getCurrentCfg();
469 ASSERT_TRUE(const_config);
470 // Sequence id equal to 1 indicates that the current configuration points
471 // to the configuration that used to be a staging configuration previously.
472 EXPECT_EQ(1, const_config->getSequence());
473 // Last commit timestamp should be between before and after.
474 auto reload = const_config->getLastCommitTime();
475 ASSERT_FALSE(reload.is_not_a_date_time());
476 EXPECT_LE(before, reload);
477 EXPECT_GE(after, reload);
478
479 // Create a new staging configuration. It should be assigned a new
480 // sequence id.
481 config = cfg_mgr.getStagingCfg();
482 ASSERT_TRUE(config);
483 EXPECT_EQ(2, config->getSequence());
484
485 // Let's execute commit a couple of times. The first invocation to commit
486 // changes the configuration having sequence 2 to current configuration.
487 // Other commits are no-op.
488 for (int i = 0; i < 5; ++i) {
489 cfg_mgr.commit();
490 }
491
492 // The current configuration now have sequence number 2.
493 const_config = cfg_mgr.getCurrentCfg();
494 ASSERT_TRUE(const_config);
495 EXPECT_EQ(2, const_config->getSequence());
496
497 // Clear configuration along with a history.
498 cfg_mgr.clear();
499
500 // After clearing configuration we should successfully get the
501 // new staging configuration.
502 config = cfg_mgr.getStagingCfg();
503 ASSERT_TRUE(config);
504 EXPECT_EQ(1, config->getSequence());
505
506 // Modify the staging configuration.
507 config->addLoggingInfo(LoggingInfo());
508 ASSERT_TRUE(config);
509 // The modified staging configuration should have one logger configured.
510 ASSERT_EQ(1, config->getLoggingInfo().size());
511
512 // Rollback should remove a staging configuration, including the logger.
513 ASSERT_NO_THROW(cfg_mgr.rollback());
514
515 // Make sure that the logger is not set. This is an indication that the
516 // rollback worked.
517 config = cfg_mgr.getStagingCfg();
518 ASSERT_TRUE(config);
519 EXPECT_EQ(0, config->getLoggingInfo().size());
520 }
521
522 // This test verifies that it is possible to revert to an old configuration.
TEST_F(CfgMgrTest,revert)523 TEST_F(CfgMgrTest, revert) {
524 CfgMgr& cfg_mgr = CfgMgr::instance();
525 // Let's create 5 unique configurations: differing by a debug level in the
526 // range of 10 to 14.
527 for (int i = 0; i < 5; ++i) {
528 SrvConfigPtr config = cfg_mgr.getStagingCfg();
529 LoggingInfo logging_info;
530 logging_info.debuglevel_ = i + 10;
531 config->addLoggingInfo(logging_info);
532 cfg_mgr.commit();
533 }
534
535 // Now we have 6 configurations with:
536 // - debuglevel = 99 (a default one)
537 // - debuglevel = 10
538 // - debuglevel = 11
539 // - debuglevel = 12
540 // - debuglevel = 13
541 // - debuglevel = 14 (current)
542
543 // Hence, the maximum index of the configuration to revert is 5 (which
544 // points to the configuration with debuglevel = 99). For the index greater
545 // than 5 we should get an exception.
546 ASSERT_THROW(cfg_mgr.revert(6), isc::OutOfRange);
547 // Value of 0 also doesn't make sense.
548 ASSERT_THROW(cfg_mgr.revert(0), isc::OutOfRange);
549
550 // We should be able to revert to configuration with debuglevel = 10.
551 ASSERT_NO_THROW(cfg_mgr.revert(4));
552 // And this configuration should be now the current one and the debuglevel
553 // of this configuration is 10.
554 EXPECT_EQ(10, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
555 EXPECT_NE(cfg_mgr.getCurrentCfg()->getSequence(), 1);
556
557 // The new set of configuration is now as follows:
558 // - debuglevel = 99
559 // - debuglevel = 10
560 // - debuglevel = 11
561 // - debuglevel = 12
562 // - debuglevel = 13
563 // - debuglevel = 14
564 // - debuglevel = 10 (current)
565 // So, reverting to configuration having index 3 means that the debug level
566 // of the current configuration will become 12.
567 ASSERT_NO_THROW(cfg_mgr.revert(3));
568 EXPECT_EQ(12, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
569 }
570
571 // This test verifies that the address family can be set and obtained
572 // from the configuration manager.
TEST_F(CfgMgrTest,family)573 TEST_F(CfgMgrTest, family) {
574 ASSERT_EQ(AF_INET, CfgMgr::instance().getFamily());
575
576 CfgMgr::instance().setFamily(AF_INET6);
577 ASSERT_EQ(AF_INET6, CfgMgr::instance().getFamily());
578
579 CfgMgr::instance().setFamily(AF_INET);
580 EXPECT_EQ(AF_INET, CfgMgr::instance().getFamily());
581 }
582
583 // This test verifies that once the configuration is committed, statistics
584 // are updated appropriately.
TEST_F(CfgMgrTest,commitStats4)585 TEST_F(CfgMgrTest, commitStats4) {
586 CfgMgr& cfg_mgr = CfgMgr::instance();
587 StatsMgr& stats_mgr = StatsMgr::instance();
588 startBackend(AF_INET);
589
590 // Let's prepare the "old" configuration: a subnet with id 123
591 // and pretend there were addresses assigned, so statistics are non-zero.
592 Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
593 CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
594 subnets->add(subnet1);
595 cfg_mgr.commit();
596 stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
597 stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
598
599 // Now, let's change the configuration to something new.
600
601 // There's a subnet 192.1.2.0/24 with ID=42
602 Subnet4Ptr subnet2(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 42));
603
604 // Let's make a pool with 128 addresses available.
605 PoolPtr pool(new Pool4(IOAddress("192.1.2.0"), 25)); // 128 addrs
606 subnet2->addPool(pool);
607
608 subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
609 subnets->add(subnet2);
610
611 // Change the stats default limits.
612 cfg_mgr.getStagingCfg()->addConfiguredGlobal("statistic-default-sample-count",
613 Element::create(15));
614 cfg_mgr.getStagingCfg()->addConfiguredGlobal("statistic-default-sample-age",
615 Element::create(2));
616
617 // Let's commit it
618 cfg_mgr.commit();
619
620 EXPECT_EQ(15, stats_mgr.getMaxSampleCountDefault());
621 EXPECT_EQ("00:00:02", durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
622
623 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-addresses"));
624 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-addresses"));
625
626 ObservationPtr total_addrs;
627 EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-addresses"));
628 ASSERT_TRUE(total_addrs);
629 EXPECT_EQ(128, total_addrs->getInteger().first);
630 EXPECT_TRUE(total_addrs->getMaxSampleCount().first);
631 EXPECT_EQ(15, total_addrs->getMaxSampleCount().second);
632 EXPECT_FALSE(total_addrs->getMaxSampleAge().first);
633 EXPECT_EQ("00:00:02", durationToText(total_addrs->getMaxSampleAge().second, 0));
634 }
635
636 // This test verifies that once the configuration is merged into the current
637 // configuration, statistics are updated appropriately.
TEST_F(CfgMgrTest,mergeIntoCurrentStats4)638 TEST_F(CfgMgrTest, mergeIntoCurrentStats4) {
639 CfgMgr& cfg_mgr = CfgMgr::instance();
640 StatsMgr& stats_mgr = StatsMgr::instance();
641 startBackend(AF_INET);
642
643 // Let's prepare the "old" configuration: a subnet with id 123
644 // and pretend there were addresses assigned, so statistics are non-zero.
645 Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
646 CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
647 subnets->add(subnet1);
648 cfg_mgr.commit();
649 stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
650 stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
651
652 // There should be no stats for subnet 42 at this point.
653 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].total-addresses"));
654 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].assigned-addresses"));
655
656 // Now, let's create new configuration with updates.
657
658 // There's a subnet 192.1.3.0/24 with ID=42
659 Subnet4Ptr subnet2(new Subnet4(IOAddress("192.1.3.0"), 24, 1, 2, 3, 42));
660
661 // Let's make a pool with 128 addresses available.
662 PoolPtr pool(new Pool4(IOAddress("192.1.3.0"), 25)); // 128 addrs
663 subnet2->addPool(pool);
664
665 // Create external configuration to be merged into current one.
666 auto external_cfg = CfgMgr::instance().createExternalCfg();
667 subnets = external_cfg->getCfgSubnets4();
668 subnets->add(subnet2);
669
670 external_cfg->addConfiguredGlobal("statistic-default-sample-count",
671 Element::create(16));
672 external_cfg->addConfiguredGlobal("statistic-default-sample-age",
673 Element::create(3));
674
675 // Let's merge it.
676 cfg_mgr.mergeIntoCurrentCfg(external_cfg->getSequence());
677
678 // The stats should have been updated and so we should be able to get
679 // observations for subnet 42.
680 EXPECT_EQ(16, stats_mgr.getMaxSampleCountDefault());
681 EXPECT_EQ("00:00:03", durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
682
683 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].total-addresses"));
684 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].assigned-addresses"));
685
686 // And also for 123
687 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-addresses"));
688 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-addresses"));
689
690 ObservationPtr total_addrs;
691 EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-addresses"));
692 ASSERT_TRUE(total_addrs);
693 EXPECT_EQ(128, total_addrs->getInteger().first);
694 }
695
696 // This test verifies that once the configuration is cleared, the statistics
697 // are removed.
TEST_F(CfgMgrTest,clearStats4)698 TEST_F(CfgMgrTest, clearStats4) {
699 CfgMgr& cfg_mgr = CfgMgr::instance();
700 StatsMgr& stats_mgr = StatsMgr::instance();
701
702 // Let's prepare the "old" configuration: a subnet with id 123
703 // and pretend there were addresses assigned, so statistics are non-zero.
704 Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
705 CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
706 subnets->add(subnet1);
707 cfg_mgr.commit();
708 stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
709 stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
710
711 // The stats should be there.
712 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-addresses"));
713 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-addresses"));
714
715 // Let's remove all configurations
716 cfg_mgr.clear();
717
718 // The stats should not be there anymore.
719 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-addresses"));
720 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-addresses"));
721 }
722
723 // This test verifies that once the configuration is committed, statistics
724 // are updated appropriately.
TEST_F(CfgMgrTest,commitStats6)725 TEST_F(CfgMgrTest, commitStats6) {
726 CfgMgr& cfg_mgr = CfgMgr::instance();
727 StatsMgr& stats_mgr = StatsMgr::instance();
728 startBackend(AF_INET6);
729
730 // Let's prepare the "old" configuration: a subnet with id 123
731 // and pretend there were addresses assigned, so statistics are non-zero.
732 Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4, 123));
733 CfgSubnets6Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets6();
734 subnets->add(subnet1);
735 cfg_mgr.commit();
736 stats_mgr.addValue("subnet[123].total-nas", static_cast<int64_t>(256));
737 stats_mgr.setValue("subnet[123].assigned-nas", static_cast<int64_t>(150));
738
739 stats_mgr.addValue("subnet[123].total-pds", static_cast<int64_t>(256));
740 stats_mgr.setValue("subnet[123].assigned-pds", static_cast<int64_t>(150));
741
742 // Now, let's change the configuration to something new.
743
744 // There's a subnet 2001:db8:2::/48 with ID=42
745 Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4, 42));
746
747 // Let's make pools with 128 addresses and 65536 prefixes available.
748 PoolPtr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), 121)); // 128 addrs
749 PoolPtr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:3::"), 96, 112)); // 65536 prefixes
750 subnet2->addPool(pool1);
751 subnet2->addPool(pool2);
752
753 subnets = cfg_mgr.getStagingCfg()->getCfgSubnets6();
754 subnets->add(subnet2);
755
756 // Change the stats default limits.
757 cfg_mgr.getStagingCfg()->addConfiguredGlobal("statistic-default-sample-count",
758 Element::create(14));
759 cfg_mgr.getStagingCfg()->addConfiguredGlobal("statistic-default-sample-age",
760 Element::create(10));
761
762 // Let's commit it
763 cfg_mgr.commit();
764
765 EXPECT_EQ(14, stats_mgr.getMaxSampleCountDefault());
766 EXPECT_EQ("00:00:10", durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
767
768 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-nas"));
769 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-nas"));
770
771 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-pds"));
772 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-pds"));
773
774 ObservationPtr total_addrs;
775 EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-nas"));
776 ASSERT_TRUE(total_addrs);
777 EXPECT_EQ(128, total_addrs->getInteger().first);
778 EXPECT_TRUE(total_addrs->getMaxSampleCount().first);
779 EXPECT_EQ(14, total_addrs->getMaxSampleCount().second);
780 EXPECT_FALSE(total_addrs->getMaxSampleAge().first);
781 EXPECT_EQ("00:00:10", durationToText(total_addrs->getMaxSampleAge().second, 0));
782
783 ObservationPtr total_prfx;
784 EXPECT_NO_THROW(total_prfx = stats_mgr.getObservation("subnet[42].total-pds"));
785 ASSERT_TRUE(total_prfx);
786 EXPECT_EQ(65536, total_prfx->getInteger().first);
787 EXPECT_TRUE(total_prfx->getMaxSampleCount().first);
788 EXPECT_EQ(14, total_prfx->getMaxSampleCount().second);
789 EXPECT_FALSE(total_prfx->getMaxSampleAge().first);
790 EXPECT_EQ("00:00:10", durationToText(total_prfx->getMaxSampleAge().second, 0));
791 }
792
793 // This test verifies that once the configuration is merged into the current
794 // configuration, statistics are updated appropriately.
795 /// @todo Enable this test once merging v6 configuration is enabled.
TEST_F(CfgMgrTest,DISABLED_mergeIntoCurrentStats6)796 TEST_F(CfgMgrTest, DISABLED_mergeIntoCurrentStats6) {
797 CfgMgr& cfg_mgr = CfgMgr::instance();
798 StatsMgr& stats_mgr = StatsMgr::instance();
799 startBackend(AF_INET6);
800
801 // Let's prepare the "old" configuration: a subnet with id 123
802 // and pretend there were addresses assigned, so statistics are non-zero.
803 Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4, 123));
804 CfgSubnets6Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets6();
805 subnets->add(subnet1);
806 cfg_mgr.commit();
807 stats_mgr.addValue("subnet[123].total-nas", static_cast<int64_t>(256));
808 stats_mgr.setValue("subnet[123].assigned-nas", static_cast<int64_t>(150));
809
810 stats_mgr.addValue("subnet[123].total-pds", static_cast<int64_t>(256));
811 stats_mgr.setValue("subnet[123].assigned-pds", static_cast<int64_t>(150));
812
813 // There should be no stats for subnet 42 at this point.
814 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].total-nas"));
815 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].assigned-nas"));
816 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].total-pds"));
817 EXPECT_FALSE(stats_mgr.getObservation("subnet[42].assigned-pds"));
818
819 // Now, let's create new configuration with updates.
820
821 // There's a subnet 2001:db8:2::/48 with ID=42
822 Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4, 42));
823
824 // Let's make pools with 128 addresses and 65536 prefixes available.
825 PoolPtr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), 121)); // 128 addrs
826 PoolPtr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:3::"), 96, 112)); // 65536 prefixes
827 subnet2->addPool(pool1);
828 subnet2->addPool(pool2);
829
830 // Create external configuration to be merged into current one.
831 auto external_cfg = CfgMgr::instance().createExternalCfg();
832 subnets = external_cfg->getCfgSubnets6();
833 subnets->add(subnet2);
834
835 external_cfg->addConfiguredGlobal("statistic-default-sample-count",
836 Element::create(17));
837 external_cfg->addConfiguredGlobal("statistic-default-sample-age",
838 Element::create(4));
839
840 // Let's merge it.
841 cfg_mgr.mergeIntoCurrentCfg(external_cfg->getSequence());
842
843 EXPECT_EQ(17, stats_mgr.getMaxSampleCountDefault());
844 EXPECT_EQ("00:00:04", durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
845
846 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].total-nas"));
847 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].assigned-nas"));
848 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].total-pds"));
849 EXPECT_TRUE(stats_mgr.getObservation("subnet[42].assigned-pds"));
850
851 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-nas"));
852 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-nas"));
853 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-pds"));
854 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-pds"));
855
856 ObservationPtr total_addrs;
857 EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-nas"));
858 ASSERT_TRUE(total_addrs);
859 EXPECT_EQ(128, total_addrs->getInteger().first);
860
861 EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-pds"));
862 ASSERT_TRUE(total_addrs);
863 EXPECT_EQ(65536, total_addrs->getInteger().first);
864 }
865
866 // This test verifies that once the configuration is cleared, the v6 statistics
867 // are removed.
TEST_F(CfgMgrTest,clearStats6)868 TEST_F(CfgMgrTest, clearStats6) {
869 CfgMgr& cfg_mgr = CfgMgr::instance();
870 StatsMgr& stats_mgr = StatsMgr::instance();
871
872 // Let's prepare the "old" configuration: a subnet with id 123
873 // and pretend there were addresses assigned, so statistics are non-zero.
874 Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4, 123));
875 CfgSubnets6Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets6();
876 subnets->add(subnet1);
877 cfg_mgr.commit();
878 stats_mgr.addValue("subnet[123].total-nas", static_cast<int64_t>(256));
879 stats_mgr.setValue("subnet[123].assigned-nas", static_cast<int64_t>(150));
880
881 stats_mgr.addValue("subnet[123].total-pds", static_cast<int64_t>(256));
882 stats_mgr.setValue("subnet[123].assigned-pds", static_cast<int64_t>(150));
883
884 // The stats should be there.
885 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-nas"));
886 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-nas"));
887
888 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].total-pds"));
889 EXPECT_TRUE(stats_mgr.getObservation("subnet[123].assigned-pds"));
890
891 // Let's remove all configurations
892 cfg_mgr.clear();
893
894 // The stats should not be there anymore.
895 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-nas"));
896 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-nas"));
897
898 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-pds"));
899 EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-pds"));
900 }
901
902 // This test verifies that the external configuration can be merged into
903 // the staging configuration via CfgMgr.
TEST_F(CfgMgrTest,mergeIntoStagingCfg)904 TEST_F(CfgMgrTest, mergeIntoStagingCfg) {
905 CfgMgr& cfg_mgr = CfgMgr::instance();
906
907 // Create first external configuration.
908 SrvConfigPtr ext_cfg1;
909 ASSERT_NO_THROW(ext_cfg1 = cfg_mgr.createExternalCfg());
910 ASSERT_TRUE(ext_cfg1);
911 // It should pick the first available sequence number.
912 EXPECT_EQ(0, ext_cfg1->getSequence());
913
914 // Create second external configuration.
915 SrvConfigPtr ext_cfg2;
916 ASSERT_NO_THROW(ext_cfg2 = cfg_mgr.createExternalCfg());
917 ASSERT_TRUE(ext_cfg2);
918 // It should pick the next available sequence number.
919 EXPECT_EQ(1, ext_cfg2->getSequence());
920
921 // Those must be two separate instances.
922 ASSERT_FALSE(ext_cfg1 == ext_cfg2);
923
924 // Add a subnet which will be merged from first configuration.
925 Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
926 ext_cfg1->getCfgSubnets4()->add(subnet1);
927
928 // Add a subnet which will be merged from the second configuration.
929 Subnet4Ptr subnet2(new Subnet4(IOAddress("192.1.3.0"), 24, 1, 2, 3, 124));
930 ext_cfg2->getCfgSubnets4()->add(subnet2);
931
932 // Merge first configuration.
933 ASSERT_NO_THROW(cfg_mgr.mergeIntoStagingCfg(ext_cfg1->getSequence()));
934 // Second attempt should fail because the configuration is discarded after
935 // the merge.
936 ASSERT_THROW(cfg_mgr.mergeIntoStagingCfg(ext_cfg1->getSequence()), BadValue);
937
938 // Check that the subnet from first configuration has been merged but not
939 // from the second configuration.
940 ASSERT_TRUE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(123));
941 ASSERT_FALSE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(124));
942
943 // Create another configuration instance to check what sequence it would
944 // pick. It should pick the first available one.
945 SrvConfigPtr ext_cfg3;
946 ASSERT_NO_THROW(ext_cfg3 = cfg_mgr.createExternalCfg());
947 ASSERT_TRUE(ext_cfg3);
948 EXPECT_EQ(2, ext_cfg3->getSequence());
949
950 // Merge the second and third (empty) configuration.
951 ASSERT_NO_THROW(cfg_mgr.mergeIntoStagingCfg(ext_cfg2->getSequence()));
952 ASSERT_NO_THROW(cfg_mgr.mergeIntoStagingCfg(ext_cfg3->getSequence()));
953
954 // Make sure that both subnets have been merged.
955 ASSERT_TRUE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(123));
956 ASSERT_TRUE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(124));
957
958 // The next configuration instance should reset the sequence to 0 because
959 // there are no other configurations in CfgMgr.
960 SrvConfigPtr ext_cfg4;
961 ASSERT_NO_THROW(ext_cfg4 = cfg_mgr.createExternalCfg());
962 ASSERT_TRUE(ext_cfg4);
963 EXPECT_EQ(0, ext_cfg4->getSequence());
964
965 // Try to commit the staging configuration.
966 ASSERT_NO_THROW(cfg_mgr.commit());
967
968 // Make sure that both subnets are present in the current configuration.
969 EXPECT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(123));
970 EXPECT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(124));
971
972 // The staging configuration should not include them.
973 EXPECT_FALSE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(123));
974 EXPECT_FALSE(cfg_mgr.getStagingCfg()->getCfgSubnets4()->getBySubnetId(124));
975 }
976
977 // This test verifies that the external configuration can be merged into
978 // the current configuration via CfgMgr.
TEST_F(CfgMgrTest,mergeIntoCurrentCfg)979 TEST_F(CfgMgrTest, mergeIntoCurrentCfg) {
980 CfgMgr& cfg_mgr = CfgMgr::instance();
981
982 // Create first external configuration.
983 SrvConfigPtr ext_cfg1;
984 ASSERT_NO_THROW(ext_cfg1 = cfg_mgr.createExternalCfg());
985 ASSERT_TRUE(ext_cfg1);
986 // It should pick the first available sequence number.
987 EXPECT_EQ(0, ext_cfg1->getSequence());
988
989 // Create second external configuration.
990 SrvConfigPtr ext_cfg2;
991 ASSERT_NO_THROW(ext_cfg2 = cfg_mgr.createExternalCfg());
992 ASSERT_TRUE(ext_cfg2);
993 // It should pick the next available sequence number.
994 EXPECT_EQ(1, ext_cfg2->getSequence());
995
996 // Those must be two separate instances.
997 ASSERT_FALSE(ext_cfg1 == ext_cfg2);
998
999 // Add a subnet which will be merged from first configuration.
1000 Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
1001 ext_cfg1->getCfgSubnets4()->add(subnet1);
1002
1003 // Add a subnet which will be merged from the second configuration.
1004 Subnet4Ptr subnet2(new Subnet4(IOAddress("192.1.3.0"), 24, 1, 2, 3, 124));
1005 ext_cfg2->getCfgSubnets4()->add(subnet2);
1006
1007 // Merge first configuration.
1008 ASSERT_NO_THROW(cfg_mgr.mergeIntoCurrentCfg(ext_cfg1->getSequence()));
1009 // Second attempt should fail because the configuration is discarded after
1010 // the merge.
1011 ASSERT_THROW(cfg_mgr.mergeIntoCurrentCfg(ext_cfg1->getSequence()), BadValue);
1012
1013 // Check that the subnet from first configuration has been merged but not
1014 // from the second configuration.
1015 ASSERT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(123));
1016 ASSERT_FALSE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(124));
1017
1018 // Create another configuration instance to check what sequence it would
1019 // pick. It should pick the first available one.
1020 SrvConfigPtr ext_cfg3;
1021 ASSERT_NO_THROW(ext_cfg3 = cfg_mgr.createExternalCfg());
1022 ASSERT_TRUE(ext_cfg3);
1023 EXPECT_EQ(2, ext_cfg3->getSequence());
1024
1025 // Merge the second and third (empty) configuration.
1026 ASSERT_NO_THROW(cfg_mgr.mergeIntoCurrentCfg(ext_cfg2->getSequence()));
1027 ASSERT_NO_THROW(cfg_mgr.mergeIntoCurrentCfg(ext_cfg3->getSequence()));
1028
1029 // Make sure that both subnets have been merged.
1030 ASSERT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(123));
1031 ASSERT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(124));
1032
1033 // The next configuration instance should reset the sequence to 0 because
1034 // there are no other configurations in CfgMgr.
1035 SrvConfigPtr ext_cfg4;
1036 ASSERT_NO_THROW(ext_cfg4 = cfg_mgr.createExternalCfg());
1037 ASSERT_TRUE(ext_cfg4);
1038 EXPECT_EQ(0, ext_cfg4->getSequence());
1039 }
1040
1041 /// @todo Add unit-tests for testing:
1042 /// - addActiveIface() with invalid interface name
1043 /// - addActiveIface() with the same interface twice
1044 /// - addActiveIface() with a bogus address
1045 ///
1046 /// This is somewhat tricky. Care should be taken here, because it is rather
1047 /// difficult to decide if interface name is valid or not. Some servers, e.g.
1048 /// dibbler, allow to specify interface names that are not currently present in
1049 /// the system. The server accepts them, but upon discovering that they are
1050 /// yet available (for different definitions of not being available), adds
1051 /// the to to-be-activated list.
1052 ///
1053 /// Cases covered by dibbler are:
1054 /// - missing interface (e.g. PPP connection that is not established yet)
1055 /// - downed interface (no link local address, no way to open sockets)
1056 /// - up, but not running interface (wifi up, but not associated)
1057 /// - tentative addresses (interface up and running, but DAD procedure is
1058 /// still in progress)
1059 /// - weird interfaces without link-local addresses (don't ask, 6rd tunnels
1060 /// look weird to me as well)
1061
1062 // No specific tests for getSubnet6. That method (2 overloaded versions) is tested
1063 // in Dhcpv6SrvTest.selectSubnetAddr and Dhcpv6SrvTest.selectSubnetIface
1064 // (see src/bin/dhcp6/tests/dhcp6_srv_unittest.cc)
1065
1066 } // end of anonymous namespace
1067