poke: exit with status 5 if prefix registration fails

Change-Id: I2147570c37146011c9a4e8c024b74bcafdf18e4e
diff --git a/manpages/ndnpoke.rst b/manpages/ndnpoke.rst
index caa7753..d92ba43 100644
--- a/manpages/ndnpoke.rst
+++ b/manpages/ndnpoke.rst
@@ -50,6 +50,8 @@
 
 2: Malformed command line
 
+5: Prefix registration failed
+
 Example
 -------
 
diff --git a/tests/peek/ndnpeek.t.cpp b/tests/peek/ndnpeek.t.cpp
index 73e6bfe..24e496b 100644
--- a/tests/peek/ndnpeek.t.cpp
+++ b/tests/peek/ndnpeek.t.cpp
@@ -156,7 +156,7 @@
   BOOST_CHECK_EQUAL(face.sentInterests.back().getForwardingHint().empty(), true);
   BOOST_CHECK_EQUAL(face.sentInterests.back().getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
   BOOST_CHECK_EQUAL(face.sentInterests.back().hasApplicationParameters(), false);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::DATA);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::DATA);
 }
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(NonDefault, OutputCheck, OutputChecks)
@@ -186,7 +186,7 @@
   BOOST_CHECK_EQUAL(face.sentInterests.back().getForwardingHint().empty(), true);
   BOOST_CHECK_EQUAL(face.sentInterests.back().getInterestLifetime(), 200_ms);
   BOOST_CHECK_EQUAL(face.sentInterests.back().hasApplicationParameters(), false);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::DATA);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::DATA);
 }
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(ReceiveNackWithReason, OutputCheck, OutputChecks)
@@ -205,7 +205,7 @@
 
   OutputCheck::checkOutput(output, nack);
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::NACK);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::NACK);
 }
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(ReceiveNackWithoutReason, OutputCheck, OutputChecks)
@@ -224,7 +224,7 @@
 
   OutputCheck::checkOutput(output, nack);
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::NACK);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::NACK);
 }
 
 BOOST_AUTO_TEST_CASE(NoTimeout)
@@ -240,12 +240,12 @@
   this->advanceClocks(io, 100_ms, 9);
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
   BOOST_CHECK_EQUAL(face.getNPendingInterests(), 1);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::UNKNOWN);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::UNKNOWN);
 
   this->advanceClocks(io, 100_ms, 2);
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
   BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::TIMEOUT);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
 }
 
 BOOST_AUTO_TEST_CASE(TimeoutLessThanLifetime)
@@ -262,7 +262,7 @@
 
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
   BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::TIMEOUT);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
 }
 
 BOOST_AUTO_TEST_CASE(TimeoutGreaterThanLifetime)
@@ -279,7 +279,7 @@
 
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
   BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
-  BOOST_CHECK(peek->getResultCode() == ResultCode::TIMEOUT);
+  BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestNdnPeek
diff --git a/tests/peek/ndnpoke.t.cpp b/tests/peek/ndnpoke.t.cpp
index 3f9a59b..46f445d 100644
--- a/tests/peek/ndnpoke.t.cpp
+++ b/tests/peek/ndnpoke.t.cpp
@@ -36,6 +36,7 @@
 
 using namespace ndn::tests;
 
+template<bool WANT_PREFIX_REG_REPLY = true>
 class NdnPokeFixture : public IdentityManagementTimeFixture
 {
 protected:
@@ -60,13 +61,13 @@
 
 protected:
   boost::asio::io_service io;
-  ndn::util::DummyClientFace face{io, m_keyChain, {true, true}};
+  ndn::util::DummyClientFace face{io, m_keyChain, {true, WANT_PREFIX_REG_REPLY}};
   std::stringstream payload{"Hello, world!\n"};
   unique_ptr<NdnPoke> poke;
 };
 
 BOOST_AUTO_TEST_SUITE(Peek)
