123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- // Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #include <config.h>
- #include <cc/command_interpreter.h>
- #include <config/module_spec.h>
- #include <dhcpsrv/parsers/dhcp_parsers.h>
- #include <process/testutils/d_test_stubs.h>
- #include <process/d_cfg_mgr.h>
- #include <boost/foreach.hpp>
- #include <boost/date_time/posix_time/posix_time.hpp>
- #include <gtest/gtest.h>
- #include <sstream>
- using namespace std;
- using namespace isc;
- using namespace isc::config;
- using namespace isc::process;
- using namespace isc::data;
- using namespace boost::posix_time;
- namespace {
- /// @brief Test Class for verifying that configuration context cannot be null
- /// during construction.
- class DCtorTestCfgMgr : public DCfgMgrBase {
- public:
- /// @brief Constructor - Note that is passes in an empty configuration
- /// pointer to the base class constructor.
- DCtorTestCfgMgr() : DCfgMgrBase(DCfgContextBasePtr()) {
- }
- /// @brief Destructor
- virtual ~DCtorTestCfgMgr() {
- }
- /// @brief Dummy implementation as this method is abstract.
- virtual DCfgContextBasePtr createNewContext() {
- return (DCfgContextBasePtr());
- }
- /// @brief Returns summary of configuration in the textual format.
- virtual std::string getConfigSummary(const uint32_t) {
- return ("");
- }
- };
- /// @brief Test fixture class for testing DCfgMgrBase class.
- /// It maintains an member instance of DStubCfgMgr and derives from
- /// ConfigParseTest fixture, thus providing methods for converting JSON
- /// strings to configuration element sets, checking parse results, and
- /// accessing the configuration context.
- class DStubCfgMgrTest : public ConfigParseTest {
- public:
- /// @brief Constructor
- DStubCfgMgrTest():cfg_mgr_(new DStubCfgMgr) {
- }
- /// @brief Destructor
- ~DStubCfgMgrTest() {
- }
- /// @brief Convenience method which returns a DStubContextPtr to the
- /// configuration context.
- ///
- /// @return returns a DStubContextPtr.
- DStubContextPtr getStubContext() {
- return (boost::dynamic_pointer_cast<DStubContext>
- (cfg_mgr_->getContext()));
- }
- /// @brief Configuration manager instance.
- DStubCfgMgrPtr cfg_mgr_;
- };
- ///@brief Tests basic construction/destruction of configuration manager.
- /// Verifies that:
- /// 1. Proper construction succeeds.
- /// 2. Configuration context is initialized by construction.
- /// 3. Destruction works properly.
- /// 4. Construction with a null context is not allowed.
- TEST(DCfgMgrBase, construction) {
- DCfgMgrBasePtr cfg_mgr;
- // Verify that configuration manager constructions without error.
- ASSERT_NO_THROW(cfg_mgr.reset(new DStubCfgMgr()));
- // Verify that the context can be retrieved and is not null.
- DCfgContextBasePtr context = cfg_mgr->getContext();
- EXPECT_TRUE(context);
- // Verify that the manager can be destructed without error.
- EXPECT_NO_THROW(cfg_mgr.reset());
- // Verify that an attempt to construct a manger with a null context fails.
- ASSERT_THROW(DCtorTestCfgMgr(), DCfgMgrBaseError);
- }
- ///@brief Tests fundamental aspects of configuration parsing.
- /// Verifies that:
- /// 1. A correctly formed simple configuration parses without error.
- /// 2. An error building the element is handled.
- /// 3. An error committing the element is handled.
- /// 4. An unknown element error is handled.
- TEST_F(DStubCfgMgrTest, basicParseTest) {
- // Create a simple configuration.
- string config = "{ \"test-value\": [] } ";
- ASSERT_TRUE(fromJSON(config));
- // Verify that we can parse a simple configuration.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
- // Verify that an unknown element error is caught and returns a failed
- // parse result.
- SimFailure::set(SimFailure::ftElementUnknown);
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(1));
- }
- ///@brief Tests ordered and non-ordered element parsing
- /// This test verifies that:
- /// 1. Non-ordered parsing parses elements in the order they are presented
- /// by the configuration set (as-they-come).
- /// 2. A parse order list with too few elements is detected.
- /// 3. Ordered parsing parses the elements in the order specified by the
- /// configuration manager's parse order list.
- /// 4. A parse order list with too many elements is detected.
- TEST_F(DStubCfgMgrTest, parseOrderTest) {
- // Element ids used for test.
- std::string charlie("charlie");
- std::string bravo("bravo");
- std::string alpha("alpha");
- std::string string_test("string_test");
- std::string uint32_test("uint32_test");
- std::string bool_test("bool_test");
- // Create the test configuration with the elements in "random" order.
- // NOTE that element sets produced by isc::data::Element::fromJSON(),
- // are in lexical order by element_id. This means that iterating over
- // such an element set, will present the elements in lexical order. Should
- // this change, this test will need to be modified accordingly.
- string config = "{"
- " \"string_test\": \"hoopla\", "
- " \"bravo\": [], "
- " \"uint32_test\": 55, "
- " \"alpha\": {}, "
- " \"charlie\": [], "
- " \"bool_test\": true "
- "} ";
- ASSERT_TRUE(fromJSON(config));
- // Verify that non-ordered parsing, results in an as-they-come parse order.
- // Create an expected parse order.
- // (NOTE that iterating over Element sets produced by fromJSON() will
- // present the elements in lexical order. Should this change, the expected
- // order list below would need to be changed accordingly).
- ElementIdList order_expected;
- // scalar params should be first and lexically
- order_expected.push_back(bool_test);
- order_expected.push_back(string_test);
- order_expected.push_back(uint32_test);
- // objects second and lexically
- order_expected.push_back(alpha);
- order_expected.push_back(bravo);
- order_expected.push_back(charlie);
- // Verify that the manager has an EMPTY parse order list. (Empty list
- // instructs the manager to parse them as-they-come.)
- EXPECT_EQ(0, cfg_mgr_->getParseOrder().size());
- // Parse the configuration, verify it parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
- // Verify that the parsed order matches what we expected.
- EXPECT_TRUE(cfg_mgr_->parsed_order_ == order_expected);
- // Clear the manager's parse order "memory".
- cfg_mgr_->parsed_order_.clear();
- // Create a parse order list that has too few entries. Verify that
- // when parsing the test config, it fails.
- cfg_mgr_->addToParseOrder(charlie);
- // Verify the parse order list is the size we expect.
- EXPECT_EQ(1, cfg_mgr_->getParseOrder().size());
- // Verify the configuration fails.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(1));
- // Verify that the configuration parses correctly, when the parse order
- // is correct. Add the needed entries to the parse order
- cfg_mgr_->addToParseOrder(bravo);
- cfg_mgr_->addToParseOrder(alpha);
- // Verify the parse order list is the size we expect.
- EXPECT_EQ(3, cfg_mgr_->getParseOrder().size());
- // Clear the manager's parse order "memory".
- cfg_mgr_->parsed_order_.clear();
- // Verify the configuration parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
- // Build expected order
- // primitives should be first and lexically
- order_expected.clear();
- order_expected.push_back(bool_test);
- order_expected.push_back(string_test);
- order_expected.push_back(uint32_test);
- // objects second and by the parse order
- order_expected.push_back(charlie);
- order_expected.push_back(bravo);
- order_expected.push_back(alpha);
- // Verify that the parsed order is the order we configured.
- EXPECT_TRUE(cfg_mgr_->parsed_order_ == order_expected);
- // Create a parse order list that has too many entries. Verify that
- // when parsing the test config, it fails.
- cfg_mgr_->addToParseOrder("delta");
- // Verify the parse order list is the size we expect.
- EXPECT_EQ(4, cfg_mgr_->getParseOrder().size());
- // Verify the configuration fails.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(1));
- }
- /// @brief Tests that element ids supported by the base class as well as those
- /// added by the derived class function properly.
- /// This test verifies that:
- /// 1. Boolean parameters can be parsed and retrieved.
- /// 2. Uint32 parameters can be parsed and retrieved.
- /// 3. String parameters can be parsed and retrieved.
- /// 4. Map elements can be parsed and retrieved.
- /// 5. List elements can be parsed and retrieved.
- /// 6. Parsing a second configuration, updates the existing context values
- /// correctly.
- TEST_F(DStubCfgMgrTest, simpleTypesTest) {
- // Create a configuration with all of the parameters.
- string config = "{ \"bool_test\": true , "
- " \"uint32_test\": 77 , "
- " \"string_test\": \"hmmm chewy\" , "
- " \"map_test\" : {} , "
- " \"list_test\": [] }";
- ASSERT_TRUE(fromJSON(config));
- // Verify that the configuration parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- ASSERT_TRUE(checkAnswer(0));
- DStubContextPtr context = getStubContext();
- ASSERT_TRUE(context);
- // Verify that the boolean parameter was parsed correctly by retrieving
- // its value from the context.
- bool actual_bool = false;
- EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
- EXPECT_EQ(true, actual_bool);
- // Verify that the uint32 parameter was parsed correctly by retrieving
- // its value from the context.
- uint32_t actual_uint32 = 0;
- EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
- EXPECT_EQ(77, actual_uint32);
- // Verify that the string parameter was parsed correctly by retrieving
- // its value from the context.
- std::string actual_string = "";
- EXPECT_NO_THROW(context->getParam("string_test", actual_string));
- EXPECT_EQ("hmmm chewy", actual_string);
- isc::data::ConstElementPtr object;
- EXPECT_NO_THROW(context->getObjectParam("map_test", object));
- EXPECT_TRUE(object);
- EXPECT_NO_THROW(context->getObjectParam("list_test", object));
- EXPECT_TRUE(object);
- // Create a configuration which "updates" all of the parameter values.
- string config2 = "{ \"bool_test\": false , "
- " \"uint32_test\": 88 , "
- " \"string_test\": \"ewww yuk!\" , "
- " \"map_test2\" : {} , "
- " \"list_test2\": [] }";
- ASSERT_TRUE(fromJSON(config2));
- // Verify that the configuration parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
- context = getStubContext();
- ASSERT_TRUE(context);
- // Verify that the boolean parameter was updated correctly by retrieving
- // its value from the context.
- actual_bool = true;
- EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
- EXPECT_FALSE(actual_bool);
- // Verify that the uint32 parameter was updated correctly by retrieving
- // its value from the context.
- actual_uint32 = 0;
- EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
- EXPECT_EQ(88, actual_uint32);
- // Verify that the string parameter was updated correctly by retrieving
- // its value from the context.
- actual_string = "";
- EXPECT_NO_THROW(context->getParam("string_test", actual_string));
- EXPECT_EQ("ewww yuk!", actual_string);
- // Verify previous objects are not there.
- EXPECT_THROW(context->getObjectParam("map_test", object),
- isc::dhcp::DhcpConfigError);
- EXPECT_THROW(context->getObjectParam("list_test", object),
- isc::dhcp::DhcpConfigError);
- // Verify new map object is there.
- EXPECT_NO_THROW(context->getObjectParam("map_test2", object));
- EXPECT_TRUE(object);
- // Verify new list object is there.
- EXPECT_NO_THROW(context->getObjectParam("list_test2", object));
- EXPECT_TRUE(object);
- }
- /// @brief Tests that the configuration context is preserved after failure
- /// during parsing causes a rollback.
- /// 1. Verifies configuration context rollback.
- TEST_F(DStubCfgMgrTest, rollBackTest) {
- // Create a configuration with all of the parameters.
- string config = "{ \"bool_test\": true , "
- " \"uint32_test\": 77 , "
- " \"string_test\": \"hmmm chewy\" , "
- " \"map_test\" : {} , "
- " \"list_test\": [] }";
- ASSERT_TRUE(fromJSON(config));
- // Verify that the configuration parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
- DStubContextPtr context = getStubContext();
- ASSERT_TRUE(context);
- // Verify that all of parameters have the expected values.
- bool actual_bool = false;
- EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
- EXPECT_EQ(true, actual_bool);
- uint32_t actual_uint32 = 0;
- EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
- EXPECT_EQ(77, actual_uint32);
- std::string actual_string = "";
- EXPECT_NO_THROW(context->getParam("string_test", actual_string));
- EXPECT_EQ("hmmm chewy", actual_string);
- isc::data::ConstElementPtr object;
- EXPECT_NO_THROW(context->getObjectParam("map_test", object));
- EXPECT_TRUE(object);
- EXPECT_NO_THROW(context->getObjectParam("list_test", object));
- EXPECT_TRUE(object);
- // Create a configuration which "updates" all of the parameter values
- // plus one unknown at the end.
- string config2 = "{ \"bool_test\": false , "
- " \"uint32_test\": 88 , "
- " \"string_test\": \"ewww yuk!\" , "
- " \"map_test2\" : {} , "
- " \"list_test2\": [] , "
- " \"zeta_unknown\": 33 } ";
- ASSERT_TRUE(fromJSON(config2));
- // Force a failure on the last element
- SimFailure::set(SimFailure::ftElementUnknown);
- answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(1));
- context = getStubContext();
- ASSERT_TRUE(context);
- // Verify that all of parameters have the original values.
- actual_bool = false;
- EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
- EXPECT_EQ(true, actual_bool);
- actual_uint32 = 0;
- EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
- EXPECT_EQ(77, actual_uint32);
- actual_string = "";
- EXPECT_NO_THROW(context->getParam("string_test", actual_string));
- EXPECT_EQ("hmmm chewy", actual_string);
- EXPECT_NO_THROW(context->getObjectParam("map_test", object));
- EXPECT_TRUE(object);
- EXPECT_NO_THROW(context->getObjectParam("list_test", object));
- EXPECT_TRUE(object);
- }
- // Tests that configuration element position is returned by getParam variants.
- TEST_F(DStubCfgMgrTest, paramPosition) {
- // Create a configuration with one of each scalar types. We end them
- // with line feeds so we can test position value.
- string config = "{ \"bool_test\": true , \n"
- " \"uint32_test\": 77 , \n"
- " \"string_test\": \"hmmm chewy\" }";
- ASSERT_TRUE(fromJSON(config));
- // Verify that the configuration parses without error.
- answer_ = cfg_mgr_->parseConfig(config_set_);
- ASSERT_TRUE(checkAnswer(0));
- DStubContextPtr context = getStubContext();
- ASSERT_TRUE(context);
- // Verify that the boolean parameter was parsed correctly by retrieving
- // its value from the context.
- bool actual_bool = false;
- isc::data::Element::Position pos;
- EXPECT_NO_THROW(pos = context->getParam("bool_test", actual_bool));
- EXPECT_EQ(true, actual_bool);
- EXPECT_EQ(1, pos.line_);
- // Verify that the uint32 parameter was parsed correctly by retrieving
- // its value from the context.
- uint32_t actual_uint32 = 0;
- EXPECT_NO_THROW(pos = context->getParam("uint32_test", actual_uint32));
- EXPECT_EQ(77, actual_uint32);
- EXPECT_EQ(2, pos.line_);
- // Verify that the string parameter was parsed correctly by retrieving
- // its value from the context.
- std::string actual_string = "";
- EXPECT_NO_THROW(pos = context->getParam("string_test", actual_string));
- EXPECT_EQ("hmmm chewy", actual_string);
- EXPECT_EQ(3, pos.line_);
- // Verify that an optional parameter that is not defined, returns the
- // zero position.
- pos = isc::data::Element::ZERO_POSITION();
- EXPECT_NO_THROW(pos = context->getParam("bogus_value",
- actual_string, true));
- EXPECT_EQ(pos.file_, isc::data::Element::ZERO_POSITION().file_);
- }
- } // end of anonymous namespace
|