Add test nack scenario for best-route, and a framework to support tests tools
refs #3157
Change-Id: I12d0241bd45e1af6796765a03751e445a6a23525
diff --git a/install_helpers/install_tools.py b/install_helpers/install_tools.py
new file mode 100644
index 0000000..5af3396
--- /dev/null
+++ b/install_helpers/install_tools.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python2
+import os
+
+# Install tools
+def run():
+ print "\nINSTALLING tools"
+ print "***********************"
+ helper_path = os.path.dirname(os.path.realpath(__file__))
+ cwd_path = os.getcwd()
+ os.chdir(helper_path)
+ os.chdir("tools")
+ os.system("make")
+ os.system("sudo make install")
+ os.chdir(cwd_path)
diff --git a/install_helpers/tools/Makefile b/install_helpers/tools/Makefile
new file mode 100644
index 0000000..fa5c8cb
--- /dev/null
+++ b/install_helpers/tools/Makefile
@@ -0,0 +1,20 @@
+CXX = g++
+CXXFLAGS = -std=c++11 -Wall -Werror `pkg-config --cflags libndn-cxx`
+LIBS = `pkg-config --libs libndn-cxx`
+DESTDIR ?= /usr/local
+
+PROGRAMS = test-nack-consumer
+
+all: $(PROGRAMS)
+
+%: %.cpp
+ $(CXX) $(CXXFLAGS) -o $@ $< $(LIBS)
+
+clean:
+ rm -f $(PROGRAMS)
+
+install: all
+ cp $(PROGRAMS) $(DESTDIR)/bin/
+
+uninstall:
+ cd $(DESTDIR)/bin && rm -f $(PROGRAMS)
diff --git a/install_helpers/tools/README b/install_helpers/tools/README
new file mode 100644
index 0000000..5db0657
--- /dev/null
+++ b/install_helpers/tools/README
@@ -0,0 +1,21 @@
+# ndn integration-tests
+
+This directory contains tools required by one or more integration tests.
+Tools are built automatically during the installation phase.
+
+## Instructions for adding a new tool:
+------------------------------------
+1. Keep each program to a single cpp file when feasible.
+2. In each program source code, insert a comment to indicate which test case(s) uses this program
+3. Add the tool name to the Makefile programs list.
+
+## Build Instructions
+
+To compile and install:
+
+ make
+ sudo make install
+
+To uninstall:
+
+ sudo make uninstall
\ No newline at end of file
diff --git a/install_helpers/tools/test-nack-consumer.cpp b/install_helpers/tools/test-nack-consumer.cpp
new file mode 100644
index 0000000..fb6cb96
--- /dev/null
+++ b/install_helpers/tools/test-nack-consumer.cpp
@@ -0,0 +1,225 @@
+/**
+ * This program is used by test_nack interation test.
+ * The program implements a simple consumer that sends one or
+ * two interests and prints the network response (timeout, data or nack).
+ * ndnpeek is not sufficient since it does not allow verifying
+ * the nonces as required by the test.
+ */
+
+#include <boost/asio.hpp>
+#include <ndn-cxx/face.hpp>
+
+namespace ndn {
+
+class TestNackConsumer : boost::noncopyable
+{
+public:
+ explicit
+ TestNackConsumer(const char* programName)
+ : m_programName(programName)
+ , m_face(m_ioService)
+ , m_interestLifetime(time::milliseconds(4000))
+ , m_secondInterestInterval(time::milliseconds(0))
+ {
+ m_nonce1 = static_cast<uint32_t>(std::rand());
+ m_nonce2 = static_cast<uint32_t>(std::rand());
+ }
+
+ void
+ usage() const
+ {
+ std::cout << "Usage:\n"
+ << " " << m_programName
+ << " -p <name> -w <wait_before_quit> [-r second_Interest_interval] \n"
+ << "\n"
+ << " -p <name> Interest prefix\n"
+ << " -w <wait_before_quit> - wait time(ms) before exit\n"
+ << "\n"
+ << "Options:\n"
+ << " [-r second_Interest_interval] - set the time (ms) between first and second Interests\n"
+ << " [-h] - print this help text and exit\n";
+ exit(EXIT_FAILURE);
+ }
+
+ void setInterestName(const Name& prefix)
+ {
+ m_interestName = prefix;
+ }
+
+ void
+ setSecondInterestInterval(int interestInterval)
+ {
+ if (interestInterval <= 0)
+ usage();
+ m_secondInterestInterval = time::milliseconds(interestInterval);
+ }
+
+ void
+ setWaitBeforeQuit(int waitTime)
+ {
+ if (waitTime <= 0)
+ usage();
+ m_waitBeforeQuit = time::milliseconds(waitTime);
+ }
+
+ void
+ signalHandler()
+ {
+ m_face.shutdown();
+ m_ioService.stop();
+
+ exit(EXIT_FAILURE);
+ }
+
+ void
+ onData(const Interest& interest, const Data& data)
+ {
+ std::cout << "DATA received for: " << interest.getName() << std::endl;
+ }
+
+ void
+ onTimeout(const Interest& interest)
+ {
+ std::cout << "TIMEOUT received for: " << interest.getName() << std::endl;
+ }
+
+ void
+ onNack(const Interest& interest,
+ const lp::Nack& nack)
+ {
+ std::cout << "NACK received for: " << interest.getName()
+ << " Nonce: " << interest.getNonce()
+ << " Reason: " << nack.getReason()
+ << std::endl;
+ }
+ void
+ sendSecondInterest(boost::asio::deadline_timer* timer)
+ {
+ Interest interest(m_interestName);
+ interest.setInterestLifetime(m_interestLifetime);
+ interest.setNonce(m_nonce2);
+
+ std::cout << "Sending Interest 2: " << interest.getName()
+ << " Nonce: " << interest.getNonce()
+ << std::endl;
+
+ m_face.expressInterest(interest,
+ bind(&TestNackConsumer::onData,
+ this, _1, _2),
+ bind(&TestNackConsumer::onNack,
+ this, _1, _2),
+ bind(&TestNackConsumer::onTimeout,
+ this, _1));
+ }
+
+ void
+ exitProgram(boost::asio::deadline_timer* timer)
+ {
+ m_face.shutdown();
+ m_ioService.stop();
+ }
+
+ void
+ run()
+ {
+ boost::asio::signal_set signalSet(m_ioService, SIGINT, SIGTERM);
+ signalSet.async_wait(bind(&TestNackConsumer::signalHandler, this));
+
+ boost::asio::deadline_timer sendSecondInterestTimer(m_ioService,
+ boost::posix_time::millisec(m_secondInterestInterval.count()));
+ boost::asio::deadline_timer exitTimer(m_ioService,
+ boost::posix_time::millisec(m_waitBeforeQuit.count()));
+
+ sendSecondInterestTimer.expires_at(sendSecondInterestTimer.expires_at() +
+ boost::posix_time::millisec(m_secondInterestInterval.count()));
+ exitTimer.expires_at(exitTimer.expires_at() +
+ boost::posix_time::millisec(m_waitBeforeQuit.count()));
+
+ try {
+ Interest interest(m_interestName);
+ interest.setInterestLifetime(m_interestLifetime);
+ interest.setNonce(m_nonce1);
+
+ std::cout << "Sending Interest 1: " << interest.getName()
+ << " Nonce: " << interest.getNonce()
+ << std::endl;
+
+ m_face.expressInterest(interest,
+ bind(&TestNackConsumer::onData,
+ this, _1, _2),
+ bind(&TestNackConsumer::onNack,
+ this, _1, _2),
+ bind(&TestNackConsumer::onTimeout,
+ this, _1));
+
+ if (m_secondInterestInterval != time::milliseconds(0))
+ {
+ // Schedule second interest
+ sendSecondInterestTimer.async_wait(bind(&TestNackConsumer::sendSecondInterest,
+ this,
+ &sendSecondInterestTimer));
+ }
+
+ // Schedule exit
+ exitTimer.async_wait(bind(&TestNackConsumer::exitProgram, this, &exitTimer));
+ m_face.processEvents();
+ }
+ catch (const std::exception& exception) {
+ m_ioService.stop();
+ }
+ }
+
+private:
+ boost::asio::io_service m_ioService;
+ std::string m_programName;
+ Face m_face;
+ Name m_interestName;
+ time::milliseconds m_interestLifetime;
+ time::milliseconds m_secondInterestInterval;
+ time::milliseconds m_waitBeforeQuit;
+ uint32_t m_nonce1;
+ uint32_t m_nonce2;
+};
+
+} // namespace ndn
+
+int
+main(int argc, char* argv[])
+{
+ std::srand(std::time(nullptr));
+ int argNumber = 0;
+ ndn::TestNackConsumer testNackConsumer(argv[0]);
+
+ int option;
+ while ((option = getopt(argc, argv, "hp:r:w:")) != -1) {
+ switch (option) {
+ case 'h':
+ testNackConsumer.usage();
+ break;
+ case 'p':
+ testNackConsumer.setInterestName(ndn::Name(optarg));
+ ++argNumber;
+ break;
+ case 'r':
+ testNackConsumer.setSecondInterestInterval(atoi(optarg));
+ break;
+ case 'w':
+ testNackConsumer.setWaitBeforeQuit(atoi(optarg));
+ ++argNumber;
+ break;
+ default:
+ testNackConsumer.usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc || argNumber < 2)
+ testNackConsumer.usage();
+
+ testNackConsumer.run();
+
+ return 0;
+}
\ No newline at end of file