mgmt: implement cs/config command

refs #4050

Change-Id: I86b050ac062855bad66197a775a502007e687d8d
diff --git a/daemon/mgmt/cs-manager.cpp b/daemon/mgmt/cs-manager.cpp
index 62c0b8f..5c6c450 100644
--- a/daemon/mgmt/cs-manager.cpp
+++ b/daemon/mgmt/cs-manager.cpp
@@ -31,12 +31,41 @@
 CsManager::CsManager(Cs& cs, const ForwarderCounters& fwCnt,
                      Dispatcher& dispatcher, CommandAuthenticator& authenticator)
   : NfdManagerBase(dispatcher, authenticator, "cs")
+  , m_cs(cs)
   , m_fwCnt(fwCnt)
 {
+  registerCommandHandler<ndn::nfd::CsConfigCommand>("config",
+    bind(&CsManager::changeConfig, this, _4, _5));
+
   registerStatusDatasetHandler("info", bind(&CsManager::serveInfo, this, _1, _2, _3));
 }
 
 void
+CsManager::changeConfig(const ControlParameters& parameters,
+                        const ndn::mgmt::CommandContinuation& done)
+{
+  using ndn::nfd::CsFlagBit;
+
+  if (parameters.hasCapacity()) {
+    m_cs.setLimit(parameters.getCapacity());
+  }
+
+  if (parameters.hasFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT)) {
+    m_cs.enableAdmit(parameters.getFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT));
+  }
+
+  if (parameters.hasFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE)) {
+    m_cs.enableServe(parameters.getFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE));
+  }
+
+  ControlParameters body;
+  body.setCapacity(m_cs.getLimit());
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT, m_cs.shouldAdmit(), false);
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE, m_cs.shouldServe(), false);
+  done(ControlResponse(200, "OK").setBody(body.wireEncode()));
+}
+
+void
 CsManager::serveInfo(const Name& topPrefix, const Interest& interest,
                      ndn::mgmt::StatusDatasetContext& context) const
 {
diff --git a/daemon/mgmt/cs-manager.hpp b/daemon/mgmt/cs-manager.hpp
index 800502d..6a862f1 100644
--- a/daemon/mgmt/cs-manager.hpp
+++ b/daemon/mgmt/cs-manager.hpp
@@ -42,6 +42,10 @@
             Dispatcher& dispatcher, CommandAuthenticator& authenticator);
 
 private:
+  void
+  changeConfig(const ControlParameters& parameters,
+               const ndn::mgmt::CommandContinuation& done);
+
   /** \brief serve CS information dataset
    */
   void
@@ -49,6 +53,7 @@
             ndn::mgmt::StatusDatasetContext& context) const;
 
 private:
+  Cs& m_cs;
   const ForwarderCounters& m_fwCnt;
 };
 
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index 10b49c3..0370cf9 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -251,6 +251,7 @@
     {
       faces
       fib
+      cs
       strategy-choice
     }
   }
diff --git a/tests/daemon/mgmt/cs-manager.t.cpp b/tests/daemon/mgmt/cs-manager.t.cpp
index a6bbb89..3edc439 100644
--- a/tests/daemon/mgmt/cs-manager.t.cpp
+++ b/tests/daemon/mgmt/cs-manager.t.cpp
@@ -39,7 +39,7 @@
     , m_manager(m_cs, m_fwCnt, m_dispatcher, *m_authenticator)
   {
     setTopPrefix();
-    // setPrivilege("cs"); not needed until there's a control command
+    setPrivilege("cs");
   }
 
 protected:
@@ -51,6 +51,51 @@
 BOOST_AUTO_TEST_SUITE(Mgmt)
 BOOST_FIXTURE_TEST_SUITE(TestCsManager, CsManagerFixture)
 
+BOOST_AUTO_TEST_CASE(Config)
+{
+  using ndn::nfd::CsFlagBit;
+  const Name cmdPrefix("/localhost/nfd/cs/config");
+
+  // setup initial CS config
+  m_cs.setLimit(22129);
+  m_cs.enableAdmit(false);
+  m_cs.enableServe(true);
+
+  // send empty cs/config command
+  auto req = makeControlCommandRequest(cmdPrefix, ControlParameters());
+  receiveInterest(req);
+
+  // response shall reflect current config
+  ControlParameters body;
+  body.setCapacity(22129);
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT, false, false);
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE, true, false);
+  BOOST_CHECK_EQUAL(checkResponse(0, req.getName(),
+                                  ControlResponse(200, "OK").setBody(body.wireEncode())),
+                    CheckResponseResult::OK);
+
+  // send filled cs/config command
+  ControlParameters parameters;
+  parameters.setCapacity(18609);
+  parameters.setFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT, true);
+  parameters.setFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE, false);
+  req = makeControlCommandRequest(cmdPrefix, parameters);
+  receiveInterest(req);
+
+  // response shall reflect updated config
+  body.setCapacity(18609);
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_ADMIT, true, false);
+  body.setFlagBit(CsFlagBit::BIT_CS_ENABLE_SERVE, false, false);
+  BOOST_CHECK_EQUAL(checkResponse(1, req.getName(),
+                                  ControlResponse(200, "OK").setBody(body.wireEncode())),
+                    CheckResponseResult::OK);
+
+  // CS shall have updated config
+  BOOST_CHECK_EQUAL(m_cs.getLimit(), 18609);
+  BOOST_CHECK_EQUAL(m_cs.shouldAdmit(), true);
+  BOOST_CHECK_EQUAL(m_cs.shouldServe(), false);
+}
+
 BOOST_AUTO_TEST_CASE(Info)
 {
   m_fwCnt.nCsHits.set(362);