///
/// Class constructor.
OptionDataParser(const std::string&)
- : options_(NULL) { }
+ : options_(NULL),
+ option_descriptor_(OptionPtr(), false) { }
/// @brief Parses the single option data.
///
/// already present in the storage they will be replaced if options with
/// the same code are present in the intermediate storage.
///
- /// @throw isc::InvalidOperation if failed to set pointer to storage
- /// prior to calling commit. If that happens the data in the storage remain
- /// not modified.
+ /// @throw isc::InvalidOperation if failed to set pointer to storage failed
+ /// to call build() prior to commit. If that happens the data in the storage
+ /// remain not modified.
virtual void commit() {
if (options_ == NULL) {
isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
"commiting option data.");
+ } else if (!option_descriptor_.option) {
+ // Before we can commit the new option should be configured. If it is not
+ // than somebody must have called commit() before build().
+ isc_throw(isc::InvalidOperation, "Parser logic error: no option has been configured and"
+ " thus there is nothing to commit. Has build() been called?");
}
- // Get all new options from the intermediate storage. Note that it holds
- // all options configured since last commit.
- BOOST_FOREACH(Subnet::OptionDescriptor desc, intermediate_storage_) {
- uint16_t opt_type = desc.option->getType();
- Subnet::OptionContainerTypeIndex& idx = options_->get<1>();
- // Try to find options with the particular option code in the main
- // storage. If found, remove these options because they will be
- // replaced with new ones.
- Subnet::OptionContainerTypeRange range =
- idx.equal_range(opt_type);
- if (std::distance(range.first, range.second) > 0) {
- idx.erase(range.first, range.second);
- }
+ uint16_t opt_type = option_descriptor_.option->getType();
+ Subnet::OptionContainerTypeIndex& idx = options_->get<1>();
+ // Try to find options with the particular option code in the main
+ // storage. If found, remove these options because they will be
+ // replaced with new one.
+ Subnet::OptionContainerTypeRange range =
+ idx.equal_range(opt_type);
+ if (std::distance(range.first, range.second) > 0) {
+ idx.erase(range.first, range.second);
}
- // Append all options from the intermediate storage to the
- // main storage.
- options_->insert(options_->end(),
- intermediate_storage_.begin(),
- intermediate_storage_.end());
+ // Append new option to the main storage.
+ options_->push_back(option_descriptor_);
}
/// @brief Set storage for the parser.
// if definition does not exist.
OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
binary));
- // The intermerdiate storage is used here because it is
- // reset for each new parser created. Thus it collects only new
- // options and can be later used to merge new options with
- // options configured earlier (replace those that have the same
- // option code and add new to storage). Merge is performed in
- // commit stage.
- Subnet::OptionDescriptor desc(option, false);
- intermediate_storage_.push_back(desc);
+ // Created option is stored in option_descriptor_ class member until commit
+ // stage when it inserted into the main storage. If option with the same
+ // code exists in main storage already it replaces old option.
+ option_descriptor_.option = option;
+ option_descriptor_.persistent = false;
} else {
// We have exactly one option definition for the particular option code.
// use it to create option instance.
try {
OptionPtr option = factory(Option::V6, option_code, binary);
Subnet::OptionDescriptor desc(option, false);
- intermediate_storage_.push_back(desc);
+ option_descriptor_.option = option;
+ option_descriptor_.persistent = false;
} catch (const isc::Exception& ex) {
isc_throw(Dhcp6ConfigError, "Parser error: option data does not match"
<< " option definition (code " << option_code << "): "
/// Pointer to options storage. This storage is provided by
/// the calling class and is shared by all OptionDataParser objects.
OptionStorage* options_;
- /// Intermediate option storage. It holds all newly configured
- /// option values.
- OptionStorage intermediate_storage_;
+ /// Option descriptor holds newly configured option.
+ Subnet::OptionDescriptor option_descriptor_;
};
/// @brief Parser for option data values with ina subnet.
/// a global option containers (option_default). That storage location
/// is overriden on a subnet basis.
OptionDataListParser(const std::string&)
- : options_(&option_defaults) { }
+ : options_(&option_defaults), local_options_() { }
/// @brief Parses entries that define options' data for a subnet.
///
boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
// options_ member will hold instances of all options thus
// each OptionDataParser takes it as a storage.
- parser->setStorage(options_);
- // Build the instance of a singkle option.
+ parser->setStorage(&local_options_);
+ // Build the instance of a single option.
parser->build(option_value);
// Store a parser as it will be used to commit.
parsers_.push_back(parser);
BOOST_FOREACH(ParserPtr parser, parsers_) {
parser->commit();
}
+ std::swap(local_options_, *options_);
}
/// @brief Create DhcpDataListParser object
return (new OptionDataListParser(param_name));
}
+ /// Intermediate option storage
+ OptionStorage local_options_;
/// Pointer to options instances storage.
OptionStorage* options_;
/// Collection of parsers;
}
~Dhcp6ParserTest() {
+ // Reset configuration database after each test.
+ resetConfiguration();
delete srv_;
};
return (stream.str());
}
+ /// @brief Reset configuration database.
+ ///
+ /// This function resets configuration data base by
+ /// removing all subnets and option-data. Reset must
+ /// be performed after each test to make sure that
+ /// contents of the database do not affect result of
+ /// subsequent tests.
+ void resetConfiguration() {
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"valid-lifetime\": 4000, "
+ "\"subnet6\": [ ], "
+ "\"option-data\": [ ] }";
+
+ try {
+ ElementPtr json = Element::fromJSON(config);
+ status = configureDhcp6Server(*srv_, json);
+ } catch (const std::exception& ex) {
+ FAIL() << "Fatal error: unable to reset configuration database"
+ << " after the test. The following configuration was used"
+ << " to reset database: " << std::endl
+ << config << std::endl
+ << " and the following error message was returned:"
+ << ex.what() << std::endl;
+ }
+
+
+ // returned value should be 0 (configuration success)
+ if (!status) {
+ FAIL() << "Fatal error: unable to reset configuration database"
+ << " after the test. Configuration function returned"
+ << " NULL pointer" << std::endl;
+ }
+ comment_ = parseAnswer(rcode_, status);
+ if (rcode_ != 0) {
+ FAIL() << "Fatal error: unable to reset configuration database"
+ << " after the test. Configuration function returned"
+ << " error code " << rcode_ << std::endl;
+ }
+ }
+
/// @brief Test invalid option parameter value.
///
/// This test function constructs the simple configuration
// Option code 3 means OPTION_IA_NA.
params["code"] = "3";
params["data"] = "ABCDEF01 02030405 06070809";
-
+
std::string config = createConfigWithOption(params);
ElementPtr json = Element::fromJSON(config);