summaryrefslogtreecommitdiffstats
path: root/src/bin/netconf/tests/netconf_controller_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/netconf/tests/netconf_controller_unittests.cc')
-rw-r--r--src/bin/netconf/tests/netconf_controller_unittests.cc225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/bin/netconf/tests/netconf_controller_unittests.cc b/src/bin/netconf/tests/netconf_controller_unittests.cc
new file mode 100644
index 0000000000..b9bb5eab19
--- /dev/null
+++ b/src/bin/netconf/tests/netconf_controller_unittests.cc
@@ -0,0 +1,225 @@
+// Copyright (C) 2018 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 <netconf/netconf_controller.h>
+#include <netconf/netconf_process.h>
+#include <cc/data.h>
+#include <process/testutils/d_test_stubs.h>
+#include <boost/pointer_cast.hpp>
+#include <sstream>
+
+using namespace std;
+using namespace isc::netconf;
+using namespace isc::data;
+using namespace isc::http;
+using namespace isc::process;
+using namespace boost::posix_time;
+
+namespace {
+
+#ifdef notyet
+/// @brief Valid Netconf Config used in tests.
+const char* valid_netconf_config =
+ "{"
+ " \"control-sockets\": {"
+ " \"dhcp4\": {"
+ " \"socket-type\": \"unix\","
+ " \"socket-name\": \"/first/dhcp4/socket\""
+ " },"
+ " \"dhcp6\": {"
+ " \"socket-type\": \"unix\","
+ " \"socket-name\": \"/first/dhcp6/socket\""
+ " }"
+ " }"
+ "}";
+#endif
+
+/// @brief test fixture class for testing NetconfController class. This
+/// class derives from DControllerTest and wraps NetconfController. Much
+/// of the underlying functionality is in the DControllerBase class which
+/// has extensive set of unit tests that are independent from Netconf.
+class NetconfControllerTest : public DControllerTest {
+public:
+
+ /// @brief Constructor.
+ NetconfControllerTest()
+ : DControllerTest(NetconfController::instance) {
+ }
+
+ /// @brief Returns pointer to NetconfProcess instance.
+ NetconfProcessPtr getNetconfProcess() {
+ return (boost::dynamic_pointer_cast<NetconfProcess>(getProcess()));
+ }
+
+ /// @brief Returns pointer to NetconfCfgMgr instance for a process.
+ NetconfCfgMgrPtr getNetconfCfgMgr() {
+ NetconfCfgMgrPtr p;
+ if (getNetconfProcess()) {
+ p = getNetconfProcess()->getNetconfCfgMgr();
+ }
+ return (p);
+ }
+
+ /// @brief Returns a pointer to the configuration context.
+ NetconfCfgContextPtr getNetconfCfgContext() {
+ NetconfCfgContextPtr p;
+ if (getNetconfCfgMgr()) {
+ p = getNetconfCfgMgr()->getNetconfCfgContext();
+ }
+ return (p);
+ }
+
+ /// @brief Compares the status in the given parse result to a given value.
+ ///
+ /// @param answer Element set containing an integer response and string
+ /// comment.
+ /// @param exp_status is an integer against which to compare the status.
+ /// @param exp_txt is expected text (not checked if "")
+ ///
+ void checkAnswer(isc::data::ConstElementPtr answer,
+ int exp_status,
+ string exp_txt = "") {
+
+ // Get rid of the outer list.
+ ASSERT_TRUE(answer);
+ ASSERT_EQ(Element::list, answer->getType());
+ ASSERT_LE(1, answer->size());
+ answer = answer->get(0);
+
+ int rcode = 0;
+ isc::data::ConstElementPtr comment;
+ comment = isc::config::parseAnswer(rcode, answer);
+
+ if (rcode != exp_status) {
+ ADD_FAILURE() << "Expected status code " << exp_status
+ << " but received " << rcode << ", comment: "
+ << (comment ? comment->str() : "(none)");
+ }
+
+ // Ok, parseAnswer interface is weird. If there are no arguments,
+ // it returns content of text. But if there is an argument,
+ // it returns the argument and it's not possible to retrieve
+ // "text" (i.e. comment).
+ if (comment->getType() != Element::string) {
+ comment = answer->get("text");
+ }
+
+ if (!exp_txt.empty()) {
+ EXPECT_EQ(exp_txt, comment->stringValue());
+ }
+ }
+
+};
+
+// Basic Controller instantiation testing.
+// Verifies that the controller singleton gets created and that the
+// basic derivation from the base class is intact.
+TEST_F(NetconfControllerTest, basicInstanceTesting) {
+ // Verify the we can the singleton instance can be fetched and that
+ // it is the correct type.
+ DControllerBasePtr& controller = DControllerTest::getController();
+ ASSERT_TRUE(controller);
+ ASSERT_NO_THROW(boost::dynamic_pointer_cast<NetconfController>(controller));
+
+ // Verify that controller's app name is correct.
+ EXPECT_TRUE(checkAppName(NetconfController::netconf_app_name_));
+
+ // Verify that controller's bin name is correct.
+ EXPECT_TRUE(checkBinName(NetconfController::netconf_bin_name_));
+
+ // Verify that controller's IOService exists.
+ EXPECT_TRUE(checkIOService());
+
+ // Verify that the Process does NOT exist.
+ EXPECT_FALSE(checkProcess());
+}
+
+
+// Tests basic command line processing.
+// Verifies that:
+// 1. Standard command line options are supported.
+// 2. Invalid options are detected.
+TEST_F(NetconfControllerTest, commandLineArgs) {
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-c"),
+ const_cast<char*>(DControllerTest::CFG_TEST_FILE),
+ const_cast<char*>("-d") };
+ int argc = 4;
+
+ // Verify that verbose flag is false initially.
+ EXPECT_TRUE(checkVerbose(false));
+
+ // Verify that standard options can be parsed without error.
+ EXPECT_NO_THROW(parseArgs(argc, argv));
+
+ // Verify that verbose flag is true.
+ EXPECT_TRUE(checkVerbose(true));
+
+ // Verify configuration file name is correct.
+ EXPECT_TRUE(checkConfigFileName(DControllerTest::CFG_TEST_FILE));
+
+ // Verify that an unknown option is detected.
+ char* argv2[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-x") };
+ argc = 2;
+ EXPECT_THROW(parseArgs(argc, argv2), InvalidUsage);
+}
+
+// Tests application process creation and initialization.
+// Verifies that the process can be successfully created and initialized.
+TEST_F(NetconfControllerTest, initProcessTesting) {
+ ASSERT_NO_THROW(initProcess());
+ EXPECT_TRUE(checkProcess());
+}
+
+#ifdef notyet
+// Tests launch and normal shutdown (stand alone mode).
+// This creates an interval timer to generate a normal shutdown and then
+// launches with a valid, stand-alone command line and no simulated errors.
+TEST_F(NetconfControllerTest, launchNormalShutdown) {
+ // Write valid_netconf_config and then run launch() for 1000 ms.
+ time_duration elapsed_time;
+ runWithConfig(valid_netconf_config, 1000, elapsed_time);
+
+ // Give a generous margin to accommodate slower test environs.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() >= 800 &&
+ elapsed_time.total_milliseconds() <= 1300);
+}
+
+// Tests that the SIGINT triggers a normal shutdown.
+TEST_F(NetconfControllerTest, sigintShutdown) {
+ // Setup to raise SIGHUP in 1 ms.
+ TimedSignal sighup(*getIOService(), SIGINT, 1);
+
+ // Write valid_netconf_config and then run launch() for a maximum
+ // of 1000 ms.
+ time_duration elapsed_time;
+ runWithConfig(valid_netconf_config, 1000, elapsed_time);
+
+ // Signaled shutdown should make our elapsed time much smaller than
+ // the maximum run time. Give generous margin to accommodate slow
+ // test environs.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
+}
+
+// Tests that the SIGTERM triggers a normal shutdown.
+TEST_F(NetconfControllerTest, sigtermShutdown) {
+ // Setup to raise SIGHUP in 1 ms.
+ TimedSignal sighup(*getIOService(), SIGTERM, 1);
+
+ // Write valid_netconf_config and then run launch() for a maximum of 1 s.
+ time_duration elapsed_time;
+ runWithConfig(valid_netconf_config, 1000, elapsed_time);
+
+ // Signaled shutdown should make our elapsed time much smaller than
+ // the maximum run time. Give generous margin to accommodate slow
+ // test environs.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
+}
+#endif
+
+}