Browse Source

[2463] Reset configuration after each unit test.

Marcin Siodelski 12 years ago
parent
commit
2a9fd6c61e
2 changed files with 84 additions and 38 deletions
  1. 36 37
      src/bin/dhcp6/config_parser.cc
  2. 48 1
      src/bin/dhcp6/tests/config_parser_unittest.cc

+ 36 - 37
src/bin/dhcp6/config_parser.cc

@@ -505,7 +505,8 @@ public:
     ///
     /// Class constructor.
     OptionDataParser(const std::string&)
-        : options_(NULL) { }
+        : options_(NULL),
+          option_descriptor_(OptionPtr(), false) { }
 
     /// @brief Parses the single option data.
     ///
@@ -570,33 +571,31 @@ public:
     /// 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.
@@ -688,14 +687,11 @@ private:
             // 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.
@@ -706,7 +702,8 @@ private:
             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 << "): "
@@ -748,9 +745,8 @@ private:
     /// 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.
@@ -768,7 +764,7 @@ public:
     /// 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.
     ///
@@ -782,8 +778,8 @@ public:
             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);
@@ -805,6 +801,7 @@ public:
         BOOST_FOREACH(ParserPtr parser, parsers_) {
             parser->commit();
         }
+        std::swap(local_options_, *options_);
     }
 
     /// @brief Create DhcpDataListParser object
@@ -816,6 +813,8 @@ public:
         return (new OptionDataListParser(param_name));
     }
 
+    /// Intermediate option storage
+    OptionStorage local_options_;
     /// Pointer to options instances storage.
     OptionStorage* options_;
     /// Collection of parsers;

+ 48 - 1
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -54,6 +54,8 @@ public:
     }
 
     ~Dhcp6ParserTest() {
+        // Reset configuration database after each test.
+        resetConfiguration();
         delete srv_;
     };
 
@@ -118,6 +120,51 @@ public:
         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
@@ -693,7 +740,7 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
     // 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);