management: FacePersistency field in ControlParameters

Change-Id: I3a93bd658d40f3d77f7790b72e8873646ecc7990
Refs: #2991
diff --git a/src/management/nfd-control-command.cpp b/src/management/nfd-control-command.cpp
index d8ab2c6..746db92 100644
--- a/src/management/nfd-control-command.cpp
+++ b/src/management/nfd-control-command.cpp
@@ -95,10 +95,20 @@
   : ControlCommand("faces", "create")
 {
   m_requestValidator
-    .required(CONTROL_PARAMETER_URI);
+    .required(CONTROL_PARAMETER_URI)
+    .optional(CONTROL_PARAMETER_FACE_PERSISTENCY);
   m_responseValidator
     .required(CONTROL_PARAMETER_URI)
-    .required(CONTROL_PARAMETER_FACE_ID);
+    .required(CONTROL_PARAMETER_FACE_ID)
+    .required(CONTROL_PARAMETER_FACE_PERSISTENCY);
+}
+
+void
+FaceCreateCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+  if (!parameters.hasFacePersistency()) {
+    parameters.setFacePersistency(FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  }
 }
 
 void
diff --git a/src/management/nfd-control-command.hpp b/src/management/nfd-control-command.hpp
index 9d3cbb3..2934e4e 100644
--- a/src/management/nfd-control-command.hpp
+++ b/src/management/nfd-control-command.hpp
@@ -142,6 +142,9 @@
   FaceCreateCommand();
 
   virtual void
+  applyDefaultsToRequest(ControlParameters& parameters) const;
+
+  virtual void
   validateResponse(const ControlParameters& parameters) const;
 };
 
diff --git a/src/management/nfd-control-parameters.cpp b/src/management/nfd-control-parameters.cpp
index d777843..d0a663e 100644
--- a/src/management/nfd-control-parameters.cpp
+++ b/src/management/nfd-control-parameters.cpp
@@ -50,6 +50,10 @@
 {
   size_t totalLength = 0;
 
+  if (this->hasFacePersistency()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::FacePersistency, m_facePersistency);
+  }
   if (this->hasExpirationPeriod()) {
     totalLength += prependNonNegativeIntegerBlock(encoder,
                    tlv::nfd::ExpirationPeriod, m_expirationPeriod.count());
@@ -180,6 +184,12 @@
   if (this->hasExpirationPeriod()) {
     m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
   }
+
+  val = m_wire.find(tlv::nfd::FacePersistency);
+  m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = val != m_wire.elements_end();
+  if (this->hasFacePersistency()) {
+    m_facePersistency = static_cast<FacePersistency>(readNonNegativeInteger(*val));
+  }
 }
 
 std::ostream&
diff --git a/src/management/nfd-control-parameters.hpp b/src/management/nfd-control-parameters.hpp
index 3a099cc..ab287a5 100644
--- a/src/management/nfd-control-parameters.hpp
+++ b/src/management/nfd-control-parameters.hpp
@@ -43,6 +43,7 @@
   CONTROL_PARAMETER_FLAGS,
   CONTROL_PARAMETER_STRATEGY,
   CONTROL_PARAMETER_EXPIRATION_PERIOD,
+  CONTROL_PARAMETER_FACE_PERSISTENCY,
   CONTROL_PARAMETER_UBOUND
 };
 
@@ -56,6 +57,7 @@
   "Flags",
   "Strategy",
   "ExpirationPeriod",
