update: Add/delete prefix to the conf file

refs: #4303

Change-Id: I401885bf76be90a5076365eebc311275461813c4
diff --git a/tests/update/test-save-delete-prefix.cpp b/tests/update/test-save-delete-prefix.cpp
new file mode 100644
index 0000000..7bbe06e
--- /dev/null
+++ b/tests/update/test-save-delete-prefix.cpp
@@ -0,0 +1,245 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "update/prefix-update-processor.hpp"
+#include "../control-commands.hpp"
+#include "../test-common.hpp"
+#include "nlsr.hpp"
+
+#include <ndn-cxx/interest.hpp>
+#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
+#include <ndn-cxx/mgmt/nfd/control-response.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/pib/identity.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <ndn-cxx/security/command-interest-signer.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include <boost/filesystem.hpp>
+
+namespace nlsr {
+namespace update {
+namespace test {
+
+namespace pt = boost::property_tree;
+using namespace pt;
+
+class PrefixSaveDeleteFixture : public nlsr::test::UnitTestTimeFixture
+{
+public:
+  PrefixSaveDeleteFixture()
+    : face(m_ioService, m_keyChain, {true, true})
+    , siteIdentityName(ndn::Name("/edu/test-site"))
+    , opIdentityName(ndn::Name("/edu/test-site").append(ndn::Name("%C1.Operator")))
+    , nlsr(m_ioService, m_scheduler, face, m_keyChain)
+    , SITE_CERT_PATH(boost::filesystem::current_path() / std::string("site.cert"))
+    , testConfFile("/tmp/nlsr.conf.test")
+    , counter(0)
+  {
+    std::ifstream source("/usr/local/etc/ndn/nlsr.conf.sample", std::ios::binary);
+    std::ofstream destination("/tmp/nlsr.conf.test", std::ios::binary);
+    destination << source.rdbuf();
+    source.close();
+    destination.close();
+
+    nlsr.setConfFileName(testConfFile);
+    siteIdentity = addIdentity(siteIdentityName);
+    saveCertificate(siteIdentity, SITE_CERT_PATH.string());
+
+    // Operator cert
+    opIdentity = addSubCertificate(opIdentityName, siteIdentity);
+    // Loading the security section's validator part into the validator
+    // See conf file processor for more details
+    std::ifstream inputFile;
+    inputFile.open(testConfFile);
+    BOOST_REQUIRE(inputFile.is_open());
+    pt::ptree pt;
+    boost::property_tree::read_info(inputFile, pt);
+    // Loads section and file name
+    for (const auto& section : pt) {
+      if (section.first == "security") {
+        auto it = section.second.begin();
+        it++;
+        if (it != pt.end() && it->first == "prefix-update-validator") {
+          nlsr.getPrefixUpdateProcessor().loadValidator(it->second, std::string(testConfFile));
+        }
+          break;
+      }
+    }
+    inputFile.close();
+    nlsr.loadCertToPublish(opIdentity.getDefaultKey().getDefaultCertificate());
+    // Site cert
+    siteIdentity = addIdentity(siteIdentityName);
+    saveCertificate(siteIdentity, SITE_CERT_PATH.string());
+
+    // Operator cert
+    opIdentity = addSubCertificate(opIdentityName, siteIdentity);
+    nlsr.loadCertToPublish(opIdentity.getDefaultKey().getDefaultCertificate());
+
+    // Set the network so the LSA prefix is constructed
+    nlsr.getConfParameter().setNetwork("/ndn");
+    nlsr.getConfParameter().setSiteName("/edu/test-site");
+    nlsr.getConfParameter().setRouterName("/%C1.Router/this-router");
+    nlsr.getConfParameter().buildRouterPrefix();
+    addIdentity(nlsr.getConfParameter().getRouterPrefix());
+
+    // Initialize NLSR so a sync socket is created
+    nlsr.initialize();
+    this->advanceClocks(ndn::time::milliseconds(10));
+    face.sentInterests.clear();
+  }
+
+  uint32_t
+  getResponseCode()
+  {
+    ndn::nfd::ControlResponse response;
+    for (const auto& data : face.sentData) {
+      response.wireDecode(data.getContent().blockFromValue());
+    }
+    return response.getCode();
+  }
+
+  bool
+  checkPrefix(const std::string prefixName)
+  {
+    counter = 0;
+    pt::ptree m_savePrefix;
+    pt::info_parser::read_info(testConfFile, m_savePrefix);
+    // counter helps to check if multiple prefix of same name exists on conf file
+    for (const auto& section : m_savePrefix.get_child("advertising")) {
+      std:: string b = section.second.get_value<std::string>();
+      if (b == prefixName) {
+        counter++;
+      }
+    }
+    if (counter > 0) {
+      return true;
+    }
+    return false;
+  }
+
+  ndn::Interest
+  advertiseWithdraw(std::string prefixName, std::string type, bool P_FLAG)
+  {
+    ndn::nfd::ControlParameters parameters;
+    parameters.setName(prefixName);
+    if (P_FLAG)
+    {
+      parameters.setFlags(PREFIX_FLAG);
+    }
+    ndn::Name advertiseCommand("/localhost/nlsr/prefix-update/advertise");
+    ndn::Name withdrawCommand("/localhost/nlsr/prefix-update/withdraw");
+    ndn:: Interest interestName;
+    ndn::security::CommandInterestSigner cis(m_keyChain);
+    // type true for advertise, else withdraw
+    if (type == "advertise") {
+      advertiseCommand.append(parameters.wireEncode());
+      interestName = cis.makeCommandInterest(advertiseCommand,
+                                             ndn::security::signingByIdentity(opIdentity));
+    }
+    else {
+      withdrawCommand.append(parameters.wireEncode());
+      interestName = cis.makeCommandInterest(withdrawCommand,
+                                             ndn::security::signingByIdentity(opIdentity));
+    }
+    return interestName;
+  }
+
+public:
+  ndn::util::DummyClientFace face;
+  ndn::Name siteIdentityName;
+  ndn::security::pib::Identity siteIdentity;
+
+  ndn::Name opIdentityName;
+  ndn::security::pib::Identity opIdentity;
+
+  Nlsr nlsr;
+  const boost::filesystem::path SITE_CERT_PATH;
+  ndn::Name sessionTime;
+  std::string testConfFile;
+  int counter;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestAdvertiseWithdrawPrefix, PrefixSaveDeleteFixture)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  // only advertise
+  face.receive(advertiseWithdraw("/prefix/to/save", "advertise", false));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(checkPrefix("/prefix/to/save"), false);
+  BOOST_CHECK_EQUAL(getResponseCode(), 200);
+  face.sentData.clear();
+
+  // trying to re-advertise
+  face.receive(advertiseWithdraw("/prefix/to/save", "advertise", false));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(getResponseCode(), 204);
+  face.sentData.clear();
+
+  // only withdraw
+  face.receive(advertiseWithdraw("/prefix/to/save", "withdraw", false));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(checkPrefix("/prefix/to/save"), false);
+  BOOST_CHECK_EQUAL(getResponseCode(), 200);
+  face.sentData.clear();
+
+  // trying to re-advertise
+  face.receive(advertiseWithdraw("/prefix/to/save", "withdraw", false));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(getResponseCode(), 204);
+  face.sentData.clear();
+}
+
+BOOST_AUTO_TEST_CASE(PrefixStillSavedAfterJustWithdrawn)
+{
+  // advertise and save
+  face.receive(advertiseWithdraw("/prefix/to/save", "advertise", true));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  face.sentData.clear();
+  BOOST_CHECK_EQUAL(checkPrefix("/prefix/to/save"), true);
+
+  // trying to advertise same name prefix
+  face.receive(advertiseWithdraw("/prefix/to/save", "advertise", true));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  BOOST_REQUIRE(counter == 1);
+  BOOST_CHECK_EQUAL(getResponseCode(), 406);
+  face.sentData.clear();
+
+  // only withdraw
+  face.receive(advertiseWithdraw("/prefix/to/save", "withdraw", false));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  // after withdrawing only prefix should still be there
+  BOOST_CHECK_EQUAL(checkPrefix("/prefix/to/save"), true);
+  BOOST_CHECK_EQUAL(getResponseCode(), 200);
+
+  // delete
+  face.receive(advertiseWithdraw("/prefix/to/save", "withdraw", true));
+  this->advanceClocks(ndn::time::milliseconds(10));
+  // after withdrawn delete prefix should be deleted from the file
+  BOOST_CHECK_EQUAL(getResponseCode(), 205);
+  BOOST_CHECK_EQUAL(checkPrefix("/prefix/to/save"), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace update
+} // namespace nlsr