mgmt,main: configure tables with defaults when missing config section/values

refs: #1743

Change-Id: Id0c24bd2b2e86df763892d194f9c04777a369d0c
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 9fd191e..70717c6 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -158,6 +158,8 @@
     config.parse(m_configFile, true);
     config.parse(m_configFile, false);
 
+    tablesConfig.ensureTablesAreConfigured();
+
     // add FIB entry for NFD Management Protocol
     shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
     entry->addNextHop(m_internalFace, 0);
diff --git a/daemon/mgmt/tables-config-section.cpp b/daemon/mgmt/tables-config-section.cpp
index 0efa02d..124a2d3 100644
--- a/daemon/mgmt/tables-config-section.cpp
+++ b/daemon/mgmt/tables-config-section.cpp
@@ -33,6 +33,8 @@
 
 NFD_LOG_INIT("TablesConfigSection");
 
+const size_t TablesConfigSection::DEFAULT_CS_MAX_PACKETS = 65536;
+
 TablesConfigSection::TablesConfigSection(Cs& cs,
                                          Pit& pit,
                                          Fib& fib,
@@ -43,11 +45,32 @@
   // , m_fib(fib)
   // , m_strategyChoice(strategyChoice)
   // , m_measurements(measurements)
+  , m_areTablesConfigured(false)
 {
 
 }
 
 void
+TablesConfigSection::setConfigFile(ConfigFile& configFile)
+{
+  configFile.addSectionHandler("tables",
+                               bind(&TablesConfigSection::onConfig, this, _1, _2, _3));
+}
+
+
+void
+TablesConfigSection::ensureTablesAreConfigured()
+{
+  if (m_areTablesConfigured)
+    {
+      return;
+    }
+
+  NFD_LOG_INFO("Setting CS max packets to " << DEFAULT_CS_MAX_PACKETS);
+  m_cs.setLimit(DEFAULT_CS_MAX_PACKETS);
+}
+
+void
 TablesConfigSection::onConfig(const ConfigSection& configSection,
                               bool isDryRun,
                               const std::string& filename)
@@ -57,6 +80,8 @@
   //    cs_max_packets 65536
   // }
 
+  size_t nCsMaxPackets = DEFAULT_CS_MAX_PACKETS;
+
   boost::optional<const ConfigSection&> csMaxPacketsNode =
     configSection.get_child_optional("cs_max_packets");
 
@@ -70,18 +95,17 @@
           throw ConfigFile::Error("Invalid value for option \"cs_max_packets\""
                                   " in \"tables\" section");
         }
-      else if (!isDryRun)
-        {
-          m_cs.setLimit(*valCsMaxPackets);
-        }
-    }
-}
 
-void
-TablesConfigSection::setConfigFile(ConfigFile& configFile)
-{
-  configFile.addSectionHandler("tables",
-                               bind(&TablesConfigSection::onConfig, this, _1, _2, _3));
+      nCsMaxPackets = *valCsMaxPackets;
+    }
+
+  if (!isDryRun)
+    {
+      NFD_LOG_INFO("Setting CS max packets to " << nCsMaxPackets);
+
+      m_cs.setLimit(nCsMaxPackets);
+      m_areTablesConfigured = true;
+    }
 }
 
 } // namespace nfd
diff --git a/daemon/mgmt/tables-config-section.hpp b/daemon/mgmt/tables-config-section.hpp
index 482ceca..4571a59 100644
--- a/daemon/mgmt/tables-config-section.hpp
+++ b/daemon/mgmt/tables-config-section.hpp
@@ -39,7 +39,6 @@
 class TablesConfigSection
 {
 public:
-
   TablesConfigSection(Cs& cs,
                       Pit& pit,
                       Fib& fib,
@@ -50,6 +49,11 @@
   setConfigFile(ConfigFile& configFile);
 
   void
+  ensureTablesAreConfigured();
+
+private:
+
+  void
   onConfig(const ConfigSection& configSection,
            bool isDryRun,
            const std::string& filename);
@@ -60,6 +64,12 @@
   // Fib& m_fib;
   // StrategyChoice& m_strategyChoice;
   // Measurements& m_measurements;
+
+  bool m_areTablesConfigured;
+
+private:
+
+  static const size_t DEFAULT_CS_MAX_PACKETS;
 };
 
 } // namespace nfd