+  "FacePersistency",
 };
 
 /**
@@ -372,6 +374,36 @@
     return *this;
   }
 
+  bool
+  hasFacePersistency() const
+  {
+    return m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY];
+  }
+
+  FacePersistency
+  getFacePersistency() const
+  {
+    BOOST_ASSERT(this->hasFacePersistency());
+    return m_facePersistency;
+  }
+
+  ControlParameters&
+  setFacePersistency(FacePersistency persistency)
+  {
+    m_wire.reset();
+    m_facePersistency = persistency;
+    m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetFacePersistency()
+  {
+    m_wire.reset();
+    m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = false;
+    return *this;
+  }
+
   const std::vector<bool>&
   getPresentFields() const
   {
@@ -390,6 +422,7 @@
   uint64_t            m_flags;
   Name                m_strategy;
   time::milliseconds  m_expirationPeriod;
+  FacePersistency     m_facePersistency;
 
 private:
   mutable Block m_wire;
diff --git a/tests/unit-tests/management/nfd-control-command.t.cpp b/tests/unit-tests/management/nfd-control-command.t.cpp
index a82c8b9..e6f4d3b 100644
--- a/tests/unit-tests/management/nfd-control-command.t.cpp
+++ b/tests/unit-tests/management/nfd-control-command.t.cpp
@@ -37,7 +37,7 @@
   p1.setUri("tcp4://192.0.2.1")
     .setFaceId(4);
   BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError);
-  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+  BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError);
 
   ControlParameters p2;
   p2.setName("ndn:/example");
@@ -50,10 +50,27 @@
   BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
 
   ControlParameters p4;
-  p4.setUri("tcp4://192.0.2.1:6363");
-  Name n4;
-  BOOST_CHECK_NO_THROW(n4 = command.getRequestName("/PREFIX", p4));
-  BOOST_CHECK(Name("ndn:/PREFIX/faces/create").isPrefixOf(n4));
+  p4.setUri("tcp4://192.0.2.1")
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p4));
+
+  p4.unsetFacePersistency();
+  BOOST_CHECK_NO_THROW(command.validateRequest(p4));
+  command.applyDefaultsToRequest(p4);
+  BOOST_REQUIRE(p4.hasFacePersistency());
+  BOOST_CHECK_EQUAL(p4.getFacePersistency(), ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+
+  ControlParameters p5;
+  p5.setUri("tcp4://192.0.2.1")
+    .setFaceId(4)
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_NO_THROW(command.validateResponse(p5));
+
+  ControlParameters p6;
+  p6.setUri("tcp4://192.0.2.1:6363");
+  Name n6;
+  BOOST_CHECK_NO_THROW(n6 = command.getRequestName("/PREFIX", p6));
+  BOOST_CHECK(Name("ndn:/PREFIX/faces/create").isPrefixOf(n6));
 }
 
 BOOST_AUTO_TEST_CASE(FaceDestroy)
diff --git a/tests/unit-tests/management/nfd-control-parameters.t.cpp b/tests/unit-tests/management/nfd-control-parameters.t.cpp
index 9a959e4..5a3a864 100644
--- a/tests/unit-tests/management/nfd-control-parameters.t.cpp
+++ b/tests/unit-tests/management/nfd-control-parameters.t.cpp
@@ -33,11 +33,12 @@
 {
   ControlParameters parameters;
   parameters.setUri("tcp4://192.0.2.1:6363");
-
+  parameters.setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
   Block wire = parameters.wireEncode();
 
   ControlParameters decoded(wire);
   BOOST_CHECK_EQUAL(decoded.getUri(), "tcp4://192.0.2.1:6363");
+  BOOST_CHECK_EQUAL(decoded.getFacePersistency(), ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
 
   BOOST_CHECK_EQUAL(decoded.hasName(), false);
   BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
@@ -67,6 +68,7 @@
   BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
 
 BOOST_AUTO_TEST_CASE(FibOptions)
@@ -89,6 +91,7 @@
   BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
 
 BOOST_AUTO_TEST_CASE(StrategyChoiceOptions)
@@ -110,6 +113,7 @@
   BOOST_CHECK_EQUAL(decoded.hasCost(), false);
   BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
 
 BOOST_AUTO_TEST_CASE(RibOptions)
@@ -135,6 +139,7 @@
   BOOST_CHECK_EQUAL(decoded.hasUri(), false);
   BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/management/nfd-controller.t.cpp b/tests/unit-tests/management/nfd-controller.t.cpp
index 2419627..07c5894 100644
--- a/tests/unit-tests/management/nfd-controller.t.cpp
+++ b/tests/unit-tests/management/nfd-controller.t.cpp
@@ -103,7 +103,8 @@
 
   ControlParameters responseBody;
   responseBody.setUri("tcp4://192.0.2.1:6363")
-              .setFaceId(22);
+              .setFaceId(22)
+              .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
   ControlResponse responsePayload(201, "created");
   responsePayload.setBody(responseBody.wireEncode());