DELETE_OPTION_DEF4_CODE_NAME,
DELETE_ALL_OPTION_DEFS4,
DELETE_OPTION4,
+ DELETE_ALL_OPTIONS4_UNASSIGNED,
DELETE_OPTION4_SUBNET_ID,
DELETE_OPTION4_POOL_RANGE,
DELETE_OPTION4_SHARED_NETWORK,
createInputContextBinding(option),
MySqlBinding::createNull(),
MySqlBinding::createNull(),
- MySqlBinding::createTimestamp(option->getModificationTime())
+ MySqlBinding::createTimestamp(option->getModificationTime()),
+ MySqlBinding::createString(tag),
+ MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
+ MySqlBinding::condCreateString(option->space_name_)
};
MySqlTransaction transaction(conn_);
MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
server_selector, "global option set", false);
- if (existing_option) {
- in_bindings.push_back(MySqlBinding::createString(tag));
- in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(option->option_->getType()));
- in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
- conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4,
- in_bindings);
-
- } else {
+ if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4,
+ in_bindings) == 0) {
+ // Remove the 3 bindings used only in case of update.
+ in_bindings.resize(in_bindings.size() - 3);
insertOption4(server_selector, in_bindings);
-
}
transaction.commit();
conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::
DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED,
MySqlBindingCollection());
- /// @todo delete dangling options and option definitions.
+
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::
+ DELETE_ALL_OPTIONS4_UNASSIGNED,
+ MySqlBindingCollection());
+ /// @todo delete option definitions.
}
transaction.commit();
conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::
DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED,
MySqlBindingCollection());
- /// @todo delete dangling options and option definitions.
+
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::
+ DELETE_ALL_OPTIONS4_UNASSIGNED,
+ MySqlBindingCollection());
+
+ /// @todo delete dangling option definitions.
}
transaction.commit();
MYSQL_DELETE_OPTION(dhcp4, AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
},
+ // Delete all options which are unassigned to any servers.
+ { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTIONS4_UNASSIGNED,
+ MYSQL_DELETE_OPTION_UNASSIGNED(dhcp4)
+ },
+
// Delete single option from a subnet.
{ MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID,
MYSQL_DELETE_OPTION(dhcp4,
DELETE_OPTION_DEF6_CODE_NAME,
DELETE_ALL_OPTION_DEFS6,
DELETE_OPTION6,
+ DELETE_ALL_OPTIONS6_UNASSIGNED,
DELETE_OPTION6_SUBNET_ID,
DELETE_OPTION6_POOL_RANGE,
DELETE_OPTION6_PD_POOL,
MySqlBinding::createNull(),
MySqlBinding::createNull(),
MySqlBinding::createTimestamp(option->getModificationTime()),
- MySqlBinding::createNull()
+ MySqlBinding::createNull(),
+ MySqlBinding::createString(tag),
+ MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
+ MySqlBinding::condCreateString(option->space_name_)
};
MySqlTransaction transaction(conn_);
MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
server_selector, "global option set", false);
- if (existing_option) {
- in_bindings.push_back(MySqlBinding::createString(tag));
- in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(option->option_->getType()));
- in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
- conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
- in_bindings);
-
- } else {
+ if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
+ in_bindings) == 0) {
+ // Remove the 3 bindings used only in case of update.
+ in_bindings.resize(in_bindings.size() - 3);
insertOption6(server_selector, in_bindings);
-
}
transaction.commit();
conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
MySqlBindingCollection());
- /// @todo delete dangling options and option definitions.
+
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
+ DELETE_ALL_OPTIONS6_UNASSIGNED,
+ MySqlBindingCollection());
+ /// @todo delete dangling option definitions.
}
transaction.commit();
conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
MySqlBindingCollection());
- /// @todo delete dangling options and option definitions.
+
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
+ DELETE_ALL_OPTIONS6_UNASSIGNED,
+ MySqlBindingCollection());
+ /// @todo delete dangling option definitions.
}
transaction.commit();
MYSQL_DELETE_OPTION(dhcp6, AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
},
+ // Delete all options which are unassigned to any servers.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTIONS6_UNASSIGNED,
+ MYSQL_DELETE_OPTION_UNASSIGNED(dhcp6)
+ },
+
// Delete single option from a subnet.
{ MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID,
MYSQL_DELETE_OPTION(dhcp6,
uint64_t last_option_id = 0;
+ OptionContainer local_options;
+
conn_.selectQuery(index, in_bindings, out_bindings,
- [this, universe, &options, &last_option_id]
+ [this, universe, &local_options, &last_option_id]
(MySqlBindingCollection& out_bindings) {
// Parse option.
if (!out_bindings[0]->amNull() &&
OptionDescriptorPtr desc = processOptionRow(universe, out_bindings.begin());
if (desc) {
// server_tag for the global option
- desc->setServerTag(out_bindings[12]->getString());
- static_cast<void>(options.push_back(*desc));
+ ServerTag last_option_server_tag(out_bindings[12]->getString());
+ desc->setServerTag(last_option_server_tag.get());
+
+ // If we're fetching options for a given server (explicit server
+ // tag is provided), it takes precedence over the same option
+ // specified for all servers. Therefore, we check if the given
+ // option already exists and belongs to 'all'.
+ auto& index = local_options.get<1>();
+ auto existing_it_pair = index.equal_range(desc->option_->getType());
+ auto existing_it = existing_it_pair.first;
+ bool found = false;
+ for ( ; existing_it != existing_it_pair.second; ++existing_it) {
+ if (existing_it->space_name_ == desc->space_name_) {
+ found = true;
+ // This option was already fetched. Let's check if we should
+ // replace it or not.
+ if (!last_option_server_tag.amAll() && existing_it->hasAllServerTag()) {
+ index.replace(existing_it, *desc);
+ return;
+ }
+ break;
+ }
+ }
+
+ // If there is no such global option yet or the existing option
+ // belongs to a different server and the inserted option is not
+ // for all servers.
+ if (!found ||
+ (!existing_it->hasServerTag(last_option_server_tag) &&
+ !last_option_server_tag.amAll())) {
+ static_cast<void>(local_options.push_back(*desc));
+ }
}
}
});
+
+ // Append the options fetched by this function into the container supplied
+ // by the caller. The container supplied by the caller may already hold
+ // some options fetched for other server tags.
+ options.insert(options.end(), local_options.begin(), local_options.end());
}
OptionDescriptorPtr
"INNER JOIN " #table_prefix "_server AS s" \
" ON a.server_id = s.id " \
"WHERE (s.tag = ? OR s.id = 1) " #__VA_ARGS__ \
- " ORDER BY o.option_id"
+ " ORDER BY o.option_id, s.id"
#define MYSQL_GET_OPTION4(...) \
MYSQL_GET_OPTION_COMMON(dhcp4, "", __VA_ARGS__)
"WHERE s.tag = ? " #__VA_ARGS__
#endif
+#ifndef MYSQL_DELETE_OPTION_UNASSIGNED
+#define MYSQL_DELETE_OPTION_UNASSIGNED(table_prefix, ...) \
+ "DELETE o FROM " #table_prefix "_options AS o " \
+ "LEFT JOIN " #table_prefix "_options_server AS a " \
+ " ON o.option_id = a.option_id " \
+ "WHERE a.option_id IS NULL " #__VA_ARGS__
+#endif
+
#ifndef MYSQL_DELETE_OPTION_POOL_RANGE
#define MYSQL_DELETE_OPTION_POOL_RANGE(table_prefix, ...) \
"DELETE o FROM " #table_prefix "_options AS o " \
desc.space_name_ = "isc";
test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+ desc = createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
+ true, false, "my-boot-file-2");
+ desc.space_name_ = DHCP4_OPTION_SPACE;
+ desc.setContext(user_context);
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
+ true, false, "my-boot-file-3");
+ desc.space_name_ = DHCP4_OPTION_SPACE;
+ desc.setContext(user_context);
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
// Add definitions for DHCPv4 non-standard options in case we need to
// compare subnets, networks and pools in JSON format. In that case,
// the @c toElement functions require option definitions to generate the
opt_boot_file_name);
// Retrieve the option again and make sure that updates were
- // properly propagated to the database.
- returned_opt_boot_file_name = cbptr_->getOption4(ServerSelector::ALL(),
+ // properly propagated to the database. Use explicit server selector
+ // which should also return this option.
+ returned_opt_boot_file_name = cbptr_->getOption4(ServerSelector::ONE("server1"),
opt_boot_file_name->option_->getType(),
opt_boot_file_name->space_name_);
ASSERT_TRUE(returned_opt_boot_file_name);
}
}
+// This test verifies that it is possible to differentiate between the
+// global options by server tag and that the option specified for the
+// particular server overrides the value specified for all servers.
+TEST_F(MySqlConfigBackendDHCPv4Test, globalOptions4WithServerTags) {
+ OptionDescriptorPtr opt_boot_file_name1 = test_options_[0];
+ OptionDescriptorPtr opt_boot_file_name2 = test_options_[6];
+ OptionDescriptorPtr opt_boot_file_name3 = test_options_[7];
+
+ EXPECT_THROW(cbptr_->createUpdateOption4(ServerSelector::ONE("server1"),
+ opt_boot_file_name1),
+ DbOperationError);
+
+ // Create two servers.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[1]));
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp4_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set");
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[2]));
+ {
+ SCOPED_TRACE("server2 is created");
+ testNewAuditEntry("dhcp4_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set");
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption4(ServerSelector::ONE("server1"),
+ opt_boot_file_name1));
+ {
+ SCOPED_TRACE("global option for server1 is set");
+ // The value of 3 means there should be 3 audit entries available for the
+ // server1, two that indicate creation of the servers and one that we
+ // validate, which sets the global option.
+ testNewAuditEntry("dhcp4_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ONE("server1"),
+ 3, 1);
+
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption4(ServerSelector::ONE("server2"),
+ opt_boot_file_name2));
+ {
+ SCOPED_TRACE("global option for server2 is set");
+ // Same as in case of the server1, there should be 3 audit entries and
+ // we validate one of them.
+ testNewAuditEntry("dhcp4_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ONE("server2"),
+ 3, 1);
+
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption4(ServerSelector::ALL(),
+ opt_boot_file_name3));
+ {
+ SCOPED_TRACE("global option for all servers is set");
+ // There should be one new audit entry for all servers. It logs
+ // the insertion of the global option.
+ testNewAuditEntry("dhcp4_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ALL(),
+ 1, 1);
+
+ }
+
+ OptionDescriptorPtr returned_option;
+
+ // Try to fetch the option specified for all servers. It should return
+ // the third option.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption4(ServerSelector::ALL(),
+ opt_boot_file_name3->option_->getType(),
+ opt_boot_file_name3->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_boot_file_name3, *returned_option);
+
+ // Try to fetch the option specified for the server1. It should override the
+ // option specified for all servers.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption4(ServerSelector::ONE("server1"),
+ opt_boot_file_name1->option_->getType(),
+ opt_boot_file_name1->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_boot_file_name1, *returned_option);
+
+ // The same in case of the server2.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption4(ServerSelector::ONE("server2"),
+ opt_boot_file_name2->option_->getType(),
+ opt_boot_file_name2->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_boot_file_name2, *returned_option);
+
+ OptionContainer returned_options;
+
+ // Try to fetch the collection of global options for the server1, server2
+ // and server3. The server3 does not have an explicit value so for this server
+ // we should get the option associated with "all" servers.
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions4(ServerSelector::
+ MULTIPLE({ "server1", "server2",
+ "server3" }));
+ );
+ ASSERT_EQ(3, returned_options.size());
+
+ // Check that expected options have been returned.
+ auto current_option = returned_options.begin();
+ testOptionsEquivalent(*opt_boot_file_name1, *current_option);
+ testOptionsEquivalent(*opt_boot_file_name2, *(++current_option));
+ testOptionsEquivalent(*opt_boot_file_name3, *(++current_option));
+
+ // Try to fetch the collection of options specified for all servers.
+ // This excludes the options specific to server1 and server2. It returns
+ // only the common ones.
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions4(ServerSelector::ALL());
+ );
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_boot_file_name3, *returned_options.begin());
+
+ // Delete the server1. It should remove associations of this server with the
+ // option and the option itself.
+ EXPECT_NO_THROW(cbptr_->deleteServer4(ServerTag("server1")));
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions4(ServerSelector::ONE("server1"));
+ );
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_boot_file_name3, *returned_options.begin());
+
+ {
+ SCOPED_TRACE("DELETE audit entry for the global option after server deletion");
+ testNewAuditEntry("dhcp4_options",
+ AuditEntry::ModificationType::DELETE,
+ "deleting a server", ServerSelector::ONE("server1"),
+ 2, 1);
+ }
+
+ // Attempt to delete global option for server1.
+ uint64_t deleted_num = 0;
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption4(ServerSelector::ONE("server1"),
+ opt_boot_file_name1->option_->getType(),
+ opt_boot_file_name1->space_name_));
+ EXPECT_EQ(0, deleted_num);
+
+ // Deleting the existing option for server2 should succeed.
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption4(ServerSelector::ONE("server2"),
+ opt_boot_file_name2->option_->getType(),
+ opt_boot_file_name2->space_name_));
+ EXPECT_EQ(1, deleted_num);
+
+ // Create this option again to test that deletion of all servers removes it too.
+ EXPECT_NO_THROW(cbptr_->createUpdateOption4(ServerSelector::ONE("server2"),
+ opt_boot_file_name2));
+
+ // Delete all servers, except 'all'.
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteAllServers4());
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions4(ServerSelector::ALL());
+ );
+ EXPECT_EQ(1, deleted_num);
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_boot_file_name3, *returned_options.begin());
+
+ {
+ SCOPED_TRACE("DELETE audit entry for the global option after deletion of"
+ " all servers");
+ testNewAuditEntry("dhcp4_options",
+ AuditEntry::ModificationType::DELETE,
+ "deleting all servers", ServerSelector::ONE("server2"),
+ 4, 1);
+ }
+}
+
// This test verifies that all global options can be retrieved.
TEST_F(MySqlConfigBackendDHCPv4Test, getAllOptions4) {
// Add three global options to the database.
desc.space_name_ = "isc";
test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+ desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
+ true, false, "my-timezone-2");
+ desc.space_name_ = DHCP6_OPTION_SPACE;
+ desc.setContext(user_context);
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
+ true, false, "my-timezone-3");
+ desc.space_name_ = DHCP6_OPTION_SPACE;
+ desc.setContext(user_context);
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
// Add definitions for DHCPv6 non-standard options in case we need to
// compare subnets, networks and pools in JSON format. In that case,
// the @c toElement functions require option definitions to generate the
opt_posix_timezone);
// Retrieve the option again and make sure that updates were
- // properly propagated to the database.
- returned_opt_posix_timezone = cbptr_->getOption6(ServerSelector::ALL(),
+ // properly propagated to the database. Use explicit server selector
+ // which should also return this option.
+ returned_opt_posix_timezone = cbptr_->getOption6(ServerSelector::ONE("server1"),
opt_posix_timezone->option_->getType(),
opt_posix_timezone->space_name_);
ASSERT_TRUE(returned_opt_posix_timezone);
}
}
+// This test verifies that it is possible to differentiate between the
+// global options by server tag and that the option specified for the
+// particular server overrides the value specified for all servers.
+TEST_F(MySqlConfigBackendDHCPv6Test, globalOptions6WithServerTags) {
+ OptionDescriptorPtr opt_timezone1 = test_options_[0];
+ OptionDescriptorPtr opt_timezone2 = test_options_[6];
+ OptionDescriptorPtr opt_timezone3 = test_options_[7];
+
+ EXPECT_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server1"),
+ opt_timezone1),
+ DbOperationError);
+
+ // Create two servers.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set");
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
+ {
+ SCOPED_TRACE("server2 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set");
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server1"),
+ opt_timezone1));
+ {
+ SCOPED_TRACE("global option for server1 is set");
+ // The value of 3 means there should be 3 audit entries available for the
+ // server1, two that indicate creation of the servers and one that we
+ // validate, which sets the global option.
+ testNewAuditEntry("dhcp6_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ONE("server1"),
+ 3, 1);
+
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server2"),
+ opt_timezone2));
+ {
+ SCOPED_TRACE("global option for server2 is set");
+ // Same as in case of the server1, there should be 3 audit entries and
+ // we validate one of them.
+ testNewAuditEntry("dhcp6_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ONE("server2"),
+ 3, 1);
+
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ALL(),
+ opt_timezone3));
+ {
+ SCOPED_TRACE("global option for all servers is set");
+ // There should be one new audit entry for all servers. It logs
+ // the insertion of the global option.
+ testNewAuditEntry("dhcp6_options",
+ AuditEntry::ModificationType::CREATE,
+ "global option set",
+ ServerSelector::ALL(),
+ 1, 1);
+
+ }
+
+ OptionDescriptorPtr returned_option;
+
+ // Try to fetch the option specified for all servers. It should return
+ // the third option.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption6(ServerSelector::ALL(),
+ opt_timezone3->option_->getType(),
+ opt_timezone3->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_timezone3, *returned_option);
+
+ // Try to fetch the option specified for the server1. It should override the
+ // option specified for all servers.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption6(ServerSelector::ONE("server1"),
+ opt_timezone1->option_->getType(),
+ opt_timezone1->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_timezone1, *returned_option);
+
+ // The same in case of the server2.
+ EXPECT_NO_THROW(
+ returned_option = cbptr_->getOption6(ServerSelector::ONE("server2"),
+ opt_timezone2->option_->getType(),
+ opt_timezone2->space_name_);
+ );
+ ASSERT_TRUE(returned_option);
+ testOptionsEquivalent(*opt_timezone2, *returned_option);
+
+ OptionContainer returned_options;
+
+ // Try to fetch the collection of global options for the server1, server2
+ // and server3. The server3 does not have an explicit value so for this server
+ // we should get the option associated with "all" servers.
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions6(ServerSelector::
+ MULTIPLE({ "server1", "server2",
+ "server3" }));
+ );
+ ASSERT_EQ(3, returned_options.size());
+
+ // Check that expected options have been returned.
+ auto current_option = returned_options.begin();
+ testOptionsEquivalent(*opt_timezone1, *current_option);
+ testOptionsEquivalent(*opt_timezone2, *(++current_option));
+ testOptionsEquivalent(*opt_timezone3, *(++current_option));
+
+ // Try to fetch the collection of options specified for all servers.
+ // This excludes the options specific to server1 and server2. It returns
+ // only the common ones.
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions6(ServerSelector::ALL());
+ );
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
+
+ // Delete the server1. It should remove associations of this server with the
+ // option and the option itself.
+ EXPECT_NO_THROW(cbptr_->deleteServer6(ServerTag("server1")));
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions6(ServerSelector::ONE("server1"));
+ );
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
+
+ {
+ SCOPED_TRACE("DELETE audit entry for the global option after server deletion");
+ testNewAuditEntry("dhcp6_options",
+ AuditEntry::ModificationType::DELETE,
+ "deleting a server", ServerSelector::ONE("server1"),
+ 2, 1);
+ }
+
+ // Attempt to delete global option for server1.
+ uint64_t deleted_num = 0;
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption6(ServerSelector::ONE("server1"),
+ opt_timezone1->option_->getType(),
+ opt_timezone1->space_name_));
+ EXPECT_EQ(0, deleted_num);
+
+ // Deleting the existing option for server2 should succeed.
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteOption6(ServerSelector::ONE("server2"),
+ opt_timezone2->option_->getType(),
+ opt_timezone2->space_name_));
+ EXPECT_EQ(1, deleted_num);
+
+ // Create this option again to test that deletion of all servers removes it too.
+ EXPECT_NO_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server2"),
+ opt_timezone2));
+
+ // Delete all servers, except 'all'.
+ EXPECT_NO_THROW(deleted_num = cbptr_->deleteAllServers6());
+ EXPECT_NO_THROW(
+ returned_options = cbptr_->getAllOptions6(ServerSelector::ALL());
+ );
+ EXPECT_EQ(1, deleted_num);
+ ASSERT_EQ(1, returned_options.size());
+ testOptionsEquivalent(*opt_timezone3, *returned_options.begin());
+
+ {
+ SCOPED_TRACE("DELETE audit entry for the global option after deletion of"
+ " all servers");
+ testNewAuditEntry("dhcp6_options",
+ AuditEntry::ModificationType::DELETE,
+ "deleting all servers", ServerSelector::ONE("server2"),
+ 4, 1);
+ }
+}
+
// This test verifies that all global options can be retrieved.
TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptions6) {
// Add three global options to the database.