diff --git a/tests/daemon/mgmt/tables-config-section.cpp b/tests/daemon/mgmt/tables-config-section.cpp
index d27321f..6ec274c 100644
--- a/tests/daemon/mgmt/tables-config-section.cpp
+++ b/tests/daemon/mgmt/tables-config-section.cpp
@@ -54,7 +54,7 @@
   }
 
   bool
-  validateException(const ConfigFile::Error& exception, const std::string& expectedMsg)
+  validateException(const std::runtime_error& exception, const std::string& expectedMsg)
   {
     return exception.what() == expectedMsg;
   }
@@ -70,11 +70,18 @@
 
   TablesConfigSection m_tablesConfig;
   ConfigFile m_config;
-
 };
 
 BOOST_FIXTURE_TEST_SUITE(TestTableConfigSection, TablesConfigSectionFixture)
 
+BOOST_AUTO_TEST_CASE(ConfigureTablesWithDefaults)
+{
+  const size_t initialLimit = m_cs.getLimit();
+
+  m_tablesConfig.ensureTablesAreConfigured();
+  BOOST_CHECK_NE(initialLimit, m_cs.getLimit());
+}
+
 BOOST_AUTO_TEST_CASE(EmptyTablesSection)
 {
   const std::string CONFIG =
@@ -85,12 +92,15 @@
   const size_t nCsMaxPackets = m_cs.getLimit();
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, true));
-
   BOOST_CHECK_EQUAL(m_cs.getLimit(), nCsMaxPackets);
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, false));
+  BOOST_CHECK_NE(m_cs.getLimit(), nCsMaxPackets);
 
-  BOOST_CHECK_EQUAL(m_cs.getLimit(), nCsMaxPackets);
+  const size_t defaultLimit = m_cs.getLimit();
+
+  m_tablesConfig.ensureTablesAreConfigured();
+  BOOST_CHECK_EQUAL(defaultLimit, m_cs.getLimit());
 }
 
 BOOST_AUTO_TEST_CASE(ValidCsMaxPackets)
@@ -104,11 +114,12 @@
   BOOST_REQUIRE_NE(m_cs.getLimit(), 101);
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, true));
-
   BOOST_CHECK_NE(m_cs.getLimit(), 101);
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, false));
+  BOOST_CHECK_EQUAL(m_cs.getLimit(), 101);
 
+  m_tablesConfig.ensureTablesAreConfigured();
   BOOST_CHECK_EQUAL(m_cs.getLimit(), 101);
 }
 
@@ -127,6 +138,11 @@
                         ConfigFile::Error,
                         bind(&TablesConfigSectionFixture::validateException,
                              this, _1, expectedMsg));
+
+  BOOST_CHECK_EXCEPTION(runConfig(CONFIG, false),
+                        ConfigFile::Error,
+                        bind(&TablesConfigSectionFixture::validateException,
+                             this, _1, expectedMsg));
 }
 
 BOOST_AUTO_TEST_CASE(InvalidValueCsMaxPackets)
@@ -144,6 +160,52 @@
                         ConfigFile::Error,
                         bind(&TablesConfigSectionFixture::validateException,
                              this, _1, expectedMsg));
+
+
+  BOOST_CHECK_EXCEPTION(runConfig(CONFIG, false),
+                        ConfigFile::Error,
+                        bind(&TablesConfigSectionFixture::validateException,
+                             this, _1, expectedMsg));
+}
+
+class IgnoreNotTablesSection
+{
+public:
+  void
+  operator()(const std::string& filename,
+             const std::string& sectionName,
+             const ConfigSection& section,
+             bool isDryRun)
+
+  {
+    // Ignore "not_tables" section
+    if (sectionName == "not_tables")
+      {
+        // do nothing
+      }
+  }
+};
+
+BOOST_AUTO_TEST_CASE(MissingTablesSection)
+{
+  const std::string CONFIG =
+    "not_tables\n"
+    "{\n"
+    "  some_other_field 0\n"
+    "}\n";
+
+  ConfigFile passiveConfig((IgnoreNotTablesSection()));
+
+  const size_t initialLimit = m_cs.getLimit();
+
+  passiveConfig.parse(CONFIG, true, "dummy-config");
+  BOOST_REQUIRE_EQUAL(initialLimit, m_cs.getLimit());
+
+  passiveConfig.parse(CONFIG, false, "dummy-config");
+  BOOST_REQUIRE_EQUAL(initialLimit, m_cs.getLimit());
+
+  m_tablesConfig.ensureTablesAreConfigured();
+  BOOST_CHECK_NE(initialLimit, m_cs.getLimit());
 }
 
 BOOST_AUTO_TEST_SUITE_END()