1 // Copyright (C) 2019-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 #include <mysql_cb_dhcp6.h>
9 #include <asiolink/addr_utilities.h>
10 #include <database/database_connection.h>
11 #include <database/db_exceptions.h>
12 #include <database/testutils/schema.h>
13 #include <dhcp/dhcp6.h>
14 #include <dhcp/libdhcp++.h>
15 #include <dhcp/option6_addrlst.h>
16 #include <dhcp/option_int.h>
17 #include <dhcp/option_space.h>
18 #include <dhcp/option_string.h>
19 #include <dhcpsrv/cfgmgr.h>
20 #include <dhcpsrv/config_backend_dhcp6_mgr.h>
21 #include <dhcpsrv/pool.h>
22 #include <dhcpsrv/subnet.h>
23 #include <dhcpsrv/testutils/mysql_generic_backend_unittest.h>
24 #include <dhcpsrv/testutils/test_utils.h>
25 #include <mysql/testutils/mysql_schema.h>
26 #include <testutils/multi_threading_utils.h>
27 #include <testutils/gtest_utils.h>
28
29 #include <boost/shared_ptr.hpp>
30 #include <gtest/gtest.h>
31 #include <mysql.h>
32 #include <map>
33 #include <sstream>
34
35 using namespace isc;
36 using namespace isc::asiolink;
37 using namespace isc::db;
38 using namespace isc::db::test;
39 using namespace isc::data;
40 using namespace isc::dhcp;
41 using namespace isc::dhcp::test;
42 using namespace isc::process;
43 using namespace isc::test;
44 namespace ph = std::placeholders;
45
46 namespace {
47
48 /// @brief Test implementation of the MySQL configuration backend.
49 ///
50 /// It exposes protected members of the @c MySqlConfigBackendDHCPv6.
51 class TestMySqlConfigBackendDHCPv6 : public MySqlConfigBackendDHCPv6 {
52 public:
53
54 /// @brief Constructor.
55 ///
56 /// @param parameters A data structure relating keywords and values
57 /// concerned with the database.
TestMySqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap & parameters)58 explicit TestMySqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters)
59 : MySqlConfigBackendDHCPv6(parameters) {
60 }
61
62 using MySqlConfigBackendDHCPv6::base_impl_;
63
64 };
65
66 /// @brief Test fixture class for @c MySqlConfigBackendDHCPv6.
67 ///
68 /// @todo The tests we're providing here only test cases when the
69 /// server selector is set to 'ALL' (configuration elements belong to
70 /// all servers). Currently we have no API to insert servers into
71 /// the database, and therefore we can't test the case when
72 /// configuration elements are assigned to particular servers by
73 /// server tags. We will have to expand existing tests when
74 /// the API is extended allowing for inserting servers to the
75 /// database.
76 class MySqlConfigBackendDHCPv6Test : public MySqlGenericBackendTest {
77 public:
78
79 /// @brief Constructor.
MySqlConfigBackendDHCPv6Test()80 MySqlConfigBackendDHCPv6Test()
81 : test_subnets_(), test_networks_(), test_option_defs_(),
82 test_options_(), test_client_classes_(), test_servers_(), timestamps_(),
83 cbptr_(), audit_entries_() {
84 // Ensure we have the proper schema with no transient data.
85 createMySQLSchema();
86
87 try {
88 // Create MySQL connection and use it to start the backend.
89 DatabaseConnection::ParameterMap params =
90 DatabaseConnection::parse(validMySQLConnectionString());
91 cbptr_.reset(new TestMySqlConfigBackendDHCPv6(params));
92
93 } catch (...) {
94 std::cerr << "*** ERROR: unable to open database. The test\n"
95 "*** environment is broken and must be fixed before\n"
96 "*** the MySQL tests will run correctly.\n"
97 "*** The reason for the problem is described in the\n"
98 "*** accompanying exception output.\n";
99 throw;
100 }
101
102 // Create test data.
103 initTestServers();
104 initTestOptions();
105 initTestSubnets();
106 initTestSharedNetworks();
107 initTestOptionDefs();
108 initTestClientClasses();
109 initTimestamps();
110 }
111
112 /// @brief Destructor.
~MySqlConfigBackendDHCPv6Test()113 virtual ~MySqlConfigBackendDHCPv6Test() {
114 cbptr_.reset();
115 // If data wipe enabled, delete transient data otherwise destroy the schema.
116 destroyMySQLSchema();
117 }
118
119 /// @brief Counts rows in a selected table in MySQL database.
120 ///
121 /// This method can be used to verify that some configuration elements were
122 /// deleted from a selected table as a result of cascade delete or a trigger.
123 /// For example, deleting a subnet should trigger deletion of its address
124 /// pools and options. By counting the rows on each table we can determine
125 /// whether the deletion took place on all tables for which it was expected.
126 ///
127 /// @param table Table name.
128 /// @return Number of rows in the specified table.
countRows(const std::string & table) const129 size_t countRows(const std::string& table) const {
130 auto p = boost::dynamic_pointer_cast<TestMySqlConfigBackendDHCPv6>(cbptr_);
131 if (!p) {
132 ADD_FAILURE() << "cbptr_ does not cast to TestMySqlConfigBackendDHCPv6";
133 return (0);
134 }
135
136 // Reuse the existing connection of the backend.
137 auto impl = boost::dynamic_pointer_cast<MySqlConfigBackendImpl>(p->base_impl_);
138 auto& conn = impl->conn_;
139
140 return (MySqlGenericBackendTest::countRows(conn, table));
141 }
142
143 /// @brief Creates several servers used in tests.
initTestServers()144 void initTestServers() {
145 test_servers_.push_back(Server::create(ServerTag("server1"), "this is server 1"));
146 test_servers_.push_back(Server::create(ServerTag("server1"), "this is server 1 bis"));
147 test_servers_.push_back(Server::create(ServerTag("server2"), "this is server 2"));
148 test_servers_.push_back(Server::create(ServerTag("server3"), "this is server 3"));
149 }
150
151 /// @brief Creates several subnets used in tests.
initTestSubnets()152 void initTestSubnets() {
153 // First subnet includes all parameters.
154 std::string interface_id_text = "whale";
155 OptionBuffer interface_id(interface_id_text.begin(), interface_id_text.end());
156 OptionPtr opt_interface_id(new Option(Option::V6, D6O_INTERFACE_ID,
157 interface_id));
158 ElementPtr user_context = Element::createMap();
159 user_context->set("foo", Element::create("bar"));
160
161 Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"),
162 64, 30, 40, 50, 60, 1024));
163 subnet->allowClientClass("home");
164 subnet->setIface("eth1");
165 subnet->setInterfaceId(opt_interface_id);
166 subnet->setT2(323212);
167 subnet->addRelayAddress(IOAddress("2001:db8:1::2"));
168 subnet->addRelayAddress(IOAddress("2001:db8:3::4"));
169 subnet->setT1(1234);
170 subnet->requireClientClass("required-class1");
171 subnet->requireClientClass("required-class2");
172 subnet->setReservationsGlobal(false);
173 subnet->setReservationsInSubnet(false);
174 subnet->setContext(user_context);
175 subnet->setValid(555555);
176 subnet->setPreferred(4444444);
177 subnet->setCalculateTeeTimes(true);
178 subnet->setT1Percent(0.345);
179 subnet->setT2Percent(0.444);
180 subnet->setDdnsSendUpdates(false);
181
182 Pool6Ptr pool1(new Pool6(Lease::TYPE_NA,
183 IOAddress("2001:db8::10"),
184 IOAddress("2001:db8::20")));
185 subnet->addPool(pool1);
186
187 Pool6Ptr pool2(new Pool6(Lease::TYPE_NA,
188 IOAddress("2001:db8::50"),
189 IOAddress("2001:db8::60")));
190 subnet->addPool(pool2);
191
192 Pool6Ptr pdpool1(new Pool6(Lease::TYPE_PD,
193 IOAddress("2001:db8:a::"), 48, 64));
194 subnet->addPool(pdpool1);
195
196 Pool6Ptr pdpool2(new Pool6(Lease::TYPE_PD,
197 IOAddress("2001:db8:b::"), 48, 64));
198 subnet->addPool(pdpool2);
199
200 // Add several options to the subnet.
201 subnet->getCfgOption()->add(test_options_[0]->option_,
202 test_options_[0]->persistent_,
203 test_options_[0]->space_name_);
204
205 subnet->getCfgOption()->add(test_options_[1]->option_,
206 test_options_[1]->persistent_,
207 test_options_[1]->space_name_);
208
209 subnet->getCfgOption()->add(test_options_[2]->option_,
210 test_options_[2]->persistent_,
211 test_options_[2]->space_name_);
212
213 test_subnets_.push_back(subnet);
214
215 // Adding another subnet with the same subnet id to test
216 // cases that this second instance can override existing
217 // subnet instance.
218 subnet.reset(new Subnet6(IOAddress("2001:db8:1::"),
219 48, 20, 30, 40, 50, 1024));
220
221 pool1.reset(new Pool6(Lease::TYPE_NA,
222 IOAddress("2001:db8:1::10"),
223 IOAddress("2001:db8:1::20")));
224 subnet->addPool(pool1);
225
226 pool1->getCfgOption()->add(test_options_[3]->option_,
227 test_options_[3]->persistent_,
228 test_options_[3]->space_name_);
229
230 pool1->getCfgOption()->add(test_options_[4]->option_,
231 test_options_[4]->persistent_,
232 test_options_[4]->space_name_);
233
234 pool2.reset(new Pool6(Lease::TYPE_NA,
235 IOAddress("2001:db8:1::50"),
236 IOAddress("2001:db8:1::60")));
237 subnet->addPool(pool2);
238
239 pool2->allowClientClass("work");
240 pool2->requireClientClass("required-class3");
241 pool2->requireClientClass("required-class4");
242 user_context = Element::createMap();
243 user_context->set("bar", Element::create("foo"));
244 pool2->setContext(user_context);
245
246 pdpool1.reset(new Pool6(IOAddress("2001:db8:c::"), 48, 64,
247 IOAddress("2001:db8:c::1"), 96));
248 subnet->addPool(pdpool1);
249
250 pdpool1->getCfgOption()->add(test_options_[3]->option_,
251 test_options_[3]->persistent_,
252 test_options_[3]->space_name_);
253
254 pdpool1->getCfgOption()->add(test_options_[4]->option_,
255 test_options_[4]->persistent_,
256 test_options_[4]->space_name_);
257
258 // Create the prefix delegation pool with an excluded prefix.
259 pdpool2.reset(new Pool6(IOAddress("2001:db8:d::"), 48, 64,
260 IOAddress("2001:db8:d::2000"), 120));
261
262 subnet->addPool(pdpool2);
263
264 pdpool2->allowClientClass("work");
265 pdpool2->requireClientClass("required-class3");
266 pdpool2->requireClientClass("required-class4");
267 user_context = Element::createMap();
268 user_context->set("bar", Element::create("foo"));
269 pdpool2->setContext(user_context);
270
271 test_subnets_.push_back(subnet);
272
273 subnet.reset(new Subnet6(IOAddress("2001:db8:3::"),
274 64, 20, 30, 40, 50, 2048));
275 Triplet<uint32_t> null_timer;
276 subnet->setPreferred(null_timer);
277 subnet->setT1(null_timer);
278 subnet->setT2(null_timer);
279 subnet->setValid(null_timer);
280 subnet->setPreferred(null_timer);
281 subnet->setDdnsSendUpdates(true);
282 subnet->setDdnsOverrideNoUpdate(true);
283 subnet->setDdnsOverrideClientUpdate(false);
284 subnet->setDdnsReplaceClientNameMode(D2ClientConfig::ReplaceClientNameMode::RCM_WHEN_PRESENT);
285 subnet->setDdnsGeneratedPrefix("myhost");
286 subnet->setDdnsQualifyingSuffix("example.org");
287
288 subnet->getCfgOption()->add(test_options_[0]->option_,
289 test_options_[0]->persistent_,
290 test_options_[0]->space_name_);
291
292 test_subnets_.push_back(subnet);
293
294 // Add a subnet with all defaults.
295 subnet.reset(new Subnet6(IOAddress("2001:db8:4::"), 64,
296 Triplet<uint32_t>(), Triplet<uint32_t>(),
297 Triplet<uint32_t>(), Triplet<uint32_t>(),
298 4096));
299 test_subnets_.push_back(subnet);
300 }
301
302 /// @brief Creates several subnets used in tests.
initTestSharedNetworks()303 void initTestSharedNetworks() {
304 ElementPtr user_context = Element::createMap();
305 user_context->set("foo", Element::create("bar"));
306
307 std::string interface_id_text = "fish";
308 OptionBuffer interface_id(interface_id_text.begin(),
309 interface_id_text.end());
310 OptionPtr opt_interface_id(new Option(Option::V6, D6O_INTERFACE_ID,
311 interface_id));
312
313 SharedNetwork6Ptr shared_network(new SharedNetwork6("level1"));
314 shared_network->allowClientClass("foo");
315 shared_network->setIface("eth1");
316 shared_network->setInterfaceId(opt_interface_id);
317 shared_network->setT2(323212);
318 shared_network->addRelayAddress(IOAddress("2001:db8:1::2"));
319 shared_network->addRelayAddress(IOAddress("2001:db8:3::4"));
320 shared_network->setT1(1234);
321 shared_network->requireClientClass("required-class1");
322 shared_network->requireClientClass("required-class2");
323 shared_network->setReservationsGlobal(false);
324 shared_network->setReservationsInSubnet(false);
325 shared_network->setContext(user_context);
326 shared_network->setValid(5555);
327 shared_network->setPreferred(4444);
328 shared_network->setCalculateTeeTimes(true);
329 shared_network->setT1Percent(0.345);
330 shared_network->setT2Percent(0.444);
331 shared_network->setDdnsSendUpdates(false);
332
333 // Add several options to the shared network.
334 shared_network->getCfgOption()->add(test_options_[2]->option_,
335 test_options_[2]->persistent_,
336 test_options_[2]->space_name_);
337
338 shared_network->getCfgOption()->add(test_options_[3]->option_,
339 test_options_[3]->persistent_,
340 test_options_[3]->space_name_);
341
342 shared_network->getCfgOption()->add(test_options_[4]->option_,
343 test_options_[4]->persistent_,
344 test_options_[4]->space_name_);
345
346 test_networks_.push_back(shared_network);
347
348 // Adding another shared network called "level1" to test
349 // cases that this second instance can override existing
350 // "level1" instance.
351 shared_network.reset(new SharedNetwork6("level1"));
352 test_networks_.push_back(shared_network);
353
354 // Add more shared networks.
355 shared_network.reset(new SharedNetwork6("level2"));
356 Triplet<uint32_t> null_timer;
357 shared_network->setPreferred(null_timer);
358 shared_network->setT1(null_timer);
359 shared_network->setT2(null_timer);
360 shared_network->setValid(null_timer);
361 shared_network->setPreferred(null_timer);
362 shared_network->setDdnsSendUpdates(true);
363 shared_network->setDdnsOverrideNoUpdate(true);
364 shared_network->setDdnsOverrideClientUpdate(false);
365 shared_network->setDdnsReplaceClientNameMode(D2ClientConfig::ReplaceClientNameMode::RCM_WHEN_PRESENT);
366 shared_network->setDdnsGeneratedPrefix("myhost");
367 shared_network->setDdnsQualifyingSuffix("example.org");
368
369 shared_network->getCfgOption()->add(test_options_[0]->option_,
370 test_options_[0]->persistent_,
371 test_options_[0]->space_name_);
372 test_networks_.push_back(shared_network);
373
374 shared_network.reset(new SharedNetwork6("level3"));
375 test_networks_.push_back(shared_network);
376 }
377
378 /// @brief Creates several option definitions used in tests.
initTestOptionDefs()379 void initTestOptionDefs() {
380 ElementPtr user_context = Element::createMap();
381 user_context->set("foo", Element::create("bar"));
382
383 OptionDefinitionPtr option_def(new OptionDefinition("foo", 1234,
384 DHCP6_OPTION_SPACE,
385 "string",
386 "espace"));
387 test_option_defs_.push_back(option_def);
388
389 option_def.reset(new OptionDefinition("bar", 1234, DHCP6_OPTION_SPACE,
390 "uint32", true));
391 test_option_defs_.push_back(option_def);
392
393 option_def.reset(new OptionDefinition("fish", 5235, DHCP6_OPTION_SPACE,
394 "record", true));
395 option_def->addRecordField("uint32");
396 option_def->addRecordField("string");
397 test_option_defs_.push_back(option_def);
398
399 option_def.reset(new OptionDefinition("whale", 20236, "xyz", "string"));
400 test_option_defs_.push_back(option_def);
401
402 option_def.reset(new OptionDefinition("bar", 1234, DHCP6_OPTION_SPACE,
403 "uint64", true));
404 test_option_defs_.push_back(option_def);
405 }
406
407 /// @brief Creates several DHCP options used in tests.
initTestOptions()408 void initTestOptions() {
409 ElementPtr user_context = Element::createMap();
410 user_context->set("foo", Element::create("bar"));
411
412 OptionDefSpaceContainer defs;
413
414 OptionDescriptor desc =
415 createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
416 true, false, "my-timezone");
417 desc.space_name_ = DHCP6_OPTION_SPACE;
418 desc.setContext(user_context);
419 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
420
421 desc = createOption<OptionUint8>(Option::V6, D6O_PREFERENCE,
422 false, true, 64);
423 desc.space_name_ = DHCP6_OPTION_SPACE;
424 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
425
426 desc = createOption<OptionUint32>(Option::V6, 1, false, false, 312131),
427 desc.space_name_ = "vendor-encapsulated-options";
428 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
429
430 desc = createAddressOption<Option6AddrLst>(1254, true, true,
431 "2001:db8::3");
432 desc.space_name_ = DHCP6_OPTION_SPACE;
433 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
434
435 desc = createEmptyOption(Option::V6, 1, true);
436 desc.space_name_ = "isc";
437 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
438
439 desc = createAddressOption<Option6AddrLst>(2, false, true,
440 "2001:db8:1::5",
441 "2001:db8:1::3",
442 "2001:db8:3::4");
443 desc.space_name_ = "isc";
444 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
445
446 desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
447 true, false, "my-timezone-2");
448 desc.space_name_ = DHCP6_OPTION_SPACE;
449 desc.setContext(user_context);
450 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
451
452 desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
453 true, false, "my-timezone-3");
454 desc.space_name_ = DHCP6_OPTION_SPACE;
455 desc.setContext(user_context);
456 test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
457
458 // Add definitions for DHCPv6 non-standard options in case we need to
459 // compare subnets, networks and pools in JSON format. In that case,
460 // the @c toElement functions require option definitions to generate the
461 // proper output.
462 defs.addItem(OptionDefinitionPtr(new OptionDefinition(
463 "vendor-encapsulated-1", 1,
464 "vendor-encapsulated-options", "uint32")));
465 defs.addItem(OptionDefinitionPtr(new OptionDefinition(
466 "option-1254", 1254, DHCP6_OPTION_SPACE,
467 "ipv6-address", true)));
468 defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-1", 1, "isc", "empty")));
469 defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-2", 2, "isc", "ipv6-address", true)));
470
471 // Register option definitions.
472 LibDHCP::setRuntimeOptionDefs(defs);
473 }
474
475 /// @brief Creates several client classes used in tests.
initTestClientClasses()476 void initTestClientClasses() {
477 ExpressionPtr match_expr = boost::make_shared<Expression>();
478 CfgOptionPtr cfg_option = boost::make_shared<CfgOption>();
479 auto class1 = boost::make_shared<ClientClassDef>("foo", match_expr, cfg_option);
480 class1->setRequired(true);
481 class1->setValid(Triplet<uint32_t>(30, 60, 90));
482 test_client_classes_.push_back(class1);
483
484 auto class2 = boost::make_shared<ClientClassDef>("bar", match_expr, cfg_option);
485 class2->setTest("member('foo')");
486 test_client_classes_.push_back(class2);
487
488 auto class3 = boost::make_shared<ClientClassDef>("foobar", match_expr, cfg_option);
489 class3->setTest("member('foo') and member('bar')");
490 test_client_classes_.push_back(class3);
491 }
492
493 /// @brief Initialize posix time values used in tests.
initTimestamps()494 void initTimestamps() {
495 // Current time minus 1 hour to make sure it is in the past.
496 timestamps_["today"] = boost::posix_time::second_clock::local_time()
497 - boost::posix_time::hours(1);
498 // One second after today.
499 timestamps_["after today"] = timestamps_["today"] + boost::posix_time::seconds(1);
500 // Yesterday.
501 timestamps_["yesterday"] = timestamps_["today"] - boost::posix_time::hours(24);
502 // One second after yesterday.
503 timestamps_["after yesterday"] = timestamps_["yesterday"] + boost::posix_time::seconds(1);
504 // Two days ago.
505 timestamps_["two days ago"] = timestamps_["today"] - boost::posix_time::hours(48);
506 // Tomorrow.
507 timestamps_["tomorrow"] = timestamps_["today"] + boost::posix_time::hours(24);
508 // One second after tomorrow.
509 timestamps_["after tomorrow"] = timestamps_["tomorrow"] + boost::posix_time::seconds(1);
510 }
511
512 /// @brief Logs audit entries in the @c audit_entries_ member.
513 ///
514 /// This function is called in case of an error.
515 ///
516 /// @param server_tag Server tag for which the audit entries should be logged.
logExistingAuditEntries(const std::string & server_tag)517 std::string logExistingAuditEntries(const std::string& server_tag) {
518 std::ostringstream s;
519
520 auto& mod_time_idx = audit_entries_[server_tag].get<AuditEntryModificationTimeIdTag>();
521
522 for (auto audit_entry_it = mod_time_idx.begin();
523 audit_entry_it != mod_time_idx.end();
524 ++audit_entry_it) {
525 auto audit_entry = *audit_entry_it;
526 s << audit_entry->getObjectType() << ", "
527 << audit_entry->getObjectId() << ", "
528 << static_cast<int>(audit_entry->getModificationType()) << ", "
529 << audit_entry->getModificationTime() << ", "
530 << audit_entry->getRevisionId() << ", "
531 << audit_entry->getLogMessage()
532 << std::endl;
533 }
534
535 return (s.str());
536 }
537
538 /// @brief Tests that the new audit entry is added.
539 ///
540 /// This method retrieves a collection of the existing audit entries and
541 /// checks that the new one has been added at the end of this collection.
542 /// It then verifies the values of the audit entry against the values
543 /// specified by the caller.
544 ///
545 /// @param exp_object_type Expected object type.
546 /// @param exp_modification_type Expected modification type.
547 /// @param exp_log_message Expected log message.
548 /// @param server_selector Server selector to be used for next query.
549 /// @param new_entries_num Number of the new entries expected to be inserted.
550 /// @param max_tested_entries Maximum number of entries tested.
testNewAuditEntry(const std::string & exp_object_type,const AuditEntry::ModificationType & exp_modification_type,const std::string & exp_log_message,const ServerSelector & server_selector=ServerSelector::ALL (),const size_t new_entries_num=1,const size_t max_tested_entries=65535)551 void testNewAuditEntry(const std::string& exp_object_type,
552 const AuditEntry::ModificationType& exp_modification_type,
553 const std::string& exp_log_message,
554 const ServerSelector& server_selector = ServerSelector::ALL(),
555 const size_t new_entries_num = 1,
556 const size_t max_tested_entries = 65535) {
557 // Get the server tag for which the entries are fetched.
558 std::string tag;
559 if (server_selector.getType() == ServerSelector::Type::ALL) {
560 // Server tag is 'all'.
561 tag = "all";
562
563 } else {
564 auto tags = server_selector.getTags();
565 // This test is not meant to handle multiple server tags all at once.
566 if (tags.size() > 1) {
567 ADD_FAILURE() << "Test error: do not use multiple server tags";
568
569 } else if (tags.size() == 1) {
570 // Get the server tag for which we run the current test.
571 tag = tags.begin()->get();
572 }
573 }
574
575 auto audit_entries_size_save = audit_entries_[tag].size();
576
577 // Audit entries for different server tags are stored in separate
578 // containers.
579 audit_entries_[tag] = cbptr_->getRecentAuditEntries(server_selector,
580 timestamps_["two days ago"], 0);
581 ASSERT_EQ(audit_entries_size_save + new_entries_num, audit_entries_[tag].size())
582 << logExistingAuditEntries(tag);
583
584 auto& mod_time_idx = audit_entries_[tag].get<AuditEntryModificationTimeIdTag>();
585
586 // Iterate over specified number of entries starting from the most recent
587 // one and check they have correct values.
588 for (auto audit_entry_it = mod_time_idx.rbegin();
589 ((std::distance(mod_time_idx.rbegin(), audit_entry_it) < new_entries_num) &&
590 (std::distance(mod_time_idx.rbegin(), audit_entry_it) < max_tested_entries));
591 ++audit_entry_it) {
592 auto audit_entry = *audit_entry_it;
593 EXPECT_EQ(exp_object_type, audit_entry->getObjectType())
594 << logExistingAuditEntries(tag);
595 EXPECT_EQ(exp_modification_type, audit_entry->getModificationType())
596 << logExistingAuditEntries(tag);
597 EXPECT_EQ(exp_log_message, audit_entry->getLogMessage())
598 << logExistingAuditEntries(tag);
599 }
600 }
601
602 /// @brief Holds pointers to subnets used in tests.
603 std::vector<Subnet6Ptr> test_subnets_;
604
605 /// @brief Holds pointers to shared networks used in tests.
606 std::vector<SharedNetwork6Ptr> test_networks_;
607
608 /// @brief Holds pointers to option definitions used in tests.
609 std::vector<OptionDefinitionPtr> test_option_defs_;
610
611 /// @brief Holds pointers to options used in tests.
612 std::vector<OptionDescriptorPtr> test_options_;
613
614 /// @brief Holds pointers to classes used in tests.
615 std::vector<ClientClassDefPtr> test_client_classes_;
616
617 /// @brief Holds pointers to the servers used in tests.
618 std::vector<ServerPtr> test_servers_;
619
620 /// @brief Holds timestamp values used in tests.
621 std::map<std::string, boost::posix_time::ptime> timestamps_;
622
623 /// @brief Holds pointer to the backend.
624 boost::shared_ptr<ConfigBackendDHCPv6> cbptr_;
625
626 /// @brief Holds the most recent audit entries.
627 std::map<std::string, AuditEntryCollection> audit_entries_;
628 };
629
630 // This test verifies that the expected backend type is returned.
TEST_F(MySqlConfigBackendDHCPv6Test,getType)631 TEST_F(MySqlConfigBackendDHCPv6Test, getType) {
632 DatabaseConnection::ParameterMap params;
633 params["name"] = "keatest";
634 params["password"] = "keatest";
635 params["user"] = "keatest";
636 ASSERT_NO_THROW(cbptr_.reset(new MySqlConfigBackendDHCPv6(params)));
637 ASSERT_NE(cbptr_->getParameters(), DatabaseConnection::ParameterMap());
638 EXPECT_EQ("mysql", cbptr_->getType());
639 }
640
641 // This test verifies that by default localhost is returned as MySQL connection
642 // host.
TEST_F(MySqlConfigBackendDHCPv6Test,getHost)643 TEST_F(MySqlConfigBackendDHCPv6Test, getHost) {
644 DatabaseConnection::ParameterMap params;
645 params["name"] = "keatest";
646 params["password"] = "keatest";
647 params["user"] = "keatest";
648 ASSERT_NO_THROW(cbptr_.reset(new MySqlConfigBackendDHCPv6(params)));
649 ASSERT_NE(cbptr_->getParameters(), DatabaseConnection::ParameterMap());
650 EXPECT_EQ("localhost", cbptr_->getHost());
651 }
652
653 // This test verifies that by default port of 0 is returned as MySQL connection
654 // port.
TEST_F(MySqlConfigBackendDHCPv6Test,getPort)655 TEST_F(MySqlConfigBackendDHCPv6Test, getPort) {
656 DatabaseConnection::ParameterMap params;
657 params["name"] = "keatest";
658 params["password"] = "keatest";
659 params["user"] = "keatest";
660 ASSERT_NO_THROW(cbptr_.reset(new MySqlConfigBackendDHCPv6(params)));
661 ASSERT_NE(cbptr_->getParameters(), DatabaseConnection::ParameterMap());
662 EXPECT_EQ(0, cbptr_->getPort());
663 }
664
665 // This test verifies that the server can be added, updated and deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeleteServer)666 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteServer) {
667 // Explicitly set modification time to make sure that the time
668 // returned from the database is correct.
669 test_servers_[0]->setModificationTime(timestamps_["yesterday"]);
670 test_servers_[1]->setModificationTime(timestamps_["today"]);
671
672 // Insert the server1 into the database.
673 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
674
675 {
676 SCOPED_TRACE("CREATE audit entry for server");
677 testNewAuditEntry("dhcp6_server",
678 AuditEntry::ModificationType::CREATE,
679 "server set");
680 }
681
682 // It should not be possible to create a duplicate of the logical
683 // server 'all'.
684 auto all_server = Server::create(ServerTag("all"), "this is logical server all");
685 EXPECT_THROW(cbptr_->createUpdateServer6(all_server), isc::InvalidOperation);
686
687 ServerPtr returned_server;
688
689 // An attempt to fetch the server that hasn't been inserted should return
690 // a null pointer.
691 EXPECT_NO_THROW(returned_server = cbptr_->getServer6(ServerTag("server2")));
692 EXPECT_FALSE(returned_server);
693
694 // Try to fetch the server which we expect to exist.
695 EXPECT_NO_THROW(returned_server = cbptr_->getServer6(ServerTag("server1")));
696 ASSERT_TRUE(returned_server);
697 EXPECT_EQ("server1", returned_server->getServerTagAsText());
698 EXPECT_EQ("this is server 1", returned_server->getDescription());
699 EXPECT_EQ(timestamps_["yesterday"], returned_server->getModificationTime());
700
701 // This call is expected to update the existing server.
702 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
703
704 {
705 SCOPED_TRACE("UPDATE audit entry for server");
706 testNewAuditEntry("dhcp6_server",
707 AuditEntry::ModificationType::UPDATE,
708 "server set");
709 }
710
711 // Verify that the server has been updated.
712 EXPECT_NO_THROW(returned_server = cbptr_->getServer6(ServerTag("server1")));
713 ASSERT_TRUE(returned_server);
714 EXPECT_EQ("server1", returned_server->getServerTag().get());
715 EXPECT_EQ("this is server 1 bis", returned_server->getDescription());
716 EXPECT_EQ(timestamps_["today"], returned_server->getModificationTime());
717
718
719 uint64_t servers_deleted = 0;
720
721 // Try to delete non-existing server.
722 EXPECT_NO_THROW(servers_deleted = cbptr_->deleteServer6(ServerTag("server2")));
723 EXPECT_EQ(0, servers_deleted);
724
725 // Make sure that the server1 wasn't deleted.
726 EXPECT_NO_THROW(returned_server = cbptr_->getServer6(ServerTag("server1")));
727 EXPECT_TRUE(returned_server);
728
729 // Deleting logical server 'all' is not allowed.
730 EXPECT_THROW(cbptr_->deleteServer6(ServerTag()), isc::InvalidOperation);
731
732 // Delete the existing server.
733 EXPECT_NO_THROW(servers_deleted = cbptr_->deleteServer6(ServerTag("server1")));
734 EXPECT_EQ(1, servers_deleted);
735
736 {
737 SCOPED_TRACE("DELETE audit entry for server");
738 testNewAuditEntry("dhcp6_server",
739 AuditEntry::ModificationType::DELETE,
740 "deleting a server");
741 }
742
743 // Make sure that the server is gone.
744 EXPECT_NO_THROW(returned_server = cbptr_->getServer6(ServerTag("server1")));
745 EXPECT_FALSE(returned_server);
746 }
747
748 // This test verifies that it is possible to retrieve all servers from the
749 // database and then delete all of them.
TEST_F(MySqlConfigBackendDHCPv6Test,getAndDeleteAllServers)750 TEST_F(MySqlConfigBackendDHCPv6Test, getAndDeleteAllServers) {
751 for (auto i = 1; i < test_servers_.size(); ++i) {
752 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[i]));
753 }
754
755 ServerCollection servers;
756 EXPECT_NO_THROW(servers = cbptr_->getAllServers6());
757 ASSERT_EQ(test_servers_.size() - 1, servers.size());
758
759 // All servers should have been returned.
760 EXPECT_TRUE(ServerFetcher::get(servers, ServerTag("server1")));
761 EXPECT_TRUE(ServerFetcher::get(servers, ServerTag("server2")));
762 EXPECT_TRUE(ServerFetcher::get(servers, ServerTag("server3")));
763
764 // The logical server all should not be returned. We merely return the
765 // user configured servers.
766 EXPECT_FALSE(ServerFetcher::get(servers, ServerTag()));
767
768 // Delete all servers and make sure they are gone.
769 uint64_t deleted_servers = 0;
770 EXPECT_NO_THROW(deleted_servers = cbptr_->deleteAllServers6());
771
772 EXPECT_NO_THROW(servers = cbptr_->getAllServers6());
773 EXPECT_TRUE(servers.empty());
774
775 // All servers should be gone.
776 EXPECT_FALSE(ServerFetcher::get(servers, ServerTag("server1")));
777 EXPECT_FALSE(ServerFetcher::get(servers, ServerTag("server2")));
778 EXPECT_FALSE(ServerFetcher::get(servers, ServerTag("server3")));
779
780 // The number of deleted server should be equal to the number of
781 // inserted servers. The logical 'all' server should be excluded.
782 EXPECT_EQ(test_servers_.size() - 1, deleted_servers);
783 }
784
785 // This test verifies that the global parameter can be added, updated and
786 // deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeleteGlobalParameter6)787 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteGlobalParameter6) {
788 StampedValuePtr global_parameter = StampedValue::create("global", "whale");
789
790 // Explicitly set modification time to make sure that the time
791 // returned from the database is correct.
792 global_parameter->setModificationTime(timestamps_["yesterday"]);
793 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
794 global_parameter);
795
796 {
797 SCOPED_TRACE("CREATE audit entry for global parameter");
798 testNewAuditEntry("dhcp6_global_parameter",
799 AuditEntry::ModificationType::CREATE,
800 "global parameter set");
801 }
802
803 // Verify returned parameter and the modification time.
804 StampedValuePtr returned_global_parameter =
805 cbptr_->getGlobalParameter6(ServerSelector::ALL(), "global");
806 ASSERT_TRUE(returned_global_parameter);
807 EXPECT_EQ("global", returned_global_parameter->getName());
808 EXPECT_EQ("whale", returned_global_parameter->getValue());
809 EXPECT_TRUE(returned_global_parameter->getModificationTime() ==
810 global_parameter->getModificationTime());
811 ASSERT_EQ(1, returned_global_parameter->getServerTags().size());
812 EXPECT_EQ("all", returned_global_parameter->getServerTags().begin()->get());
813
814 // Because we have added the global parameter for all servers, it
815 // should be also returned for the explicitly specified server.
816 returned_global_parameter = cbptr_->getGlobalParameter6(ServerSelector::ONE("server1"),
817 "global");
818 ASSERT_TRUE(returned_global_parameter);
819 EXPECT_EQ("global", returned_global_parameter->getName());
820 EXPECT_EQ("whale", returned_global_parameter->getValue());
821 EXPECT_TRUE(returned_global_parameter->getModificationTime() ==
822 global_parameter->getModificationTime());
823 ASSERT_EQ(1, returned_global_parameter->getServerTags().size());
824 EXPECT_EQ("all", returned_global_parameter->getServerTags().begin()->get());
825
826 // Check that the parameter is updated when selector is specified correctly.
827 global_parameter = StampedValue::create("global", "fish");
828 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
829 global_parameter);
830 returned_global_parameter = cbptr_->getGlobalParameter6(ServerSelector::ALL(),
831 "global");
832 ASSERT_TRUE(returned_global_parameter);
833 EXPECT_EQ("global", returned_global_parameter->getName());
834 EXPECT_EQ("fish", returned_global_parameter->getValue());
835 EXPECT_TRUE(returned_global_parameter->getModificationTime() ==
836 global_parameter->getModificationTime());
837
838 {
839 SCOPED_TRACE("UPDATE audit entry for the global parameter");
840 testNewAuditEntry("dhcp6_global_parameter",
841 AuditEntry::ModificationType::UPDATE,
842 "global parameter set");
843 }
844
845 // Should not delete parameter specified for all servers if explicit
846 // server name is provided.
847 EXPECT_EQ(0, cbptr_->deleteGlobalParameter6(ServerSelector::ONE("server1"),
848 "global"));
849
850 // Delete parameter and make sure it is gone.
851 cbptr_->deleteGlobalParameter6(ServerSelector::ALL(), "global");
852 returned_global_parameter = cbptr_->getGlobalParameter6(ServerSelector::ALL(),
853 "global");
854 EXPECT_FALSE(returned_global_parameter);
855
856 {
857 SCOPED_TRACE("DELETE audit entry for the global parameter");
858 testNewAuditEntry("dhcp6_global_parameter",
859 AuditEntry::ModificationType::DELETE,
860 "global parameter deleted");
861 }
862 }
863
864 // This test verifies that it is possible to differentiate between the
865 // global parameters by server tag and that the value specified for the
866 // particular server overrides the value specified for all servers.
TEST_F(MySqlConfigBackendDHCPv6Test,globalParameters6WithServerTags)867 TEST_F(MySqlConfigBackendDHCPv6Test, globalParameters6WithServerTags) {
868 // Create three global parameters having the same name.
869 StampedValuePtr global_parameter1 = StampedValue::create("global", "value1");
870 StampedValuePtr global_parameter2 = StampedValue::create("global", "value2");
871 StampedValuePtr global_parameter3 = StampedValue::create("global", "value3");
872
873 // Try to insert one of them and associate with non-existing server.
874 // This should fail because the server must be inserted first.
875 EXPECT_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server1"),
876 global_parameter1),
877 NullKeyError);
878
879 // Create two servers.
880 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
881 {
882 SCOPED_TRACE("server1 is created");
883 testNewAuditEntry("dhcp6_server",
884 AuditEntry::ModificationType::CREATE,
885 "server set");
886 }
887
888 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
889 {
890 SCOPED_TRACE("server2 is created");
891 testNewAuditEntry("dhcp6_server",
892 AuditEntry::ModificationType::CREATE,
893 "server set");
894 }
895
896 // This time inserting the global parameters for the server1 and server2 should
897 // be successful.
898 EXPECT_NO_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server1"),
899 global_parameter1));
900 {
901 SCOPED_TRACE("Global parameter for server1 is set");
902 // The value of 3 means there should be 3 audit entries available for the
903 // server1, two that indicate creation of the servers and one that we
904 // validate, which sets the global value.
905 testNewAuditEntry("dhcp6_global_parameter",
906 AuditEntry::ModificationType::CREATE,
907 "global parameter set",
908 ServerSelector::ONE("server1"),
909 3, 1);
910 }
911
912
913 EXPECT_NO_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server2"),
914 global_parameter2));
915 {
916 SCOPED_TRACE("Global parameter for server2 is set");
917 // Same as in case of the server2, there should be 3 audit entries of
918 // which one we validate.
919 testNewAuditEntry("dhcp6_global_parameter",
920 AuditEntry::ModificationType::CREATE,
921 "global parameter set",
922 ServerSelector::ONE("server2"),
923 3, 1);
924 }
925
926 // The last parameter is associated with all servers.
927 EXPECT_NO_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
928 global_parameter3));
929 {
930 SCOPED_TRACE("Global parameter for all servers is set");
931 // There should be one new audit entry for all servers. It indicates
932 // the insertion of the global value.
933 testNewAuditEntry("dhcp6_global_parameter",
934 AuditEntry::ModificationType::CREATE,
935 "global parameter set",
936 ServerSelector::ALL(),
937 1, 1);
938 }
939
940 StampedValuePtr returned_global;
941
942 // Try to fetch the value specified for all servers.
943 EXPECT_NO_THROW(
944 returned_global = cbptr_->getGlobalParameter6(ServerSelector::ALL(),
945 "global")
946 );
947 ASSERT_TRUE(returned_global);
948 EXPECT_EQ(global_parameter3->getValue(), returned_global->getValue());
949 ASSERT_EQ(1, returned_global->getServerTags().size());
950 EXPECT_EQ("all", returned_global->getServerTags().begin()->get());
951
952 // Try to fetch the value specified for the server1. This should override the
953 // value specified for all servers.
954 EXPECT_NO_THROW(
955 returned_global = cbptr_->getGlobalParameter6(ServerSelector::ONE("server1"),
956 "global")
957 );
958 ASSERT_TRUE(returned_global);
959 EXPECT_EQ(global_parameter1->getValue(), returned_global->getValue());
960
961 ASSERT_EQ(1, returned_global->getServerTags().size());
962 EXPECT_EQ("server1", returned_global->getServerTags().begin()->get());
963
964 // The same in case of the server2.
965 EXPECT_NO_THROW(
966 returned_global = cbptr_->getGlobalParameter6(ServerSelector::ONE("server2"),
967 "global")
968 );
969 ASSERT_TRUE(returned_global);
970 EXPECT_EQ(global_parameter2->getValue(), returned_global->getValue());
971 ASSERT_EQ(1, returned_global->getServerTags().size());
972 EXPECT_EQ("server2", returned_global->getServerTags().begin()->get());
973
974 StampedValueCollection returned_globals;
975
976 // Try to fetch the collection of globals for the server1, server2 and server3.
977 // The server3 does not have an explicit value so for this server we should get
978 /// the value for 'all'.
979 EXPECT_NO_THROW(
980 returned_globals = cbptr_->getAllGlobalParameters6(ServerSelector::
981 MULTIPLE({ "server1", "server2",
982 "server3" }));
983 );
984 ASSERT_EQ(3, returned_globals.size());
985
986 // Capture the returned values into the map so as we can check the
987 // values against the servers.
988 std::map<std::string, std::string> values;
989 for (auto g = returned_globals.begin(); g != returned_globals.end(); ++g) {
990 ASSERT_EQ(1, (*g)->getServerTags().size());
991 values[(*g)->getServerTags().begin()->get()] = ((*g)->getValue());
992 }
993
994 ASSERT_EQ(3, values.size());
995 EXPECT_EQ(global_parameter1->getValue(), values["server1"]);
996 EXPECT_EQ(global_parameter2->getValue(), values["server2"]);
997 EXPECT_EQ(global_parameter3->getValue(), values["all"]);
998
999 // Try to fetch the collection of global parameters specified for all servers.
1000 // This excludes the values specific to server1 and server2. It returns only the
1001 // common ones.
1002 EXPECT_NO_THROW(
1003 returned_globals = cbptr_->getAllGlobalParameters6(ServerSelector::ALL())
1004 );
1005 ASSERT_EQ(1, returned_globals.size());
1006 returned_global = *returned_globals.begin();
1007 EXPECT_EQ(global_parameter3->getValue(), returned_global->getValue());
1008 ASSERT_EQ(1, returned_global->getServerTags().size());
1009 EXPECT_EQ("all", returned_global->getServerTags().begin()->get());
1010
1011 // Delete the server1. It should remove associations of this server with the
1012 // global parameter and the global parameter itself.
1013 EXPECT_NO_THROW(cbptr_->deleteServer6(ServerTag("server1")));
1014 EXPECT_NO_THROW(
1015 returned_globals = cbptr_->getAllGlobalParameters6(ServerSelector::ONE("server1"))
1016 );
1017 ASSERT_EQ(1, returned_globals.size());
1018 returned_global = *returned_globals.begin();
1019 // As a result, the value fetched for the server1 should be the one available for
1020 // all servers, rather than the one dedicated for server1. The association of
1021 // the server1 specific value with the server1 should be gone.
1022 EXPECT_EQ(global_parameter3->getValue(), returned_global->getValue());
1023 ASSERT_EQ(1, returned_global->getServerTags().size());
1024 EXPECT_EQ("all", returned_global->getServerTags().begin()->get());
1025
1026 {
1027 SCOPED_TRACE("DELETE audit entry for the global parameter after server deletion");
1028 // We expect two new audit entries for the server1, one indicating that the
1029 // server has been deleted and another one indicating that the corresponding
1030 // global value has been deleted. We check the latter entry.
1031 testNewAuditEntry("dhcp6_global_parameter",
1032 AuditEntry::ModificationType::DELETE,
1033 "deleting a server", ServerSelector::ONE("server1"),
1034 2, 1);
1035 }
1036
1037 // Attempt to delete global parameter for server1.
1038 uint64_t deleted_num = 0;
1039 EXPECT_NO_THROW(deleted_num = cbptr_->deleteGlobalParameter6(ServerSelector::ONE("server1"),
1040 "global"));
1041 // No parameters should be deleted. In particular, the parameter for the logical
1042 // server 'all' should not be deleted.
1043 EXPECT_EQ(0, deleted_num);
1044
1045 // Deleting the existing value for server2 should succeed.
1046 EXPECT_NO_THROW(deleted_num = cbptr_->deleteGlobalParameter6(ServerSelector::ONE("server2"),
1047 "global"));
1048 EXPECT_EQ(1, deleted_num);
1049
1050 // Create it again to test that deletion of all server removes this too.
1051 EXPECT_NO_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server2"),
1052 global_parameter2));
1053
1054 // Delete all servers, except 'all'.
1055 EXPECT_NO_THROW(deleted_num = cbptr_->deleteAllServers6());
1056 EXPECT_NO_THROW(
1057 returned_globals = cbptr_->getAllGlobalParameters6(ServerSelector::ALL())
1058 );
1059 EXPECT_EQ(1, deleted_num);
1060 ASSERT_EQ(1, returned_globals.size());
1061 returned_global = *returned_globals.begin();
1062 // The common value for all servers should still be available because 'all'
1063 // logical server should not be deleted.
1064 EXPECT_EQ(global_parameter3->getValue(), returned_global->getValue());
1065 ASSERT_EQ(1, returned_global->getServerTags().size());
1066 EXPECT_EQ("all", returned_global->getServerTags().begin()->get());
1067
1068 {
1069 SCOPED_TRACE("DELETE audit entry for the global parameter after deletion of"
1070 " all servers");
1071 // There should be 4 new audit entries. One for deleting the global, one for
1072 // re-creating it, one for deleting the server2 and one for deleting the
1073 // global again as a result of deleting the server2.
1074 testNewAuditEntry("dhcp6_global_parameter",
1075 AuditEntry::ModificationType::DELETE,
1076 "deleting all servers", ServerSelector::ONE("server2"),
1077 4, 1);
1078 }
1079 }
1080
1081 // This test verifies that all global parameters can be retrieved and deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllGlobalParameters6)1082 TEST_F(MySqlConfigBackendDHCPv6Test, getAllGlobalParameters6) {
1083 // Create 3 parameters and put them into the database.
1084 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1085 StampedValue::create("name1", "value1"));
1086 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1087 StampedValue::create("name2", Element::create(static_cast<int64_t>(65))));
1088 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1089 StampedValue::create("name3", "value3"));
1090 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1091 StampedValue::create("name4", Element::create(static_cast<bool>(true))));
1092 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1093 StampedValue::create("name5", Element::create(static_cast<double>(1.65))));
1094
1095 // Fetch all parameters.
1096 auto parameters = cbptr_->getAllGlobalParameters6(ServerSelector::ALL());
1097 ASSERT_EQ(5, parameters.size());
1098
1099 const auto& parameters_index = parameters.get<StampedValueNameIndexTag>();
1100
1101 for (auto param = parameters_index.begin(); param != parameters_index.end();
1102 ++param) {
1103 ASSERT_EQ(1, (*param)->getServerTags().size());
1104 EXPECT_EQ("all", (*param)->getServerTags().begin()->get());
1105 }
1106
1107 // Verify their values.
1108 EXPECT_EQ("value1", (*parameters_index.find("name1"))->getValue());
1109 EXPECT_EQ(65, (*parameters_index.find("name2"))->getIntegerValue());
1110 EXPECT_EQ("value3", (*parameters_index.find("name3"))->getValue());
1111 EXPECT_TRUE((*parameters_index.find("name4"))->getBoolValue());
1112 EXPECT_EQ(1.65, (*parameters_index.find("name5"))->getDoubleValue());
1113
1114 // Should be able to fetch these parameters when explicitly providing
1115 // the server tag.
1116 parameters = cbptr_->getAllGlobalParameters6(ServerSelector::ONE("server1"));
1117 EXPECT_EQ(5, parameters.size());
1118
1119 // Deleting global parameters with non-matching server selector
1120 // should fail.
1121 EXPECT_EQ(0, cbptr_->deleteAllGlobalParameters6(ServerSelector::ONE("server1")));
1122
1123 // Delete all parameters and make sure they are gone.
1124 EXPECT_EQ(5, cbptr_->deleteAllGlobalParameters6(ServerSelector::ALL()));
1125 parameters = cbptr_->getAllGlobalParameters6(ServerSelector::ALL());
1126 EXPECT_TRUE(parameters.empty());
1127 }
1128
1129 // This test verifies that modified global parameters can be retrieved.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedGlobalParameters6)1130 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedGlobalParameters6) {
1131 // Create 3 global parameters and assign modification times:
1132 // "yesterday", "today" and "tomorrow" respectively.
1133 StampedValuePtr value = StampedValue::create("name1", "value1");
1134 value->setModificationTime(timestamps_["yesterday"]);
1135 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1136 value);
1137
1138 value = StampedValue::create("name2", Element::create(static_cast<int64_t>(65)));
1139 value->setModificationTime(timestamps_["today"]);
1140 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1141 value);
1142
1143 value = StampedValue::create("name3", "value3");
1144 value->setModificationTime(timestamps_["tomorrow"]);
1145 cbptr_->createUpdateGlobalParameter6(ServerSelector::ALL(),
1146 value);
1147
1148 // Get parameters modified after "today".
1149 auto parameters = cbptr_->getModifiedGlobalParameters6(ServerSelector::ALL(),
1150 timestamps_["after today"]);
1151
1152 const auto& parameters_index = parameters.get<StampedValueNameIndexTag>();
1153
1154 // It should be the one modified "tomorrow".
1155 ASSERT_EQ(1, parameters_index.size());
1156
1157 auto parameter = parameters_index.find("name3");
1158 ASSERT_FALSE(parameter == parameters_index.end());
1159
1160 ASSERT_TRUE(*parameter);
1161 EXPECT_EQ("value3", (*parameter)->getValue());
1162
1163 // Should be able to fetct these parameters when explicitly providing
1164 // the server tag.
1165 parameters = cbptr_->getModifiedGlobalParameters6(ServerSelector::ONE("server1"),
1166 timestamps_["after today"]);
1167 EXPECT_EQ(1, parameters.size());
1168 }
1169
1170 // Test that the NullKeyError message is correctly updated.
TEST_F(MySqlConfigBackendDHCPv6Test,nullKeyError)1171 TEST_F(MySqlConfigBackendDHCPv6Test, nullKeyError) {
1172 // Create a global parameter (it should work with any object type).
1173 StampedValuePtr global_parameter = StampedValue::create("global", "value");
1174
1175 // Try to insert it and associate with non-existing server.
1176 std::string msg;
1177 try {
1178 cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server1"),
1179 global_parameter);
1180 msg = "got no exception";
1181 } catch (const NullKeyError& ex) {
1182 msg = ex.what();
1183 } catch (const std::exception&) {
1184 msg = "got another exception";
1185 }
1186 EXPECT_EQ("server 'server1' does not exist", msg);
1187 }
1188
1189 // Test that ceateUpdateSubnet6 throws appropriate exceptions for various
1190 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateSubnet6Selectors)1191 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSubnet6Selectors) {
1192 ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
1193 ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
1194
1195 // Supported selectors.
1196 Subnet6Ptr subnet = test_subnets_[0];
1197 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(),
1198 subnet));
1199 subnet = test_subnets_[2];
1200 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ONE("server1"),
1201 subnet));
1202 subnet = test_subnets_[3];
1203 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1204 subnet));
1205
1206 // Not supported server selectors.
1207 EXPECT_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ANY(), subnet),
1208 isc::InvalidOperation);
1209
1210 // Not implemented server selectors.
1211 EXPECT_THROW(cbptr_->createUpdateSubnet6(ServerSelector::UNASSIGNED(),
1212 subnet),
1213 isc::NotImplemented);
1214 }
1215
1216 // Test that subnet can be inserted, fetched, updated and then fetched again.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6)1217 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6) {
1218 // Insert the server2 into the database.
1219 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
1220 {
1221 SCOPED_TRACE("CREATE audit entry for server");
1222 testNewAuditEntry("dhcp6_server",
1223 AuditEntry::ModificationType::CREATE,
1224 "server set");
1225 }
1226
1227 auto subnet = test_subnets_[0];
1228 auto subnet2 = test_subnets_[2];
1229
1230 // An attempt to add a subnet to a non-existing server (server1) should fail.
1231 EXPECT_THROW(cbptr_->createUpdateSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1232 subnet2),
1233 NullKeyError);
1234
1235 // The subnet shouldn't have been added, even though one of the servers exists.
1236 Subnet6Ptr returned_subnet;
1237 ASSERT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::ONE("server2"),
1238 subnet2->getID()));
1239 EXPECT_FALSE(returned_subnet);
1240
1241 // Insert two subnets, one for all servers and one for server2.
1242 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet));
1243 {
1244 SCOPED_TRACE("CREATE audit entry for the subnet");
1245 testNewAuditEntry("dhcp6_subnet",
1246 AuditEntry::ModificationType::CREATE,
1247 "subnet set");
1248 }
1249
1250
1251 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ONE("server2"), subnet2));
1252 {
1253 SCOPED_TRACE("CREATE audit entry for the subnet");
1254 testNewAuditEntry("dhcp6_subnet",
1255 AuditEntry::ModificationType::CREATE,
1256 "subnet set", ServerSelector::ONE("subnet2"),
1257 2, 1);
1258 }
1259
1260 // We are not going to support selection of a single entry for multiple servers.
1261 EXPECT_THROW(cbptr_->getSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1262 subnet->getID()),
1263 isc::InvalidOperation);
1264
1265 EXPECT_THROW(cbptr_->getSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1266 subnet->toText()),
1267 isc::InvalidOperation);
1268
1269 // Test that this subnet will be fetched for various server selectors.
1270 auto test_get_subnet = [this, &subnet] (const std::string& test_case_name,
1271 const ServerSelector& server_selector,
1272 const std::string& expected_tag = ServerTag::ALL) {
1273 SCOPED_TRACE(test_case_name);
1274
1275 // Test fetching subnet by id.
1276 Subnet6Ptr returned_subnet;
1277 ASSERT_NO_THROW(returned_subnet = cbptr_->getSubnet6(server_selector, subnet->getID()));
1278 ASSERT_TRUE(returned_subnet);
1279
1280 ASSERT_EQ(1, returned_subnet->getServerTags().size());
1281 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag(expected_tag)));
1282
1283 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1284
1285 // Test fetching subnet by prefix.
1286 ASSERT_NO_THROW(returned_subnet = cbptr_->getSubnet6(server_selector,
1287 subnet->toText()));
1288 ASSERT_TRUE(returned_subnet);
1289
1290 ASSERT_EQ(1, returned_subnet->getServerTags().size());
1291 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag(expected_tag)));
1292
1293 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1294 };
1295
1296 {
1297 SCOPED_TRACE("testing various server selectors before update");
1298 test_get_subnet("all servers", ServerSelector::ALL());
1299 test_get_subnet("one server", ServerSelector::ONE("server1"));
1300 test_get_subnet("any server", ServerSelector::ANY());
1301 }
1302
1303 subnet = subnet2;
1304 {
1305 SCOPED_TRACE("testing server selectors for another server");
1306 test_get_subnet("one server", ServerSelector::ONE("server2"), "server2");
1307 test_get_subnet("any server", ServerSelector::ANY(), "server2");
1308 }
1309
1310 // Update the subnet in the database (both use the same ID).
1311 subnet = test_subnets_[1];
1312 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet));
1313 {
1314 SCOPED_TRACE("CREATE audit entry for the subnet");
1315 testNewAuditEntry("dhcp6_subnet",
1316 AuditEntry::ModificationType::UPDATE,
1317 "subnet set");
1318 }
1319
1320 {
1321 SCOPED_TRACE("testing various server selectors after update");
1322 test_get_subnet("all servers", ServerSelector::ALL());
1323 test_get_subnet("one server", ServerSelector::ONE("server1"));
1324 test_get_subnet("any server", ServerSelector::ANY());
1325 }
1326
1327 // The server2 specific subnet should not be returned if the server selector
1328 // is not matching.
1329 EXPECT_FALSE(cbptr_->getSubnet6(ServerSelector::ALL(), subnet2->getID()));
1330 EXPECT_FALSE(cbptr_->getSubnet6(ServerSelector::ALL(), subnet2->toText()));
1331 EXPECT_FALSE(cbptr_->getSubnet6(ServerSelector::ONE("server1"), subnet2->getID()));
1332 EXPECT_FALSE(cbptr_->getSubnet6(ServerSelector::ONE("server1"), subnet2->toText()));
1333
1334 // Update the subnet in the database (both use the same prefix).
1335 subnet2.reset(new Subnet6(IOAddress("2001:db8:3::"),
1336 64, 30, 40, 50, 80, 8192));
1337 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ONE("server2"), subnet2));
1338
1339 // Fetch again and verify.
1340 returned_subnet = cbptr_->getSubnet6(ServerSelector::ONE("server2"), subnet2->toText());
1341 ASSERT_TRUE(returned_subnet);
1342 EXPECT_EQ(subnet2->toElement()->str(), returned_subnet->toElement()->str());
1343
1344 // Update the subnet when it conflicts same id and same prefix both
1345 // with different subnets. This should throw.
1346 // Subnets are 2001:db8:1::/48 id 1024 and 2001:db8:3::/64 id 8192
1347 subnet2.reset(new Subnet6(IOAddress("2001:db8:1::"),
1348 48, 30, 40, 50, 80, 8192));
1349 EXPECT_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ONE("server2"), subnet2),
1350 DuplicateEntry);
1351 }
1352
1353 // Test that getSubnet6 by ID throws appropriate exceptions for various server
1354 // selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6byIdSelectors)1355 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6byIdSelectors) {
1356 // Supported selectors.
1357 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ANY(), SubnetID(1)));
1358 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::UNASSIGNED(), SubnetID(1)));
1359 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ALL(), SubnetID(1)));
1360 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ONE("server1"), SubnetID(1)));
1361
1362 // Not supported selectors.
1363 EXPECT_THROW(cbptr_->getSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1364 SubnetID(1)),
1365 isc::InvalidOperation);
1366 }
1367
1368 // Test that the information about unspecified optional parameters gets
1369 // propagated to the database.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6WithOptionalUnspecified)1370 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6WithOptionalUnspecified) {
1371 // Create a subnet and wrap it within a shared network. It is important
1372 // to have the shared network to verify that the subnet doesn't inherit
1373 // the values of the shared network but stores the NULL values in the
1374 // for those parameters that are unspecified on the subnet level.
1375 Subnet6Ptr subnet = test_subnets_[2];
1376 SharedNetwork6Ptr shared_network = test_networks_[0];
1377 shared_network->add(subnet);
1378
1379 // Need to add the shared network to the database because otherwise
1380 // the subnet foreign key would fail.
1381 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), shared_network);
1382 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
1383
1384 // Fetch this subnet by subnet identifier.
1385 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
1386 subnet->getID());
1387 ASSERT_TRUE(returned_subnet);
1388
1389 EXPECT_TRUE(returned_subnet->getIface().unspecified());
1390 EXPECT_TRUE(returned_subnet->getIface().empty());
1391
1392 EXPECT_TRUE(returned_subnet->getClientClass().unspecified());
1393 EXPECT_TRUE(returned_subnet->getClientClass().empty());
1394
1395 EXPECT_TRUE(returned_subnet->getValid().unspecified());
1396 EXPECT_EQ(0, returned_subnet->getValid().get());
1397
1398 EXPECT_TRUE(returned_subnet->getPreferred().unspecified());
1399 EXPECT_EQ(0, returned_subnet->getPreferred().get());
1400
1401 EXPECT_TRUE(returned_subnet->getT1().unspecified());
1402 EXPECT_EQ(0, returned_subnet->getT1().get());
1403
1404 EXPECT_TRUE(returned_subnet->getT2().unspecified());
1405 EXPECT_EQ(0, returned_subnet->getT2().get());
1406
1407 EXPECT_TRUE(returned_subnet->getReservationsGlobal().unspecified());
1408 EXPECT_FALSE(returned_subnet->getReservationsGlobal().get());
1409
1410 EXPECT_TRUE(returned_subnet->getReservationsInSubnet().unspecified());
1411 EXPECT_TRUE(returned_subnet->getReservationsInSubnet().get());
1412
1413 EXPECT_TRUE(returned_subnet->getReservationsOutOfPool().unspecified());
1414 EXPECT_FALSE(returned_subnet->getReservationsOutOfPool().get());
1415
1416 EXPECT_TRUE(returned_subnet->getCalculateTeeTimes().unspecified());
1417 EXPECT_FALSE(returned_subnet->getCalculateTeeTimes().get());
1418
1419 EXPECT_TRUE(returned_subnet->getT1Percent().unspecified());
1420 EXPECT_EQ(0.0, returned_subnet->getT1Percent().get());
1421
1422 EXPECT_TRUE(returned_subnet->getT2Percent().unspecified());
1423 EXPECT_EQ(0.0, returned_subnet->getT2Percent().get());
1424
1425 EXPECT_TRUE(returned_subnet->getRapidCommit().unspecified());
1426 EXPECT_FALSE(returned_subnet->getRapidCommit().get());
1427
1428 EXPECT_FALSE(returned_subnet->getDdnsSendUpdates().unspecified());
1429 EXPECT_TRUE(returned_subnet->getDdnsSendUpdates().get());
1430
1431 EXPECT_FALSE(returned_subnet->getDdnsOverrideNoUpdate().unspecified());
1432 EXPECT_TRUE(returned_subnet->getDdnsOverrideNoUpdate().get());
1433
1434 EXPECT_FALSE(returned_subnet->getDdnsOverrideClientUpdate().unspecified());
1435 EXPECT_FALSE(returned_subnet->getDdnsOverrideClientUpdate().get());
1436
1437 EXPECT_FALSE(returned_subnet->getDdnsReplaceClientNameMode().unspecified());
1438 EXPECT_EQ(D2ClientConfig::ReplaceClientNameMode::RCM_WHEN_PRESENT,
1439 returned_subnet->getDdnsReplaceClientNameMode().get());
1440
1441 EXPECT_FALSE(returned_subnet->getDdnsGeneratedPrefix().unspecified());
1442 EXPECT_EQ("myhost", returned_subnet->getDdnsGeneratedPrefix().get());
1443
1444 EXPECT_FALSE(returned_subnet->getDdnsQualifyingSuffix().unspecified());
1445 EXPECT_EQ("example.org", returned_subnet->getDdnsQualifyingSuffix().get());
1446
1447 // The easiest way to verify whether the returned subnet matches the inserted
1448 // subnet is to convert both to text.
1449 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1450
1451 }
1452
1453 // Test that subnet can be associated with a shared network.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6SharedNetwork)1454 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6SharedNetwork) {
1455 Subnet6Ptr subnet = test_subnets_[0];
1456 SharedNetwork6Ptr shared_network = test_networks_[0];
1457
1458 // Add subnet to a shared network.
1459 shared_network->add(subnet);
1460
1461 // Store shared network in the database.
1462 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
1463 shared_network);
1464
1465 // Store subnet associated with the shared network in the database.
1466 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
1467
1468 // Fetch this subnet by subnet identifier.
1469 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
1470 test_subnets_[0]->getID());
1471 ASSERT_TRUE(returned_subnet);
1472 ASSERT_EQ(1, returned_subnet->getServerTags().size());
1473 EXPECT_EQ("all", returned_subnet->getServerTags().begin()->get());
1474
1475 // The easiest way to verify whether the returned subnet matches the inserted
1476 // subnet is to convert both to text.
1477 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1478
1479 // However, the check above doesn't verify whether shared network name was
1480 // correctly returned from the database.
1481 EXPECT_EQ(shared_network->getName(), returned_subnet->getSharedNetworkName());
1482 }
1483
1484 // Test that subnet can be fetched by prefix.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6ByPrefix)1485 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6ByPrefix) {
1486 // Insert subnet to the database.
1487 Subnet6Ptr subnet = test_subnets_[0];
1488 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
1489
1490 // Fetch the subnet by prefix.
1491 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
1492 "2001:db8::/64");
1493 ASSERT_TRUE(returned_subnet);
1494 ASSERT_EQ(1, returned_subnet->getServerTags().size());
1495 EXPECT_EQ("all", returned_subnet->getServerTags().begin()->get());
1496
1497 // Verify subnet contents.
1498 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1499
1500 // Fetching the subnet for an explicitly specified server tag should
1501 // succeed too.
1502 returned_subnet = cbptr_->getSubnet6(ServerSelector::ONE("server1"),
1503 "2001:db8::/64");
1504 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
1505 }
1506
1507 // Test that getSubnet6 by prefix throws appropriate exceptions for various server
1508 // selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getSubnet6byPrefixSelectors)1509 TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6byPrefixSelectors) {
1510 // Supported selectors.
1511 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ANY(), "192.0.2.0/26"));
1512 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::UNASSIGNED(), "192.0.2.0/26"));
1513 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ALL(), "192.0.2.0/26"));
1514 EXPECT_NO_THROW(cbptr_->getSubnet6(ServerSelector::ONE("server1"), "192.0.2.0/26"));
1515
1516 // Not supported selectors.
1517 EXPECT_THROW(cbptr_->getSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1518 "192.0.2.0/26"),
1519 isc::InvalidOperation);
1520 }
1521
1522 // Test that all subnets can be fetched and then deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSubnets6)1523 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6) {
1524 // Insert test subnets into the database. Note that the second subnet will
1525 // overwrite the first subnet as they use the same ID.
1526 for (auto subnet : test_subnets_) {
1527 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
1528
1529 // That subnet overrides the first subnet so the audit entry should
1530 // indicate an update.
1531 if (subnet->toText() == "2001:db8:1::/48") {
1532 SCOPED_TRACE("UPDATE audit entry for the subnet " + subnet->toText());
1533 testNewAuditEntry("dhcp6_subnet",
1534 AuditEntry::ModificationType::UPDATE,
1535 "subnet set");
1536
1537 } else {
1538 SCOPED_TRACE("CREATE audit entry for the subnet " + subnet->toText());
1539 testNewAuditEntry("dhcp6_subnet",
1540 AuditEntry::ModificationType::CREATE,
1541 "subnet set");
1542 }
1543 }
1544
1545 // Fetch all subnets.
1546 Subnet6Collection subnets = cbptr_->getAllSubnets6(ServerSelector::ALL());
1547 ASSERT_EQ(test_subnets_.size() - 1, subnets.size());
1548
1549 // All subnets should also be returned for explicitly specified server tag.
1550 subnets = cbptr_->getAllSubnets6(ServerSelector::ONE("server1"));
1551 ASSERT_EQ(test_subnets_.size() - 1, subnets.size());
1552
1553 // See if the subnets are returned ok.
1554 auto subnet_it = subnets.begin();
1555 for (auto i = 0; i < subnets.size(); ++i, ++subnet_it) {
1556 EXPECT_EQ(test_subnets_[i + 1]->toElement()->str(),
1557 (*subnet_it)->toElement()->str());
1558 ASSERT_EQ(1, (*subnet_it)->getServerTags().size());
1559 EXPECT_EQ("all", (*subnet_it)->getServerTags().begin()->get());
1560 }
1561
1562 // Attempt to remove the non existing subnet should return 0.
1563 EXPECT_EQ(0, cbptr_->deleteSubnet6(ServerSelector::ALL(), 22));
1564 EXPECT_EQ(0, cbptr_->deleteSubnet6(ServerSelector::ALL(),
1565 "2001:db8:555::/64"));
1566 // All subnets should be still there.
1567 ASSERT_EQ(test_subnets_.size() - 1, subnets.size());
1568
1569 // Should not delete the subnet for explicit server tag because
1570 // our subnet is for all servers.
1571 EXPECT_EQ(0, cbptr_->deleteSubnet6(ServerSelector::ONE("server1"),
1572 test_subnets_[1]->getID()));
1573
1574 // Also, verify that behavior when deleting by prefix.
1575 EXPECT_EQ(0, cbptr_->deleteSubnet6(ServerSelector::ONE("server1"),
1576 test_subnets_[2]->toText()));
1577
1578 // Same for all subnets.
1579 EXPECT_EQ(0, cbptr_->deleteAllSubnets6(ServerSelector::ONE("server1")));
1580
1581 // Delete first subnet by id and verify that it is gone.
1582 EXPECT_EQ(1, cbptr_->deleteSubnet6(ServerSelector::ALL(),
1583 test_subnets_[1]->getID()));
1584
1585 {
1586 SCOPED_TRACE("DELETE first subnet audit entry");
1587 testNewAuditEntry("dhcp6_subnet",
1588 AuditEntry::ModificationType::DELETE,
1589 "subnet deleted");
1590 }
1591
1592 subnets = cbptr_->getAllSubnets6(ServerSelector::ALL());
1593 ASSERT_EQ(test_subnets_.size() - 2, subnets.size());
1594
1595 // Delete second subnet by prefix and verify it is gone.
1596 EXPECT_EQ(1, cbptr_->deleteSubnet6(ServerSelector::ALL(),
1597 test_subnets_[2]->toText()));
1598 subnets = cbptr_->getAllSubnets6(ServerSelector::ALL());
1599 ASSERT_EQ(test_subnets_.size() - 3, subnets.size());
1600
1601 {
1602 SCOPED_TRACE("DELETE second subnet audit entry");
1603 testNewAuditEntry("dhcp6_subnet",
1604 AuditEntry::ModificationType::DELETE,
1605 "subnet deleted");
1606 }
1607
1608 // Delete all.
1609 EXPECT_EQ(1, cbptr_->deleteAllSubnets6(ServerSelector::ALL()));
1610 subnets = cbptr_->getAllSubnets6(ServerSelector::ALL());
1611 ASSERT_TRUE(subnets.empty());
1612
1613 {
1614 SCOPED_TRACE("DELETE all subnets audit entry");
1615 testNewAuditEntry("dhcp6_subnet",
1616 AuditEntry::ModificationType::DELETE,
1617 "deleted all subnets");
1618 }
1619 }
1620
1621 // Test that getAllSubnets6 throws appropriate exceptions for various
1622 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSubnets6Selectors)1623 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6Selectors) {
1624 // Supported selectors.
1625 EXPECT_NO_THROW(cbptr_->getAllSubnets6(ServerSelector::UNASSIGNED()));
1626 EXPECT_NO_THROW(cbptr_->getAllSubnets6(ServerSelector::ALL()));
1627 EXPECT_NO_THROW(cbptr_->getAllSubnets6(ServerSelector::ONE("server1")));
1628 EXPECT_NO_THROW(cbptr_->getAllSubnets6(ServerSelector::MULTIPLE({ "server1", "server2" })));
1629
1630 // Not supported selectors.
1631 EXPECT_THROW(cbptr_->getAllSubnets6(ServerSelector::ANY()), isc::InvalidOperation);
1632 }
1633
1634 // Test that subnets with different server associations are returned.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSubnets6WithServerTags)1635 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6WithServerTags) {
1636 auto subnet1 = test_subnets_[0];
1637 auto subnet2 = test_subnets_[2];
1638 auto subnet3 = test_subnets_[3];
1639
1640 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
1641 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
1642
1643 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(),
1644 subnet1));
1645 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ONE("server1"),
1646 subnet2));
1647 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1648 subnet3));
1649
1650 Subnet6Collection subnets;
1651
1652 // All three subnets are associated with the server1.
1653 EXPECT_NO_THROW(subnets = cbptr_->getAllSubnets6(ServerSelector::ONE("server1")));
1654 EXPECT_EQ(3, subnets.size());
1655
1656 // First subnet is associated with all servers.
1657 auto returned_subnet = SubnetFetcher6::get(subnets, SubnetID(1024));
1658 ASSERT_TRUE(returned_subnet);
1659 EXPECT_TRUE(returned_subnet->hasAllServerTag());
1660 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server1")));
1661 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server2")));
1662
1663 // Second subnet is only associated with the server1.
1664 returned_subnet = SubnetFetcher6::get(subnets, SubnetID(2048));
1665 ASSERT_TRUE(returned_subnet);
1666 EXPECT_FALSE(returned_subnet->hasAllServerTag());
1667 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag("server1")));
1668 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server2")));
1669
1670 // Third subnet is associated with both server1 and server2.
1671 returned_subnet = SubnetFetcher6::get(subnets, SubnetID(4096));
1672 ASSERT_TRUE(returned_subnet);
1673 EXPECT_FALSE(returned_subnet->hasAllServerTag());
1674 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag("server1")));
1675 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag("server2")));
1676
1677 // For server2 we should only get two subnets, i.e. first and last.
1678 EXPECT_NO_THROW(subnets = cbptr_->getAllSubnets6(ServerSelector::ONE("server2")));
1679 EXPECT_EQ(2, subnets.size());
1680
1681 // First subnet is associated with all servers.
1682 returned_subnet = SubnetFetcher6::get(subnets, SubnetID(1024));
1683 ASSERT_TRUE(returned_subnet);
1684 EXPECT_TRUE(returned_subnet->hasAllServerTag());
1685 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server1")));
1686 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server2")));
1687
1688 // Last subnet is associated with server1 and server2.
1689 returned_subnet = SubnetFetcher6::get(subnets, SubnetID(4096));
1690 ASSERT_TRUE(returned_subnet);
1691 EXPECT_FALSE(returned_subnet->hasAllServerTag());
1692 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag("server1")));
1693 EXPECT_TRUE(returned_subnet->hasServerTag(ServerTag("server2")));
1694
1695 // Only the first subnet is associated with all servers.
1696 EXPECT_NO_THROW(subnets = cbptr_->getAllSubnets6(ServerSelector::ALL()));
1697 EXPECT_EQ(1, subnets.size());
1698
1699 returned_subnet = SubnetFetcher6::get(subnets, SubnetID(1024));
1700 ASSERT_TRUE(returned_subnet);
1701 EXPECT_TRUE(returned_subnet->hasAllServerTag());
1702 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server1")));
1703 EXPECT_FALSE(returned_subnet->hasServerTag(ServerTag("server2")));
1704 }
1705
1706 // Test that selected subnet can be deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSubnet6)1707 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6) {
1708 // Create two servers in the database.
1709 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
1710 {
1711 SCOPED_TRACE("CREATE audit entry for server");
1712 testNewAuditEntry("dhcp6_server",
1713 AuditEntry::ModificationType::CREATE,
1714 "server set");
1715 }
1716
1717 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
1718 {
1719 SCOPED_TRACE("CREATE audit entry for server");
1720 testNewAuditEntry("dhcp6_server",
1721 AuditEntry::ModificationType::CREATE,
1722 "server set");
1723 }
1724
1725 auto subnet1 = test_subnets_[0];
1726 auto subnet2 = test_subnets_[2];
1727 auto subnet3 = test_subnets_[3];
1728
1729 auto create_test_subnets = [&] () {
1730 // Insert three subnets, one for all servers, one for server2 and one for two
1731 // servers: server1 and server2.
1732 EXPECT_NO_THROW(
1733 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet1)
1734 );
1735 EXPECT_NO_THROW(
1736 cbptr_->createUpdateSubnet6(ServerSelector::ONE("server2"), subnet2)
1737 );
1738 EXPECT_NO_THROW(
1739 cbptr_->createUpdateSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1740 subnet3)
1741 );
1742 };
1743
1744 create_test_subnets();
1745
1746 // Test that subnet is not deleted for a specified server selector.
1747 auto test_no_delete = [this] (const std::string& test_case_name,
1748 const ServerSelector& server_selector,
1749 const Subnet6Ptr& subnet) {
1750 SCOPED_TRACE(test_case_name);
1751 uint64_t deleted_count = 0;
1752 EXPECT_NO_THROW(
1753 deleted_count = cbptr_->deleteSubnet6(server_selector, subnet->getID())
1754 );
1755 EXPECT_EQ(0, deleted_count);
1756
1757 deleted_count = 0;
1758 EXPECT_NO_THROW(
1759 deleted_count = cbptr_->deleteSubnet6(server_selector, subnet->toText())
1760 );
1761 EXPECT_EQ(0, deleted_count);
1762 };
1763
1764 {
1765 SCOPED_TRACE("Test valid but non matching server selectors");
1766 test_no_delete("selector: one, actual: all", ServerSelector::ONE("server2"),
1767 subnet1);
1768 test_no_delete("selector: all, actual: one", ServerSelector::ALL(),
1769 subnet2);
1770 test_no_delete("selector: all, actual: multiple", ServerSelector::ALL(),
1771 subnet3);
1772 }
1773
1774 // Test successful deletion of a subnet by ID.
1775 auto test_delete_by_id = [this] (const std::string& test_case_name,
1776 const ServerSelector& server_selector,
1777 const Subnet6Ptr& subnet) {
1778 SCOPED_TRACE(test_case_name);
1779 uint64_t deleted_count = 0;
1780 EXPECT_NO_THROW(
1781 deleted_count = cbptr_->deleteSubnet6(server_selector, subnet->getID())
1782 );
1783 EXPECT_EQ(1, deleted_count);
1784
1785 EXPECT_FALSE(cbptr_->getSubnet6(server_selector, subnet->getID()));
1786 };
1787
1788 test_delete_by_id("all servers", ServerSelector::ALL(), subnet1);
1789 test_delete_by_id("any server", ServerSelector::ANY(), subnet2);
1790 test_delete_by_id("one server", ServerSelector::ONE("server1"), subnet3);
1791
1792 // Re-create deleted subnets.
1793 create_test_subnets();
1794
1795 // Test successful deletion of a subnet by prefix.
1796 auto test_delete_by_prefix = [this] (const std::string& test_case_name,
1797 const ServerSelector& server_selector,
1798 const Subnet6Ptr& subnet) {
1799 SCOPED_TRACE(test_case_name);
1800 uint64_t deleted_count = 0;
1801 EXPECT_NO_THROW(
1802 deleted_count = cbptr_->deleteSubnet6(server_selector, subnet->toText())
1803 );
1804 EXPECT_EQ(1, deleted_count);
1805
1806 EXPECT_FALSE(cbptr_->getSubnet6(server_selector, subnet->toText()));
1807 };
1808
1809 test_delete_by_prefix("all servers", ServerSelector::ALL(), subnet1);
1810 test_delete_by_prefix("any server", ServerSelector::ANY(), subnet2);
1811 test_delete_by_prefix("one server", ServerSelector::ONE("server1"), subnet3);
1812 }
1813
1814 // Test that deleteSubnet6 by ID throws appropriate exceptions for various
1815 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSubnet6ByIdSelectors)1816 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6ByIdSelectors) {
1817 // Supported selectors.
1818 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ANY(), SubnetID(1)));
1819 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ALL(), SubnetID(1)));
1820 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ONE("server1"), SubnetID(1)));
1821
1822 // Not supported selectors.
1823 EXPECT_THROW(cbptr_->deleteSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1824 SubnetID(1)),
1825 isc::InvalidOperation);
1826
1827 // Not implemented selectors.
1828 EXPECT_THROW(cbptr_->deleteSubnet6(ServerSelector::UNASSIGNED(), SubnetID(1)),
1829 isc::NotImplemented);
1830 }
1831
1832 // Test that deleteSubnet6 by prefix throws appropriate exceptions for various
1833 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSubnet6ByPrefixSelectors)1834 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6ByPrefixSelectors) {
1835 // Supported selectors.
1836 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ANY(), "192.0.2.0/26"));
1837 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ALL(), "192.0.2.0/26"));
1838 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ONE("server1"), "192.0.2.0/26"));
1839
1840 // Not supported selectors.
1841 EXPECT_THROW(cbptr_->deleteSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
1842 "192.0.2.0/26"),
1843 isc::InvalidOperation);
1844
1845 // Not implemented selectors.
1846 EXPECT_THROW(cbptr_->deleteSubnet6(ServerSelector::UNASSIGNED(), "192.0.2.0/26"),
1847 isc::NotImplemented);
1848 }
1849
1850 // Test that deleteAllSubnets6 throws appropriate exceptions for various
1851 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteAllSubnets6Selectors)1852 TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllSubnets6Selectors) {
1853 // Supported selectors.
1854 EXPECT_NO_THROW(cbptr_->deleteAllSubnets6(ServerSelector::UNASSIGNED()));
1855 EXPECT_NO_THROW(cbptr_->deleteAllSubnets6(ServerSelector::ALL()));
1856 EXPECT_NO_THROW(cbptr_->deleteAllSubnets6(ServerSelector::ONE("server1")));
1857
1858 // Not supported selectors.
1859 EXPECT_THROW(cbptr_->deleteAllSubnets6(ServerSelector::ANY()),
1860 isc::InvalidOperation);
1861 EXPECT_THROW(cbptr_->deleteAllSubnets6(ServerSelector::MULTIPLE({ "server1", "server2" })),
1862 isc::InvalidOperation);
1863 }
1864
1865 // Test that it is possible to retrieve and delete orphaned subnet.
TEST_F(MySqlConfigBackendDHCPv6Test,unassignedSubnet6)1866 TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSubnet6) {
1867 // Create the server.
1868 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
1869
1870 // Create the subnets and associate them with the server1.
1871 auto subnet = test_subnets_[0];
1872 auto subnet2 = test_subnets_[2];
1873 EXPECT_NO_THROW(
1874 cbptr_->createUpdateSubnet6(ServerSelector::ONE("server1"), subnet)
1875 );
1876 EXPECT_NO_THROW(
1877 cbptr_->createUpdateSubnet6(ServerSelector::ONE("server1"), subnet2)
1878 );
1879
1880 // Delete the server. The subnets should be preserved but are considered orphaned,
1881 // i.e. do not belong to any server.
1882 uint64_t deleted_count = 0;
1883 EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer6(ServerTag("server1")));
1884 EXPECT_EQ(1, deleted_count);
1885
1886 // Trying to fetch the subnet by server tag should return no result.
1887 Subnet6Ptr returned_subnet;
1888 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::ONE("server1"),
1889 subnet->getID()));
1890 EXPECT_FALSE(returned_subnet);
1891
1892 // The same if we use other calls.
1893 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::ONE("server1"),
1894 subnet->toText()));
1895 EXPECT_FALSE(returned_subnet);
1896
1897 Subnet6Collection returned_subnets;
1898 EXPECT_NO_THROW(returned_subnets = cbptr_->getAllSubnets6(ServerSelector::ONE("server1")));
1899 EXPECT_TRUE(returned_subnets.empty());
1900
1901 EXPECT_NO_THROW(
1902 returned_subnets = cbptr_->getModifiedSubnets6(ServerSelector::ONE("server1"),
1903 timestamps_["two days ago"])
1904 );
1905 EXPECT_TRUE(returned_subnets.empty());
1906
1907 // We should get the subnet if we ask for unassigned.
1908 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::UNASSIGNED(),
1909 subnet->getID()));
1910 ASSERT_TRUE(returned_subnet);
1911
1912 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::UNASSIGNED(),
1913 subnet->toText()));
1914 ASSERT_TRUE(returned_subnet);
1915
1916 // Also if we ask for all unassigned subnets it should be returned.
1917 EXPECT_NO_THROW(returned_subnets = cbptr_->getAllSubnets6(ServerSelector::UNASSIGNED()));
1918 ASSERT_EQ(2, returned_subnets.size());
1919
1920 // Same for modified subnets.
1921 EXPECT_NO_THROW(
1922 returned_subnets = cbptr_->getModifiedSubnets6(ServerSelector::UNASSIGNED(),
1923 timestamps_["two days ago"])
1924 );
1925 ASSERT_EQ(2, returned_subnets.size());
1926
1927 // If we ask for any subnet by subnet id, it should be returned too.
1928 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::ANY(),
1929 subnet->getID()));
1930 ASSERT_TRUE(returned_subnet);
1931
1932 EXPECT_NO_THROW(returned_subnet = cbptr_->getSubnet6(ServerSelector::ANY(),
1933 subnet->toText()));
1934 ASSERT_TRUE(returned_subnet);
1935
1936 // Deleting the subnet with the mismatched server tag should not affect our
1937 // subnet.
1938 EXPECT_NO_THROW(
1939 deleted_count = cbptr_->deleteSubnet6(ServerSelector::ONE("server1"),
1940 subnet->getID())
1941 );
1942 EXPECT_EQ(0, deleted_count);
1943
1944 // Also, if we delete all subnets for server1.
1945 EXPECT_NO_THROW(
1946 deleted_count = cbptr_->deleteAllSubnets6(ServerSelector::ONE("server1"))
1947 );
1948 EXPECT_EQ(0, deleted_count);
1949
1950 // We can delete this subnet when we specify ANY and the matching id.
1951 EXPECT_NO_THROW(
1952 deleted_count = cbptr_->deleteSubnet6(ServerSelector::ANY(), subnet->getID())
1953 );
1954 EXPECT_EQ(1, deleted_count);
1955
1956 // We can delete all subnets using UNASSIGNED selector.
1957 EXPECT_NO_THROW(
1958 deleted_count = cbptr_->deleteAllSubnets6(ServerSelector::UNASSIGNED());
1959 );
1960 EXPECT_EQ(1, deleted_count);
1961 }
1962
1963 // Test that subnets modified after given time can be fetched.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedSubnets6)1964 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSubnets6) {
1965 // Explicitly set timestamps of subnets. First subnet has a timestamp
1966 // pointing to the future. Second subnet has timestamp pointing to the
1967 // past (yesterday). Third subnet has a timestamp pointing to the
1968 // past (an hour ago).
1969 test_subnets_[1]->setModificationTime(timestamps_["tomorrow"]);
1970 test_subnets_[2]->setModificationTime(timestamps_["yesterday"]);
1971 test_subnets_[3]->setModificationTime(timestamps_["today"]);
1972
1973 // Insert subnets into the database.
1974 for (int i = 1; i < test_subnets_.size(); ++i) {
1975 cbptr_->createUpdateSubnet6(ServerSelector::ALL(),
1976 test_subnets_[i]);
1977 }
1978
1979 // Fetch subnets with timestamp later than today. Only one subnet
1980 // should be returned.
1981 Subnet6Collection
1982 subnets = cbptr_->getModifiedSubnets6(ServerSelector::ALL(),
1983 timestamps_["after today"]);
1984 ASSERT_EQ(1, subnets.size());
1985
1986 // All subnets should also be returned for explicitly specified server tag.
1987 subnets = cbptr_->getModifiedSubnets6(ServerSelector::ONE("server1"),
1988 timestamps_["after today"]);
1989 ASSERT_EQ(1, subnets.size());
1990
1991 // Fetch subnets with timestamp later than yesterday. We should get
1992 // two subnets.
1993 subnets = cbptr_->getModifiedSubnets6(ServerSelector::ALL(),
1994 timestamps_["after yesterday"]);
1995 ASSERT_EQ(2, subnets.size());
1996
1997 // Fetch subnets with timestamp later than tomorrow. Nothing should
1998 // be returned.
1999 subnets = cbptr_->getModifiedSubnets6(ServerSelector::ALL(),
2000 timestamps_["after tomorrow"]);
2001 ASSERT_TRUE(subnets.empty());
2002 }
2003
2004 // Test that getModifiedSubnets6 throws appropriate exceptions for various
2005 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedSubnets6Selectors)2006 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSubnets6Selectors) {
2007 // Supported selectors.
2008 EXPECT_NO_THROW(cbptr_->getModifiedSubnets6(ServerSelector::UNASSIGNED(),
2009 timestamps_["yesterday"]));
2010 EXPECT_NO_THROW(cbptr_->getModifiedSubnets6(ServerSelector::ALL(),
2011 timestamps_["yesterday"]));
2012 EXPECT_NO_THROW(cbptr_->getModifiedSubnets6(ServerSelector::ONE("server1"),
2013 timestamps_["yesterday"]));
2014 EXPECT_NO_THROW(cbptr_->getModifiedSubnets6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2015 timestamps_["yesterday"]));
2016
2017 // Not supported selectors.
2018 EXPECT_THROW(cbptr_->getModifiedSubnets6(ServerSelector::ANY(),
2019 timestamps_["yesterday"]),
2020 isc::InvalidOperation);
2021 }
2022
2023 // Test that lifetimes in subnets are handled as expected.
TEST_F(MySqlConfigBackendDHCPv6Test,subnetLifetime)2024 TEST_F(MySqlConfigBackendDHCPv6Test, subnetLifetime) {
2025 // Insert new subnet with unspecified valid lifetime
2026 Triplet<uint32_t> unspecified;
2027 Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 64, 30, 40,
2028 unspecified, unspecified, 1111));
2029 subnet->setIface("eth1");
2030 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
2031
2032 // Fetch this subnet by subnet identifier
2033 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
2034 subnet->getID());
2035 ASSERT_TRUE(returned_subnet);
2036
2037 // Verified returned and original subnets match.
2038 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
2039
2040 // Update the preferred and valid lifetime.
2041 subnet->setPreferred( Triplet<uint32_t>(100, 200, 300));
2042 subnet->setValid( Triplet<uint32_t>(200, 300, 400));
2043 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
2044
2045 // Fetch and verify again.
2046 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID());
2047 ASSERT_TRUE(returned_subnet);
2048 EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
2049 }
2050
2051 // Test that subnets belonging to a shared network can be retrieved.
TEST_F(MySqlConfigBackendDHCPv6Test,getSharedNetworkSubnets6)2052 TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetworkSubnets6) {
2053 // Assign test subnets to shared networks level1 and level2.
2054 test_subnets_[1]->setSharedNetworkName("level1");
2055 test_subnets_[2]->setSharedNetworkName("level2");
2056 test_subnets_[3]->setSharedNetworkName("level2");
2057
2058 // Store shared networks in the database.
2059 for (auto network : test_networks_) {
2060 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), network);
2061 }
2062
2063 // Store subnets in the database.
2064 for (auto subnet : test_subnets_) {
2065 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
2066 }
2067
2068 // Fetch all subnets belonging to shared network level1.
2069 Subnet6Collection subnets = cbptr_->getSharedNetworkSubnets6(ServerSelector::ALL(),
2070 "level1");
2071 ASSERT_EQ(1, subnets.size());
2072
2073 // Returned subnet should match test subnet #1.
2074 EXPECT_TRUE(isEquivalent(test_subnets_[1]->toElement(),
2075 (*subnets.begin())->toElement()));
2076
2077 // All subnets should also be returned for ANY server.
2078 subnets = cbptr_->getSharedNetworkSubnets6(ServerSelector::ANY(), "level1");
2079 ASSERT_EQ(1, subnets.size());
2080
2081 // Returned subnet should match test subnet #1.
2082 EXPECT_TRUE(isEquivalent(test_subnets_[1]->toElement(),
2083 (*subnets.begin())->toElement()));
2084
2085 // Fetch all subnets belonging to shared network level2.
2086 subnets = cbptr_->getSharedNetworkSubnets6(ServerSelector::ALL(), "level2");
2087 ASSERT_EQ(2, subnets.size());
2088
2089 ElementPtr test_list = Element::createList();
2090 test_list->add(test_subnets_[2]->toElement());
2091 test_list->add(test_subnets_[3]->toElement());
2092
2093 ElementPtr returned_list = Element::createList();
2094 auto subnet = subnets.begin();
2095 returned_list->add((*subnet)->toElement());
2096 returned_list->add((*++subnet)->toElement());
2097
2098 EXPECT_TRUE(isEquivalent(returned_list, test_list));
2099
2100 // All subnets should also be returned for explicitly specified server tag.
2101 subnets = cbptr_->getSharedNetworkSubnets6(ServerSelector::ONE("server1"), "level2");
2102 ASSERT_EQ(2, subnets.size());
2103
2104 returned_list = Element::createList();
2105 subnet = subnets.begin();
2106 returned_list->add((*subnet)->toElement());
2107 returned_list->add((*++subnet)->toElement());
2108
2109 EXPECT_TRUE(isEquivalent(returned_list, test_list));
2110 }
2111
2112 // Test that pools are properly updated as a result a subnet update.
TEST_F(MySqlConfigBackendDHCPv6Test,subnetUpdatePools)2113 TEST_F(MySqlConfigBackendDHCPv6Test, subnetUpdatePools) {
2114
2115 auto test_subnet_update = [this](const std::string& subnet_prefix,
2116 const SubnetID& subnet_id) {
2117 // Add the subnet with two address pools and two prefix delegation
2118 // pools.
2119 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(),
2120 test_subnets_[0]));
2121 // Make sure that the pools have been added to the database.
2122 EXPECT_EQ(2, countRows("dhcp6_pool"));
2123 EXPECT_EQ(2, countRows("dhcp6_pd_pool"));
2124
2125 // Create the subnet without options which updates the existing
2126 // subnet.
2127 Subnet6Ptr subnet(new Subnet6(IOAddress(subnet_prefix), 64, 30, 60, 50, 60,
2128 subnet_id));
2129 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet));
2130 // Check that options are gone.
2131 EXPECT_EQ(0, countRows("dhcp6_pool"));
2132 EXPECT_EQ(0, countRows("dhcp6_pd_pool"));
2133 };
2134
2135 {
2136 SCOPED_TRACE("update subnet, modify subnet id");
2137 // Create another subnet with the same prefix as the original subnet but
2138 // different id. This is legal to update the subnet id if the prefix is
2139 // stable. However, the new subnet has no address pools, so we need to
2140 // check of the pools associated with the existing subnet instance are
2141 // gone after the update.
2142 test_subnet_update("2001:db8::", 2048);
2143 }
2144
2145 {
2146 SCOPED_TRACE("update subnet, modify prefix");
2147 // Create a subnet with the same subnet id but different prefix.
2148 // The prefix should be updated.
2149 test_subnet_update("2001:db9::", 1024);
2150 }
2151 }
2152
2153 // Test that deleting a subnet triggers deletion of the options associated
2154 // with the subnet and pools.
TEST_F(MySqlConfigBackendDHCPv6Test,subnetOptions)2155 TEST_F(MySqlConfigBackendDHCPv6Test, subnetOptions) {
2156 // Add the subnet with two pools and three options.
2157 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[0]));
2158 EXPECT_EQ(2, countRows("dhcp6_pool"));
2159 EXPECT_EQ(2, countRows("dhcp6_pd_pool"));
2160 EXPECT_EQ(3, countRows("dhcp6_options"));
2161
2162 // The second subnet uses the same subnet id, so this operation should replace
2163 // the existing subnet and its options. The new instance has four pools, each
2164 // including one option, so we should end up with four options.
2165 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[1]));
2166 EXPECT_EQ(2, countRows("dhcp6_pool"));
2167 EXPECT_EQ(2, countRows("dhcp6_pd_pool"));
2168 EXPECT_EQ(4, countRows("dhcp6_options"));
2169
2170 // Add third subnet with a single option. The number of options in the database
2171 // should now be 5.
2172 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[2]));
2173 EXPECT_EQ(2, countRows("dhcp6_pool"));
2174 EXPECT_EQ(2, countRows("dhcp6_pd_pool"));
2175 EXPECT_EQ(5, countRows("dhcp6_options"));
2176
2177 // Delete the subnet. All options and pools it contains should also be removed, leaving
2178 // the last added subnet and its sole option.
2179 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ALL(), test_subnets_[1]->getID()));
2180 EXPECT_EQ(1, countRows("dhcp6_subnet"));
2181 EXPECT_EQ(0, countRows("dhcp6_pool"));
2182 EXPECT_EQ(0, countRows("dhcp6_pd_pool"));
2183 EXPECT_EQ(1, countRows("dhcp6_options"));
2184
2185 // Add the first subnet again. We should now have 4 options: 3 options from the
2186 // newly added subnet and one option from the existing subnet.
2187 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[0]));
2188 EXPECT_EQ(2, countRows("dhcp6_pool"));
2189 EXPECT_EQ(2, countRows("dhcp6_pd_pool"));
2190 EXPECT_EQ(4, countRows("dhcp6_options"));
2191
2192 // Delete the subnet including 3 options. The option from the other subnet should not
2193 // be affected.
2194 EXPECT_NO_THROW(cbptr_->deleteSubnet6(ServerSelector::ALL(), test_subnets_[0]->getID()));
2195 EXPECT_EQ(1, countRows("dhcp6_subnet"));
2196 EXPECT_EQ(0, countRows("dhcp6_pool"));
2197 EXPECT_EQ(0, countRows("dhcp6_pd_pool"));
2198 EXPECT_EQ(1, countRows("dhcp6_options"));
2199 }
2200
2201 // Test that shared network can be inserted, fetched, updated and then
2202 // fetched again.
TEST_F(MySqlConfigBackendDHCPv6Test,getSharedNetwork6)2203 TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6) {
2204 // Insert the server2 into the database.
2205 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
2206 {
2207 SCOPED_TRACE("CREATE audit entry for server");
2208 testNewAuditEntry("dhcp6_server",
2209 AuditEntry::ModificationType::CREATE,
2210 "server set");
2211 }
2212
2213 auto shared_network = test_networks_[0];
2214 auto shared_network2 = test_networks_[2];
2215
2216 // Insert two shared networks, one for all servers, and one for server2.
2217 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2218 shared_network));
2219 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server2"),
2220 shared_network2));
2221
2222 // We are not going to support selection of a single entry for multiple servers.
2223 EXPECT_THROW(cbptr_->getSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2224 test_networks_[0]->getName()),
2225 isc::InvalidOperation);
2226
2227 // Test that this shared network will be fetched for various server selectors.
2228 auto test_get_network = [this, &shared_network] (const std::string& test_case_name,
2229 const ServerSelector& server_selector,
2230 const std::string& expected_tag = ServerTag::ALL) {
2231 SCOPED_TRACE(test_case_name);
2232 SharedNetwork6Ptr network;
2233 ASSERT_NO_THROW(network = cbptr_->getSharedNetwork6(server_selector,
2234 shared_network->getName()));
2235 ASSERT_TRUE(network);
2236
2237 EXPECT_GT(network->getId(), 0);
2238 ASSERT_EQ(1, network->getServerTags().size());
2239 EXPECT_EQ(expected_tag, network->getServerTags().begin()->get());
2240
2241 // The easiest way to verify whether the returned shared network matches the
2242 // inserted shared network is to convert both to text.
2243 EXPECT_EQ(shared_network->toElement()->str(), network->toElement()->str());
2244 };
2245
2246 {
2247 SCOPED_TRACE("testing various server selectors before update");
2248 test_get_network("all servers", ServerSelector::ALL());
2249 test_get_network("one server", ServerSelector::ONE("server1"));
2250 test_get_network("any server", ServerSelector::ANY());
2251 }
2252
2253 {
2254 SCOPED_TRACE("CREATE audit entry for a shared network");
2255 testNewAuditEntry("dhcp6_shared_network",
2256 AuditEntry::ModificationType::CREATE,
2257 "shared network set");
2258 }
2259
2260 // Update shared network in the database.
2261 shared_network = test_networks_[1];
2262 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2263 shared_network));
2264
2265 {
2266 SCOPED_TRACE("testing various server selectors after update");
2267 test_get_network("all servers after update", ServerSelector::ALL());
2268 test_get_network("one server after update", ServerSelector::ONE("server1"));
2269 test_get_network("any server after update", ServerSelector::ANY());
2270 }
2271
2272 {
2273 SCOPED_TRACE("UPDATE audit entry for a shared network");
2274 testNewAuditEntry("dhcp6_shared_network",
2275 AuditEntry::ModificationType::UPDATE,
2276 "shared network set");
2277 }
2278
2279 // The server2 specific shared network should not be returned if the
2280 // server selector is not matching.
2281 EXPECT_FALSE(cbptr_->getSharedNetwork6(ServerSelector::ALL(),
2282 shared_network2->getName()));
2283 EXPECT_FALSE(cbptr_->getSharedNetwork6(ServerSelector::ONE("server1"),
2284 shared_network2->getName()));
2285
2286 {
2287 SCOPED_TRACE("testing selectors for server2 specific shared network");
2288 shared_network = shared_network2;
2289 test_get_network("one server", ServerSelector::ONE("server2"), "server2");
2290 test_get_network("any server", ServerSelector::ANY(), "server2");
2291 }
2292 }
2293
2294 // Test that getSharedNetwork6 throws appropriate exceptions for various
2295 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getSharedNetwork6Selectors)2296 TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6Selectors) {
2297 // Supported selectors.
2298 EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ANY(), "level1"));
2299 EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::UNASSIGNED(), "level1"));
2300 EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ALL(), "level1"));
2301 EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ONE("server1"), "level1"));
2302
2303 // Not supported selectors.
2304 EXPECT_THROW(cbptr_->getSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2305 "level1"),
2306 isc::InvalidOperation);
2307 }
2308
2309 // Test that shared network may be created and updated and the server tags
2310 // are properly assigned to it.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateSharedNetwork6)2311 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6) {
2312 auto shared_network = test_networks_[0];
2313
2314 // An attempt to insert the shared network for non-existing server should fail.
2315 EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"),
2316 shared_network),
2317 NullKeyError);
2318
2319 // Insert the server1 into the database.
2320 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
2321 {
2322 SCOPED_TRACE("CREATE audit entry for server");
2323 testNewAuditEntry("dhcp6_server",
2324 AuditEntry::ModificationType::CREATE,
2325 "server set");
2326 }
2327
2328 // Insert the server2 into the database.
2329 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
2330 {
2331 SCOPED_TRACE("CREATE audit entry for server");
2332 testNewAuditEntry("dhcp6_server",
2333 AuditEntry::ModificationType::CREATE,
2334 "server set");
2335 }
2336
2337 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2338 shared_network));
2339 {
2340 SCOPED_TRACE("CREATE audit entry for shared network and ALL servers");
2341 testNewAuditEntry("dhcp6_shared_network",
2342 AuditEntry::ModificationType::CREATE,
2343 "shared network set");
2344 }
2345
2346 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2347 shared_network));
2348 {
2349 SCOPED_TRACE("UPDATE audit entry for shared network and MULTIPLE servers");
2350 testNewAuditEntry("dhcp6_shared_network",
2351 AuditEntry::ModificationType::UPDATE,
2352 "shared network set");
2353 }
2354
2355 SharedNetwork6Ptr network;
2356 ASSERT_NO_THROW(network = cbptr_->getSharedNetwork6(ServerSelector::ANY(),
2357 shared_network->getName()));
2358 ASSERT_TRUE(network);
2359 EXPECT_TRUE(network->hasServerTag(ServerTag("server1")));
2360 EXPECT_TRUE(network->hasServerTag(ServerTag("server2")));
2361 EXPECT_FALSE(network->hasServerTag(ServerTag()));
2362 }
2363
2364 // Test that createUpdateSharedNetwork6 throws appropriate exceptions for various
2365 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateSharedNetwork6Selectors)2366 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6Selectors) {
2367 ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
2368 ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
2369
2370 // Supported selectors.
2371 SharedNetwork6Ptr shared_network(new SharedNetwork6("all"));
2372 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2373 shared_network));
2374 shared_network.reset(new SharedNetwork6("one"));
2375 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"),
2376 shared_network));
2377 shared_network.reset(new SharedNetwork6("multiple"));
2378 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2379 shared_network));
2380
2381 // Not supported server selectors.
2382 EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ANY(), shared_network),
2383 isc::InvalidOperation);
2384
2385 // Not implemented server selectors.
2386 EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::UNASSIGNED(),
2387 shared_network),
2388 isc::NotImplemented);
2389 }
2390
2391 // Test that the information about unspecified optional parameters gets
2392 // propagated to the database.
TEST_F(MySqlConfigBackendDHCPv6Test,getSharedNetwork6WithOptionalUnspecified)2393 TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecified) {
2394 // Insert new shared network.
2395 SharedNetwork6Ptr shared_network = test_networks_[2];
2396 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), shared_network);
2397
2398 // Fetch this shared network by name.
2399 SharedNetwork6Ptr
2400 returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(),
2401 test_networks_[2]->getName());
2402 ASSERT_TRUE(returned_network);
2403
2404 EXPECT_TRUE(returned_network->getIface().unspecified());
2405 EXPECT_TRUE(returned_network->getIface().empty());
2406
2407 EXPECT_TRUE(returned_network->getClientClass().unspecified());
2408 EXPECT_TRUE(returned_network->getClientClass().empty());
2409
2410 EXPECT_TRUE(returned_network->getValid().unspecified());
2411 EXPECT_EQ(0, returned_network->getValid().get());
2412
2413 EXPECT_TRUE(returned_network->getPreferred().unspecified());
2414 EXPECT_EQ(0, returned_network->getPreferred().get());
2415
2416 EXPECT_TRUE(returned_network->getT1().unspecified());
2417 EXPECT_EQ(0, returned_network->getT1().get());
2418
2419 EXPECT_TRUE(returned_network->getT2().unspecified());
2420 EXPECT_EQ(0, returned_network->getT2().get());
2421
2422 EXPECT_TRUE(returned_network->getReservationsGlobal().unspecified());
2423 EXPECT_FALSE(returned_network->getReservationsGlobal().get());
2424
2425 EXPECT_TRUE(returned_network->getReservationsInSubnet().unspecified());
2426 EXPECT_TRUE(returned_network->getReservationsInSubnet().get());
2427
2428 EXPECT_TRUE(returned_network->getReservationsOutOfPool().unspecified());
2429 EXPECT_FALSE(returned_network->getReservationsOutOfPool().get());
2430
2431 EXPECT_TRUE(returned_network->getCalculateTeeTimes().unspecified());
2432 EXPECT_FALSE(returned_network->getCalculateTeeTimes().get());
2433
2434 EXPECT_TRUE(returned_network->getT1Percent().unspecified());
2435 EXPECT_EQ(0.0, returned_network->getT1Percent().get());
2436
2437 EXPECT_TRUE(returned_network->getT2Percent().unspecified());
2438 EXPECT_EQ(0.0, returned_network->getT2Percent().get());
2439
2440 EXPECT_TRUE(returned_network->getRapidCommit().unspecified());
2441 EXPECT_FALSE(returned_network->getRapidCommit().get());
2442
2443 EXPECT_FALSE(returned_network->getDdnsSendUpdates().unspecified());
2444 EXPECT_TRUE(returned_network->getDdnsSendUpdates().get());
2445
2446 EXPECT_FALSE(returned_network->getDdnsOverrideNoUpdate().unspecified());
2447 EXPECT_TRUE(returned_network->getDdnsOverrideNoUpdate().get());
2448
2449 EXPECT_FALSE(returned_network->getDdnsOverrideClientUpdate().unspecified());
2450 EXPECT_FALSE(returned_network->getDdnsOverrideClientUpdate().get());
2451
2452 EXPECT_FALSE(returned_network->getDdnsReplaceClientNameMode().unspecified());
2453 EXPECT_EQ(D2ClientConfig::ReplaceClientNameMode::RCM_WHEN_PRESENT,
2454 returned_network->getDdnsReplaceClientNameMode().get());
2455
2456 EXPECT_FALSE(returned_network->getDdnsGeneratedPrefix().unspecified());
2457 EXPECT_EQ("myhost", returned_network->getDdnsGeneratedPrefix().get());
2458
2459 EXPECT_FALSE(returned_network->getDdnsQualifyingSuffix().unspecified());
2460 EXPECT_EQ("example.org", returned_network->getDdnsQualifyingSuffix().get());
2461 }
2462
2463 // Test that deleteSharedNetworkSubnets6 with not ANY selector throw.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSharedNetworkSubnets6)2464 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetworkSubnets6) {
2465 EXPECT_THROW(cbptr_->deleteSharedNetworkSubnets6(ServerSelector::UNASSIGNED(),
2466 test_networks_[1]->getName()),
2467 isc::InvalidOperation);
2468 EXPECT_THROW(cbptr_->deleteSharedNetworkSubnets6(ServerSelector::ALL(),
2469 test_networks_[1]->getName()),
2470 isc::InvalidOperation);
2471 EXPECT_THROW(cbptr_->deleteSharedNetworkSubnets6(ServerSelector::ONE("server1"),
2472 test_networks_[1]->getName()),
2473 isc::InvalidOperation);
2474 EXPECT_THROW(cbptr_->deleteSharedNetworkSubnets6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2475 test_networks_[1]->getName()),
2476 isc::InvalidOperation);
2477 }
2478
2479 // Test that all shared networks can be fetched.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSharedNetworks6)2480 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6) {
2481 // Insert test shared networks into the database. Note that the second shared
2482 // network will overwrite the first shared network as they use the same name.
2483 for (auto network : test_networks_) {
2484 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), network);
2485
2486 // That shared network overrides the first one so the audit entry should
2487 // indicate an update.
2488 if ((network->getName() == "level1") && (!audit_entries_["all"].empty())) {
2489 SCOPED_TRACE("UPDATE audit entry for the shared network " +
2490 network->getName());
2491 testNewAuditEntry("dhcp6_shared_network",
2492 AuditEntry::ModificationType::UPDATE,
2493 "shared network set");
2494
2495 } else {
2496 SCOPED_TRACE("CREATE audit entry for the shared network " +
2497 network->getName());
2498 testNewAuditEntry("dhcp6_shared_network",
2499 AuditEntry::ModificationType::CREATE,
2500 "shared network set");
2501 }
2502 }
2503
2504 // Fetch all shared networks.
2505 SharedNetwork6Collection networks =
2506 cbptr_->getAllSharedNetworks6(ServerSelector::ALL());
2507 ASSERT_EQ(test_networks_.size() - 1, networks.size());
2508
2509 // All shared networks should also be returned for explicitly specified
2510 // server tag.
2511 networks = cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1"));
2512 ASSERT_EQ(test_networks_.size() - 1, networks.size());
2513
2514 // See if shared networks are returned ok.
2515 for (auto i = 0; i < networks.size(); ++i) {
2516 EXPECT_EQ(test_networks_[i + 1]->toElement()->str(),
2517 networks[i]->toElement()->str());
2518 ASSERT_EQ(1, networks[i]->getServerTags().size());
2519 EXPECT_EQ("all", networks[i]->getServerTags().begin()->get());
2520 }
2521
2522 // Add some subnets.
2523 test_networks_[1]->add(test_subnets_[0]);
2524 test_subnets_[2]->setSharedNetworkName("level2");
2525 test_networks_[2]->add(test_subnets_[3]);
2526 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[0]);
2527 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[2]);
2528 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[3]);
2529
2530 // Both ways to attach a subnet are equivalent.
2531 Subnet6Ptr subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
2532 test_subnets_[0]->getID());
2533 ASSERT_TRUE(subnet);
2534 EXPECT_EQ("level1", subnet->getSharedNetworkName());
2535
2536 {
2537 SCOPED_TRACE("CREATE audit entry for subnets");
2538 testNewAuditEntry("dhcp6_subnet",
2539 AuditEntry::ModificationType::CREATE,
2540 "subnet set", ServerSelector::ALL(), 3);
2541 }
2542
2543 // Deleting non-existing shared network should return 0.
2544 EXPECT_EQ(0, cbptr_->deleteSharedNetwork6(ServerSelector::ALL(),
2545 "big-fish"));
2546 // All shared networks should be still there.
2547 ASSERT_EQ(test_networks_.size() - 1, networks.size());
2548
2549 // Should not delete the shared network for explicit server tag
2550 // because our shared network is for all servers.
2551 EXPECT_EQ(0, cbptr_->deleteSharedNetwork6(ServerSelector::ONE("server1"),
2552 test_networks_[1]->getName()));
2553
2554 // Same for all shared networks.
2555 EXPECT_EQ(0, cbptr_->deleteAllSharedNetworks6(ServerSelector::ONE("server1")));
2556
2557 // Delete first shared network with it subnets and verify it is gone.
2558 // Begin by its subnet.
2559 EXPECT_EQ(1, cbptr_->deleteSharedNetworkSubnets6(ServerSelector::ANY(),
2560 test_networks_[1]->getName()));
2561
2562 {
2563 SCOPED_TRACE("DELETE audit entry for subnets of the first shared network");
2564 testNewAuditEntry("dhcp6_subnet",
2565 AuditEntry::ModificationType::DELETE,
2566 "deleted all subnets for a shared network");
2567 }
2568
2569 // Check that the subnet is gone..
2570 subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
2571 test_subnets_[0]->getID());
2572 EXPECT_FALSE(subnet);
2573
2574 // And after the shared network itself.
2575 EXPECT_EQ(1, cbptr_->deleteSharedNetwork6(ServerSelector::ALL(),
2576 test_networks_[1]->getName()));
2577 networks = cbptr_->getAllSharedNetworks6(ServerSelector::ALL());
2578 ASSERT_EQ(test_networks_.size() - 2, networks.size());
2579
2580 {
2581 SCOPED_TRACE("DELETE audit entry for the first shared network");
2582 testNewAuditEntry("dhcp6_shared_network",
2583 AuditEntry::ModificationType::DELETE,
2584 "shared network deleted");
2585 }
2586
2587 // Delete all.
2588 EXPECT_EQ(2, cbptr_->deleteAllSharedNetworks6(ServerSelector::ALL()));
2589 networks = cbptr_->getAllSharedNetworks6(ServerSelector::ALL());
2590 ASSERT_TRUE(networks.empty());
2591
2592 {
2593 SCOPED_TRACE("DELETE audit entry for the remaining two shared networks");
2594 // The last parameter indicates that we expect two new audit entries.
2595 testNewAuditEntry("dhcp6_shared_network",
2596 AuditEntry::ModificationType::DELETE,
2597 "deleted all shared networks",
2598 ServerSelector::ALL(), 2);
2599 }
2600
2601 // Check that subnets are still there but detached.
2602 subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
2603 test_subnets_[2]->getID());
2604 ASSERT_TRUE(subnet);
2605 EXPECT_TRUE(subnet->getSharedNetworkName().empty());
2606 subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
2607 test_subnets_[3]->getID());
2608 ASSERT_TRUE(subnet);
2609 EXPECT_TRUE(subnet->getSharedNetworkName().empty());
2610 }
2611
2612 // Test that getAllSharedNetworks6 throws appropriate exceptions for various
2613 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSharedNetworks6Selectors)2614 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6Selectors) {
2615 // Supported selectors.
2616 EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::UNASSIGNED()));
2617 EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ALL()));
2618 EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1")));
2619 EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" })));
2620
2621 // Not supported selectors.
2622 EXPECT_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ANY()),
2623 isc::InvalidOperation);
2624 }
2625
2626 // Test that shared networks with different server associations are returned.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllSharedNetworks6WithServerTags)2627 TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6WithServerTags) {
2628 auto shared_network1 = test_networks_[0];
2629 auto shared_network2 = test_networks_[2];
2630 auto shared_network3 = test_networks_[3];
2631
2632 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
2633 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
2634
2635 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2636 shared_network1));
2637 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"),
2638 shared_network2));
2639 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2640 shared_network3));
2641
2642 SharedNetwork6Collection networks;
2643
2644 // All three networks are associated with the server1.
2645 EXPECT_NO_THROW(networks = cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1")));
2646 EXPECT_EQ(3, networks.size());
2647
2648 // First network is associated with all servers.
2649 auto returned_network = SharedNetworkFetcher6::get(networks, "level1");
2650 ASSERT_TRUE(returned_network);
2651 EXPECT_TRUE(returned_network->hasAllServerTag());
2652 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server1")));
2653 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server2")));
2654
2655 // Second network is only associated with the server1.
2656 returned_network = SharedNetworkFetcher6::get(networks, "level2");
2657 ASSERT_TRUE(returned_network);
2658 EXPECT_FALSE(returned_network->hasAllServerTag());
2659 EXPECT_TRUE(returned_network->hasServerTag(ServerTag("server1")));
2660 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server2")));
2661
2662 // Third network is associated with both server1 and server2.
2663 returned_network = SharedNetworkFetcher6::get(networks, "level3");
2664 ASSERT_TRUE(returned_network);
2665 EXPECT_FALSE(returned_network->hasAllServerTag());
2666 EXPECT_TRUE(returned_network->hasServerTag(ServerTag("server1")));
2667 EXPECT_TRUE(returned_network->hasServerTag(ServerTag("server2")));
2668
2669 // For server2 we should only get two shared networks, i.e. first and last.
2670 EXPECT_NO_THROW(networks = cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server2")));
2671 EXPECT_EQ(2, networks.size());
2672
2673 // First shared network is associated with all servers.
2674 returned_network = SharedNetworkFetcher6::get(networks, "level1");
2675 ASSERT_TRUE(returned_network);
2676 EXPECT_TRUE(returned_network->hasAllServerTag());
2677 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server1")));
2678 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server2")));
2679
2680 // Last shared network is associated with server1 and server2.
2681 returned_network = SharedNetworkFetcher6::get(networks, "level3");
2682 ASSERT_TRUE(returned_network);
2683 EXPECT_FALSE(returned_network->hasAllServerTag());
2684 EXPECT_TRUE(returned_network->hasServerTag(ServerTag("server1")));
2685 EXPECT_TRUE(returned_network->hasServerTag(ServerTag("server2")));
2686
2687 // Only the first shared network is associated with all servers.
2688 EXPECT_NO_THROW(networks = cbptr_->getAllSharedNetworks6(ServerSelector::ALL()));
2689 EXPECT_EQ(1, networks.size());
2690
2691 returned_network = SharedNetworkFetcher6::get(networks, "level1");
2692 ASSERT_TRUE(returned_network);
2693 EXPECT_TRUE(returned_network->hasAllServerTag());
2694 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server1")));
2695 EXPECT_FALSE(returned_network->hasServerTag(ServerTag("server2")));
2696 }
2697
2698 // Test that shared networks modified after given time can be fetched.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedSharedNetworks6)2699 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6) {
2700 // Explicitly set timestamps of shared networks. First shared
2701 // network has a timestamp pointing to the future. Second shared
2702 // network has timestamp pointing to the past (yesterday).
2703 // Third shared network has a timestamp pointing to the
2704 // past (an hour ago).
2705 test_networks_[1]->setModificationTime(timestamps_["tomorrow"]);
2706 test_networks_[2]->setModificationTime(timestamps_["yesterday"]);
2707 test_networks_[3]->setModificationTime(timestamps_["today"]);
2708
2709 // Insert shared networks into the database.
2710 for (int i = 1; i < test_networks_.size(); ++i) {
2711 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
2712 test_networks_[i]);
2713 }
2714
2715 // Fetch shared networks with timestamp later than today. Only one
2716 // shared network should be returned.
2717 SharedNetwork6Collection
2718 networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::ALL(),
2719 timestamps_["after today"]);
2720 ASSERT_EQ(1, networks.size());
2721
2722 // Fetch shared networks with timestamp later than yesterday. We
2723 // should get two shared networks.
2724 networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::ALL(),
2725 timestamps_["after yesterday"]);
2726 ASSERT_EQ(2, networks.size());
2727
2728 // Fetch shared networks with timestamp later than tomorrow. Nothing
2729 // should be returned.
2730 networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::ALL(),
2731 timestamps_["after tomorrow"]);
2732 ASSERT_TRUE(networks.empty());
2733 }
2734
2735 // Test that getModifiedSharedNetworks6 throws appropriate exceptions for various
2736 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedSharedNetworks6Selectors)2737 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6Selectors) {
2738 // Supported selectors.
2739 EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::UNASSIGNED(),
2740 timestamps_["yesterday"]));
2741 EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ALL(),
2742 timestamps_["yesterday"]));
2743 EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ONE("server1"),
2744 timestamps_["yesterday"]));
2745 EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2746 timestamps_["yesterday"]));
2747
2748 // Not supported selectors.
2749 EXPECT_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ANY(),
2750 timestamps_["yesterday"]),
2751 isc::InvalidOperation);
2752 }
2753
2754 // Test that selected shared network can be deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSharedNetwork6)2755 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6) {
2756 // Create two servers in the database.
2757 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
2758 {
2759 SCOPED_TRACE("CREATE audit entry for server");
2760 testNewAuditEntry("dhcp6_server",
2761 AuditEntry::ModificationType::CREATE,
2762 "server set");
2763 }
2764
2765 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
2766 {
2767 SCOPED_TRACE("CREATE audit entry for server");
2768 testNewAuditEntry("dhcp6_server",
2769 AuditEntry::ModificationType::CREATE,
2770 "server set");
2771 }
2772
2773 auto shared_network1 = test_networks_[0];
2774 auto shared_network2 = test_networks_[2];
2775 auto shared_network3 = test_networks_[3];
2776
2777 // Insert two shared networks, one for all servers, and one for server2.
2778 EXPECT_NO_THROW(
2779 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), shared_network1)
2780 );
2781 EXPECT_NO_THROW(
2782 cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server2"), shared_network2)
2783 );
2784 EXPECT_NO_THROW(
2785 cbptr_->createUpdateSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2786 shared_network3)
2787 );
2788
2789 auto test_no_delete = [this] (const std::string& test_case_name,
2790 const ServerSelector& server_selector,
2791 const SharedNetwork6Ptr& shared_network) {
2792 SCOPED_TRACE(test_case_name);
2793 uint64_t deleted_count = 0;
2794 EXPECT_NO_THROW(
2795 deleted_count = cbptr_->deleteSharedNetwork6(server_selector,
2796 shared_network->getName())
2797 );
2798 EXPECT_EQ(0, deleted_count);
2799 };
2800
2801 {
2802 SCOPED_TRACE("Test valid but non matching server selectors");
2803 test_no_delete("selector: one, actual: all", ServerSelector::ONE("server2"),
2804 shared_network1);
2805 test_no_delete("selector: all, actual: one", ServerSelector::ALL(),
2806 shared_network2);
2807 test_no_delete("selector: all, actual: multiple", ServerSelector::ALL(),
2808 shared_network3);
2809 }
2810
2811 // We are not going to support deletion of a single entry for multiple servers.
2812 EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2813 shared_network3->getName()),
2814 isc::InvalidOperation);
2815
2816 // We currently don't support deleting a shared network with specifying
2817 // an unassigned server tag. Use ANY to delete any subnet instead.
2818 EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::UNASSIGNED(),
2819 shared_network1->getName()),
2820 isc::NotImplemented);
2821
2822 // Test successful deletion of a shared network.
2823 auto test_delete = [this] (const std::string& test_case_name,
2824 const ServerSelector& server_selector,
2825 const SharedNetwork6Ptr& shared_network) {
2826 SCOPED_TRACE(test_case_name);
2827 uint64_t deleted_count = 0;
2828 EXPECT_NO_THROW(
2829 deleted_count = cbptr_->deleteSharedNetwork6(server_selector,
2830 shared_network->getName())
2831 );
2832 EXPECT_EQ(1, deleted_count);
2833
2834 EXPECT_FALSE(cbptr_->getSharedNetwork6(server_selector,
2835 shared_network->getName()));
2836 };
2837
2838 test_delete("all servers", ServerSelector::ALL(), shared_network1);
2839 test_delete("any server", ServerSelector::ANY(), shared_network2);
2840 test_delete("one server", ServerSelector::ONE("server1"), shared_network3);
2841 }
2842
2843 // Test that deleteSharedNetwork6 throws appropriate exceptions for various
2844 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteSharedNetwork6Selectors)2845 TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6Selectors) {
2846 // Supported selectors.
2847 EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ANY(), "level1"));
2848 EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ALL(), "level1"));
2849 EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ONE("server1"), "level1"));
2850
2851 // Not supported selectors.
2852 EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
2853 "level1"),
2854 isc::InvalidOperation);
2855
2856 // Not implemented selectors.
2857 EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::UNASSIGNED(), "level1"),
2858 isc::NotImplemented);
2859 }
2860
2861 // Test that deleteAllSharedNetworks6 throws appropriate exceptions for various
2862 // server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteAllSharedNetworks6Selectors)2863 TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllSharedNetworks6Selectors) {
2864 // Supported selectors.
2865 EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::UNASSIGNED()));
2866 EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ALL()));
2867 EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ONE("server1")));
2868
2869 // Not supported selectors.
2870 EXPECT_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ANY()),
2871 isc::InvalidOperation);
2872 EXPECT_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" })),
2873 isc::InvalidOperation);
2874 }
2875
2876 // Test that it is possible to retrieve and delete orphaned shared network.
TEST_F(MySqlConfigBackendDHCPv6Test,unassignedSharedNetwork)2877 TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSharedNetwork) {
2878 // Create the server.
2879 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
2880
2881 // Create the shared networks and associate them with the server1.
2882 auto shared_network = test_networks_[0];
2883 auto shared_network2 = test_networks_[2];
2884 EXPECT_NO_THROW(
2885 cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"), shared_network)
2886 );
2887 EXPECT_NO_THROW(
2888 cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"), shared_network2)
2889 );
2890
2891 // Delete the server. The shared networks should be preserved but are
2892 // considered orphaned, i.e. do not belong to any server.
2893 uint64_t deleted_count = 0;
2894 EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer6(ServerTag("server1")));
2895 EXPECT_EQ(1, deleted_count);
2896
2897 // Trying to fetch this shared network by server tag should return no result.
2898 SharedNetwork6Ptr returned_network;
2899 EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::ONE("server1"),
2900 "level1"));
2901 EXPECT_FALSE(returned_network);
2902
2903 // The same if we use other calls.
2904 SharedNetwork6Collection returned_networks;
2905 EXPECT_NO_THROW(
2906 returned_networks = cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1"))
2907 );
2908 EXPECT_TRUE(returned_networks.empty());
2909
2910 EXPECT_NO_THROW(
2911 returned_networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::ONE("server1"),
2912 timestamps_["two days ago"])
2913 );
2914 EXPECT_TRUE(returned_networks.empty());
2915
2916 // We should get the shared network if we ask for unassigned.
2917 EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::UNASSIGNED(),
2918 "level1"));
2919 ASSERT_TRUE(returned_network);
2920
2921 // Also if we ask for all unassigned networks it should be returned.
2922 EXPECT_NO_THROW(returned_networks = cbptr_->getAllSharedNetworks6(ServerSelector::UNASSIGNED()));
2923 ASSERT_EQ(2, returned_networks.size());
2924
2925 // And all modified.
2926 EXPECT_NO_THROW(
2927 returned_networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::UNASSIGNED(),
2928 timestamps_["two days ago"])
2929 );
2930 ASSERT_EQ(2, returned_networks.size());
2931
2932 // If we ask for any network by name, it should be returned too.
2933 EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::ANY(),
2934 "level1"));
2935 ASSERT_TRUE(returned_network);
2936
2937 // Deleting a shared network with the mismatched server tag should not affect
2938 // our shared network.
2939 EXPECT_NO_THROW(
2940 deleted_count = cbptr_->deleteSharedNetwork6(ServerSelector::ONE("server1"),
2941 "level1")
2942 );
2943 EXPECT_EQ(0, deleted_count);
2944
2945 // Also, if we delete all shared networks for server1.
2946 EXPECT_NO_THROW(
2947 deleted_count = cbptr_->deleteAllSharedNetworks6(ServerSelector::ONE("server1"))
2948 );
2949 EXPECT_EQ(0, deleted_count);
2950
2951 // We can delete this shared network when we specify ANY and the matching name.
2952 EXPECT_NO_THROW(
2953 deleted_count = cbptr_->deleteSharedNetwork6(ServerSelector::ANY(), "level1")
2954 );
2955 EXPECT_EQ(1, deleted_count);
2956
2957 // We can delete all second networks using UNASSIGNED selector.
2958 EXPECT_NO_THROW(
2959 deleted_count = cbptr_->deleteAllSharedNetworks6(ServerSelector::UNASSIGNED());
2960 );
2961 EXPECT_EQ(1, deleted_count);
2962 }
2963
2964 // Test that lifetimes in shared networks are handled as expected.
TEST_F(MySqlConfigBackendDHCPv6Test,sharedNetworkLifetime)2965 TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkLifetime) {
2966 // Insert new shared network with unspecified valid lifetime
2967 SharedNetwork6Ptr network(new SharedNetwork6("foo"));
2968 Triplet<uint32_t> unspecified;
2969 network->setPreferred(unspecified);
2970 network->setValid(unspecified);
2971 network->setIface("eth1");
2972 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), network);
2973
2974 // Fetch this shared network.
2975 SharedNetwork6Ptr returned_network =
2976 cbptr_->getSharedNetwork6(ServerSelector::ALL(), "foo");
2977 ASSERT_TRUE(returned_network);
2978
2979 // Verified returned and original shared networks match.
2980 EXPECT_EQ(network->toElement()->str(),
2981 returned_network->toElement()->str());
2982
2983 // Update the preferred and valid lifetime.
2984 network->setPreferred( Triplet<uint32_t>(100, 200, 300));
2985 network->setValid( Triplet<uint32_t>(200, 300, 400));
2986 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), network);
2987
2988 // Fetch and verify again.
2989 returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(), "foo");
2990 ASSERT_TRUE(returned_network);
2991 EXPECT_EQ(network->toElement()->str(),
2992 returned_network->toElement()->str());
2993 }
2994
2995 // Test that deleting a shared network triggers deletion of the options
2996 // associated with the shared network.
TEST_F(MySqlConfigBackendDHCPv6Test,sharedNetworkOptions)2997 TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkOptions) {
2998 // Add shared network with three options.
2999 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), test_networks_[0]));
3000 EXPECT_EQ(3, countRows("dhcp6_options"));
3001
3002 // Add another shared network with a single option. The numnber of options in the
3003 // database should now be 4.
3004 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), test_networks_[2]));
3005 EXPECT_EQ(4, countRows("dhcp6_options"));
3006
3007 // The second shared network uses the same name as the first shared network, so
3008 // this operation should replace the existing shared network and its options.
3009 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), test_networks_[1]));
3010 EXPECT_EQ(1, countRows("dhcp6_options"));
3011
3012 // Remove the shared network. This should not affect options assigned to the
3013 // other shared network.
3014 EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ALL(),
3015 test_networks_[1]->getName()));
3016 EXPECT_EQ(1, countRows("dhcp6_shared_network"));
3017 EXPECT_EQ(1, countRows("dhcp6_options"));
3018
3019 // Create the first option again. The number of options should be equal to the
3020 // sum of options associated with both shared networks.
3021 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), test_networks_[0]));
3022 EXPECT_EQ(4, countRows("dhcp6_options"));
3023
3024 // Delete this shared network. This should not affect the option associated
3025 // with the remaining shared network.
3026 EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ALL(),
3027 test_networks_[0]->getName()));
3028 EXPECT_EQ(1, countRows("dhcp6_shared_network"));
3029 EXPECT_EQ(1, countRows("dhcp6_options"));
3030 }
3031
3032 // Test that option definition can be inserted, fetched, updated and then
3033 // fetched again.
TEST_F(MySqlConfigBackendDHCPv6Test,getOptionDef6)3034 TEST_F(MySqlConfigBackendDHCPv6Test, getOptionDef6) {
3035 // Insert new option definition.
3036 OptionDefinitionPtr option_def = test_option_defs_[0];
3037 cbptr_->createUpdateOptionDef6(ServerSelector::ALL(), option_def);
3038
3039 // Fetch this option_definition by subnet identifier.
3040 OptionDefinitionPtr returned_option_def =
3041 cbptr_->getOptionDef6(ServerSelector::ALL(),
3042 test_option_defs_[0]->getCode(),
3043 test_option_defs_[0]->getOptionSpaceName());
3044 ASSERT_TRUE(returned_option_def);
3045 EXPECT_GT(returned_option_def->getId(), 0);
3046 ASSERT_EQ(1, returned_option_def->getServerTags().size());
3047 EXPECT_EQ("all", returned_option_def->getServerTags().begin()->get());
3048
3049 EXPECT_TRUE(returned_option_def->equals(*option_def));
3050
3051 {
3052 SCOPED_TRACE("CREATE audit entry for an option definition");
3053 testNewAuditEntry("dhcp6_option_def",
3054 AuditEntry::ModificationType::CREATE,
3055 "option definition set");
3056 }
3057
3058 // Update the option definition in the database.
3059 OptionDefinitionPtr option_def2 = test_option_defs_[1];
3060 cbptr_->createUpdateOptionDef6(ServerSelector::ALL(), option_def2);
3061
3062 // Fetch updated option definition and see if it matches.
3063 returned_option_def = cbptr_->getOptionDef6(ServerSelector::ALL(),
3064 test_option_defs_[1]->getCode(),
3065 test_option_defs_[1]->getOptionSpaceName());
3066 EXPECT_TRUE(returned_option_def->equals(*option_def2));
3067
3068 // Fetching option definition for an explicitly specified server tag
3069 // should succeed too.
3070 returned_option_def = cbptr_->getOptionDef6(ServerSelector::ONE("server1"),
3071 test_option_defs_[1]->getCode(),
3072 test_option_defs_[1]->getOptionSpaceName());
3073 EXPECT_TRUE(returned_option_def->equals(*option_def2));
3074
3075 {
3076 SCOPED_TRACE("UPDATE audit entry for an option definition");
3077 testNewAuditEntry("dhcp6_option_def",
3078 AuditEntry::ModificationType::UPDATE,
3079 "option definition set");
3080 }
3081 }
3082
3083 // This test verifies that it is possible to differentiate between the
3084 // option definitions by server tag and that the option definition
3085 // specified for the particular server overrides the definition for
3086 // all servers.
TEST_F(MySqlConfigBackendDHCPv6Test,optionDefs6WithServerTags)3087 TEST_F(MySqlConfigBackendDHCPv6Test, optionDefs6WithServerTags) {
3088 OptionDefinitionPtr option1 = test_option_defs_[0];
3089 OptionDefinitionPtr option2 = test_option_defs_[1];
3090 OptionDefinitionPtr option3 = test_option_defs_[4];
3091
3092 // An attempt to create option definition for non-existing server should
3093 // fail.
3094 EXPECT_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ONE("server1"),
3095 option1),
3096 NullKeyError);
3097
3098 // Create two servers.
3099 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
3100 {
3101 SCOPED_TRACE("server1 is created");
3102 testNewAuditEntry("dhcp6_server",
3103 AuditEntry::ModificationType::CREATE,
3104 "server set");
3105 }
3106
3107 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
3108 {
3109 SCOPED_TRACE("server2 is created");
3110 testNewAuditEntry("dhcp6_server",
3111 AuditEntry::ModificationType::CREATE,
3112 "server set");
3113 }
3114
3115 // This time creation of the option definition for the server1 should pass.
3116 EXPECT_NO_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ONE("server1"),
3117 option1));
3118 {
3119 SCOPED_TRACE("option definition for server1 is set");
3120 // The value of 3 means there should be 3 audit entries available for the
3121 // server1, two that indicate creation of the servers and one that we
3122 // validate, which sets the option definition.
3123 testNewAuditEntry("dhcp6_option_def",
3124 AuditEntry::ModificationType::CREATE,
3125 "option definition set",
3126 ServerSelector::ONE("server1"),
3127 3, 1);
3128 }
3129
3130 // Creation of the option definition for the server2 should also pass.
3131 EXPECT_NO_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ONE("server2"),
3132 option2));
3133 {
3134 SCOPED_TRACE("option definition for server2 is set");
3135 // Same as in case of the server1, there should be 3 audit entries and
3136 // we validate one of them.
3137 testNewAuditEntry("dhcp6_option_def",
3138 AuditEntry::ModificationType::CREATE,
3139 "option definition set",
3140 ServerSelector::ONE("server2"),
3141 3, 1);
3142 }
3143
3144 // Finally, creation of the option definition for all servers should
3145 // also pass.
3146 EXPECT_NO_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ALL(),
3147 option3));
3148 {
3149 SCOPED_TRACE("option definition for server2 is set");
3150 // There should be one new audit entry for all servers. It logs
3151 // the insertion of the option definition.
3152 testNewAuditEntry("dhcp6_option_def",
3153 AuditEntry::ModificationType::CREATE,
3154 "option definition set",
3155 ServerSelector::ALL(),
3156 1, 1);
3157 }
3158
3159 OptionDefinitionPtr returned_option_def;
3160
3161 // Try to fetch the option definition specified for all servers. It should
3162 // return the third one.
3163 EXPECT_NO_THROW(
3164 returned_option_def = cbptr_->getOptionDef6(ServerSelector::ALL(),
3165 option3->getCode(),
3166 option3->getOptionSpaceName())
3167 );
3168 ASSERT_TRUE(returned_option_def);
3169 EXPECT_TRUE(returned_option_def->equals(*option3));
3170
3171 // Try to fetch the option definition specified for server1. It should
3172 // override the definition for all servers.
3173 EXPECT_NO_THROW(
3174 returned_option_def = cbptr_->getOptionDef6(ServerSelector::ONE("server1"),
3175 option1->getCode(),
3176 option1->getOptionSpaceName())
3177 );
3178 ASSERT_TRUE(returned_option_def);
3179 EXPECT_TRUE(returned_option_def->equals(*option1));
3180
3181 // The same in case of the server2.
3182 EXPECT_NO_THROW(
3183 returned_option_def = cbptr_->getOptionDef6(ServerSelector::ONE("server2"),
3184 option2->getCode(),
3185 option2->getOptionSpaceName())
3186 );
3187 ASSERT_TRUE(returned_option_def);
3188 EXPECT_TRUE(returned_option_def->equals(*option2));
3189
3190 OptionDefContainer returned_option_defs;
3191
3192 // Try to fetch the collection of the option definitions for server1, server2
3193 // and server3. The server3 does not have an explicit option definition, so
3194 // for this server we should get the definition associated with "all" servers.
3195 EXPECT_NO_THROW(
3196 returned_option_defs = cbptr_->getAllOptionDefs6(ServerSelector::
3197 MULTIPLE({ "server1", "server2",
3198 "server3" }));
3199 );
3200 ASSERT_EQ(3, returned_option_defs.size());
3201
3202 // Check that expected option definitions have been returned.
3203 auto current_option = returned_option_defs.begin();
3204 EXPECT_TRUE((*current_option)->equals(*option1));
3205 EXPECT_TRUE((*(++current_option))->equals(*option2));
3206 EXPECT_TRUE((*(++current_option))->equals(*option3));
3207
3208 // Try to fetch the collection of options specified for all servers.
3209 // This excludes the options specific to server1 and server2. It returns
3210 // only the common ones.
3211 EXPECT_NO_THROW(
3212 returned_option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ALL());
3213
3214 );
3215 ASSERT_EQ(1, returned_option_defs.size());
3216 EXPECT_TRUE((*returned_option_defs.begin())->equals(*option3));
3217
3218 // Delete the server1. It should remove associations of this server with the
3219 // option definitions and the option definition itself.
3220 EXPECT_NO_THROW(cbptr_->deleteServer6(ServerTag("server1")));
3221 EXPECT_NO_THROW(
3222 returned_option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ONE("server1"));
3223
3224 );
3225 ASSERT_EQ(1, returned_option_defs.size());
3226 EXPECT_TRUE((*returned_option_defs.begin())->equals(*option3));
3227
3228 {
3229 SCOPED_TRACE("DELETE audit entry for the option definition after server deletion");
3230 testNewAuditEntry("dhcp6_option_def",
3231 AuditEntry::ModificationType::DELETE,
3232 "deleting a server", ServerSelector::ONE("server1"),
3233 2, 1);
3234 }
3235
3236 // Attempt to delete option definition for server1.
3237 uint64_t deleted_num = 0;
3238 EXPECT_NO_THROW(deleted_num = cbptr_->deleteOptionDef6(ServerSelector::ONE("server1"),
3239 option1->getCode(),
3240 option1->getOptionSpaceName()));
3241 EXPECT_EQ(0, deleted_num);
3242
3243 // Deleting the existing option definition for server2 should succeed.
3244 EXPECT_NO_THROW(deleted_num = cbptr_->deleteOptionDef6(ServerSelector::ONE("server2"),
3245 option2->getCode(),
3246 option2->getOptionSpaceName()));
3247 EXPECT_EQ(1, deleted_num);
3248
3249 // Create this option definition again to test that deletion of all servers
3250 // removes it too.
3251 EXPECT_NO_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ONE("server2"),
3252 option2));
3253
3254 // Delete all servers, except 'all'.
3255 EXPECT_NO_THROW(deleted_num = cbptr_->deleteAllServers6());
3256 EXPECT_NO_THROW(
3257 returned_option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ALL());
3258 );
3259 EXPECT_EQ(1, deleted_num);
3260 EXPECT_EQ(1, returned_option_defs.size());
3261 EXPECT_TRUE((*returned_option_defs.begin())->equals(*option3));
3262
3263 {
3264 SCOPED_TRACE("DELETE audit entry for the option definition after deletion of"
3265 " all servers");
3266 testNewAuditEntry("dhcp6_option_def",
3267 AuditEntry::ModificationType::DELETE,
3268 "deleting all servers", ServerSelector::ONE("server2"),
3269 4, 1);
3270 }
3271 }
3272
3273 // Test that all option definitions can be fetched.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllOptionDefs6)3274 TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptionDefs6) {
3275 // Insert test option definitions into the database. Note that the second
3276 // option definition will overwrite the first option definition as they use
3277 // the same code and space.
3278 size_t updates_num = 0;
3279 for (auto option_def : test_option_defs_) {
3280 cbptr_->createUpdateOptionDef6(ServerSelector::ALL(), option_def);
3281
3282 // That option definition overrides the first one so the audit entry should
3283 // indicate an update.
3284 if (option_def->getName() == "bar") {
3285 SCOPED_TRACE("UPDATE audit entry for the option definition " +
3286 option_def->getName());
3287 testNewAuditEntry("dhcp6_option_def",
3288 AuditEntry::ModificationType::UPDATE,
3289 "option definition set");
3290 ++updates_num;
3291
3292 } else {
3293 SCOPED_TRACE("CREATE audit entry for the option definition " +
3294 option_def->getName());
3295 testNewAuditEntry("dhcp6_option_def",
3296 AuditEntry::ModificationType::CREATE,
3297 "option definition set");
3298 }
3299 }
3300
3301 // Fetch all option_definitions.
3302 OptionDefContainer option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ALL());
3303 ASSERT_EQ(test_option_defs_.size() - updates_num, option_defs.size());
3304
3305 // All option definitions should also be returned for explicitly specified
3306 // server tag.
3307 option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ONE("server1"));
3308 ASSERT_EQ(test_option_defs_.size() - updates_num, option_defs.size());
3309
3310 // See if option definitions are returned ok.
3311 for (auto def = option_defs.begin(); def != option_defs.end(); ++def) {
3312 ASSERT_EQ(1, (*def)->getServerTags().size());
3313 EXPECT_EQ("all", (*def)->getServerTags().begin()->get());
3314 bool success = false;
3315 for (auto i = 1; i < test_option_defs_.size(); ++i) {
3316 if ((*def)->equals(*test_option_defs_[i])) {
3317 success = true;
3318 }
3319 }
3320 ASSERT_TRUE(success) << "failed for option definition " << (*def)->getCode()
3321 << ", option space " << (*def)->getOptionSpaceName();
3322 }
3323
3324 // Deleting non-existing option definition should return 0.
3325 EXPECT_EQ(0, cbptr_->deleteOptionDef6(ServerSelector::ALL(),
3326 99, "non-exiting-space"));
3327 // All option definitions should be still there.
3328 ASSERT_EQ(test_option_defs_.size() - updates_num, option_defs.size());
3329
3330 // Should not delete option definition for explicit server tag
3331 // because our option definition is for all servers.
3332 EXPECT_EQ(0, cbptr_->deleteOptionDef6(ServerSelector::ONE("server1"),
3333 test_option_defs_[1]->getCode(),
3334 test_option_defs_[1]->getOptionSpaceName()));
3335
3336 // Same for all option definitions.
3337 EXPECT_EQ(0, cbptr_->deleteAllOptionDefs6(ServerSelector::ONE("server1")));
3338
3339 // Delete one of the option definitions and see if it is gone.
3340 EXPECT_EQ(1, cbptr_->deleteOptionDef6(ServerSelector::ALL(),
3341 test_option_defs_[2]->getCode(),
3342 test_option_defs_[2]->getOptionSpaceName()));
3343 ASSERT_FALSE(cbptr_->getOptionDef6(ServerSelector::ALL(),
3344 test_option_defs_[2]->getCode(),
3345 test_option_defs_[2]->getOptionSpaceName()));
3346
3347 {
3348 SCOPED_TRACE("DELETE audit entry for the first option definition");
3349 testNewAuditEntry("dhcp6_option_def",
3350 AuditEntry::ModificationType::DELETE,
3351 "option definition deleted");
3352 }
3353
3354 // Delete all remaining option definitions.
3355 EXPECT_EQ(2, cbptr_->deleteAllOptionDefs6(ServerSelector::ALL()));
3356 option_defs = cbptr_->getAllOptionDefs6(ServerSelector::ALL());
3357 ASSERT_TRUE(option_defs.empty());
3358
3359 {
3360 SCOPED_TRACE("DELETE audit entries for the remaining option definitions");
3361 // The last parameter indicates that we expect two new audit entries.
3362 testNewAuditEntry("dhcp6_option_def",
3363 AuditEntry::ModificationType::DELETE,
3364 "deleted all option definitions",
3365 ServerSelector::ALL(), 2);
3366 }
3367 }
3368
3369 // Test that option definitions modified after given time can be fetched.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedOptionDefs6)3370 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedOptionDefs6) {
3371 // Explicitly set timestamps of option definitions. First option
3372 // definition has a timestamp pointing to the future. Second option
3373 // definition has timestamp pointing to the past (yesterday).
3374 // Third option definitions has a timestamp pointing to the
3375 // past (an hour ago).
3376 test_option_defs_[1]->setModificationTime(timestamps_["tomorrow"]);
3377 test_option_defs_[2]->setModificationTime(timestamps_["yesterday"]);
3378 test_option_defs_[3]->setModificationTime(timestamps_["today"]);
3379
3380 // Insert option definitions into the database.
3381 for (int i = 1; i < test_networks_.size(); ++i) {
3382 cbptr_->createUpdateOptionDef6(ServerSelector::ALL(),
3383 test_option_defs_[i]);
3384 }
3385
3386 // Fetch option definitions with timestamp later than today. Only one
3387 // option definition should be returned.
3388 OptionDefContainer
3389 option_defs = cbptr_->getModifiedOptionDefs6(ServerSelector::ALL(),
3390 timestamps_["after today"]);
3391 ASSERT_EQ(1, option_defs.size());
3392
3393 // Fetch option definitions with timestamp later than yesterday. We
3394 // should get two option definitions.
3395 option_defs = cbptr_->getModifiedOptionDefs6(ServerSelector::ALL(),
3396 timestamps_["after yesterday"]);
3397 ASSERT_EQ(2, option_defs.size());
3398
3399 // Fetch option definitions with timestamp later than tomorrow. Nothing
3400 // should be returned.
3401 option_defs = cbptr_->getModifiedOptionDefs6(ServerSelector::ALL(),
3402 timestamps_["after tomorrow"]);
3403 ASSERT_TRUE(option_defs.empty());
3404 }
3405
3406 // This test verifies that global option can be added, updated and deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeleteOption6)3407 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteOption6) {
3408 // Add option to the database.
3409 OptionDescriptorPtr opt_posix_timezone = test_options_[0];
3410 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3411 opt_posix_timezone);
3412
3413 // Make sure we can retrieve this option and that it is equal to the
3414 // option we have inserted into the database.
3415 OptionDescriptorPtr returned_opt_posix_timezone =
3416 cbptr_->getOption6(ServerSelector::ALL(),
3417 opt_posix_timezone->option_->getType(),
3418 opt_posix_timezone->space_name_);
3419 ASSERT_TRUE(returned_opt_posix_timezone);
3420
3421 {
3422 SCOPED_TRACE("verify created option");
3423 testOptionsEquivalent(*opt_posix_timezone,
3424 *returned_opt_posix_timezone);
3425 }
3426
3427 {
3428 SCOPED_TRACE("CREATE audit entry for an option");
3429 testNewAuditEntry("dhcp6_options",
3430 AuditEntry::ModificationType::CREATE,
3431 "global option set");
3432 }
3433
3434 // Modify option and update it in the database.
3435 opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
3436 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3437 opt_posix_timezone);
3438
3439 // Retrieve the option again and make sure that updates were
3440 // properly propagated to the database. Use explicit server selector
3441 // which should also return this option.
3442 returned_opt_posix_timezone = cbptr_->getOption6(ServerSelector::ONE("server1"),
3443 opt_posix_timezone->option_->getType(),
3444 opt_posix_timezone->space_name_);
3445 ASSERT_TRUE(returned_opt_posix_timezone);
3446
3447 {
3448 SCOPED_TRACE("verify updated option");
3449 testOptionsEquivalent(*opt_posix_timezone,
3450 *returned_opt_posix_timezone);
3451 }
3452
3453 {
3454 SCOPED_TRACE("UPDATE audit entry for an option");
3455 testNewAuditEntry("dhcp6_options",
3456 AuditEntry::ModificationType::UPDATE,
3457 "global option set");
3458 }
3459
3460 // Deleting an option with explicitly specified server tag should fail.
3461 EXPECT_EQ(0, cbptr_->deleteOption6(ServerSelector::ONE("server1"),
3462 opt_posix_timezone->option_->getType(),
3463 opt_posix_timezone->space_name_));
3464
3465 // Deleting option for all servers should succeed.
3466 EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ALL(),
3467 opt_posix_timezone->option_->getType(),
3468 opt_posix_timezone->space_name_));
3469
3470 EXPECT_FALSE(cbptr_->getOption6(ServerSelector::ALL(),
3471 opt_posix_timezone->option_->getType(),
3472 opt_posix_timezone->space_name_));
3473
3474 {
3475 SCOPED_TRACE("DELETE audit entry for an option");
3476 testNewAuditEntry("dhcp6_options",
3477 AuditEntry::ModificationType::DELETE,
3478 "global option deleted");
3479 }
3480 }
3481
3482 // This test verifies that it is possible to differentiate between the
3483 // global options by server tag and that the option specified for the
3484 // particular server overrides the value specified for all servers.
TEST_F(MySqlConfigBackendDHCPv6Test,globalOptions6WithServerTags)3485 TEST_F(MySqlConfigBackendDHCPv6Test, globalOptions6WithServerTags) {
3486 OptionDescriptorPtr opt_timezone1 = test_options_[0];
3487 OptionDescriptorPtr opt_timezone2 = test_options_[6];
3488 OptionDescriptorPtr opt_timezone3 = test_options_[7];
3489
3490 EXPECT_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server1"),
3491 opt_timezone1),
3492 NullKeyError);
3493
3494 // Create two servers.
3495 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
3496 {
3497 SCOPED_TRACE("server1 is created");
3498 testNewAuditEntry("dhcp6_server",
3499 AuditEntry::ModificationType::CREATE,
3500 "server set");
3501 }
3502
3503 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
3504 {
3505 SCOPED_TRACE("server2 is created");
3506 testNewAuditEntry("dhcp6_server",
3507 AuditEntry::ModificationType::CREATE,
3508 "server set");
3509 }
3510
3511 EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server1"),
3512 opt_timezone1));
3513 {
3514 SCOPED_TRACE("global option for server1 is set");
3515 // The value of 3 means there should be 3 audit entries available for the
3516 // server1, two that indicate creation of the servers and one that we
3517 // validate, which sets the global option.
3518 testNewAuditEntry("dhcp6_options",
3519 AuditEntry::ModificationType::CREATE,
3520 "global option set",
3521 ServerSelector::ONE("server1"),
3522 3, 1);
3523
3524 }
3525
3526 EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server2"),
3527 opt_timezone2));
3528 {
3529 SCOPED_TRACE("global option for server2 is set");
3530 // Same as in case of the server1, there should be 3 audit entries and
3531 // we validate one of them.
3532 testNewAuditEntry("dhcp6_options",
3533 AuditEntry::ModificationType::CREATE,
3534 "global option set",
3535 ServerSelector::ONE("server2"),
3536 3, 1);
3537
3538 }
3539
3540 EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ALL(),
3541 opt_timezone3));
3542 {
3543 SCOPED_TRACE("global option for all servers is set");
3544 // There should be one new audit entry for all servers. It logs
3545 // the insertion of the global option.
3546 testNewAuditEntry("dhcp6_options",
3547 AuditEntry::ModificationType::CREATE,
3548 "global option set",
3549 ServerSelector::ALL(),
3550 1, 1);
3551
3552 }
3553
3554 OptionDescriptorPtr returned_option;
3555
3556 // Try to fetch the option specified for all servers. It should return
3557 // the third option.
3558 EXPECT_NO_THROW(
3559 returned_option = cbptr_->getOption6(ServerSelector::ALL(),
3560 opt_timezone3->option_->getType(),
3561 opt_timezone3->space_name_);
3562 );
3563 ASSERT_TRUE(returned_option);
3564 testOptionsEquivalent(*opt_timezone3, *returned_option);
3565
3566 // Try to fetch the option specified for the server1. It should override the
3567 // option specified for all servers.
3568 EXPECT_NO_THROW(
3569 returned_option = cbptr_->getOption6(ServerSelector::ONE("server1"),
3570 opt_timezone1->option_->getType(),
3571 opt_timezone1->space_name_);
3572 );
3573 ASSERT_TRUE(returned_option);
3574 testOptionsEquivalent(*opt_timezone1, *returned_option);
3575
3576 // The same in case of the server2.
3577 EXPECT_NO_THROW(
3578 returned_option = cbptr_->getOption6(ServerSelector::ONE("server2"),
3579 opt_timezone2->option_->getType(),
3580 opt_timezone2->space_name_);
3581 );
3582 ASSERT_TRUE(returned_option);
3583 testOptionsEquivalent(*opt_timezone2, *returned_option);
3584
3585 OptionContainer returned_options;
3586
3587 // Try to fetch the collection of global options for the server1, server2
3588 // and server3. The server3 does not have an explicit value so for this server
3589 // we should get the option associated with "all" servers.
3590 EXPECT_NO_THROW(
3591 returned_options = cbptr_->getAllOptions6(ServerSelector::
3592 MULTIPLE({ "server1", "server2",
3593 "server3" }));
3594 );
3595 ASSERT_EQ(3, returned_options.size());
3596
3597 // Check that expected options have been returned.
3598 auto current_option = returned_options.begin();
3599 testOptionsEquivalent(*opt_timezone1, *current_option);
3600 testOptionsEquivalent(*opt_timezone2, *(++current_option));
3601 testOptionsEquivalent(*opt_timezone3, *(++current_option));
3602
3603 // Try to fetch the collection of options specified for all servers.
3604 // This excludes the options specific to server1 and server2. It returns
3605 // only the common ones.
3606 EXPECT_NO_THROW(
3607 returned_options = cbptr_->getAllOptions6(ServerSelector::ALL());
3608 );
3609 ASSERT_EQ(1, returned_options.size());
3610 testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
3611
3612 // Delete the server1. It should remove associations of this server with the
3613 // option and the option itself.
3614 EXPECT_NO_THROW(cbptr_->deleteServer6(ServerTag("server1")));
3615 EXPECT_NO_THROW(
3616 returned_options = cbptr_->getAllOptions6(ServerSelector::ONE("server1"));
3617 );
3618 ASSERT_EQ(1, returned_options.size());
3619 testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
3620
3621 {
3622 SCOPED_TRACE("DELETE audit entry for the global option after server deletion");
3623 testNewAuditEntry("dhcp6_options",
3624 AuditEntry::ModificationType::DELETE,
3625 "deleting a server", ServerSelector::ONE("server1"),
3626 2, 1);
3627 }
3628
3629 // Attempt to delete global option for server1.
3630 uint64_t deleted_num = 0;
3631 EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption6(ServerSelector::ONE("server1"),
3632 opt_timezone1->option_->getType(),
3633 opt_timezone1->space_name_));
3634 EXPECT_EQ(0, deleted_num);
3635
3636 // Deleting the existing option for server2 should succeed.
3637 EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption6(ServerSelector::ONE("server2"),
3638 opt_timezone2->option_->getType(),
3639 opt_timezone2->space_name_));
3640 EXPECT_EQ(1, deleted_num);
3641
3642 // Create this option again to test that deletion of all servers removes it too.
3643 EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server2"),
3644 opt_timezone2));
3645
3646 // Delete all servers, except 'all'.
3647 EXPECT_NO_THROW(deleted_num = cbptr_->deleteAllServers6());
3648 EXPECT_NO_THROW(
3649 returned_options = cbptr_->getAllOptions6(ServerSelector::ALL());
3650 );
3651 EXPECT_EQ(1, deleted_num);
3652 ASSERT_EQ(1, returned_options.size());
3653 testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
3654
3655 {
3656 SCOPED_TRACE("DELETE audit entry for the global option after deletion of"
3657 " all servers");
3658 testNewAuditEntry("dhcp6_options",
3659 AuditEntry::ModificationType::DELETE,
3660 "deleting all servers", ServerSelector::ONE("server2"),
3661 4, 1);
3662 }
3663 }
3664
3665 // This test verifies that all global options can be retrieved.
TEST_F(MySqlConfigBackendDHCPv6Test,getAllOptions6)3666 TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptions6) {
3667 // Add three global options to the database.
3668 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3669 test_options_[0]);
3670 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3671 test_options_[1]);
3672 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3673 test_options_[5]);
3674
3675 // Retrieve all these options.
3676 OptionContainer returned_options = cbptr_->getAllOptions6(ServerSelector::ALL());
3677 ASSERT_EQ(3, returned_options.size());
3678
3679 // Fetching global options with explicitly specified server tag should return
3680 // the same result.
3681 returned_options = cbptr_->getAllOptions6(ServerSelector::ONE("server1"));
3682 ASSERT_EQ(3, returned_options.size());
3683
3684 // Get the container index used to search options by option code.
3685 const OptionContainerTypeIndex& index = returned_options.get<1>();
3686
3687 // Verify that all options we put into the database were
3688 // returned.
3689 {
3690 SCOPED_TRACE("verify test_options_[0]");
3691 auto option0 = index.find(test_options_[0]->option_->getType());
3692 ASSERT_FALSE(option0 == index.end());
3693 testOptionsEquivalent(*test_options_[0], *option0);
3694 EXPECT_GT(option0->getId(), 0);
3695 ASSERT_EQ(1, option0->getServerTags().size());
3696 EXPECT_EQ("all", option0->getServerTags().begin()->get());
3697 }
3698
3699 {
3700 SCOPED_TRACE("verify test_options_[1]");
3701 auto option1 = index.find(test_options_[1]->option_->getType());
3702 ASSERT_FALSE(option1 == index.end());
3703 testOptionsEquivalent(*test_options_[1], *option1);
3704 EXPECT_GT(option1->getId(), 0);
3705 ASSERT_EQ(1, option1->getServerTags().size());
3706 EXPECT_EQ("all", option1->getServerTags().begin()->get());
3707 }
3708
3709 {
3710 SCOPED_TRACE("verify test_options_[5]");
3711 auto option5 = index.find(test_options_[5]->option_->getType());
3712 ASSERT_FALSE(option5 == index.end());
3713 testOptionsEquivalent(*test_options_[5], *option5);
3714 EXPECT_GT(option5->getId(), 0);
3715 ASSERT_EQ(1, option5->getServerTags().size());
3716 EXPECT_EQ("all", option5->getServerTags().begin()->get());
3717 }
3718 }
3719
3720 // This test verifies that modified global options can be retrieved.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedOptions6)3721 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedOptions6) {
3722 // Assign timestamps to the options we're going to store in the
3723 // database.
3724 test_options_[0]->setModificationTime(timestamps_["tomorrow"]);
3725 test_options_[1]->setModificationTime(timestamps_["yesterday"]);
3726 test_options_[5]->setModificationTime(timestamps_["today"]);
3727
3728 // Put options into the database.
3729 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3730 test_options_[0]);
3731 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3732 test_options_[1]);
3733 cbptr_->createUpdateOption6(ServerSelector::ALL(),
3734 test_options_[5]);
3735
3736 // Get options with the timestamp later than today. Only
3737 // one option should be returned.
3738 OptionContainer returned_options =
3739 cbptr_->getModifiedOptions6(ServerSelector::ALL(),
3740 timestamps_["after today"]);
3741 ASSERT_EQ(1, returned_options.size());
3742
3743 // Fetching modified options with explicitly specified server selector
3744 // should return the same result.
3745 returned_options = cbptr_->getModifiedOptions6(ServerSelector::ONE("server1"),
3746 timestamps_["after today"]);
3747 ASSERT_EQ(1, returned_options.size());
3748
3749 // The returned option should be the one with the timestamp
3750 // set to tomorrow.
3751 const OptionContainerTypeIndex& index = returned_options.get<1>();
3752 auto option0 = index.find(test_options_[0]->option_->getType());
3753 ASSERT_FALSE(option0 == index.end());
3754 {
3755 SCOPED_TRACE("verify returned option");
3756 testOptionsEquivalent(*test_options_[0], *option0);
3757 }
3758 }
3759
3760 // This test verifies that subnet level option can be added, updated and
3761 // deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeleteSubnetOption6)3762 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteSubnetOption6) {
3763 // Insert new subnet.
3764 Subnet6Ptr subnet = test_subnets_[1];
3765 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
3766
3767 // Fetch this subnet by subnet identifier.
3768 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3769 subnet->getID());
3770 ASSERT_TRUE(returned_subnet);
3771
3772 {
3773 SCOPED_TRACE("CREATE audit entry for a new subnet");
3774 testNewAuditEntry("dhcp6_subnet",
3775 AuditEntry::ModificationType::CREATE,
3776 "subnet set");
3777 }
3778
3779 // The inserted subnet contains four options.
3780 ASSERT_EQ(4, countRows("dhcp6_options"));
3781
3782 OptionDescriptorPtr opt_posix_timezone = test_options_[0];
3783 cbptr_->createUpdateOption6(ServerSelector::ANY(), subnet->getID(),
3784 opt_posix_timezone);
3785
3786 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3787 subnet->getID());
3788 ASSERT_TRUE(returned_subnet);
3789
3790 OptionDescriptor returned_opt_posix_timezone =
3791 returned_subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
3792 ASSERT_TRUE(returned_opt_posix_timezone.option_);
3793
3794 {
3795 SCOPED_TRACE("verify returned option");
3796 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
3797 EXPECT_GT(returned_opt_posix_timezone.getId(), 0);
3798 }
3799
3800 {
3801 SCOPED_TRACE("UPDATE audit entry for an added subnet option");
3802 // Instead of adding an audit entry for an option we add an audit
3803 // entry for the entire subnet so as the server refreshes the
3804 // subnet with the new option. Note that the server doesn't
3805 // have means to retrieve only the newly added option.
3806 testNewAuditEntry("dhcp6_subnet",
3807 AuditEntry::ModificationType::UPDATE,
3808 "subnet specific option set");
3809 }
3810
3811 // We have added one option to the existing subnet. We should now have
3812 // five options.
3813 ASSERT_EQ(5, countRows("dhcp6_options"));
3814
3815 opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
3816 cbptr_->createUpdateOption6(ServerSelector::ANY(), subnet->getID(),
3817 opt_posix_timezone);
3818
3819 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3820 subnet->getID());
3821 ASSERT_TRUE(returned_subnet);
3822 returned_opt_posix_timezone =
3823 returned_subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
3824 ASSERT_TRUE(returned_opt_posix_timezone.option_);
3825
3826 {
3827 SCOPED_TRACE("verify returned option with modified persistence");
3828 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
3829 }
3830
3831 {
3832 SCOPED_TRACE("UPDATE audit entry for an updated subnet option");
3833 testNewAuditEntry("dhcp6_subnet",
3834 AuditEntry::ModificationType::UPDATE,
3835 "subnet specific option set");
3836 }
3837
3838 // Updating the option should replace the existing instance with the new
3839 // instance. Therefore, we should still have five options.
3840 ASSERT_EQ(5, countRows("dhcp6_options"));
3841
3842 // It should succeed for any server.
3843 EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), subnet->getID(),
3844 opt_posix_timezone->option_->getType(),
3845 opt_posix_timezone->space_name_));
3846
3847 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3848 subnet->getID());
3849 ASSERT_TRUE(returned_subnet);
3850
3851 EXPECT_FALSE(returned_subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE).option_);
3852
3853 {
3854 SCOPED_TRACE("UPDATE audit entry for a deleted subnet option");
3855 testNewAuditEntry("dhcp6_subnet",
3856 AuditEntry::ModificationType::UPDATE,
3857 "subnet specific option deleted");
3858 }
3859
3860 // We should have only four options after deleting one of them.
3861 ASSERT_EQ(4, countRows("dhcp6_options"));
3862 }
3863
3864 // This test verifies that option can be inserted, updated and deleted
3865 // from the pool.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeletePoolOption6)3866 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeletePoolOption6) {
3867 // Insert new subnet.
3868 Subnet6Ptr subnet = test_subnets_[1];
3869 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
3870
3871 {
3872 SCOPED_TRACE("CREATE audit entry for a subnet");
3873 testNewAuditEntry("dhcp6_subnet",
3874 AuditEntry::ModificationType::CREATE,
3875 "subnet set");
3876 }
3877
3878 // Inserted subnet has four options.
3879 ASSERT_EQ(4, countRows("dhcp6_options"));
3880
3881 // Add an option into the pool.
3882 const PoolPtr pool = subnet->getPool(Lease::TYPE_NA,
3883 IOAddress("2001:db8::10"));
3884 ASSERT_TRUE(pool);
3885 OptionDescriptorPtr opt_posix_timezone = test_options_[0];
3886 cbptr_->createUpdateOption6(ServerSelector::ANY(),
3887 pool->getFirstAddress(),
3888 pool->getLastAddress(),
3889 opt_posix_timezone);
3890
3891 // Query for a subnet.
3892 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3893 subnet->getID());
3894 ASSERT_TRUE(returned_subnet);
3895
3896 // The returned subnet should include our pool.
3897 const PoolPtr returned_pool = returned_subnet->getPool(Lease::TYPE_NA,
3898 IOAddress("2001:db8::10"));
3899 ASSERT_TRUE(returned_pool);
3900
3901 // The pool should contain option we added earlier.
3902 OptionDescriptor returned_opt_posix_timezone =
3903 returned_pool->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
3904 ASSERT_TRUE(returned_opt_posix_timezone.option_);
3905
3906 {
3907 SCOPED_TRACE("verify returned pool option");
3908 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
3909 EXPECT_GT(returned_opt_posix_timezone.getId(), 0);
3910 }
3911
3912 {
3913 SCOPED_TRACE("UPDATE audit entry for a subnet after adding an option "
3914 "to the address pool");
3915 testNewAuditEntry("dhcp6_subnet",
3916 AuditEntry::ModificationType::UPDATE,
3917 "address pool specific option set");
3918 }
3919
3920 // With the newly inserted option we should now have five options.
3921 ASSERT_EQ(5, countRows("dhcp6_options"));
3922
3923 // Modify the option and update it in the database.
3924 opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
3925 cbptr_->createUpdateOption6(ServerSelector::ANY(),
3926 pool->getFirstAddress(),
3927 pool->getLastAddress(),
3928 opt_posix_timezone);
3929
3930 // Fetch the subnet and the corresponding pool.
3931 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3932 subnet->getID());
3933 ASSERT_TRUE(returned_subnet);
3934 const PoolPtr returned_pool1 = returned_subnet->getPool(Lease::TYPE_NA,
3935 IOAddress("2001:db8::10"));
3936 ASSERT_TRUE(returned_pool1);
3937
3938 // Test that the option has been correctly updated in the database.
3939 returned_opt_posix_timezone =
3940 returned_pool1->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
3941 ASSERT_TRUE(returned_opt_posix_timezone.option_);
3942
3943 {
3944 SCOPED_TRACE("verify updated option with modified persistence");
3945 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
3946 }
3947
3948 {
3949 SCOPED_TRACE("UPDATE audit entry for a subnet when updating "
3950 "address pool specific option");
3951 testNewAuditEntry("dhcp6_subnet",
3952 AuditEntry::ModificationType::UPDATE,
3953 "address pool specific option set");
3954 }
3955
3956 // The new option instance should replace the existing one, so we should
3957 // still have five options.
3958 ASSERT_EQ(5, countRows("dhcp6_options"));
3959
3960 // Delete option for any server should succeed.
3961 EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(),
3962 pool->getFirstAddress(),
3963 pool->getLastAddress(),
3964 opt_posix_timezone->option_->getType(),
3965 opt_posix_timezone->space_name_));
3966
3967 // Fetch the subnet and the pool from the database again to make sure
3968 // that the option is really gone.
3969 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
3970 subnet->getID());
3971 ASSERT_TRUE(returned_subnet);
3972 const PoolPtr returned_pool2 = returned_subnet->getPool(Lease::TYPE_NA,
3973 IOAddress("2001:db8::10"));
3974 ASSERT_TRUE(returned_pool2);
3975
3976 // Option should be gone.
3977 EXPECT_FALSE(returned_pool2->getCfgOption()->get(DHCP6_OPTION_SPACE,
3978 D6O_NEW_POSIX_TIMEZONE).option_);
3979
3980 {
3981 SCOPED_TRACE("UPDATE audit entry for a subnet when deleting "
3982 "address pool specific option");
3983 testNewAuditEntry("dhcp6_subnet",
3984 AuditEntry::ModificationType::UPDATE,
3985 "address pool specific option deleted");
3986 }
3987
3988 // The option has been deleted so the number of options should now
3989 // be down to 4.
3990 EXPECT_EQ(4, countRows("dhcp6_options"));
3991 }
3992
3993 // This test verifies that option can be inserted, updated and deleted
3994 // from the pd pool.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeletePdPoolOption6)3995 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeletePdPoolOption6) {
3996 // Insert new subnet.
3997 Subnet6Ptr subnet = test_subnets_[1];
3998 cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet);
3999
4000 {
4001 SCOPED_TRACE("CREATE audit entry for a subnet");
4002 testNewAuditEntry("dhcp6_subnet",
4003 AuditEntry::ModificationType::CREATE,
4004 "subnet set");
4005 }
4006
4007 // Inserted subnet has four options.
4008 ASSERT_EQ(4, countRows("dhcp6_options"));
4009
4010 // Add an option into the pd pool.
4011 const PoolPtr pd_pool = subnet->getPool(Lease::TYPE_PD,
4012 IOAddress("2001:db8:a:10::"));
4013 ASSERT_TRUE(pd_pool);
4014 OptionDescriptorPtr opt_posix_timezone = test_options_[0];
4015 int pd_pool_len = prefixLengthFromRange(pd_pool->getFirstAddress(),
4016 pd_pool->getLastAddress());
4017 cbptr_->createUpdateOption6(ServerSelector::ANY(),
4018 pd_pool->getFirstAddress(),
4019 static_cast<uint8_t>(pd_pool_len),
4020 opt_posix_timezone);
4021
4022 // Query for a subnet.
4023 Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
4024 subnet->getID());
4025 ASSERT_TRUE(returned_subnet);
4026
4027 // The returned subnet should include our pool.
4028 const PoolPtr returned_pd_pool =
4029 returned_subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:a:10::"));
4030 ASSERT_TRUE(returned_pd_pool);
4031
4032 // The pd pool should contain option we added earlier.
4033 OptionDescriptor returned_opt_posix_timezone =
4034 returned_pd_pool->getCfgOption()->get(DHCP6_OPTION_SPACE,
4035 D6O_NEW_POSIX_TIMEZONE);
4036 ASSERT_TRUE(returned_opt_posix_timezone.option_);
4037
4038 {
4039 SCOPED_TRACE("verify returned pool option");
4040 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
4041 EXPECT_GT(returned_opt_posix_timezone.getId(), 0);
4042 }
4043
4044 {
4045 SCOPED_TRACE("UPDATE audit entry for a subnet after adding an option "
4046 "to the prefix delegation pool");
4047 testNewAuditEntry("dhcp6_subnet",
4048 AuditEntry::ModificationType::UPDATE,
4049 "prefix delegation pool specific option set");
4050 }
4051
4052 // With the newly inserted option we should now have five options.
4053 ASSERT_EQ(5, countRows("dhcp6_options"));
4054
4055 // Modify the option and update it in the database.
4056 opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
4057 cbptr_->createUpdateOption6(ServerSelector::ANY(),
4058 pd_pool->getFirstAddress(),
4059 static_cast<uint8_t>(pd_pool_len),
4060 opt_posix_timezone);
4061
4062 // Fetch the subnet and the corresponding pd pool.
4063 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
4064 subnet->getID());
4065 ASSERT_TRUE(returned_subnet);
4066 const PoolPtr returned_pd_pool1 =
4067 returned_subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:a:10::"));
4068 ASSERT_TRUE(returned_pd_pool1);
4069
4070 // Test that the option has been correctly updated in the database.
4071 returned_opt_posix_timezone =
4072 returned_pd_pool1->getCfgOption()->get(DHCP6_OPTION_SPACE,
4073 D6O_NEW_POSIX_TIMEZONE);
4074 ASSERT_TRUE(returned_opt_posix_timezone.option_);
4075
4076 {
4077 SCOPED_TRACE("verify updated option with modified persistence");
4078 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
4079 }
4080
4081 {
4082 SCOPED_TRACE("UPDATE audit entry for a subnet when updating "
4083 "prefix delegation pool specific option");
4084 testNewAuditEntry("dhcp6_subnet",
4085 AuditEntry::ModificationType::UPDATE,
4086 "prefix delegation pool specific option set");
4087 }
4088
4089 // The new option instance should replace the existing one, so we should
4090 // still have five options.
4091 ASSERT_EQ(5, countRows("dhcp6_options"));
4092
4093 // Delete option for any server should succeed.
4094 EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(),
4095 pd_pool->getFirstAddress(),
4096 static_cast<uint8_t>(pd_pool_len),
4097 opt_posix_timezone->option_->getType(),
4098 opt_posix_timezone->space_name_));
4099
4100 // Fetch the subnet and the pool from the database again to make sure
4101 // that the option is really gone.
4102 returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(),
4103 subnet->getID());
4104 ASSERT_TRUE(returned_subnet);
4105 const PoolPtr returned_pd_pool2 =
4106 returned_subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:a:10::"));
4107 ASSERT_TRUE(returned_pd_pool2);
4108
4109 // Option should be gone.
4110 EXPECT_FALSE(returned_pd_pool2->getCfgOption()->get(DHCP6_OPTION_SPACE,
4111 D6O_NEW_POSIX_TIMEZONE).option_);
4112
4113 {
4114 SCOPED_TRACE("UPDATE audit entry for a subnet when deleting "
4115 "prefix delegation pool specific option");
4116 testNewAuditEntry("dhcp6_subnet",
4117 AuditEntry::ModificationType::UPDATE,
4118 "prefix delegation pool specific option deleted");
4119 }
4120
4121 // The option has been deleted so the number of options should now
4122 // be down to 4.
4123 EXPECT_EQ(4, countRows("dhcp6_options"));
4124 }
4125
4126 // This test verifies that shared network level option can be added,
4127 // updated and deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateDeleteSharedNetworkOption6)4128 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteSharedNetworkOption6) {
4129 // Insert new shared network.
4130 SharedNetwork6Ptr shared_network = test_networks_[1];
4131 cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
4132 shared_network);
4133
4134 // Fetch this shared network by name.
4135 SharedNetwork6Ptr returned_network =
4136 cbptr_->getSharedNetwork6(ServerSelector::ALL(),
4137 shared_network->getName());
4138 ASSERT_TRUE(returned_network);
4139
4140 {
4141 SCOPED_TRACE("CREATE audit entry for the new shared network");
4142 testNewAuditEntry("dhcp6_shared_network",
4143 AuditEntry::ModificationType::CREATE,
4144 "shared network set");
4145 }
4146
4147 // The inserted shared network has no options.
4148 ASSERT_EQ(0, countRows("dhcp6_options"));
4149
4150 OptionDescriptorPtr opt_posix_timezone = test_options_[0];
4151 cbptr_->createUpdateOption6(ServerSelector::ANY(),
4152 shared_network->getName(),
4153 opt_posix_timezone);
4154
4155 returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(),
4156 shared_network->getName());
4157 ASSERT_TRUE(returned_network);
4158
4159 OptionDescriptor returned_opt_posix_timezone =
4160 returned_network->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
4161 ASSERT_TRUE(returned_opt_posix_timezone.option_);
4162
4163 {
4164 SCOPED_TRACE("verify returned option");
4165 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
4166 EXPECT_GT(returned_opt_posix_timezone.getId(), 0);
4167 }
4168
4169 {
4170 SCOPED_TRACE("UPDATE audit entry for the added shared network option");
4171 // Instead of adding an audit entry for an option we add an audit
4172 // entry for the entire shared network so as the server refreshes the
4173 // shared network with the new option. Note that the server doesn't
4174 // have means to retrieve only the newly added option.
4175 testNewAuditEntry("dhcp6_shared_network",
4176 AuditEntry::ModificationType::UPDATE,
4177 "shared network specific option set");
4178 }
4179
4180 // One option should now be stored in the database.
4181 ASSERT_EQ(1, countRows("dhcp6_options"));
4182
4183 opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
4184 cbptr_->createUpdateOption6(ServerSelector::ANY(),
4185 shared_network->getName(),
4186 opt_posix_timezone);
4187
4188 returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(),
4189 shared_network->getName());
4190 ASSERT_TRUE(returned_network);
4191 returned_opt_posix_timezone =
4192 returned_network->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
4193 ASSERT_TRUE(returned_opt_posix_timezone.option_);
4194
4195 {
4196 SCOPED_TRACE("verify updated option with modified persistence");
4197 testOptionsEquivalent(*opt_posix_timezone, returned_opt_posix_timezone);
4198 }
4199
4200 {
4201 SCOPED_TRACE("UPDATE audit entry for the updated shared network option");
4202 testNewAuditEntry("dhcp6_shared_network",
4203 AuditEntry::ModificationType::UPDATE,
4204 "shared network specific option set");
4205 }
4206
4207 // The new option instance should replace the existing option instance,
4208 // so we should still have one option.
4209 ASSERT_EQ(1, countRows("dhcp6_options"));
4210
4211 // Deleting an option for any server should succeed.
4212 EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(),
4213 shared_network->getName(),
4214 opt_posix_timezone->option_->getType(),
4215 opt_posix_timezone->space_name_));
4216 returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(),
4217 shared_network->getName());
4218 ASSERT_TRUE(returned_network);
4219 EXPECT_FALSE(returned_network->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE).option_);
4220
4221 {
4222 SCOPED_TRACE("UPDATE audit entry for the deleted shared network option");
4223 testNewAuditEntry("dhcp6_shared_network",
4224 AuditEntry::ModificationType::UPDATE,
4225 "shared network specific option deleted");
4226 }
4227
4228 // After deleting the option we should be back to 0.
4229 EXPECT_EQ(0, countRows("dhcp6_options"));
4230 }
4231
4232 // This test verifies that option id values in one subnet do
4233 // not impact options returned in subsequent subnets when
4234 // fetching subnets from the backend.
TEST_F(MySqlConfigBackendDHCPv6Test,subnetOptionIdOrder)4235 TEST_F(MySqlConfigBackendDHCPv6Test, subnetOptionIdOrder) {
4236
4237 // Add a network with two pools with two options each.
4238 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[1]));
4239 EXPECT_EQ(2, countRows("dhcp6_pool"));
4240 EXPECT_EQ(4, countRows("dhcp6_options"));
4241
4242 // Add second subnet with a single option. The number of options in the database
4243 // should now be 3.
4244 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[2]));
4245 EXPECT_EQ(2, countRows("dhcp6_pool"));
4246 EXPECT_EQ(5, countRows("dhcp6_options"));
4247
4248 // Now replace the first subnet with three options and two pools. This will cause
4249 // the option id values for this subnet to be larger than those in the second
4250 // subnet.
4251 EXPECT_NO_THROW(cbptr_->createUpdateSubnet6(ServerSelector::ALL(), test_subnets_[0]));
4252 EXPECT_EQ(2, countRows("dhcp6_pool"));
4253 EXPECT_EQ(4, countRows("dhcp6_options"));
4254
4255 // Now fetch all subnets.
4256 Subnet6Collection subnets;
4257 EXPECT_NO_THROW(subnets = cbptr_->getAllSubnets6(ServerSelector::ALL()));
4258 ASSERT_EQ(2, subnets.size());
4259
4260 // Verify that the subnets returned are as expected.
4261 for (auto subnet : subnets) {
4262 ASSERT_EQ(1, subnet->getServerTags().size());
4263 EXPECT_EQ("all", subnet->getServerTags().begin()->get());
4264 if (subnet->getID() == 1024) {
4265 EXPECT_EQ(test_subnets_[0]->toElement()->str(), subnet->toElement()->str());
4266 } else if (subnet->getID() == 2048) {
4267 EXPECT_EQ(test_subnets_[2]->toElement()->str(), subnet->toElement()->str());
4268 } else {
4269 ADD_FAILURE() << "unexpected subnet id:" << subnet->getID();
4270 }
4271 }
4272 }
4273
4274 // This test verifies that option id values in one shared network do
4275 // not impact options returned in subsequent shared networks when
4276 // fetching shared networks from the backend.
TEST_F(MySqlConfigBackendDHCPv6Test,sharedNetworkOptionIdOrder)4277 TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkOptionIdOrder) {
4278 auto level1_options = test_networks_[0];
4279 auto level1_no_options = test_networks_[1];
4280 auto level2 = test_networks_[2];
4281
4282 // Insert two shared networks. We insert level1 without options first,
4283 // then level2.
4284 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
4285 level1_no_options));
4286
4287 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
4288 level2));
4289 // Fetch all shared networks.
4290 SharedNetwork6Collection networks =
4291 cbptr_->getAllSharedNetworks6(ServerSelector::ALL());
4292
4293 ASSERT_EQ(2, networks.size());
4294
4295 // See if shared networks are returned ok.
4296 for (auto i = 0; i < networks.size(); ++i) {
4297 if (i == 0) {
4298 // level1_no_options
4299 EXPECT_EQ(level1_no_options->toElement()->str(),
4300 networks[i]->toElement()->str());
4301 } else {
4302 // bar
4303 EXPECT_EQ(level2->toElement()->str(),
4304 networks[i]->toElement()->str());
4305 }
4306 }
4307
4308 EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
4309 level1_options));
4310
4311 // Fetch all shared networks.
4312 networks = cbptr_->getAllSharedNetworks6(ServerSelector::ALL());
4313 ASSERT_EQ(2, networks.size());
4314
4315 // See if shared networks are returned ok.
4316 for (auto i = 0; i < networks.size(); ++i) {
4317 if (i == 0) {
4318 // level1_no_options
4319 EXPECT_EQ(level1_options->toElement()->str(),
4320 networks[i]->toElement()->str());
4321 } else {
4322 // bar
4323 EXPECT_EQ(level2->toElement()->str(),
4324 networks[i]->toElement()->str());
4325 }
4326 }
4327 }
4328
4329 // This test verifies that it is possible to create client classes, update them
4330 // and retrieve all classes for a given server.
TEST_F(MySqlConfigBackendDHCPv6Test,setAndGetAllClientClasses6)4331 TEST_F(MySqlConfigBackendDHCPv6Test, setAndGetAllClientClasses6) {
4332 // Create a server.
4333 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4334 {
4335 SCOPED_TRACE("server1 is created");
4336 testNewAuditEntry("dhcp6_server",
4337 AuditEntry::ModificationType::CREATE,
4338 "server set",
4339 ServerSelector::ONE("server1"));
4340 }
4341 // Create first class.
4342 auto class1 = test_client_classes_[0];
4343 class1->setTest("pkt6.msgtype == 1");
4344 ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4345 {
4346 SCOPED_TRACE("client class foo is created");
4347 testNewAuditEntry("dhcp6_client_class",
4348 AuditEntry::ModificationType::CREATE,
4349 "client class set",
4350 ServerSelector::ONE("server1"));
4351 }
4352 // Create second class.
4353 auto class2 = test_client_classes_[1];
4354 ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
4355 {
4356 SCOPED_TRACE("client class bar is created");
4357 testNewAuditEntry("dhcp6_client_class",
4358 AuditEntry::ModificationType::CREATE,
4359 "client class set",
4360 ServerSelector::ONE("server1"));
4361 }
4362 // Create third class.
4363 auto class3 = test_client_classes_[2];
4364 ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
4365 {
4366 SCOPED_TRACE("client class foobar is created");
4367 testNewAuditEntry("dhcp6_client_class",
4368 AuditEntry::ModificationType::CREATE,
4369 "client class set",
4370 ServerSelector::ONE("server1"));
4371 }
4372 // Update the third class to depend on the second class.
4373 class3->setTest("member('foo')");
4374 ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
4375 {
4376 SCOPED_TRACE("client class bar is updated");
4377 testNewAuditEntry("dhcp6_client_class",
4378 AuditEntry::ModificationType::UPDATE,
4379 "client class set",
4380 ServerSelector::ONE("server1"));
4381 }
4382 // Only the first class should be returned for the server selector ALL.
4383 auto client_classes = cbptr_->getAllClientClasses6(ServerSelector::ALL());
4384 ASSERT_EQ(1, client_classes.getClasses()->size());
4385 // All three classes should be returned for the server1.
4386 client_classes = cbptr_->getAllClientClasses6(ServerSelector::ONE("server1"));
4387 auto classes_list = client_classes.getClasses();
4388 ASSERT_EQ(3, classes_list->size());
4389 EXPECT_EQ("foo", (*classes_list->begin())->getName());
4390 EXPECT_EQ("bar", (*(classes_list->begin() + 1))->getName());
4391 EXPECT_EQ("foobar", (*(classes_list->begin() + 2))->getName());
4392
4393 // Move the third class between the first and second class.
4394 ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, "foo"));
4395
4396 // Ensure that the classes order has changed.
4397 client_classes = cbptr_->getAllClientClasses6(ServerSelector::ONE("server1"));
4398 classes_list = client_classes.getClasses();
4399 ASSERT_EQ(3, classes_list->size());
4400 EXPECT_EQ("foo", (*classes_list->begin())->getName());
4401 EXPECT_EQ("foobar", (*(classes_list->begin() + 1))->getName());
4402 EXPECT_EQ("bar", (*(classes_list->begin() + 2))->getName());
4403
4404 // Update the foobar class without specifying its position. It should not
4405 // be moved.
4406 ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
4407
4408 client_classes = cbptr_->getAllClientClasses6(ServerSelector::ONE("server1"));
4409 classes_list = client_classes.getClasses();
4410 ASSERT_EQ(3, classes_list->size());
4411 EXPECT_EQ("foo", (*classes_list->begin())->getName());
4412 EXPECT_EQ("foobar", (*(classes_list->begin() + 1))->getName());
4413 EXPECT_EQ("bar", (*(classes_list->begin() + 2))->getName());
4414 }
4415
4416 // This test verifies that a single class can be retrieved from the database.
TEST_F(MySqlConfigBackendDHCPv6Test,getClientClass6)4417 TEST_F(MySqlConfigBackendDHCPv6Test, getClientClass6) {
4418 // Create a server.
4419 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4420
4421 // Add classes.
4422 auto class1 = test_client_classes_[0];
4423 EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[0]->option_,
4424 test_options_[0]->persistent_,
4425 test_options_[0]->space_name_));
4426 EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[1]->option_,
4427 test_options_[1]->persistent_,
4428 test_options_[1]->space_name_));
4429
4430 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4431
4432 auto class2 = test_client_classes_[1];
4433 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
4434
4435 // Get the first client class and validate its contents.
4436 ClientClassDefPtr client_class;
4437 ASSERT_NO_THROW_LOG(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
4438 ASSERT_TRUE(client_class);
4439 EXPECT_EQ("foo", client_class->getName());
4440 EXPECT_TRUE(client_class->getRequired());
4441 EXPECT_EQ(30, client_class->getValid().getMin());
4442 EXPECT_EQ(60, client_class->getValid().get());
4443 EXPECT_EQ(90, client_class->getValid().getMax());
4444
4445 // Validate options belonging to this class.
4446 ASSERT_TRUE(client_class->getCfgOption());
4447 OptionDescriptor returned_opt_new_posix_timezone =
4448 client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
4449 ASSERT_TRUE(returned_opt_new_posix_timezone.option_);
4450
4451 OptionDescriptor returned_opt_preference =
4452 client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_PREFERENCE);
4453 ASSERT_TRUE(returned_opt_preference.option_);
4454
4455 // Fetch the same class using different server selectors.
4456 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ANY(),
4457 class1->getName()));
4458 EXPECT_TRUE(client_class);
4459
4460 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ONE("server1"),
4461 class1->getName()));
4462 EXPECT_TRUE(client_class);
4463
4464 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::UNASSIGNED(),
4465 class1->getName()));
4466 EXPECT_FALSE(client_class);
4467
4468 // Fetch the second client class using different selectors. This time the
4469 // class should not be returned for the ALL server selector because it is
4470 // associated with the server1.
4471 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(),
4472 class2->getName()));
4473 EXPECT_FALSE(client_class);
4474
4475 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ANY(),
4476 class2->getName()));
4477 EXPECT_TRUE(client_class);
4478
4479 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ONE("server1"),
4480 class2->getName()));
4481 EXPECT_TRUE(client_class);
4482
4483 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::UNASSIGNED(),
4484 class2->getName()));
4485 EXPECT_FALSE(client_class);
4486 }
4487
4488 // This test verifies that client class specific DHCP options can be
4489 // modified during the class update.
TEST_F(MySqlConfigBackendDHCPv6Test,createUpdateClientClass6Options)4490 TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateClientClass6Options) {
4491 // Add class with two options and two option definitions.
4492 auto class1 = test_client_classes_[0];
4493 EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[0]->option_,
4494 test_options_[0]->persistent_,
4495 test_options_[0]->space_name_));
4496 EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[1]->option_,
4497 test_options_[1]->persistent_,
4498 test_options_[1]->space_name_));
4499 auto cfg_option_def = boost::make_shared<CfgOptionDef>();
4500 class1->setCfgOptionDef(cfg_option_def);
4501 EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[0]));
4502 EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[2]));
4503 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4504
4505 // Fetch the class and the options from the database.
4506 ClientClassDefPtr client_class;
4507 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
4508 ASSERT_TRUE(client_class);
4509
4510 // Validate options belonging to the class.
4511 ASSERT_TRUE(client_class->getCfgOption());
4512 OptionDescriptor returned_opt_new_posix_timezone =
4513 client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
4514 ASSERT_TRUE(returned_opt_new_posix_timezone.option_);
4515
4516 OptionDescriptor returned_opt_preference =
4517 client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_PREFERENCE);
4518 ASSERT_TRUE(returned_opt_preference.option_);
4519
4520 // Validate option definitions belonging to the class.
4521 ASSERT_TRUE(client_class->getCfgOptionDef());
4522 auto returned_def_foo = client_class->getCfgOptionDef()->get(test_option_defs_[0]->getOptionSpaceName(),
4523 test_option_defs_[0]->getCode());
4524
4525 ASSERT_TRUE(returned_def_foo);
4526 EXPECT_EQ(1234, returned_def_foo->getCode());
4527 EXPECT_EQ("foo", returned_def_foo->getName());
4528 EXPECT_EQ(DHCP6_OPTION_SPACE, returned_def_foo->getOptionSpaceName());
4529 EXPECT_EQ("espace", returned_def_foo->getEncapsulatedSpace());
4530 EXPECT_EQ(OPT_STRING_TYPE, returned_def_foo->getType());
4531 EXPECT_FALSE(returned_def_foo->getArrayType());
4532
4533 auto returned_def_fish = client_class->getCfgOptionDef()->get(test_option_defs_[2]->getOptionSpaceName(),
4534 test_option_defs_[2]->getCode());
4535 ASSERT_TRUE(returned_def_fish);
4536 EXPECT_EQ(5235, returned_def_fish->getCode());
4537 EXPECT_EQ("fish", returned_def_fish->getName());
4538 EXPECT_EQ(DHCP6_OPTION_SPACE, returned_def_fish->getOptionSpaceName());
4539 EXPECT_TRUE(returned_def_fish->getEncapsulatedSpace().empty());
4540 EXPECT_EQ(OPT_RECORD_TYPE, returned_def_fish->getType());
4541 EXPECT_TRUE(returned_def_fish->getArrayType());
4542
4543 // Replace client class specific option definitions. Leave only one option
4544 // definition.
4545 cfg_option_def = boost::make_shared<CfgOptionDef>();
4546 class1->setCfgOptionDef(cfg_option_def);
4547 EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[2]));
4548
4549 // Delete one of the options and update the class.
4550 class1->getCfgOption()->del(test_options_[0]->space_name_,
4551 test_options_[0]->option_->getType());
4552 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4553 EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
4554 ASSERT_TRUE(client_class);
4555
4556 // Ensure that the first option definition is gone.
4557 ASSERT_TRUE(client_class->getCfgOptionDef());
4558 returned_def_foo = client_class->getCfgOptionDef()->get(test_option_defs_[0]->getOptionSpaceName(),
4559 test_option_defs_[0]->getCode());
4560 EXPECT_FALSE(returned_def_foo);
4561
4562 // The second option definition should be present.
4563 returned_def_fish = client_class->getCfgOptionDef()->get(test_option_defs_[2]->getOptionSpaceName(),
4564 test_option_defs_[2]->getCode());
4565 EXPECT_TRUE(returned_def_fish);
4566
4567 // Make sure that the first option is gone.
4568 ASSERT_TRUE(client_class->getCfgOption());
4569 returned_opt_new_posix_timezone = client_class->getCfgOption()->get(DHCP6_OPTION_SPACE,
4570 D6O_NEW_POSIX_TIMEZONE);
4571 EXPECT_FALSE(returned_opt_new_posix_timezone.option_);
4572
4573 // The second option should be there.
4574 returned_opt_preference = client_class->getCfgOption()->get(DHCP6_OPTION_SPACE,
4575 D6O_PREFERENCE);
4576 ASSERT_TRUE(returned_opt_preference.option_);
4577 }
4578
4579 // This test verifies that modified client classes can be retrieved from the database.
TEST_F(MySqlConfigBackendDHCPv6Test,getModifiedClientClasses6)4580 TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedClientClasses6) {
4581 // Create server1.
4582 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4583
4584 // Add three classes to the database with different timestamps.
4585 auto class1 = test_client_classes_[0];
4586 class1->setModificationTime(timestamps_["yesterday"]);
4587 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4588
4589 auto class2 = test_client_classes_[1];
4590 class2->setModificationTime(timestamps_["today"]);
4591 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""));
4592
4593 auto class3 = test_client_classes_[2];
4594 class3->setModificationTime(timestamps_["tomorrow"]);
4595 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
4596
4597 // Get modified client classes configured for all servers.
4598 auto client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ALL(),
4599 timestamps_["two days ago"]);
4600 EXPECT_EQ(2, client_classes.getClasses()->size());
4601
4602 // Get modified client classes appropriate for server1. It includes classes
4603 // for all servers and for the server1.
4604 client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
4605 timestamps_["two days ago"]);
4606 EXPECT_EQ(3, client_classes.getClasses()->size());
4607
4608 // Get the classes again but use the timestamp equal to the modification
4609 // time of the first class.
4610 client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
4611 timestamps_["yesterday"]);
4612 EXPECT_EQ(3, client_classes.getClasses()->size());
4613
4614 // Get modified classes starting from today. It should return only two.
4615 client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
4616 timestamps_["today"]);
4617 EXPECT_EQ(2, client_classes.getClasses()->size());
4618
4619 // Get client classes modified in the future. It should return none.
4620 client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
4621 timestamps_["after tomorrow"]);
4622 EXPECT_EQ(0, client_classes.getClasses()->size());
4623
4624 // Getting modified client classes for any server is unsupported.
4625 EXPECT_THROW(cbptr_->getModifiedClientClasses6(ServerSelector::ANY(),
4626 timestamps_["two days ago"]),
4627 InvalidOperation);
4628 }
4629
4630 // This test verifies that a specified client class can be deleted.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteClientClass6)4631 TEST_F(MySqlConfigBackendDHCPv6Test, deleteClientClass6) {
4632 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4633 {
4634 SCOPED_TRACE("server1 is created");
4635 testNewAuditEntry("dhcp6_server",
4636 AuditEntry::ModificationType::CREATE,
4637 "server set",
4638 ServerSelector::ONE("server1"));
4639 }
4640 {
4641 SCOPED_TRACE("server1 is created");
4642 testNewAuditEntry("dhcp6_server",
4643 AuditEntry::ModificationType::CREATE,
4644 "server set",
4645 ServerSelector::ONE("server2"));
4646 }
4647
4648 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
4649 {
4650 SCOPED_TRACE("server1 is created and available for server1");
4651 testNewAuditEntry("dhcp6_server",
4652 AuditEntry::ModificationType::CREATE,
4653 "server set",
4654 ServerSelector::ONE("server1"));
4655 }
4656 {
4657 SCOPED_TRACE("server1 is created and available for server2");
4658 testNewAuditEntry("dhcp6_server",
4659 AuditEntry::ModificationType::CREATE,
4660 "server set",
4661 ServerSelector::ONE("server2"));
4662 }
4663
4664 auto class1 = test_client_classes_[0];
4665 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4666 {
4667 SCOPED_TRACE("client class foo is created and available for server1");
4668 testNewAuditEntry("dhcp6_client_class",
4669 AuditEntry::ModificationType::CREATE,
4670 "client class set",
4671 ServerSelector::ONE("server1"));
4672 }
4673 {
4674 SCOPED_TRACE("client class foo is created and available for server 2");
4675 testNewAuditEntry("dhcp6_client_class",
4676 AuditEntry::ModificationType::CREATE,
4677 "client class set",
4678 ServerSelector::ONE("server2"));
4679 }
4680
4681 auto class2 = test_client_classes_[1];
4682 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
4683 {
4684 SCOPED_TRACE("client class bar is created");
4685 testNewAuditEntry("dhcp6_client_class",
4686 AuditEntry::ModificationType::CREATE,
4687 "client class set",
4688 ServerSelector::ONE("server1"));
4689 }
4690
4691 auto class3 = test_client_classes_[2];
4692 class3->setTest("member('foo')");
4693 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server2"), class3, ""));
4694 {
4695 SCOPED_TRACE("client class foobar is created");
4696 testNewAuditEntry("dhcp6_client_class",
4697 AuditEntry::ModificationType::CREATE,
4698 "client class set",
4699 ServerSelector::ONE("server2"));
4700 }
4701
4702 uint64_t result;
4703 EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ONE("server1"),
4704 class2->getName()));
4705 EXPECT_EQ(1, result);
4706 {
4707 SCOPED_TRACE("client class bar is deleted");
4708 testNewAuditEntry("dhcp6_client_class",
4709 AuditEntry::ModificationType::DELETE,
4710 "client class deleted",
4711 ServerSelector::ONE("server1"));
4712 }
4713
4714 EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ONE("server2"),
4715 class3->getName()));
4716 EXPECT_EQ(1, result);
4717 {
4718 SCOPED_TRACE("client class foobar is deleted");
4719 testNewAuditEntry("dhcp6_client_class",
4720 AuditEntry::ModificationType::DELETE,
4721 "client class deleted",
4722 ServerSelector::ONE("server2"));
4723 }
4724
4725 EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ANY(),
4726 class1->getName()));
4727 EXPECT_EQ(1, result);
4728 {
4729 SCOPED_TRACE("client class foo is deleted and no longer available for the server1");
4730 testNewAuditEntry("dhcp6_client_class",
4731 AuditEntry::ModificationType::DELETE,
4732 "client class deleted",
4733 ServerSelector::ONE("server1"));
4734 }
4735 {
4736 SCOPED_TRACE("client class foo is deleted and no longer available for the server2");
4737 testNewAuditEntry("dhcp6_client_class",
4738 AuditEntry::ModificationType::DELETE,
4739 "client class deleted",
4740 ServerSelector::ONE("server2"));
4741 }
4742 }
4743
4744 // This test verifies that all client classes can be deleted using
4745 // a specified server selector.
TEST_F(MySqlConfigBackendDHCPv6Test,deleteAllClientClasses6)4746 TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllClientClasses6) {
4747 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4748 {
4749 SCOPED_TRACE("server1 is created");
4750 testNewAuditEntry("dhcp6_server",
4751 AuditEntry::ModificationType::CREATE,
4752 "server set",
4753 ServerSelector::ONE("server1"));
4754 }
4755 {
4756 SCOPED_TRACE("server1 is created");
4757 testNewAuditEntry("dhcp6_server",
4758 AuditEntry::ModificationType::CREATE,
4759 "server set",
4760 ServerSelector::ONE("server2"));
4761 }
4762
4763 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
4764 {
4765 SCOPED_TRACE("server1 is created and available for server1");
4766 testNewAuditEntry("dhcp6_server",
4767 AuditEntry::ModificationType::CREATE,
4768 "server set",
4769 ServerSelector::ONE("server1"));
4770 }
4771 {
4772 SCOPED_TRACE("server1 is created and available for server2");
4773 testNewAuditEntry("dhcp6_server",
4774 AuditEntry::ModificationType::CREATE,
4775 "server set",
4776 ServerSelector::ONE("server2"));
4777 }
4778
4779 auto class1 = test_client_classes_[0];
4780 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4781 {
4782 SCOPED_TRACE("client class foo is created and available for server1");
4783 testNewAuditEntry("dhcp6_client_class",
4784 AuditEntry::ModificationType::CREATE,
4785 "client class set",
4786 ServerSelector::ONE("server1"));
4787 }
4788 {
4789 SCOPED_TRACE("client class foo is created and available for server 2");
4790 testNewAuditEntry("dhcp6_client_class",
4791 AuditEntry::ModificationType::CREATE,
4792 "client class set",
4793 ServerSelector::ONE("server2"));
4794 }
4795
4796 auto class2 = test_client_classes_[1];
4797 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
4798 {
4799 SCOPED_TRACE("client class bar is created");
4800 testNewAuditEntry("dhcp6_client_class",
4801 AuditEntry::ModificationType::CREATE,
4802 "client class set",
4803 ServerSelector::ONE("server1"));
4804 }
4805
4806 auto class3 = test_client_classes_[2];
4807 class3->setTest("member('foo')");
4808 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server2"), class3, ""));
4809 {
4810 SCOPED_TRACE("client class foobar is created");
4811 testNewAuditEntry("dhcp6_client_class",
4812 AuditEntry::ModificationType::CREATE,
4813 "client class set",
4814 ServerSelector::ONE("server2"));
4815 }
4816
4817 uint64_t result;
4818
4819 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::UNASSIGNED()));
4820 EXPECT_EQ(0, result);
4821
4822 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server2")));
4823 EXPECT_EQ(1, result);
4824 {
4825 SCOPED_TRACE("client classes for server2 deleted");
4826 testNewAuditEntry("dhcp6_client_class",
4827 AuditEntry::ModificationType::DELETE,
4828 "deleted all client classes",
4829 ServerSelector::ONE("server2"));
4830 }
4831
4832 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server2")));
4833 EXPECT_EQ(0, result);
4834
4835 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server1")));
4836 EXPECT_EQ(1, result);
4837 {
4838 SCOPED_TRACE("client classes for server1 deleted");
4839 testNewAuditEntry("dhcp6_client_class",
4840 AuditEntry::ModificationType::DELETE,
4841 "deleted all client classes",
4842 ServerSelector::ONE("server1"));
4843 }
4844
4845 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server1")));
4846 EXPECT_EQ(0, result);
4847
4848 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ALL()));
4849 EXPECT_EQ(1, result);
4850 {
4851 SCOPED_TRACE("client classes for all deleted");
4852 testNewAuditEntry("dhcp6_client_class",
4853 AuditEntry::ModificationType::DELETE,
4854 "deleted all client classes",
4855 ServerSelector::ONE("server1"));
4856 }
4857
4858 EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ALL()));
4859 EXPECT_EQ(0, result);
4860
4861 // Deleting multiple objects using ANY server tag is unsupported.
4862 EXPECT_THROW(cbptr_->deleteAllClientClasses6(ServerSelector::ANY()), InvalidOperation);
4863 }
4864
4865 // This test verifies that client class dependencies are tracked when the
4866 // classes are added to the database. It verifies that an attempt to update
4867 // a class violating the dependencies results in an error.
TEST_F(MySqlConfigBackendDHCPv6Test,clientClassDependencies6)4868 TEST_F(MySqlConfigBackendDHCPv6Test, clientClassDependencies6) {
4869 // Create a server.
4870 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
4871
4872 // Create first class. It depends on KNOWN built-in class.
4873 auto class1 = test_client_classes_[0];
4874 class1->setTest("member('KNOWN')");
4875 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
4876
4877 // Create second class which depends on the first class. This yelds indirect
4878 // dependency on KNOWN class.
4879 auto class2 = test_client_classes_[1];
4880 class2->setTest("member('foo')");
4881 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""));
4882
4883 // Create third class depending on the second class. This also yelds indirect
4884 // dependency on KNOWN class.
4885 auto class3 = test_client_classes_[2];
4886 class3->setTest("member('bar')");
4887 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class3, ""));
4888
4889 // An attempt to move the first class to the end of the class hierarchy should
4890 // fail because other classes depend on it.
4891 EXPECT_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, "bar"),
4892 DbOperationError);
4893
4894 // Try to change the dependency of the first class. There are other classes
4895 // having indirect dependency on KNOWN class via this class. Therefore, the
4896 // update should be unsuccessful.
4897 class1->setTest("member('HA_server1')");
4898 EXPECT_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""),
4899 DbOperationError);
4900
4901 // Try to change the dependency of the second class. This should result in
4902 // an error because the third class depends on it.
4903 class2->setTest("member('HA_server1')");
4904 EXPECT_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""),
4905 DbOperationError);
4906
4907 // Changing the indirect dependency of the third class should succeed, because
4908 // no other classes depend on this class.
4909 class3->setTest("member('HA_server1')");
4910 EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class3, ""));
4911 }
4912
4913 /// This test verifies that audit entries can be retrieved from a given
4914 /// timestamp and id including when two entries can get the same timestamp.
4915 /// (either it is a common even and this should catch it, or it is a rare
4916 /// event and it does not matter).
TEST_F(MySqlConfigBackendDHCPv6Test,multipleAuditEntries)4917 TEST_F(MySqlConfigBackendDHCPv6Test, multipleAuditEntries) {
4918 // Get current time.
4919 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
4920
4921 // Create a server.
4922 EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
4923
4924 // Create a global parameter and update it many times.
4925 const ServerSelector& server_selector = ServerSelector::ALL();
4926 StampedValuePtr param;
4927 ElementPtr value;
4928 for (int i = 0; i < 100; ++i) {
4929 value = Element::create(i);
4930 param = StampedValue::create("my-parameter", value);
4931 cbptr_->createUpdateGlobalParameter6(server_selector, param);
4932 }
4933
4934 // Get all audit entries from now.
4935 AuditEntryCollection audit_entries =
4936 cbptr_->getRecentAuditEntries(server_selector, now, 0);
4937
4938 // Check that partial retrieves return the right count.
4939 auto& mod_time_idx = audit_entries.get<AuditEntryModificationTimeIdTag>();
4940 for (auto it = mod_time_idx.begin(); it != mod_time_idx.end(); ++it) {
4941 size_t partial_size =
4942 cbptr_->getRecentAuditEntries(server_selector,
4943 (*it)->getModificationTime(),
4944 (*it)->getRevisionId()).size();
4945 EXPECT_EQ(partial_size + 1,
4946 std::distance(it, mod_time_idx.end()));
4947 }
4948 }
4949
4950 class MySqlConfigBackendDHCPv6DbLostCallbackTest : public ::testing::Test {
4951 public:
MySqlConfigBackendDHCPv6DbLostCallbackTest()4952 MySqlConfigBackendDHCPv6DbLostCallbackTest()
4953 : db_lost_callback_called_(0), db_recovered_callback_called_(0),
4954 db_failed_callback_called_(0),
4955 io_service_(boost::make_shared<isc::asiolink::IOService>()) {
4956 isc::db::DatabaseConnection::db_lost_callback_ = 0;
4957 isc::db::DatabaseConnection::db_recovered_callback_ = 0;
4958 isc::db::DatabaseConnection::db_failed_callback_ = 0;
4959 isc::dhcp::MySqlConfigBackendImpl::setIOService(io_service_);
4960 isc::dhcp::TimerMgr::instance()->setIOService(io_service_);
4961 isc::dhcp::CfgMgr::instance().clear();
4962 }
4963
~MySqlConfigBackendDHCPv6DbLostCallbackTest()4964 virtual ~MySqlConfigBackendDHCPv6DbLostCallbackTest() {
4965 isc::db::DatabaseConnection::db_lost_callback_ = 0;
4966 isc::db::DatabaseConnection::db_recovered_callback_ = 0;
4967 isc::db::DatabaseConnection::db_failed_callback_ = 0;
4968 isc::dhcp::MySqlConfigBackendImpl::setIOService(isc::asiolink::IOServicePtr());
4969 isc::dhcp::TimerMgr::instance()->unregisterTimers();
4970 isc::dhcp::CfgMgr::instance().clear();
4971 }
4972
4973 /// @brief Prepares the class for a test.
4974 ///
4975 /// Invoked by gtest prior test entry, we create the
4976 /// appropriate schema and create a basic DB manager to
4977 /// wipe out any prior instance
SetUp()4978 virtual void SetUp() {
4979 // Ensure we have the proper schema with no transient data.
4980 createMySQLSchema();
4981 isc::dhcp::CfgMgr::instance().clear();
4982 isc::dhcp::MySqlConfigBackendDHCPv6::registerBackendType();
4983 }
4984
4985 /// @brief Pre-text exit clean up
4986 ///
4987 /// Invoked by gtest upon test exit, we destroy the schema
4988 /// we created.
TearDown()4989 virtual void TearDown() {
4990 // If data wipe enabled, delete transient data otherwise destroy the schema
4991 destroyMySQLSchema();
4992 isc::dhcp::CfgMgr::instance().clear();
4993 isc::dhcp::MySqlConfigBackendDHCPv6::unregisterBackendType();
4994 }
4995
4996 /// @brief Method which returns the back end specific connection
4997 /// string
validConnectString()4998 virtual std::string validConnectString() {
4999 return (validMySQLConnectionString());
5000 }
5001
5002 /// @brief Method which returns invalid back end specific connection
5003 /// string
invalidConnectString()5004 virtual std::string invalidConnectString() {
5005 return (connectionString(MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
5006 VALID_USER, VALID_PASSWORD));
5007 }
5008
5009 /// @brief Verifies open failures do NOT invoke db lost callback
5010 ///
5011 /// The db lost callback should only be invoked after successfully
5012 /// opening the DB and then subsequently losing it. Failing to
5013 /// open should be handled directly by the application layer.
5014 void testNoCallbackOnOpenFailure();
5015
5016 /// @brief Verifies the CB manager's behavior if DB connection is lost
5017 ///
5018 /// This function creates a CB manager with a back end that supports
5019 /// connectivity lost callback. It verifies connectivity by issuing a known
5020 /// valid query. Next it simulates connectivity lost by identifying and
5021 /// closing the socket connection to the CB backend. It then reissues the
5022 /// query and verifies that:
5023 /// -# The Query throws DbOperationError (rather than exiting)
5024 /// -# The registered DbLostCallback was invoked
5025 /// -# The registered DbRecoveredCallback was invoked
5026 void testDbLostAndRecoveredCallback();
5027
5028 /// @brief Verifies the CB manager's behavior if DB connection is lost
5029 ///
5030 /// This function creates a CB manager with a back end that supports
5031 /// connectivity lost callback. It verifies connectivity by issuing a known
5032 /// valid query. Next it simulates connectivity lost by identifying and
5033 /// closing the socket connection to the CB backend. It then reissues the
5034 /// query and verifies that:
5035 /// -# The Query throws DbOperationError (rather than exiting)
5036 /// -# The registered DbLostCallback was invoked
5037 /// -# The registered DbFailedCallback was invoked
5038 void testDbLostAndFailedCallback();
5039
5040 /// @brief Verifies the CB manager's behavior if DB connection is lost
5041 ///
5042 /// This function creates a CB manager with a back end that supports
5043 /// connectivity lost callback. It verifies connectivity by issuing a known
5044 /// valid query. Next it simulates connectivity lost by identifying and
5045 /// closing the socket connection to the CB backend. It then reissues the
5046 /// query and verifies that:
5047 /// -# The Query throws DbOperationError (rather than exiting)
5048 /// -# The registered DbLostCallback was invoked
5049 /// -# The registered DbRecoveredCallback was invoked after two reconnect
5050 /// attempts (once failing and second triggered by timer)
5051 void testDbLostAndRecoveredAfterTimeoutCallback();
5052
5053 /// @brief Verifies the CB manager's behavior if DB connection is lost
5054 ///
5055 /// This function creates a CB manager with a back end that supports
5056 /// connectivity lost callback. It verifies connectivity by issuing a known
5057 /// valid query. Next it simulates connectivity lost by identifying and
5058 /// closing the socket connection to the CB backend. It then reissues the
5059 /// query and verifies that:
5060 /// -# The Query throws DbOperationError (rather than exiting)
5061 /// -# The registered DbLostCallback was invoked
5062 /// -# The registered DbFailedCallback was invoked after two reconnect
5063 /// attempts (once failing and second triggered by timer)
5064 void testDbLostAndFailedAfterTimeoutCallback();
5065
5066 /// @brief Callback function registered with the CB manager
db_lost_callback(db::ReconnectCtlPtr)5067 bool db_lost_callback(db::ReconnectCtlPtr /* not_used */) {
5068 return (++db_lost_callback_called_);
5069 }
5070
5071 /// @brief Flag used to detect calls to db_lost_callback function
5072 uint32_t db_lost_callback_called_;
5073
5074 /// @brief Callback function registered with the CB manager
db_recovered_callback(db::ReconnectCtlPtr)5075 bool db_recovered_callback(db::ReconnectCtlPtr /* not_used */) {
5076 return (++db_recovered_callback_called_);
5077 }
5078
5079 /// @brief Flag used to detect calls to db_recovered_callback function
5080 uint32_t db_recovered_callback_called_;
5081
5082 /// @brief Callback function registered with the CB manager
db_failed_callback(db::ReconnectCtlPtr)5083 bool db_failed_callback(db::ReconnectCtlPtr /* not_used */) {
5084 return (++db_failed_callback_called_);
5085 }
5086
5087 /// @brief Flag used to detect calls to db_failed_callback function
5088 uint32_t db_failed_callback_called_;
5089
5090 /// The IOService object, used for all ASIO operations.
5091 isc::asiolink::IOServicePtr io_service_;
5092 };
5093
5094 void
testNoCallbackOnOpenFailure()5095 MySqlConfigBackendDHCPv6DbLostCallbackTest::testNoCallbackOnOpenFailure() {
5096 isc::db::DatabaseConnection::db_lost_callback_ =
5097 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_lost_callback, this, ph::_1);
5098
5099 // Set the connectivity recovered callback.
5100 isc::db::DatabaseConnection::db_recovered_callback_ =
5101 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_recovered_callback, this, ph::_1);
5102
5103 // Set the connectivity failed callback.
5104 isc::db::DatabaseConnection::db_failed_callback_ =
5105 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_failed_callback, this, ph::_1);
5106
5107 std::string access = invalidConnectString();
5108
5109 // Connect to the CB backend.
5110 ASSERT_THROW(ConfigBackendDHCPv6Mgr::instance().addBackend(access), DbOpenError);
5111
5112 io_service_->poll();
5113
5114 EXPECT_EQ(0, db_lost_callback_called_);
5115 EXPECT_EQ(0, db_recovered_callback_called_);
5116 EXPECT_EQ(0, db_failed_callback_called_);
5117 }
5118
5119 void
testDbLostAndRecoveredCallback()5120 MySqlConfigBackendDHCPv6DbLostCallbackTest::testDbLostAndRecoveredCallback() {
5121 // Set the connectivity lost callback.
5122 isc::db::DatabaseConnection::db_lost_callback_ =
5123 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_lost_callback, this, ph::_1);
5124
5125 // Set the connectivity recovered callback.
5126 isc::db::DatabaseConnection::db_recovered_callback_ =
5127 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_recovered_callback, this, ph::_1);
5128
5129 // Set the connectivity failed callback.
5130 isc::db::DatabaseConnection::db_failed_callback_ =
5131 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_failed_callback, this, ph::_1);
5132
5133 std::string access = validConnectString();
5134
5135 ConfigControlInfoPtr config_ctl_info(new ConfigControlInfo());
5136 config_ctl_info->addConfigDatabase(access);
5137 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5138
5139 // Find the most recently opened socket. Our SQL client's socket should
5140 // be the next one.
5141 int last_open_socket = findLastSocketFd();
5142
5143 // Fill holes.
5144 FillFdHoles holes(last_open_socket);
5145
5146 // Connect to the CB backend.
5147 ASSERT_NO_THROW(ConfigBackendDHCPv6Mgr::instance().addBackend(access));
5148
5149 // Find the SQL client socket.
5150 int sql_socket = findLastSocketFd();
5151 ASSERT_TRUE(sql_socket > last_open_socket);
5152
5153 // Verify we can execute a query. We don't care about the answer.
5154 ServerCollection servers;
5155 ASSERT_NO_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()));
5156
5157 // Now close the sql socket out from under backend client
5158 ASSERT_EQ(0, close(sql_socket));
5159
5160 // A query should fail with DbConnectionUnusable.
5161 ASSERT_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()),
5162 DbConnectionUnusable);
5163
5164 io_service_->poll();
5165
5166 // Our lost and recovered connectivity callback should have been invoked.
5167 EXPECT_EQ(1, db_lost_callback_called_);
5168 EXPECT_EQ(1, db_recovered_callback_called_);
5169 EXPECT_EQ(0, db_failed_callback_called_);
5170 }
5171
5172 void
testDbLostAndFailedCallback()5173 MySqlConfigBackendDHCPv6DbLostCallbackTest::testDbLostAndFailedCallback() {
5174 // Set the connectivity lost callback.
5175 isc::db::DatabaseConnection::db_lost_callback_ =
5176 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_lost_callback, this, ph::_1);
5177
5178 // Set the connectivity recovered callback.
5179 isc::db::DatabaseConnection::db_recovered_callback_ =
5180 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_recovered_callback, this, ph::_1);
5181
5182 // Set the connectivity failed callback.
5183 isc::db::DatabaseConnection::db_failed_callback_ =
5184 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_failed_callback, this, ph::_1);
5185
5186 std::string access = validConnectString();
5187 ConfigControlInfoPtr config_ctl_info(new ConfigControlInfo());
5188 config_ctl_info->addConfigDatabase(access);
5189 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5190
5191 // Find the most recently opened socket. Our SQL client's socket should
5192 // be the next one.
5193 int last_open_socket = findLastSocketFd();
5194
5195 // Fill holes.
5196 FillFdHoles holes(last_open_socket);
5197
5198 // Connect to the CB backend.
5199 ASSERT_NO_THROW(ConfigBackendDHCPv6Mgr::instance().addBackend(access));
5200
5201 // Find the SQL client socket.
5202 int sql_socket = findLastSocketFd();
5203 ASSERT_TRUE(sql_socket > last_open_socket);
5204
5205 // Verify we can execute a query. We don't care about the answer.
5206 ServerCollection servers;
5207 ASSERT_NO_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()));
5208
5209 access = invalidConnectString();
5210 CfgMgr::instance().clear();
5211 // by adding an invalid access will cause the manager factory to throw
5212 // resulting in failure to recreate the manager
5213 config_ctl_info.reset(new ConfigControlInfo());
5214 config_ctl_info->addConfigDatabase(access);
5215 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5216 const ConfigDbInfoList& cfg = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo()->getConfigDatabases();
5217 (const_cast<ConfigDbInfoList&>(cfg))[0].setAccessString(access, true);
5218
5219 // Now close the sql socket out from under backend client
5220 ASSERT_EQ(0, close(sql_socket));
5221
5222 // A query should fail with DbConnectionUnusable.
5223 ASSERT_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()),
5224 DbConnectionUnusable);
5225
5226 io_service_->poll();
5227
5228 // Our lost and failed connectivity callback should have been invoked.
5229 EXPECT_EQ(1, db_lost_callback_called_);
5230 EXPECT_EQ(0, db_recovered_callback_called_);
5231 EXPECT_EQ(1, db_failed_callback_called_);
5232 }
5233
5234 void
testDbLostAndRecoveredAfterTimeoutCallback()5235 MySqlConfigBackendDHCPv6DbLostCallbackTest::testDbLostAndRecoveredAfterTimeoutCallback() {
5236 // Set the connectivity lost callback.
5237 isc::db::DatabaseConnection::db_lost_callback_ =
5238 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_lost_callback, this, ph::_1);
5239
5240 // Set the connectivity recovered callback.
5241 isc::db::DatabaseConnection::db_recovered_callback_ =
5242 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_recovered_callback, this, ph::_1);
5243
5244 // Set the connectivity failed callback.
5245 isc::db::DatabaseConnection::db_failed_callback_ =
5246 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_failed_callback, this, ph::_1);
5247
5248 std::string access = validConnectString();
5249 std::string extra = " max-reconnect-tries=3 reconnect-wait-time=1";
5250 access += extra;
5251 ConfigControlInfoPtr config_ctl_info(new ConfigControlInfo());
5252 config_ctl_info->addConfigDatabase(access);
5253 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5254
5255 // Find the most recently opened socket. Our SQL client's socket should
5256 // be the next one.
5257 int last_open_socket = findLastSocketFd();
5258
5259 // Fill holes.
5260 FillFdHoles holes(last_open_socket);
5261
5262 // Connect to the CB backend.
5263 ASSERT_NO_THROW(ConfigBackendDHCPv6Mgr::instance().addBackend(access));
5264
5265 // Find the SQL client socket.
5266 int sql_socket = findLastSocketFd();
5267 ASSERT_TRUE(sql_socket > last_open_socket);
5268
5269 // Verify we can execute a query. We don't care about the answer.
5270 ServerCollection servers;
5271 ASSERT_NO_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()));
5272
5273 access = invalidConnectString();
5274 access += extra;
5275 CfgMgr::instance().clear();
5276 // by adding an invalid access will cause the manager factory to throw
5277 // resulting in failure to recreate the manager
5278 config_ctl_info.reset(new ConfigControlInfo());
5279 config_ctl_info->addConfigDatabase(access);
5280 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5281 const ConfigDbInfoList& cfg = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo()->getConfigDatabases();
5282 (const_cast<ConfigDbInfoList&>(cfg))[0].setAccessString(access, true);
5283
5284 // Now close the sql socket out from under backend client
5285 ASSERT_EQ(0, close(sql_socket));
5286
5287 // A query should fail with DbConnectionUnusable.
5288 ASSERT_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()),
5289 DbConnectionUnusable);
5290
5291 io_service_->poll();
5292
5293 // Our lost connectivity callback should have been invoked.
5294 EXPECT_EQ(1, db_lost_callback_called_);
5295 EXPECT_EQ(0, db_recovered_callback_called_);
5296 EXPECT_EQ(0, db_failed_callback_called_);
5297
5298 access = validConnectString();
5299 access += extra;
5300 CfgMgr::instance().clear();
5301 config_ctl_info.reset(new ConfigControlInfo());
5302 config_ctl_info->addConfigDatabase(access);
5303 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5304
5305 sleep(1);
5306
5307 io_service_->poll();
5308
5309 // Our lost and recovered connectivity callback should have been invoked.
5310 EXPECT_EQ(2, db_lost_callback_called_);
5311 EXPECT_EQ(1, db_recovered_callback_called_);
5312 EXPECT_EQ(0, db_failed_callback_called_);
5313
5314 sleep(1);
5315
5316 io_service_->poll();
5317
5318 // No callback should have been invoked.
5319 EXPECT_EQ(2, db_lost_callback_called_);
5320 EXPECT_EQ(1, db_recovered_callback_called_);
5321 EXPECT_EQ(0, db_failed_callback_called_);
5322 }
5323
5324 void
testDbLostAndFailedAfterTimeoutCallback()5325 MySqlConfigBackendDHCPv6DbLostCallbackTest::testDbLostAndFailedAfterTimeoutCallback() {
5326 // Set the connectivity lost callback.
5327 isc::db::DatabaseConnection::db_lost_callback_ =
5328 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_lost_callback, this, ph::_1);
5329
5330 // Set the connectivity recovered callback.
5331 isc::db::DatabaseConnection::db_recovered_callback_ =
5332 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_recovered_callback, this, ph::_1);
5333
5334 // Set the connectivity failed callback.
5335 isc::db::DatabaseConnection::db_failed_callback_ =
5336 std::bind(&MySqlConfigBackendDHCPv6DbLostCallbackTest::db_failed_callback, this, ph::_1);
5337
5338 std::string access = validConnectString();
5339 std::string extra = " max-reconnect-tries=3 reconnect-wait-time=1";
5340 access += extra;
5341 ConfigControlInfoPtr config_ctl_info(new ConfigControlInfo());
5342 config_ctl_info->addConfigDatabase(access);
5343 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5344
5345 // Find the most recently opened socket. Our SQL client's socket should
5346 // be the next one.
5347 int last_open_socket = findLastSocketFd();
5348
5349 // Fill holes.
5350 FillFdHoles holes(last_open_socket);
5351
5352 // Connect to the CB backend.
5353 ASSERT_NO_THROW(ConfigBackendDHCPv6Mgr::instance().addBackend(access));
5354
5355 // Find the SQL client socket.
5356 int sql_socket = findLastSocketFd();
5357 ASSERT_TRUE(sql_socket > last_open_socket);
5358
5359 // Verify we can execute a query. We don't care about the answer.
5360 ServerCollection servers;
5361 ASSERT_NO_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()));
5362
5363 access = invalidConnectString();
5364 access += extra;
5365 CfgMgr::instance().clear();
5366 // by adding an invalid access will cause the manager factory to throw
5367 // resulting in failure to recreate the manager
5368 config_ctl_info.reset(new ConfigControlInfo());
5369 config_ctl_info->addConfigDatabase(access);
5370 CfgMgr::instance().getCurrentCfg()->setConfigControlInfo(config_ctl_info);
5371 const ConfigDbInfoList& cfg = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo()->getConfigDatabases();
5372 (const_cast<ConfigDbInfoList&>(cfg))[0].setAccessString(access, true);
5373
5374 // Now close the sql socket out from under backend client
5375 ASSERT_EQ(0, close(sql_socket));
5376
5377 // A query should fail with DbConnectionUnusable.
5378 ASSERT_THROW(servers = ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()),
5379 DbConnectionUnusable);
5380
5381 io_service_->poll();
5382
5383 // Our lost connectivity callback should have been invoked.
5384 EXPECT_EQ(1, db_lost_callback_called_);
5385 EXPECT_EQ(0, db_recovered_callback_called_);
5386 EXPECT_EQ(0, db_failed_callback_called_);
5387
5388 sleep(1);
5389
5390 io_service_->poll();
5391
5392 // Our lost connectivity callback should have been invoked.
5393 EXPECT_EQ(2, db_lost_callback_called_);
5394 EXPECT_EQ(0, db_recovered_callback_called_);
5395 EXPECT_EQ(0, db_failed_callback_called_);
5396
5397 sleep(1);
5398
5399 io_service_->poll();
5400
5401 // Our lost and failed connectivity callback should have been invoked.
5402 EXPECT_EQ(3, db_lost_callback_called_);
5403 EXPECT_EQ(0, db_recovered_callback_called_);
5404 EXPECT_EQ(1, db_failed_callback_called_);
5405 }
5406
5407 /// @brief Verifies that db lost callback is not invoked on an open failure
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testNoCallbackOnOpenFailure)5408 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailure) {
5409 MultiThreadingTest mt(false);
5410 testNoCallbackOnOpenFailure();
5411 }
5412
5413 /// @brief Verifies that db lost callback is not invoked on an open failure
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testNoCallbackOnOpenFailureMultiThreading)5414 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
5415 MultiThreadingTest mt(true);
5416 testNoCallbackOnOpenFailure();
5417 }
5418
5419 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndRecoveredCallback)5420 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallback) {
5421 MultiThreadingTest mt(false);
5422 testDbLostAndRecoveredCallback();
5423 }
5424
5425 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndRecoveredCallbackMultiThreading)5426 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
5427 MultiThreadingTest mt(true);
5428 testDbLostAndRecoveredCallback();
5429 }
5430
5431 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndFailedCallback)5432 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallback) {
5433 MultiThreadingTest mt(false);
5434 testDbLostAndFailedCallback();
5435 }
5436
5437 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndFailedCallbackMultiThreading)5438 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
5439 MultiThreadingTest mt(true);
5440 testDbLostAndFailedCallback();
5441 }
5442
5443 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndRecoveredAfterTimeoutCallback)5444 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
5445 MultiThreadingTest mt(false);
5446 testDbLostAndRecoveredAfterTimeoutCallback();
5447 }
5448
5449 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading)5450 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
5451 MultiThreadingTest mt(true);
5452 testDbLostAndRecoveredAfterTimeoutCallback();
5453 }
5454
5455 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndFailedAfterTimeoutCallback)5456 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
5457 MultiThreadingTest mt(false);
5458 testDbLostAndFailedAfterTimeoutCallback();
5459 }
5460
5461 /// @brief Verifies that loss of connectivity to MySQL is handled correctly.
TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest,testDbLostAndFailedAfterTimeoutCallbackMultiThreading)5462 TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
5463 MultiThreadingTest mt(true);
5464 testDbLostAndFailedAfterTimeoutCallback();
5465 }
5466
5467 }
5468