Add NextHopFaceId test scenario
Add libssl-dev to install_dependencies.py
refs #1942
Change-Id: I39270df30f5946e9acc18e1c008a30b6184bca47
diff --git a/install_helpers/install_dependencies.py b/install_helpers/install_dependencies.py
index d08de8b..6c5d1f3 100644
--- a/install_helpers/install_dependencies.py
+++ b/install_helpers/install_dependencies.py
@@ -6,4 +6,4 @@
print "\nINSTALLING DEPENDENCIES"
print "***********************"
os.system("sudo apt-get -qq update")
- os.system("sudo apt-get -qq install build-essential git libboost-all-dev libcrypto++-dev libpcap-dev pkg-config libsqlite3-dev socat bind9")
+ os.system("sudo apt-get -qq install build-essential git libboost-all-dev libcrypto++-dev libpcap-dev pkg-config libsqlite3-dev socat bind9 libssl-dev")
diff --git a/install_helpers/tools/Makefile b/install_helpers/tools/Makefile
index fa5c8cb..0d802a4 100644
--- a/install_helpers/tools/Makefile
+++ b/install_helpers/tools/Makefile
@@ -3,7 +3,7 @@
LIBS = `pkg-config --libs libndn-cxx`
DESTDIR ?= /usr/local
-PROGRAMS = test-nack-consumer
+PROGRAMS = test-nack-consumer test-nexthopfaceid-consumer
all: $(PROGRAMS)
diff --git a/install_helpers/tools/test-nexthopfaceid-consumer.cpp b/install_helpers/tools/test-nexthopfaceid-consumer.cpp
new file mode 100644
index 0000000..90ba6b6
--- /dev/null
+++ b/install_helpers/tools/test-nexthopfaceid-consumer.cpp
@@ -0,0 +1,102 @@
+/**
+ * Consumer for the NextHopFaceId test (test_nexthopfaceid)
+ *
+ * Author: Eric Newberry <enewberry@email.arizona.edu>
+ *
+ * Based on ndn-cxx example consumer
+ */
+
+#include <ndn-cxx/lp/tags.hpp>
+#include <ndn-cxx/mgmt/nfd/controller.hpp>
+
+#include <cstring>
+#include <cstdlib>
+
+using namespace ndn;
+
+class TestNextHopFaceIdConsumer : noncopyable
+{
+public:
+ void
+ run(Name name, bool enableLocalFields, int nextHopFaceId)
+ {
+ nfd::ControlParameters params;
+ params.setFlagBit(nfd::BIT_LOCAL_FIELDS_ENABLED, enableLocalFields);
+
+ ndn::nfd::Controller controller(m_face, m_keyChain);
+ controller.start<ndn::nfd::FaceUpdateCommand>(params,
+ nullptr,
+ [] (const ndn::nfd::ControlResponse& resp) {
+ throw std::runtime_error("Unable to toggle local fields");
+ });
+ m_face.processEvents();
+
+ // Now, send test case Interest
+ Interest interest(name);
+
+ if (nextHopFaceId != -1) {
+ interest.setTag(make_shared<lp::NextHopFaceIdTag>(nextHopFaceId));
+ }
+
+ m_face.expressInterest(interest,
+ [] (const Interest& interest, const Data& data) {
+ std::cout.write(reinterpret_cast<const char*>(data.getContent().value()),
+ data.getContent().value_size());
+ std::cout << std::endl;
+ },
+ [] (const Interest& interest, const lp::Nack& nack) {
+ std::cout << "Nack" << std::endl;
+ },
+ [] (const Interest& interest) {
+ std::cout << "Timeout" << std::endl;
+ });
+ m_face.processEvents();
+ }
+
+private:
+ Face m_face;
+ KeyChain m_keyChain;
+};
+
+static void
+usage(const char* name)
+{
+ std::cerr << "Usage: " << name
+ << " [prefix] [enableLocalFields - t/f] [NextHopFaceId (-1 if not set)]" << std::endl;
+}
+
+int
+main(int argc, char** argv)
+{
+ if (argc != 4) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ Name name(argv[1]);
+
+ bool enableLocalFields = false;
+ if (std::strcmp(argv[2], "t") == 0) {
+ enableLocalFields = true;
+ }
+ else if (std::strcmp(argv[2], "f") == 0) {
+ enableLocalFields = false;
+ }
+ else {
+ usage(argv[0]);
+ return -1;
+ }
+
+ int nextHopFaceId = std::atoi(argv[3]);
+
+ try {
+ TestNextHopFaceIdConsumer consumer;
+ consumer.run(name, enableLocalFields, nextHopFaceId);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return -2;
+ }
+
+ return 0;
+}
diff --git a/test_nexthopfaceid/NDNTrafficServer-B.conf b/test_nexthopfaceid/NDNTrafficServer-B.conf
new file mode 100644
index 0000000..41c905d
--- /dev/null
+++ b/test_nexthopfaceid/NDNTrafficServer-B.conf
@@ -0,0 +1,4 @@
+##########
+Name=/P
+Content=BBBBBBBB
+##########
diff --git a/test_nexthopfaceid/NDNTrafficServer-C.conf b/test_nexthopfaceid/NDNTrafficServer-C.conf
new file mode 100644
index 0000000..fa88f4c
--- /dev/null
+++ b/test_nexthopfaceid/NDNTrafficServer-C.conf
@@ -0,0 +1,4 @@
+##########
+Name=/P
+Content=CCCCCCCC
+##########
diff --git a/test_nexthopfaceid/README.md b/test_nexthopfaceid/README.md
new file mode 100644
index 0000000..aff116b
--- /dev/null
+++ b/test_nexthopfaceid/README.md
@@ -0,0 +1,17 @@
+# Test NextHopFaceId tag and LP field
+
+## Topology
+
+B--A--C
+
+## Steps
+
+1. Start NFD on A, B, and C.
+2. On A, create routes for prefix ndn:/P toward B and C. The cost toward B is lower than the cost toward C.
+3. On B, start ndn-traffic-server on ndn:/P, serving payload "BBBBBBBB".
+4. On C, start ndn-traffic-server on ndn:/P, serving payload "CCCCCCCC".
+5. On A, execute a consumer to enable local fields and then express an Interest for ndn:/P/1, without NextHopFaceId tag. Expect Data with payload "BBBBBBBB".
+6. On A, execute a consumer to enable local fields and then express an Interest for ndn:/P/2, with NextHopFaceId=faceB. Expect Data with payload "BBBBBBBB".
+7. On A, execute a consumer to enable local fields and then express an Interest for ndn:/P/3, with NextHopFaceId=faceC. Expect Data with payload "CCCCCCCC".
+8. On A, execute a consumer to enable local fields and then express an Interest for ndn:/P/4, with NextHopFaceId=null-face. Expect either timeout or Nack.
+9. On A, execute a consumer to disable local fields and then express an Interest for ndn:/P/5, with NextHopFaceId=faceC. Expect either timeout or Data with payload "BBBBBBBB".
diff --git a/test_nexthopfaceid/nexthopfaceid-test.sh b/test_nexthopfaceid/nexthopfaceid-test.sh
new file mode 100755
index 0000000..d4b22b7
--- /dev/null
+++ b/test_nexthopfaceid/nexthopfaceid-test.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+source ../multi-host.conf
+echo "host B IP address $IP4_B1"
+echo "host C IP address $IP4_C1"
+
+clean_up() {
+ r=$(ssh $CTRL_B "sudo killall ndn-traffic-server" 2>&1)
+ r=$(ssh $CTRL_B "sudo killall nfd" 2>&1)
+ r=$(ssh $CTRL_C "sudo killall ndn-traffic-server" 2>&1)
+ r=$(ssh $CTRL_C "sudo killall nfd" 2>&1)
+ r=$(sudo killall nfd 2>&1)
+}
+
+mkdir -p logs
+
+# Start NFD on hosts A, B, and C
+workdir=$(pwd)
+echo "starting nfd on host A..."
+sudo nfd > $workdir/logs/nfd.log 2>&1 &
+sleep 1
+
+echo "starting nfd on host B..."
+ssh $CTRL_B "mkdir -p $workdir/logs;\
+ sudo nfd &> $workdir/logs/nfd.log &"
+sleep 1
+
+echo "starting nfd on host C..."
+ssh $CTRL_C "mkdir -p $workdir/logs;\
+ sudo nfd &> $workdir/logs/nfd.log &"
+sleep 1
+
+# A: Create route for prefix ndn:/P toward B with cost 10
+nfdc register -c 10 ndn:/P udp4://$IP4_B1
+if [[ $? -ne 0 ]]
+then
+ echo "Failed to create route for ndn:/P toward host B"
+ clean_up
+ exit 1
+fi
+
+# A: Create route for prefix ndn:/P toward C with cost 20
+nfdc register -c 20 ndn:/P udp4://$IP4_C1
+if [[ $? -ne 0 ]]
+then
+ echo "Failed to create route for ndn:/P toward host C"
+ clean_up
+ exit 1
+fi
+
+# Get face IDs on A
+faceB=$(nfdc face list | grep "udp4://$IP4_B1" | cut -d" " -f3 | cut -d"=" -f2)
+faceC=$(nfdc face list | grep "udp4://$IP4_C1" | cut -d" " -f3 | cut -d"=" -f2)
+
+# B: Start ndn-traffic-server serving "BBBBBBBB" on ndn:/P
+echo "starting ndn-traffic-server on host B..."
+ssh $CTRL_B "ndn-traffic-server $workdir/NDNTrafficServer-B.conf > $workdir/logs/server.log 2>&1 &"
+
+# C: Start ndn-traffic-server serving "CCCCCCCC" on ndn:/P
+echo "starting ndn-traffic-server on host C..."
+ssh $CTRL_C "ndn-traffic-server $workdir/NDNTrafficServer-C.conf > $workdir/logs/server.log 2>&1 &"
+
+# A: Start consumer to enable local fields and express Interest for ndn:/P/1 w/o NextHopFaceId
+# Expect Data w/ payload "BBBBBBBB"
+echo "From A, sending Interest for ndn:/P/1 (LocalFields=enabled)..."
+output=$(test-nexthopfaceid-consumer /P/1 t -1)
+if [[ $output != "BBBBBBBB" ]]; then
+ echo "Interest ndn:/P/1 not answered with Data containing payload 'BBBBBBBB'"
+ clean_up
+ exit 2
+fi
+
+# A: Start consumer to enable local fields and express Interest for ndn:/P/2 w/ NextHopFaceId=faceB
+# Expect Data w/ payload "BBBBBBBB"
+echo "From A, sending Interest for ndn:/P/2 (LocalFields=enabled, NextHopFaceId=faceB)..."
+output=$(test-nexthopfaceid-consumer /P/2 t $faceB)
+if [[ $output != "BBBBBBBB" ]]; then
+ echo "Interest ndn:/P/2 not answered with Data containing payload 'BBBBBBBB'"
+ clean_up
+ exit 3
+fi
+
+# A: Start consumer to enable local fields and express Interest for ndn:/P/3 w/ NextHopFaceId=faceC
+# Expect Data w/ payload "CCCCCCCC"
+echo "From A, sending Interest for ndn:/P/3 (LocalFields=enabled, NextHopFaceId=faceC)..."
+output=$(test-nexthopfaceid-consumer /P/3 t $faceC)
+if [[ $output != "CCCCCCCC" ]]; then
+ echo "Interest ndn:/P/3 not answered with Data containing payload 'CCCCCCCC'"
+ clean_up
+ exit 4
+fi
+
+# A: Start consumer to enable local fields and express Interest for ndn:/P/4 w/ NextHopFaceId=null-face
+# Expect either timeout or Nack
+echo "From A, sending Interest for ndn:/P/4 (LocalFields=enabled, NextHopFaceId=null-face)..."
+output=$(test-nexthopfaceid-consumer /P/4 t 0)
+if [[ $output != "Timeout" && $output != "Nack" ]]; then
+ echo "Interest ndn:/P/4 was not answered with a Nack and did not time out"
+ clean_up
+ exit 5
+fi
+
+# A: Start consumer to disable local fields and express Interest for ndn:/P/5w/ NextHopFaceId=faceC
+# Expect either timeout or Data w/ payload "BBBBBBBB"
+echo "From A, sending Interest for ndn:/P/5 (LocalFields=disabled, NextHopFaceId=faceC)..."
+output=$(test-nexthopfaceid-consumer /P/5 f $faceC)
+if [[ $output != "Timeout" && $output != "BBBBBBBB" ]]; then
+ echo "Interest ndn:/P/5 was not answered with Data containing payload 'BBBBBBBB' and did not time out"
+ clean_up
+ exit 6
+fi
+
+clean_up
+echo "NextHopFaceId Test PASSED"
diff --git a/test_nexthopfaceid/test_nexthopfaceid.py b/test_nexthopfaceid/test_nexthopfaceid.py
new file mode 100644
index 0000000..5dc2b8a
--- /dev/null
+++ b/test_nexthopfaceid/test_nexthopfaceid.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python2
+# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2016 University of Arizona
+# Author: Eric Newberry <enewberry@cs.arizona.edu>
+# See COPYING for copyright and distribution information.
+#
+
+import os
+import unittest
+import subprocess
+
+class test_nexthopfaceid(unittest.TestCase):
+ """Test case for NextHopFaceId field"""
+
+ def setUp(self):
+ print "\nTesting NextHopFaceId"
+ print "*****************"
+ os.chdir("test_nexthopfaceid")
+
+ def tearDown(self):
+ print "*****************"
+ os.chdir("..")
+
+ def test_nexthopfaceid(self):
+ ret = subprocess.call(["./nexthopfaceid-test.sh"], shell=True)
+ print "Test script return value:", ret
+ errormsg = {
+ 1 : "Failed to create required routes",
+ 2 : "Interest ndn:/P/1 not answered with Data containing payload 'BBBBBBBB'",
+ 3 : "Interest ndn:/P/2 not answered with Data containing payload 'BBBBBBBB'",
+ 4 : "Interest ndn:/P/3 not answered with Data containing payload 'CCCCCCCC'",
+ 5 : "Interest ndn:/P/4 was not answered with a Nack and did not time out",
+ 6 : "Interest ndn:/P/5 was not answered with Data containing payload 'BBBBBBBB' and did not time out",
+ }
+ if (ret != 0):
+ self.fail(errormsg[ret])