install-apps: script to install NDN applications required for testing
test-ndntlvping: sample test case for testing ndn-tlv-ping

Change-Id: Ib54bd606f6854672ed890d3971ff5827197435e8
refs: #1220
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0e81f58
--- /dev/null
+++ b/README.md
@@ -0,0 +1,46 @@
+Integration Tests For NFD (nfd-integration-tests)
+=================================================
+
+This is a Python based unit test repository which is designed for end-to-end
+integration testing of NDN Forwarding Daemon, NFD.
+
+## Prerequisites ##
+
+1. Python must be installed  (2.7 <= version < 3)
+
+-----------------------------------------------------
+
+## Setup Instructions: ##
+
+To install NDN applications used for the tests
+
+    USAGE:
+      ./install_apps.py [OPTIONS]
+
+      Install NDN applications
+      Latest source codes will be downloaded from their GitHub named-data repositories
+
+    OPTIONS:
+      install_ndncppdev  - install ndn-cpp-dev (https://github.com/named-data/ndn-cpp-dev)
+      setup_security     - create an identity (/tmp/nfd_integration) using ndnsec
+      install_NFD        - install NFD (https://github.com/named-data/NFD)
+      install_ndntraffic - install ndn-traffic-generator (https://github.com/named-data/ndn-traffic-generator)
+      install_ndntlvping - install ndn-tlv-ping (https://github.com/named-data/ndn-tlv-ping)
+      install_all        - do all of the above
+      help               - print this message and exit
+
+## Test Run Instructions: #
+
+To run tests
+
+    USAGE:
+      ./run_tests.py [OPTIONS]
+
+      Run a subset of NFD integration test cases
+      The test case(s) to be executed should be provided as command line option(s)
+
+    OPTIONS:
+      test_ndntlvping
+      test_all           - run all the above tests
+      help               - print this message and exit
+
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/__init__.py
diff --git a/install_apps.py b/install_apps.py
new file mode 100755
index 0000000..c2c0edc
--- /dev/null
+++ b/install_apps.py
@@ -0,0 +1,79 @@
+#!/usr/bin/python2
+import os
+import sys
+import inspect
+from sets import Set
+
+def usage():
+    print "\nUSAGE:"
+    print "  ./install_apps.py [OPTIONS]\n"
+    print "  Install NDN applications"
+    print "  Latest source codes will be downloaded from their GitHub"
+    print "  named-data repositories (https://github.com/named-data)"
+    print "\nOPTIONS:"
+    print "  install_ndncppdev  - install ndn-cpp-dev (named-data/ndn-cpp-dev)"
+    print "  setup_security     - create an identity using ndnsec (/tmp/nfd_integration)"
+    print "  install_NFD        - install NFD (named-data/NFD)"
+    print "  install_ndntraffic - install ndn-traffic-generator (named-data/ndn-traffic-generator)"
+    print "  install_ndntlvping - install ndn-tlv-ping (named-data/ndn-tlv-ping)"
+    print "  install_all        - do all of the above"
+    print "  help               - print this message and exit\n"
+
+
+def main():
+    cmd_subfolder = os.path.realpath(
+        os.path.abspath(os.path.join(os.path.split(
+            inspect.getfile(inspect.currentframe()))[0], "install_helpers")))
+    if cmd_subfolder not in sys.path:
+        sys.path.insert(0, cmd_subfolder)
+    validOptions = [ "install_ndncppdev",
+                     "setup_security",
+                     "install_NFD",
+                     "install_ndntraffic",
+                     "install_ndntlvping",
+                     "install_all",
+                     "help" ]
+
+    if len(sys.argv) > 1:
+        actionList = Set(sys.argv[1:])
+        optionsStatus = 0
+        for option in actionList:
+            if option not in validOptions:
+                print "Invalid option provided - " + option
+                optionsStatus = -1
+                break
+        if optionsStatus == 0 and "help" not in actionList:
+            if "install_all" in actionList:
+                actionList.add("install_ndncppdev")
+                actionList.add("setup_security")
+                actionList.add("install_NFD")
+                actionList.add("install_ndntraffic")
+                actionList.add("install_ndntlvping")
+            module = __import__("setup_preparation_folder")
+            module.run()
+            module = __import__("install_dependencies")
+            module.run()
+            if "install_ndncppdev" in actionList:
+                module = __import__("install_ndncppdev")
+                module.run()
+            if "setup_security" in actionList:
+                module = __import__("setup_security")
+                module.run()
+            if "install_NFD" in actionList:
+                module = __import__("install_NFD")
+                module.run()
+            if "install_ndntraffic" in actionList:
+                module = __import__("install_ndntraffic")
+                module.run()
+            if "install_ndntlvping" in actionList:
+                module = __import__("install_ndntlvping")
+                module.run()
+            print ""
+        else:
+            usage()
+    else:
+        usage()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/install_helpers/__init__.py b/install_helpers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/install_helpers/__init__.py
diff --git a/install_helpers/install_NFD.py b/install_helpers/install_NFD.py
new file mode 100644
index 0000000..171b2e6
--- /dev/null
+++ b/install_helpers/install_NFD.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python2
+import os
+
+# Install NFD
+def run():
+    print "\nINSTALLING NFD"
+    print "**************"
+    os.system("git clone https://github.com/named-data/NFD --depth 1")
+    os.chdir("NFD")
+    os.system("./waf distclean")
+    os.system("./waf configure")
+    os.system("./waf -j1")
+    os.system("sudo ./waf install")
+    os.system("sudo cp /usr/local/etc/ndn/nfd.conf.sample /usr/local/etc/ndn/nfd.conf")
+    os.system("sudo mkdir /usr/local/etc/ndn/keys/")
+    os.system("ndnsec-cert-dump -i `ndnsec-get-default` > ~/default.ndncert")
+    os.system("sudo mv ~/default.ndncert /usr/local/etc/ndn/keys")
+    os.chdir("..")
diff --git a/install_helpers/install_dependencies.py b/install_helpers/install_dependencies.py
new file mode 100644
index 0000000..ab27a96
--- /dev/null
+++ b/install_helpers/install_dependencies.py
@@ -0,0 +1,9 @@
+#!/usr/bin/python2
+import os
+
+# Install Dependencies & Necessary Tools
+def run():
+    print "\nINSTALLING DEPENDENCIES"
+    print "***********************"
+    os.system("sudo apt-get -qq update")
+    os.system("sudo apt-get -qq install libboost1.48-all-dev libcrypto++-dev pkg-config libsqlite3-dev")
diff --git a/install_helpers/install_ndncppdev.py b/install_helpers/install_ndncppdev.py
new file mode 100644
index 0000000..8dc09b7
--- /dev/null
+++ b/install_helpers/install_ndncppdev.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python2
+import os
+
+# Install ndn-cpp-dev
+def run():
+    print "\nINSTALLING ndn-cpp-dev"
+    print "**********************"
+    os.system("git clone https://github.com/named-data/ndn-cpp-dev --depth 1")
+    os.chdir("ndn-cpp-dev")
+    os.system("./waf distclean")
+    os.system("./waf configure")
+    os.system("./waf -j1")
+    os.system("sudo ./waf install")
+    os.chdir("..")
diff --git a/install_helpers/install_ndntlvping.py b/install_helpers/install_ndntlvping.py
new file mode 100644
index 0000000..c27f254
--- /dev/null
+++ b/install_helpers/install_ndntlvping.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python2
+import os
+
+# Install ndn-tlv-ping
+def run():
+    print "\nINSTALLING ndn-tlv-ping"
+    print "***********************"
+    os.system("git clone https://github.com/named-data/ndn-tlv-ping --depth 1")
+    os.chdir("ndn-tlv-ping")
+    os.system("./waf distclean")
+    os.system("./waf configure")
+    os.system("./waf -j1")
+    os.system("sudo ./waf install")
+    os.chdir("..")
diff --git a/install_helpers/install_ndntraffic.py b/install_helpers/install_ndntraffic.py
new file mode 100644
index 0000000..3203dce
--- /dev/null
+++ b/install_helpers/install_ndntraffic.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python2
+import os
+
+# Install ndn-traffic-generator
+def run():
+    print "\nINSTALLING ndn-traffic-generator"
+    print "********************************"
+    os.system("git clone https://github.com/named-data/ndn-traffic-generator --depth 1")
+    os.chdir("ndn-traffic-generator")
+    os.system("./waf distclean")
+    os.system("./waf configure")
+    os.system("./waf -j1")
+    os.system("sudo ./waf install")
+    os.chdir("..")
diff --git a/install_helpers/setup_preparation_folder.py b/install_helpers/setup_preparation_folder.py
new file mode 100644
index 0000000..777fb73
--- /dev/null
+++ b/install_helpers/setup_preparation_folder.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python2
+import os
+from os.path import expanduser
+
+# Setup Preparation Folder
+def run():
+    print "\nSETTING UP PREPARATION FOLDER"
+    print "******************************"
+    home = expanduser("~")
+    os.chdir(home)
+    os.system("rm -rf nfd_prepare")
+    os.mkdir("nfd_prepare")
+    os.chdir("nfd_prepare")
+
diff --git a/install_helpers/setup_security.py b/install_helpers/setup_security.py
new file mode 100644
index 0000000..4d550cd
--- /dev/null
+++ b/install_helpers/setup_security.py
@@ -0,0 +1,8 @@
+#!/usr/bin/python2
+import os
+
+# Configure Security Environment Using ndnsec
+def run():
+    print "\nCONFIGURING SECURITY ENVIRONMENT WITH ndnsec"
+    print "********************************************"
+    os.system("ndnsec-keygen -n '/tmp/nfd_integration_tests/' | ndnsec-install-cert -")
diff --git a/library_helpers/__init__.py b/library_helpers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/library_helpers/__init__.py
diff --git a/library_helpers/process_manager.py b/library_helpers/process_manager.py
new file mode 100644
index 0000000..ebc4862
--- /dev/null
+++ b/library_helpers/process_manager.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python2
+# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2014 University of Arizona
+# Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+# See COPYING for copyright and distribution information.
+#
+
+import errno
+import subprocess
+import multiprocessing as mp
+
+class process_manager:
+
+    manager = mp.Manager()
+    processes = dict()
+    subprocesses = manager.dict()
+    results = manager.dict()
+
+    def runProcess(self, processKey, processCallFormat, message, subprocesses, results):
+        print message
+        process = subprocess.Popen(
+            processCallFormat, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+        subprocesses[processKey] = process
+        try:
+            stdout, stderr = process.communicate()
+            returnCode = process.returncode
+            results[processKey] = (returnCode, stdout, stderr)
+        except IOError as e:
+            pass
+
+    def startProcess(self, processKey, processCallFormat, message):
+        self.processes[processKey] = mp.Process(
+            target = self.runProcess,
+                args = [processKey, processCallFormat, message, self.subprocesses, self.results])
+        self.processes[processKey].start()
+
+    def killProcess(self, processKey):
+        if processKey not in self.results:
+            self.subprocesses[processKey].terminate()
+
+    def hasProcessCompleted(self, processKey):
+        if processKey in self.results:
+            return True
+        else:
+            return False
+
+    def waitForProcessCompletion(self, processKey, waitTime):
+        self.processes[processKey].join(waitTime)
+
+    def getProcessReturnCode(self, processKey):
+        if processKey in self.results:
+            (returnCode, stdout, stderr) = self.results[processKey]
+            return returnCode
+        else:
+            print "Invalid processKey provided - " + processKey
+            return -1
+
+    def getProcessError(self, processKey):
+        if processKey in self.results:
+            (returnCode, stdout, stderr) = self.results[processKey]
+            return stderr
+        else:
+            return "Error not available for processKey - " + processKey
+
+    def startNfd(self):
+        self.startProcess("nfd", ["sudo", "nfd"], "-> Starting NFD")
+
+    def killNfd(self):
+        self.killProcess("nfd")
diff --git a/run_tests.py b/run_tests.py
new file mode 100755
index 0000000..a71fd3b
--- /dev/null
+++ b/run_tests.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python2
+import os
+import sys
+import glob
+import inspect
+import unittest
+from sets import Set
+
+def usage(testCases):
+    print "\nUSAGE:"
+    print "  ./run_tests.py [OPTIONS]\n"
+    print "  Run a subset of NFD integration test cases"
+    print "  The test case(s) to be executed should be provided as command line option(s)"
+    print "\nOPTIONS:"
+    for testCase in testCases:
+        print "  " + testCase
+    print "  test_all           - run all the above tests"
+    print "  help               - print this message and exit\n"
+
+
+def main():
+    cmd_subfolder = os.path.realpath(
+        os.path.abspath(os.path.join(os.path.split(
+            inspect.getfile(inspect.currentframe()))[0], "library_helpers")))
+    if cmd_subfolder not in sys.path:
+        sys.path.insert(0, cmd_subfolder)
+    validOptions = [ "test_all",
+                     "help" ]
+    testCases = glob.glob('test_*')
+    validOptions.extend(testCases)
+
+    if len(sys.argv) > 1:
+        actionList = Set(sys.argv[1:])
+        optionStatus = 0
+        for action in actionList:
+            if action not in validOptions:
+                print "Invalid option provided - " + action
+                optionStatus = -1
+                break
+        if optionStatus == 0 and "help" not in actionList:
+            if "test_all" in actionList:
+                actionList.remove("test_all")
+                actionList = Set(testCases)
+            suiteList = []
+            for action in actionList:
+                cmd_subfolder = os.path.realpath(
+                    os.path.abspath(os.path.join(os.path.split(
+                        inspect.getfile(inspect.currentframe()))[0], action)))
+                if cmd_subfolder not in sys.path:
+                    sys.path.insert(0, cmd_subfolder)
+                suiteList.append(
+                    unittest.defaultTestLoader.loadTestsFromName(action + "." + action))
+            mainSuite = unittest.TestSuite(suiteList)
+            unittest.TextTestRunner().run(mainSuite)
+        else:
+            usage(testCases)
+    else:
+        usage(testCases)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/test_ndntlvping/README.md b/test_ndntlvping/README.md
new file mode 100644
index 0000000..71daa36
--- /dev/null
+++ b/test_ndntlvping/README.md
@@ -0,0 +1,12 @@
+Test Case - ndnlvping
+=====================
+
+## Objective ##
+
+To test the ndn-tlv-ping application on a single host.
+
+## Description ##
+
+This test case will run the NFD, ndnping and ndnpingserver binaries.
+This will report SUCCESS if one ping interest/data is successfully exchanged between the ndnping and ndnpingserver.
+In all other scenarios, the test case will report FAILURE
diff --git a/test_ndntlvping/__init__.py b/test_ndntlvping/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test_ndntlvping/__init__.py
diff --git a/test_ndntlvping/test_ndntlvping.py b/test_ndntlvping/test_ndntlvping.py
new file mode 100644
index 0000000..fbe1690
--- /dev/null
+++ b/test_ndntlvping/test_ndntlvping.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python2
+# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2014 University of Arizona
+# Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+# See COPYING for copyright and distribution information.
+#
+
+import time
+import unittest
+import process_manager
+
+class test_ndntlvping(unittest.TestCase, process_manager.process_manager):
+    """Test case for testing ndn-tlv-ping application"""
+
+    def setUp(self):
+        print "\nTesting ndn-tlv-ping"
+        print "********************"
+
+    def tearDown(self):
+        self.killNfd()
+        self.killProcess("ndnpingserver")
+        self.killProcess("ndnping")
+
+    def test_ping(self):
+        self.startNfd()
+        time.sleep(1)
+        self.startProcess("ndnpingserver",
+            ["ndnpingserver", "-p 1", "/test/ndntlvping"], "-> Starting Ping Server")
+        time.sleep(1)
+        self.startProcess("ndnping",
+            ["ndnping", "-c 1", "/test/ndntlvping"], "-> Starting Ping Client")
+        time.sleep(1)
+        self.waitForProcessCompletion("ndnping", 10)
+        self.waitForProcessCompletion("ndnpingserver", 10)
+        self.killProcess("ndnping")
+        self.killProcess("ndnpingserver")
+        self.killNfd()
+        if self.hasProcessCompleted("ndnping"):
+            if self.getProcessReturnCode("ndnping") != 0:
+                print self.getProcessError("ndnping")
+                self.fail(">> TEST FAILED - received non-zero return code from ndnping")
+        else:
+            self.fail(">> TEST FAILED - ndnping failed to complete")
+        if self.hasProcessCompleted("ndnpingserver"):
+            if self.getProcessReturnCode("ndnpingserver") != 0:
+                print self.getProcessError("ndnpingserver")
+                self.fail(">> TEST FAILED - received non-zero return code from ndnpingserver")
+        else:
+            self.fail(">> TEST FAILED - ndnpingserver failed to complete")
+        print ">> TEST SUCCESSFUL"