-BOOST_FIXTURE_TEST_SUITE(TestNdnPoke, NdnPokeFixture)
+BOOST_FIXTURE_TEST_SUITE(TestNdnPoke, NdnPokeFixture<>)
 
 BOOST_AUTO_TEST_CASE(Basic)
 {
@@ -83,7 +84,7 @@
   this->advanceClocks(io, 1_ms, 10);
   io.run();
 
-  BOOST_CHECK(poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
   BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
   BOOST_CHECK(!face.sentData.back().getFinalBlock());
@@ -110,7 +111,7 @@
   this->advanceClocks(io, 1_ms, 10);
   io.run();
 
-  BOOST_CHECK(poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
   BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
   BOOST_CHECK(!face.sentData.back().getFinalBlock());
@@ -132,7 +133,7 @@
   this->advanceClocks(io, 1_ms, 10);
   io.run();
 
-  BOOST_CHECK(poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
   BOOST_CHECK_EQUAL(face.sentData.back().getName(), options.name);
   BOOST_REQUIRE(face.sentData.back().getFinalBlock());
@@ -154,7 +155,7 @@
   this->advanceClocks(io, 1_ms, 10);
   io.run();
 
-  BOOST_CHECK(poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
   BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
   BOOST_CHECK(!face.sentData.back().getFinalBlock());
@@ -171,7 +172,7 @@
   poke->start();
   this->advanceClocks(io, 1_ms, 10);
 
-  BOOST_CHECK(poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
   BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
   BOOST_CHECK(!face.sentData.back().getFinalBlock());
@@ -194,7 +195,7 @@
 
   this->advanceClocks(io, 1_s, 4);
 
-  BOOST_CHECK(!poke->didSendData());
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::UNKNOWN);
   BOOST_CHECK_EQUAL(face.sentData.size(), 0);
 
   // Check for prefix unregistration
@@ -202,6 +203,23 @@
   BOOST_CHECK_EQUAL(face.sentInterests.back().getName().getPrefix(4), "/localhost/nfd/rib/unregister");
 }
 
+BOOST_FIXTURE_TEST_CASE(PrefixRegTimeout, NdnPokeFixture<false>)
+{
+  initialize();
+
+  poke->start();
+  this->advanceClocks(io, 1_ms, 10);
+
+  // Check for prefix registration
+  BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face.sentInterests.front().getName().getPrefix(4), "/localhost/nfd/rib/register");
+
+  this->advanceClocks(io, 1_s, 10);
+
+  BOOST_CHECK(poke->getResult() == NdnPoke::Result::PREFIX_REG_FAIL);
+  BOOST_CHECK_EQUAL(face.sentData.size(), 0);
+}
+
 BOOST_AUTO_TEST_CASE(OversizedPacket)
 {
   payload << std::string(MAX_NDN_PACKET_SIZE, 'A');
@@ -213,8 +231,8 @@
   face.receive(*makeInterest("/poke/test"));
   BOOST_CHECK_THROW(face.processEvents(), Face::OversizedPacketError);
 
-  // No point in checking didSendData() here. The exception is thrown from processEvents(),
-  // not from put(), so didSendData() is still set to true even though no packets are sent.
+  // No point in checking getResult() here. The exception is thrown from processEvents(),
+  // not from put(), so the result is still DATA_SENT even though no packets were sent.
   BOOST_CHECK_EQUAL(face.sentData.size(), 0);
 }
 
diff --git a/tools/peek/ndnpeek/main.cpp b/tools/peek/ndnpeek/main.cpp
index f763b96..ead3d70 100644
--- a/tools/peek/ndnpeek/main.cpp
+++ b/tools/peek/ndnpeek/main.cpp
@@ -150,7 +150,7 @@
     program.start();
     face.processEvents();
 
-    return static_cast<int>(program.getResultCode());
+    return static_cast<int>(program.getResult());
   }
   catch (const std::exception& e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
diff --git a/tools/peek/ndnpeek/ndnpeek.cpp b/tools/peek/ndnpeek/ndnpeek.cpp
index 8ce23f6..8969216 100644
--- a/tools/peek/ndnpeek/ndnpeek.cpp
+++ b/tools/peek/ndnpeek/ndnpeek.cpp
@@ -79,7 +79,7 @@
 void
 NdnPeek::onData(const Data& data)
 {
-  m_resultCode = ResultCode::DATA;
+  m_result = Result::DATA;
   m_timeoutEvent.cancel();
 
   if (m_options.isVerbose) {
@@ -101,7 +101,7 @@
 void
 NdnPeek::onNack(const lp::Nack& nack)
 {
-  m_resultCode = ResultCode::NACK;
+  m_result = Result::NACK;
   m_timeoutEvent.cancel();
 
   lp::NackHeader header = nack.getHeader();
@@ -123,7 +123,7 @@
 void
 NdnPeek::onTimeout()
 {
-  m_resultCode = ResultCode::TIMEOUT;
+  m_result = Result::TIMEOUT;
   m_timeoutEvent.cancel();
 
   if (m_options.isVerbose) {
diff --git a/tools/peek/ndnpeek/ndnpeek.hpp b/tools/peek/ndnpeek/ndnpeek.hpp
index a544b37..0a9f503 100644
--- a/tools/peek/ndnpeek/ndnpeek.hpp
+++ b/tools/peek/ndnpeek/ndnpeek.hpp
@@ -55,25 +55,26 @@
   optional<time::milliseconds> timeout;
 };
 
-enum class ResultCode {
-  UNKNOWN = 1,
-  DATA = 0,
-  NACK = 4,
-  TIMEOUT = 3,
-};
-
 class NdnPeek : boost::noncopyable
 {
 public:
   NdnPeek(Face& face, const PeekOptions& options);
 
+  enum class Result {
+    DATA = 0,
+    UNKNOWN = 1,
+    // 2 is reserved for "malformed command line"
+    TIMEOUT = 3,
+    NACK = 4,
+  };
+
   /**
    * @return the result of NdnPeek execution
    */
-  ResultCode
-  getResultCode() const
+  Result
+  getResult() const
   {
-    return m_resultCode;
+    return m_result;
   }
 
   /**
@@ -112,7 +113,7 @@
   time::steady_clock::TimePoint m_sendTime;
   ScopedPendingInterestHandle m_pendingInterest;
   scheduler::ScopedEventId m_timeoutEvent;
-  ResultCode m_resultCode = ResultCode::UNKNOWN;
+  Result m_result = Result::UNKNOWN;
 };
 
 } // namespace peek
diff --git a/tools/peek/ndnpoke/main.cpp b/tools/peek/ndnpoke/main.cpp
index 33d91ea..fb26ab0 100644
--- a/tools/peek/ndnpoke/main.cpp
+++ b/tools/peek/ndnpoke/main.cpp
@@ -159,7 +159,7 @@
     program.start();
     face.processEvents();
 
-    return program.didSendData() ? 0 : 1;
+    return static_cast<int>(program.getResult());
   }
   catch (const std::exception& e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
diff --git a/tools/peek/ndnpoke/ndnpoke.cpp b/tools/peek/ndnpoke/ndnpoke.cpp
index 2934404..e6730cf 100644
--- a/tools/peek/ndnpoke/ndnpoke.cpp
+++ b/tools/peek/ndnpoke/ndnpoke.cpp
@@ -48,7 +48,7 @@
 
   if (m_options.wantForceData) {
     m_face.put(*data);
-    m_didSendData = true;
+    m_result = Result::DATA_SENT;
     return;
   }
 
@@ -56,7 +56,7 @@
     [this, data] (auto&&...) {
       m_timeoutEvent.cancel();
       m_face.put(*data);
-      m_didSendData = true;
+      m_result = Result::DATA_SENT;
       m_registeredPrefix.cancel();
     },
     [this] (auto&&) {
@@ -64,7 +64,8 @@
         m_registeredPrefix.cancel();
       });
     },
-    [] (auto&&, const auto& reason) {
+    [this] (auto&&, const auto& reason) {
+      m_result = Result::PREFIX_REG_FAIL;
       std::cerr << "Prefix registration failure (" << reason << ")\n";
     });
 }
diff --git a/tools/peek/ndnpoke/ndnpoke.hpp b/tools/peek/ndnpoke/ndnpoke.hpp
index af5ad34..e47da81 100644
--- a/tools/peek/ndnpoke/ndnpoke.hpp
+++ b/tools/peek/ndnpoke/ndnpoke.hpp
@@ -56,15 +56,27 @@
 public:
   NdnPoke(Face& face, KeyChain& keyChain, std::istream& input, const PokeOptions& options);
 
+  enum class Result {
+    DATA_SENT = 0,
+    UNKNOWN = 1,
+    // 2 is reserved for "malformed command line"
+    TIMEOUT = 3,
+    // 4 is reserved for "nack"
+    PREFIX_REG_FAIL = 5,
+  };
+
+  /**
+   * @return the result of NdnPoke execution
+   */
+  Result
+  getResult() const
+  {
+    return m_result;
+  }
+
   void
   start();
 
-  bool
-  didSendData() const
-  {
-    return m_didSendData;
-  }
-
 private:
   shared_ptr<Data>
   createData() const;
@@ -77,7 +89,7 @@
   Scheduler m_scheduler;
   ScopedRegisteredPrefixHandle m_registeredPrefix;
   scheduler::ScopedEventId m_timeoutEvent;
-  bool m_didSendData = false;
+  Result m_result = Result::UNKNOWN;
 };
 
 } // namespace peek