Merge branch 'ONOS-Next' of https://github.com/OPENNETWORKINGLAB/ONLabTest into ONOS-Next
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index ccf3baf..419ee06 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -808,6 +808,7 @@
 
         '''
         import json
+        #main.log.debug("Switches_json string: ", switches_json)
         output = {"switches":[]}
         for switch in topo.graph.switches: #iterate through the MN topology and pull out switches and and port info
             #print vars(switch)
@@ -818,7 +819,10 @@
             output['switches'].append({"name": switch.name, "dpid": str(switch.dpid).zfill(16), "ports": ports })
         #print output
 
+        #print "mn"
         #print json.dumps(output, sort_keys=True,indent=4,separators=(',', ': '))
+        #print "onos"
+        #print json.dumps(switches_json, sort_keys=True,indent=4,separators=(',', ': '))
 
 
         # created sorted list of dpid's in MN and ONOS for comparison
@@ -828,7 +832,7 @@
         mnDPIDs.sort()
         #print mnDPIDs
         if switches_json == "":#if rest call fails
-            main.log.error(self.name + ".compare_topo(): Empty JSON object given from ONOS")
+            main.log.error(self.name + ".compare_switches(): Empty JSON object given from ONOS")
             return main.FALSE
         onos=switches_json
         onosDPIDs=[]
@@ -1019,184 +1023,6 @@
         return link_results
 
 
-
-
-    def compare_topo(self, topo, onos_json):
-        '''
-        compares mn topology with ONOS topology
-        onos_list is a list of ONOS controllers, each element of the list should be (handle, name, ip, port)
-        onos_json is the output of the onos get_json function calling the /wm/onos/topology REST API
-        Returns: True if MN and ONOS topology match and False if the differ. 
-        Differences between ONOS and MN topology will be printed to the log.
-
-        Dependency: Requires STS to be installed on the TestON machine. STS can be pulled 
-        from https://github.com/ucb-sts/sts.git . Currently the required functions from STS are located in the 
-        topology_refactoring2 branch, but may be merged into the master branch soon. You may need to install some
-        python modules such as networkx to use the STS functions.
-
-        To install sts:
-            $ git clone git://github.com/ucb-sts/sts.git
-            $ cd sts
-            $ git clone -b debugger git://github.com/ucb-sts/pox.git
-            $ sudo apt-get install python-dev
-            $ ./tools/install_hassel_python.sh
-            $ sudo pip install networkx
-
-        Include sts in your PYTHONPATH. it should looks comething like: 
-            PYTHONPATH=/home/admin/TestON:/home/admin/sts
-
-        '''
-        import sys
-        sys.path.append("~/sts")
-        #NOTE: Create this once per Test and pass the TestONTopology object around. It takes too long to create this object.
-        #      This will make it easier to use the sts methods for severing links and solve that issue
-        import json
-
-        link_results = main.TRUE
-        switch_results = main.TRUE
-        port_results = main.TRUE
-
-        ########Switches#######
-        output = {"switches":[]}
-        for switch in topo.graph.switches: #iterate through the MN topology and pull out switches and and port info
-            ports = []
-            for port in switch.ports.values():
-                #print port.hw_addr.toStr(separator = '')
-                ports.append({'of_port': port.port_no, 'mac': str(port.hw_addr).replace('\'',''), 'name': port.name})
-            output['switches'].append({"name": switch.name, "dpid": str(switch.dpid).zfill(16), "ports": ports })
-        #print output
-
-        #print json.dumps(output, sort_keys=True,indent=4,separators=(',', ': '))
-
-
-        # created sorted list of dpid's in MN and ONOS for comparison
-        mnDPIDs=[]
-        for switch in output['switches']:
-            mnDPIDs.append(switch['dpid'])
-        mnDPIDs.sort()
-        #print mnDPIDs
-        if onos_json == "":#if rest call fails
-            main.log.error(self.name + ".compare_topo(): Empty JSON object given from ONOS rest call")
-            return main.FALSE
-        onos=onos_json
-        onosDPIDs=[]
-        for switch in onos['switches']:
-            onosDPIDs.append(switch['dpid'].replace(":",''))
-        onosDPIDs.sort()
-        #print onosDPIDs
-
-        if mnDPIDs!=onosDPIDs:
-            switch_results = main.FALSE
-            main.log.report( "Switches in MN but not in ONOS:")
-            main.log.report( str([switch for switch in mnDPIDs if switch not in onosDPIDs]))
-            main.log.report( "Switches in ONOS but not in MN:")
-            main.log.report(  str([switch for switch in onosDPIDs if switch not in mnDPIDs]))
-        else:#list of dpid's match in onos and mn
-            switch_results = main.TRUE
-
-        ################ports#############
-            for switch in output['switches']:
-                mn_ports = []
-                onos_ports = []
-                for port in switch['ports']:
-                    mn_ports.append(port['of_port'])
-                for onos_switch in onos['switches']:
-                    if onos_switch['dpid'].replace(':','') == switch['dpid']:
-                        for port in onos_switch['ports']:
-                            onos_ports.append(port['portNumber']) 
-                mn_ports.sort()
-                onos_ports.sort()
-                #print "mn_ports[] = ", mn_ports
-                #print "onos_ports90 = ", onos_ports
-                
-                #if mn_ports == onos_ports:
-                    #pass #don't set results to true here as this is just one of many checks and it might override a failure
-
-                #For OF1.3, the OFP_local port number is 0xfffffffe or 4294967294 instead of 0xfffe or 65534 in OF1.0, ONOS topology
-                #sees the correct port number, however MN topology as read from line 151 of https://github.com/ucb-sts/sts/blob/
-                #topology_refactoring2/sts/entities/teston_entities.py is 0xfffe which doesn't work correctly with OF1.3 switches.
-                #So a short term fix is to ignore the case when mn_port == 65534 and onos_port ==4294967294.
-                for mn_port,onos_port in zip(mn_ports,onos_ports):
-                    if mn_port == onos_port or (mn_port == 65534 and onos_port ==4294967294):
-                        continue
-                    else:
-                        port_results = main.FALSE
-                        break
-                '''
-                else: #the ports of this switch don't match
-                    port_results = main.FALSE
-                    main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid'])) 
-                    main.log.report( str([port for port in mn_ports if port not in onos_ports]))
-                    main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
-                    main.log.report( str([port for port in onos_ports if port not in mn_ports]))
-                '''
-                if port_results == main.FALSE:
-                    main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid'])) 
-                    main.log.report( str([port for port in mn_ports if port not in onos_ports]))
-                    main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
-                    main.log.report( str([port for port in onos_ports if port not in mn_ports]))
-
-        #######Links########
-        # iterate through MN links and check if and ONOS link exists in both directions
-        # NOTE: Will currently only show mn links as down if they are cut through STS. 
-        #       We can either do everything through STS or wait for up_network_links 
-        #       and down_network_links to be fully implemented.
-        for link in topo.patch_panel.network_links: 
-            #print "Link: %s" % link
-            #TODO: Find a more efficient search method
-            node1 = None
-            port1 = None
-            node2 = None
-            port2 = None
-            first_dir = main.FALSE
-            second_dir = main.FALSE
-            for switch in output['switches']:
-                if switch['name'] == link.node1.name:
-                    node1 = switch['dpid']
-                    for port in switch['ports']:
-                        if str(port['name']) == str(link.port1):
-                            port1 = port['of_port'] 
-                    if node1 is not None and node2 is not None:
-                        break
-                if switch['name'] == link.node2.name:
-                    node2 = switch['dpid']
-                    for port in switch['ports']: 
-                        if str(port['name']) == str(link.port2):
-                            port2 = port['of_port'] 
-                    if node1 is not None and node2 is not None:
-                        break
-            # check onos link from node1 to node2
-            for onos_link in onos['links']:
-                if onos_link['src']['dpid'].replace(":",'') == node1 and onos_link['dst']['dpid'].replace(":",'') == node2:
-                    if onos_link['src']['portNumber'] == port1 and onos_link['dst']['portNumber'] == port2:
-                        first_dir = main.TRUE
-                    else:
-                        main.log.report('the port numbers do not match for ' +str(link) + ' between ONOS and MN')
-                    #print node1, ' to ', node2
-                elif onos_link['src']['dpid'].replace(":",'') == node2 and onos_link['dst']['dpid'].replace(":",'') == node1:
-                    if onos_link['src']['portNumber'] == port2 and onos_link['dst']['portNumber'] == port1:
-                        second_dir = main.TRUE
-                    else:
-                        main.log.report('the port numbers do not match for ' +str(link) + ' between ONOS and MN')
-                    #print node2, ' to ', node1
-                else:#this is not the link you're looking for
-                    pass
-            if not first_dir:
-                main.log.report('ONOS has issues with the link from '+str(link.node1.name) +"(dpid: "+ str(node1)+"):"+str(link.port1)+"(portNumber: "+str(port1)+")"+ ' to ' + str(link.node2.name) +"(dpid: "+ str(node2)+"):"+str(link.port2)+"(portNumber: "+str(port2)+")")
-            if not second_dir:
-                main.log.report('ONOS has issues with the link from '+str(link.node2.name) +"(dpid: "+ str(node2)+"):"+str(link.port2)+"(portNumber: "+str(port2)+")"+ ' to ' + str(link.node1.name) +"(dpid: "+ str(node1)+"):"+str(link.port1)+"(portNumber: "+str(port1)+")")
-            link_results = link_results and first_dir and second_dir
-
-        
-        results =  switch_results and port_results and link_results
-#        if not results: #To print out both topologies
-#            main.log.error("Topology comparison failed, printing json objects, MN then ONOS")
-#            main.log.error(str(json.dumps(output, sort_keys=True,indent=4,separators=(',', ': '))))
-#            main.log.error('MN Links:')
-#            for link in topo.patch_panel.network_links: main.log.error(str("\tLink: %s" % link))
-#            main.log.error(str(json.dumps(onos, sort_keys=True,indent=4,separators=(',', ': '))))
-        return results
-
     def get_hosts(self):
         '''
         Returns a list of all hosts
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index e6caa6e..ee71d64 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -151,7 +151,26 @@
 
             #Wait for onos start (-w) and enter onos cli
             self.handle.sendline("onos -w "+str(ONOS_ip))
-            self.handle.expect("onos>", timeout = 60)
+            i = self.handle.expect([
+                    "onos>",
+                    pexpect.TIMEOUT],timeout=60)
+
+            if i == 0:
+                main.log.info(str(ONOS_ip)+" CLI Started successfully")
+                return main.TRUE
+            else:
+                #If failed, send ctrl+c to process and try again
+                main.log.info("Starting CLI failed. Retrying...")
+                self.handle.sendline("\x03")
+                self.handle.sendline("onos -w "+str(ONOS_ip))
+                i = self.handle.expect(["onos>",pexpect.TIMEOUT],
+                        timeout=30)
+                if i == 0:
+                    return main.TRUE
+                else:
+                    main.log.error("Connection to CLI "+\
+                        str(ONOS_ip)+" timeout")
+                    return main.FALSE
 
         except pexpect.EOF:
             main.log.error(self.name + ": EOF exception found")
@@ -190,6 +209,8 @@
             handle += self.handle.after
 
             main.log.info("Command sent.")
+            ansi_escape = re.compile(r'\x1b[^m]*m')
+            handle = ansi_escape.sub('', handle)
 
             return handle
         except pexpect.EOF:
@@ -670,8 +691,95 @@
             main.cleanup()
             main.exit()
     
-    #TODO:
-    #def hosts(self):
+    def hosts(self, json_format=True, grep_str=""):
+        '''
+        Lists all discovered hosts 
+        Optional argument:
+            * grep_str - pass in a string to grep
+        '''
+        try:
+            self.handle.sendline("")
+            self.handle.expect("onos>")
+            
+            if json_format:
+                if not grep_str:
+                    self.handle.sendline("hosts -j")
+                    self.handle.expect("hosts -j")
+                    self.handle.expect("onos>")
+                else:
+                    self.handle.sendline("hosts -j | grep '"+
+                        str(grep_str)+"'")
+                    self.handle.expect("hosts -j | grep '"+str(grep_str)+"'")
+                    self.handle.expect("onos>")
+                handle = self.handle.before
+                '''
+                handle variable here contains some ANSI escape color code sequences at the end which are invisible in the print command output
+                To make that escape sequence visible, use repr() function. The repr(handle) output when printed shows the ANSI escape sequences.
+                In json.loads(somestring), this somestring variable is actually repr(somestring) and json.loads would fail with the escape sequence.
+                So we take off that escape sequence using 
+                ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
+                handle1 = ansi_escape.sub('', handle) 
+                '''
+                #print "repr(handle) =", repr(handle)
+                ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
+                handle1 = ansi_escape.sub('', handle)
+                #print "repr(handle1) = ", repr(handle1)
+                return handle1
+            else:
+                if not grep_str:
+                    self.handle.sendline("hosts")
+                    self.handle.expect("onos>")
+                else:
+                    self.handle.sendline("hosts | grep '"+
+                        str(grep_str)+"'")
+                    self.handle.expect("onos>")
+                handle = self.handle.before
+                print "handle =",handle
+                return handle
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
+
+    def get_host(self, mac):
+        '''
+        Return the first host from the hosts api whose 'id' contains 'mac'
+        Note: mac must be a colon seperated mac address, but could be a partial mac address
+        Return None if there is no match
+        '''
+        import json
+        try:
+            if mac == None:
+                return None
+            else:
+                mac = mac
+                raw_hosts = self.hosts()
+                hosts_json = json.loads(raw_hosts)
+                #search json for the host with mac then return the device
+                for host in hosts_json:
+                    print "%s in  %s?" % (mac, host['id'])
+                    if mac in host['id']:
+                        return host
+            return None
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
+
 
     def get_hosts_id(self, host_list):
         '''
@@ -757,6 +865,42 @@
             main.cleanup()
             main.exit()
 
+    def add_optical_intent(self, ingress_device, egress_device):
+        '''
+        Required:
+            * ingress_device: device id of ingress device
+            * egress_device: device id of egress device
+        Optional:
+            TODO: Still needs to be implemented via dev side
+        ''' 
+        try:
+            self.handle.sendline("add-optical-intent "+
+                    str(ingress_device) + " " + str(egress_device))
+            self.handle.expect("add-optical-intent")
+            i = self.handle.expect([
+                "Error",
+                "onos>"])
+
+            handle = self.handle.before
+
+            #If error, return error message
+            if i == 0:
+                return handle
+            else:
+                return main.TRUE
+        
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
+
     def add_point_intent(self, ingress_device, port_ingress,
             egress_device, port_egress, ethType="", ethSrc="",
             ethDst=""):
@@ -1146,4 +1290,65 @@
             main.cleanup()
             main.exit()
 
+    def check_status(self, ip, numoswitch, numolink, log_level="info"):
+        '''
+        Checks the number of swithes & links that ONOS sees against the 
+        supplied values. By default this will report to main.log, but the 
+        log level can be specifid.
+        
+        Params: ip = ip used for the onos cli
+                numoswitch = expected number of switches
+                numlink = expected number of links
+                log_level = level to log to. Currently accepts 'info', 'warn' and 'report'
+
+
+        log_level can
+
+        Returns: main.TRUE if the number of switchs and links are correct, 
+                 main.FALSE if the numer of switches and links is incorrect,
+                 and main.ERROR otherwise
+        '''
+
+        try:
+            topology = self.get_topology(ip)
+            if topology == {}:
+                return main.ERROR
+            output = ""
+            #Is the number of switches is what we expected
+            devices = topology.get('devices',False)
+            links = topology.get('links',False)
+            if devices == False or links == False:
+                return main.ERROR
+            switch_check = ( int(devices) == int(numoswitch) )
+            #Is the number of links is what we expected
+            link_check = ( int(links) == int(numolink) )
+            if (switch_check and link_check):
+                #We expected the correct numbers
+                output = output + "The number of links and switches match "\
+                        + "what was expected"
+                result = main.TRUE
+            else:
+                output = output + \
+                        "The number of links and switches does not match what was expected"
+                result = main.FALSE
+            output = output + "\n ONOS sees %i devices (%i expected) and %i links (%i expected)"\
+                    % ( int(devices), int(numoswitch), int(links), int(numolink) )
+            if log_level == "report":
+                main.log.report(output)
+            elif log_level == "warn":
+                main.log.warn(output)
+            else:
+                main.log.info(output)
+            return result 
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
     #***********************************
diff --git a/TestON/drivers/common/cli/onosdriver.py b/TestON/drivers/common/cli/onosdriver.py
index f22f064..e924c29 100644
--- a/TestON/drivers/common/cli/onosdriver.py
+++ b/TestON/drivers/common/cli/onosdriver.py
@@ -366,10 +366,14 @@
             self.handle.sendline("export TERM=xterm-256color")
             self.handle.expect("xterm-256color")
             self.handle.expect("\$")
-            self.handle.sendline("cd " + self.home + "; git log -1 --pretty=fuller --decorate=short | grep -A 5 \"commit\" --color=never; cd \.\.")
-            self.handle.expect("cd ..")
+            self.handle.sendline("\n")
+            self.handle.expect("\$")
+            self.handle.sendline("cd " + self.home + "; git log -1 --pretty=fuller --decorate=short | grep -A 6 \"commit\" --color=never")
+            self.handle.expect("--color=never")
             self.handle.expect("\$")
             response=(self.name +": \n"+ str(self.handle.before + self.handle.after))
+            self.handle.sendline("cd " + self.home)
+            self.handle.expect("\$")
             lines=response.splitlines()
             for line in lines:
                 print line
@@ -411,7 +415,9 @@
         temp_directory = "/tmp/"
         #Create the cell file in the directory for writing (w+)
         cell_file = open(temp_directory+file_name , 'w+')
-        
+       
+        comment = ""
+        comment_string = "#"+ comment
         #Feature string is hardcoded environment variables
         #That you may wish to use by default on startup.
         #Note that you  may not want certain features listed
@@ -430,24 +436,24 @@
         #Omit last element of list to format for NIC
         temp_list = temp_list[:-1]
         #Structure the nic string ip
-        nic_addr = ".".join(temp_list) + ".*\n"
+        nic_addr = ".".join(temp_list) + ".*"
         onos_nic_string = "export ONOS_NIC="+nic_addr
 
         try:
             #Start writing to file
-            cell_file.write(core_feature_string + "\n")
-            cell_file.write(onos_nic_string) 
-            cell_file.write(mn_string +"'"+ mn_ip_addrs +"'"+ "\n") 
+            cell_file.write(onos_nic_string + "\n") 
 
             for arg in onos_ip_addrs:
                 #For each argument in onos_ip_addrs, write to file
                 #Output should look like the following:
-                #   export OC1='10.128.20.11'
-                #   export OC2='10.128.20.12'
+                #   export OC1="10.128.20.11"
+                #   export OC2="10.128.20.12"
                 cell_file.write(onos_string + str(temp_count) +
-                        "=" + "'" + arg + "'" + "\n" )
+                        "=" + "\"" + arg + "\"" + "\n" )
                 temp_count = temp_count + 1
             
+            cell_file.write(mn_string +"\""+ mn_ip_addrs +"\""+ "\n") 
+            cell_file.write(core_feature_string + "\n")
             cell_file.close()
 
             #We use os.system to send the command to TestON cluster
@@ -629,10 +635,10 @@
                 main.log.warn("Network is unreachable")
                 return main.FALSE
             elif i == 1:
-                main.log.info("ONOS was installed on the VM and started")
+                main.log.info("ONOS was installed on " + node + " and started")
                 return main.TRUE
             elif i == 2: 
-                main.log.info("Installation of ONOS on the VM timed out")
+                main.log.info("Installation of ONOS on " + node + " timed out")
                 return main.FALSE
 
         except pexpect.EOF:
@@ -996,7 +1002,7 @@
         self.handle.expect("\$")
         self.handle.sendline("")
         self.handle.sendline("tshark -i "+str(interface)+
-                " -t e | grep --line-buffered \""+str(grep)+"\" > "+directory+" &")
+                " -t e | grep --line-buffered \""+str(grep)+"\" >"+directory+" &")
         self.handle.sendline("\r")
         self.handle.expect("Capturing on")
         self.handle.sendline("\r")
@@ -1006,7 +1012,8 @@
         '''
         Removes wireshark files from /tmp and kills all tshark processes
         '''
-        self.execute(cmd="rm /tmp/wireshark*")
+        #Remove all pcap from previous captures
+        self.execute(cmd="sudo rm /tmp/wireshark*")
         self.handle.sendline("")
         self.handle.sendline("sudo kill -9 `ps -ef | grep \"tshark -i\" |"+
                 " grep -v grep | awk '{print $2}'`")
diff --git a/TestON/tests/JonTest/JonTest.params b/TestON/tests/JonTest/JonTest.params
new file mode 100755
index 0000000..f0b64a5
--- /dev/null
+++ b/TestON/tests/JonTest/JonTest.params
@@ -0,0 +1,18 @@
+<PARAMS>
+    
+    <testcases>1,4,3,7</testcases>
+    
+    <Git>True</Git>
+    #Environment variables
+    <ENV>
+        <cellName>multi</cellName>
+    </ENV>
+
+    <CTRL>
+        <ip1>10.128.30.11</ip1>
+        <port1>6633</port1>
+        <ip2>10.128.30.12</ip2>
+        <port2>6633</port2>
+    </CTRL>
+
+</PARAMS>
diff --git a/TestON/tests/JonTest/JonTest.py b/TestON/tests/JonTest/JonTest.py
new file mode 100755
index 0000000..5ed17db
--- /dev/null
+++ b/TestON/tests/JonTest/JonTest.py
@@ -0,0 +1,376 @@
+
+#Testing the basic functionality of ONOS Next
+#For sanity and driver functionality excercises only.
+
+import time
+import sys
+import os
+import re
+
+class JonTest:
+    def __init__(self):
+        self.default = ''
+
+    def CASE1(self, main):
+        '''
+        Startup sequence:
+        git pull
+        mvn clean install
+        onos-package
+        cell <name>
+        onos-verify-cell
+        onos-install -f
+        onos-wait-for-start
+        '''
+        import time
+        
+        PULL_CODE = False
+        if main.params['Git'] == 'True':
+            PULL_CODE = True
+        cell_name = main.params['ENV']['cellName']
+        ONOS1_ip = main.params['CTRL']['ip1']
+        ONOS1_port = main.params['CTRL']['port1']
+        ONOS2_ip = main.params['CTRL']['ip2']
+        ONOS2_port = main.params['CTRL']['port2']
+        
+        main.case("Setting up test environment")
+        
+        main.step("Applying cell variable to environment")
+        cell_result = main.ONOSbench.set_cell(cell_name)
+        #cell_result = main.ONOSbench.set_cell("temp_cell_2")
+        verify_result = main.ONOSbench.verify_cell()
+
+        if PULL_CODE:
+            main.step("Git checkout and pull master")
+            #main.log.report("Skipping git pull")
+            main.ONOSbench.git_checkout("master")
+            git_pull_result = main.ONOSbench.git_pull()
+            main.log.report(main.ONOSbench.get_version())
+
+            main.step("Using mvn clean & install")
+            clean_install_result = main.FALSE
+            if git_pull_result:
+                clean_install_result = main.ONOSbench.clean_install()
+            else:
+                main.log.report("git pull failed so skipping mvn clean install")
+
+        main.step("Creating ONOS package")
+        package_result = main.ONOSbench.onos_package()
+
+        main.step("Installing ONOS package")
+        onos1_install_result = main.ONOSbench.onos_install(options="-f", node=ONOS1_ip)
+        onos2_install_result = main.ONOSbench.onos_install(options="-f", node=ONOS2_ip)
+        onos1_isup = main.ONOSbench.isup(ONOS1_ip)
+        onos2_isup = main.ONOSbench.isup(ONOS2_ip)
+   
+        main.step("Starting ONOS service")
+        start_result = main.TRUE
+        #start_result = main.ONOSbench.onos_start(ONOS1_ip)
+
+        case1_result = (clean_install_result and package_result and\
+                cell_result and verify_result and onos1_install_result and\
+                onos2_install_result and onos1_isup and onos2_isup )
+        utilities.assert_equals(expect=main.TRUE, actual=case1_result,
+                onpass="Test startup successful",
+                onfail="Test startup NOT successful")
+
+
+    def CASE11(self, main):
+        '''
+        Cleanup sequence:
+        onos-service <node_ip> stop
+        onos-uninstall
+
+        TODO: Define rest of cleanup
+        
+        '''
+
+        ONOS1_ip = main.params['CTRL']['ip1']
+
+        main.case("Cleaning up test environment")
+
+        main.step("Testing ONOS kill function")
+        kill_result = main.ONOSbench.onos_kill(ONOS1_ip)
+
+        main.step("Stopping ONOS service")
+        stop_result = main.ONOSbench.onos_stop(ONOS1_ip)
+
+        main.step("Uninstalling ONOS service") 
+        uninstall_result = main.ONOSbench.onos_uninstall()
+
+    def CASE3(self, main):
+        '''
+        Test 'onos' command and its functionality in driver
+        '''
+        
+        ONOS1_ip = main.params['CTRL']['ip1']
+
+        main.case("Testing 'onos' command")
+
+        main.step("Sending command 'onos -w <onos-ip> system:name'")
+        cmdstr1 = "system:name"
+        cmd_result1 = main.ONOSbench.onos_cli(ONOS1_ip, cmdstr1) 
+        main.log.info("onos command returned: "+cmd_result1)
+
+        main.step("Sending command 'onos -w <onos-ip> onos:topology'")
+        cmdstr2 = "onos:topology"
+        cmd_result2 = main.ONOSbench.onos_cli(ONOS1_ip, cmdstr2)
+        main.log.info("onos command returned: "+cmd_result2)
+        
+        main.step("Testing check_status")
+        check_status_results = main.FALSE
+        check_status_results =  main.ONOSbench.check_status(ONOS1_ip, 4, 6)
+        main.log.info("Results of check_status " + str(check_status_results))
+
+        main.step("Sending command 'onos -w <onos-ip> bundle:list'")
+        cmdstr3 = "bundle:list"
+        cmd_result3 = main.ONOSbench.onos_cli(ONOS1_ip, cmdstr3)
+        main.log.info("onos command returned: "+cmd_result3)
+        case3_result = (cmd_result1 and cmd_result2 and\
+                check_status_results and cmd_result3 )
+        utilities.assert_equals(expect=main.TRUE, actual=case3_result,
+                onpass="Test case 3 successful",
+                onfail="Test case 3 NOT successful")
+
+    def CASE4(self, main):
+        import re
+        import time
+        main.case("Pingall Test(No intents are added)")
+        main.step("Assigning switches to controllers")
+        for i in range(1,5): #1 to (num of switches +1)
+            main.Mininet1.assign_sw_controller(sw=str(i),count=2, 
+                    ip1=ONOS1_ip, port1=ONOS1_port,
+                    ip2=ONOS2_ip, port2=ONOS2_port)
+
+        switch_mastership = main.TRUE
+        for i in range (1,5):
+            response = main.Mininet1.get_sw_controller("s"+str(i))
+            print("Response is " + str(response))
+            if re.search("tcp:"+ONOS1_ip,response):
+                switch_mastership = switch_mastership and main.TRUE
+            else:
+                switch_mastership = main.FALSE
+
+
+        #REACTIVE FWD test
+        main.step("Pingall")
+        ping_result = main.FALSE
+        time1 = time.time()
+        ping_result = main.Mininet1.pingall()
+        time2 = time.time()
+        print "Time for pingall: %2f seconds" % (time2 - time1)
+      
+        case4_result = switch_mastership and ping_result
+        utilities.assert_equals(expect=main.TRUE, actual=case4_result,
+                onpass="Pingall Test successful",
+                onfail="Pingall Test NOT successful")
+
+    def CASE5(self, main):
+        '''
+        Test the ONOS-cli functionality
+        
+        Below are demonstrations of what the 
+        ONOS cli driver functions can be used for.
+        '''
+        import time
+        import json
+
+        cell_name = main.params['ENV']['cellName']
+        ONOS1_ip = main.params['CTRL']['ip1']
+        
+        main.case("Testing the ONOS-cli")
+        
+        main.step("Set cell for ONOS-cli environment")
+        main.ONOScli.set_cell(cell_name)
+
+        main.step("Start ONOS-cli")
+        main.ONOScli.start_onos_cli(ONOS1_ip)
+
+        main.step("issue command: onos:topology")
+        topology_obj = main.ONOScli.topology()
+
+        main.step("issue various feature:install <str> commands")
+        #main.ONOScli.feature_install("onos-app-fwd")
+        #main.ONOScli.feature_install("onos-rest")
+
+        main.step("Add a bad node")
+        node_result = main.ONOScli.add_node("111", "10.128.20.")
+        if node_result == main.TRUE:
+            main.log.info("Node successfully added")
+
+        main.step("Add a correct node")
+        node_result = main.ONOScli.add_node("111", "10.128.20.12")
+
+        main.step("Assign switches and list devices")
+        for i in range(1,8):
+            main.Mininet1.handle.sendline("sh ovs-vsctl set-controller s"+str(i)+
+                    " tcp:10.128.20.11")
+            main.Mininet1.handle.expect("mininet>")
+        #Need to sleep to allow switch add processing
+        time.sleep(5)
+        list_result = main.ONOScli.devices()
+        main.log.info(list_result)
+
+        main.step("Get all devices id")
+        devices_id_list = main.ONOScli.get_all_devices_id()
+        main.log.info(devices_id_list)
+
+        main.step("Get path and cost between device 1 and 7")
+        (path, cost) = main.ONOScli.paths(devices_id_list[0], devices_id_list[6])
+        main.log.info("Path: "+str(path))
+        main.log.info("Cost: "+str(cost))
+
+        main.step("Get nodes currently visible")
+        nodes_str = main.ONOScli.nodes()
+        main.log.info(nodes_str)
+
+        main.step("Get all nodes id's")
+        node_id_list = main.ONOScli.get_all_nodes_id()
+        main.log.info(node_id_list)
+
+        main.step("Set device "+str(devices_id_list[0])+" to role: standby")
+        device_role_result = main.ONOScli.device_role(
+                devices_id_list[0], node_id_list[0], "standby")
+        if device_role_result == main.TRUE:
+            main.log.report("Device role successfully set")
+
+        main.step("Revert device role to master")
+        device_role = main.ONOScli.device_role(
+                devices_id_list[0], node_id_list[0], "master")
+
+        main.step("Check devices / role again")
+        dev_result = main.ONOScli.devices()
+        main.log.info(dev_result)
+       
+        #Sample steps to push intents ***********
+        # * Obtain host id in ONOS format 
+        # * Push intents
+        main.step("Get list of hosts from Mininet")
+        host_list = main.Mininet2.get_hosts()
+        main.log.info(host_list)
+
+        main.step("Get host list in ONOS format")
+        host_onos_list = main.ONOScli.get_hosts_id(host_list)
+        main.log.info(host_onos_list)
+
+        main.step("Ensure that reactive forwarding is installed")
+        feature_result = main.ONOScli.feature_install("onos-app-fwd")
+
+        time.sleep(5)
+
+        main.Mininet2.handle.sendline("\r")
+        main.Mininet2.handle.sendline("h4 ping h5 -c 1")
+
+        time.sleep(5)
+
+        main.step("Get hosts")
+        main.ONOScli.handle.sendline("hosts")
+        main.ONOScli.handle.expect("onos>")
+        hosts = main.ONOScli.handle.before
+        main.log.info(hosts)
+
+        main.step("Install host-to-host-intents between h4 and h5")
+        intent_install = main.ONOScli.add_host_intent(
+                host_onos_list[3], host_onos_list[4])
+        main.log.info(intent_install)
+
+        main.step("Uninstall reactive forwarding to test host-to-host intent")
+        main.ONOScli.feature_uninstall("onos-app-fwd")
+
+        main.step("Get intents installed on ONOS")
+        get_intent_result = main.ONOScli.intents()
+        main.log.info(get_intent_result)
+        #****************************************
+
+
+    def CASE7(self, main):
+        '''
+        Test compare topo functions
+        '''
+        import sys
+        sys.path.append("/home/admin/sts") # Trying to remove some dependancies, #FIXME add this path to params
+        from sts.topology.teston_topology import TestONTopology # assumes that sts is already in you PYTHONPATH
+        import json
+
+        main.step("Create TestONTopology object")
+        ctrls = []
+        count = 1
+        while True:
+            temp = ()
+            if ('ip' + str(count)) in main.params['CTRL']:
+                temp = temp + (getattr(main,('ONOS' + str(count))),)
+                temp = temp + ("ONOS"+str(count),)
+                temp = temp + (main.params['CTRL']['ip'+str(count)],)
+                temp = temp + (eval(main.params['CTRL']['port'+str(count)]),)
+                ctrls.append(temp)
+                count = count + 1
+            else:
+                break
+        MNTopo = TestONTopology(main.Mininet1, ctrls) # can also add Intent API info for intent operations
+
+        ONOS1_ip = main.params['CTRL']['ip1']
+        ONOS2_ip = main.params['CTRL']['ip2']
+
+        main.ONOScli1.start_onos_cli(ONOS1_ip)
+        main.ONOScli2.start_onos_cli(ONOS2_ip)
+    
+        main.step("Collecting topology information from ONOS")
+        devices1 = main.ONOScli1.devices()
+        devices2 = main.ONOScli2.devices()
+        switch1 = main.ONOScli1.get_device("0000000000000001")
+        hosts1 = main.ONOScli1.hosts()
+        hosts2 = main.ONOScli2.hosts()
+        host1 = main.ONOScli1.get_host("00:00:00:00:00:01")
+        print json.dumps(json.loads(hosts1), sort_keys=True,indent=4,separators=(',', ': '))
+        print json.dumps(json.loads(hosts2), sort_keys=True,indent=4,separators=(',', ': '))
+        print json.dumps(host1, sort_keys=True,indent=4,separators=(',', ': '))
+        ports1 = main.ONOScli1.ports()
+        ports2 = main.ONOScli2.ports()
+        links1 = main.ONOScli1.links()
+        links2 = main.ONOScli2.links()
+
+
+        main.step("Comparing ONOS topology to MN")
+        #results =  main.Mininet1.compare_topo(MNTopo, json.loads(devices))
+        switches_results1 =  main.Mininet1.compare_switches(MNTopo, json.loads(devices1))
+        utilities.assert_equals(expect=main.TRUE, actual=switches_results1,
+                onpass="ONOS1 Switches view is correct",
+                onfail="ONOS1 Switches view is incorrect")
+
+        switches_results2 =  main.Mininet1.compare_switches(MNTopo, json.loads(devices2))
+        utilities.assert_equals(expect=main.TRUE, actual=switches_results2,
+                onpass="ONOS2 Switches view is correct",
+                onfail="ONOS2 Switches view is incorrect")
+
+
+        ports_results1 =  main.Mininet1.compare_ports(MNTopo, json.loads(ports1))
+        utilities.assert_equals(expect=main.TRUE, actual=ports_results1,
+                onpass="ONOS1 Ports view is correct",
+                onfail="ONOS1 Ports view is incorrect")
+
+        ports_results2 =  main.Mininet1.compare_ports(MNTopo, json.loads(ports2))
+        utilities.assert_equals(expect=main.TRUE, actual=ports_results2,
+                onpass="ONOS2 Ports view is correct",
+                onfail="ONOS2 Ports view is incorrect")
+
+        links_results1 =  main.Mininet1.compare_links(MNTopo, json.loads(links1))
+        utilities.assert_equals(expect=main.TRUE, actual=links_results1,
+                onpass="ONOS1 Links view is correct",
+                onfail="ONOS1 Links view is incorrect")
+
+        links_results2 =  main.Mininet1.compare_links(MNTopo, json.loads(links2))
+        utilities.assert_equals(expect=main.TRUE, actual=links_results2,
+                onpass="ONOS2 Links view is correct",
+                onfail="ONOS2 Links view is incorrect")
+
+        topo_result = switches_results1 and switches_results2 \
+                and ports_results1 and ports_results2\
+                and links_results1 and links_results2
+        utilities.assert_equals(expect=main.TRUE, actual=topo_result,
+                onpass="Topology Check Test successful",
+                onfail="Topology Check Test NOT successful")
+
+######
+#jhall@onlab.us
+#andrew@onlab.us
+######
diff --git a/TestON/tests/JonTest/JonTest.topo b/TestON/tests/JonTest/JonTest.topo
new file mode 100755
index 0000000..bf8cb18
--- /dev/null
+++ b/TestON/tests/JonTest/JonTest.topo
@@ -0,0 +1,65 @@
+<TOPOLOGY>
+    <COMPONENT>
+
+        <ONOSbench>
+            <host>10.128.30.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOSbench>
+
+        <ONOScli1>
+            <host>10.128.30.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli1>
+
+        <ONOScli2>
+            <host>10.128.30.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli2>
+
+        <ONOS1>
+            <host>10.128.30.11</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS1>
+
+        <ONOS2>
+            <host>10.128.30.12</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS2>
+
+        <Mininet1>
+            <host>10.128.11.11</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>MininetCliDriver</type>
+            <connect_order>4</connect_order>
+            <COMPONENTS>
+                #Specify the Option for mininet
+                <arg1> --topo tree,2,3</arg1>
+                <arg2> </arg2>
+                <arg3> </arg3>
+                <controller> remote </controller>
+            </COMPONENTS>
+        </Mininet1>
+
+    </COMPONENT>
+</TOPOLOGY>
diff --git a/TestON/tests/JonTest/__init__.py b/TestON/tests/JonTest/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/TestON/tests/JonTest/__init__.py
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.params b/TestON/tests/TopoPerfNext/TopoPerfNext.params
index 463ec02..53d61b8 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.params
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.params
@@ -27,7 +27,7 @@
     </MN>
 
     <BENCH>
-        <ip>10.128.20.10</ip>
+        <ip>10.128.174.10</ip>
     </BENCH>
 
     <TEST>
@@ -35,4 +35,11 @@
         <numIter>10</numIter>
          
     </TEST>
+
+    <JSON>
+        <deviceTimestamp>topologyDeviceEventTimestamp</deviceTimestamp>
+        <hostTimestamp>topologyHostEventTimestamp</hostTimestamp>
+        <linkTimestamp>topologyLinkEventTimestamp</linkTimestamp>
+        <graphTimestamp>topologyGraphEventTimestamp</graphTimestamp>
+    </JSON>
 </PARAMS>
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.py b/TestON/tests/TopoPerfNext/TopoPerfNext.py
index eb49669..446befa 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.py
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.py
@@ -17,6 +17,8 @@
         '''
         ONOS startup sequence
         '''
+        import time
+    
         cell_name = main.params['ENV']['cellName']
 
         git_pull = main.params['GIT']['autoPull']
@@ -57,20 +59,25 @@
         package_result = main.ONOSbench.onos_package()
 
         main.step("Installing ONOS package")
-        install_result = main.ONOSbench.onos_install()
+        install1_result = main.ONOSbench.onos_install(node=ONOS1_ip)
+        install2_result = main.ONOSbench.onos_install(node=ONOS2_ip)
+        install3_result = main.ONOSbench.onos_install(node=ONOS3_ip)
 
-        main.step("Starting ONOS service")
-        start_result = main.ONOSbench.onos_start(ONOS1_ip)
+        #NOTE: This step may be unnecessary
+        #main.step("Starting ONOS service")
+        #start_result = main.ONOSbench.onos_start(ONOS1_ip)
 
         main.step("Set cell for ONOS cli env")
         main.ONOS1cli.set_cell(cell_name)
         main.ONOS2cli.set_cell(cell_name)
         main.ONOS3cli.set_cell(cell_name)
 
+        time.sleep(10)
+
         main.step("Start onos cli")
-        main.ONOS1cli.start_onos_cli(ONOS1_ip)
-        main.ONOS2cli.start_onos_cli(ONOS2_ip)
-        main.ONOS3cli.start_onos_cli(ONOS3_ip)
+        cli1 = main.ONOS1cli.start_onos_cli(ONOS1_ip)
+        cli2 = main.ONOS2cli.start_onos_cli(ONOS2_ip)
+        cli3 = main.ONOS3cli.start_onos_cli(ONOS3_ip)
 
         main.step("Enable metrics feature")
         main.ONOS1cli.feature_install("onos-app-metrics-topology")
@@ -81,13 +88,27 @@
                 actual= cell_file_result and cell_apply_result and\
                         verify_cell_result and checkout_result and\
                         pull_result and mvn_result and\
-                        install_result and start_result,
+                        install1_result and install2_result and\
+                        install3_result,
                 onpass="ONOS started successfully",
                 onfail="Failed to start ONOS")
 
     def CASE2(self, main):
         '''
         Assign s1 to ONOS1 and measure latency
+        
+        There are 4 levels of latency measurements to this test:
+        1) End-to-end measurement: Complete end-to-end measurement
+           from TCP (SYN/ACK) handshake to Graph change
+        2) OFP-to-graph measurement: 'ONOS processing' snippet of
+           measurement from OFP Vendor message to Graph change
+        3) OFP-to-device measurement: 'ONOS processing without 
+           graph change' snippet of measurement from OFP vendor
+           message to Device change timestamp
+        4) T0-to-device measurement: Measurement that includes
+           the switch handshake to devices timestamp without 
+           the graph view change. (TCP handshake -> Device 
+           change)
         '''
         import time
         import subprocess
@@ -105,6 +126,18 @@
         #Number of iterations of case
         num_iter = main.params['TEST']['numIter']
        
+        #Timestamp 'keys' for json metrics output.
+        #These are subject to change, hence moved into params
+        deviceTimestamp = main.params['JSON']['deviceTimestamp']
+        graphTimestamp = main.params['JSON']['graphTimestamp']
+
+        #List of switch add latency collected from
+        #all iterations
+        latency_end_to_end_list = []
+        latency_ofp_to_graph_list = []
+        latency_ofp_to_device_list = []
+        latency_t0_to_device_list = []
+
         #Directory/file to store tshark results
         tshark_of_output = "/tmp/tshark_of_topo.txt"
         tshark_tcp_output = "/tmp/tshark_tcp_topo.txt"
@@ -144,7 +177,8 @@
             #Wait and ensure switch is assigned
             #before stopping tshark
             time.sleep(30)
-    
+   
+            main.log.info("Stopping all Tshark processes")
             main.ONOS1.stop_tshark()
 
             #tshark output is saved in ONOS. Use subprocess
@@ -163,7 +197,7 @@
             main.log.info("Object read in from TCP capture: "+
                     str(temp_text))
             if len(temp_text) > 1:
-                t0_tcp = int(float(temp_text[1])*1000)
+                t0_tcp = float(temp_text[1])*1000.0
             else:
                 main.log.error("Tshark output file for TCP"+
                         " returned unexpected results")
@@ -179,6 +213,7 @@
             of_file = open(tshark_of_output, 'r')
            
             line_ofp = ""
+            #Read until last line of file
             while True:
                 temp_text = of_file.readline()
                 if temp_text !='':
@@ -191,7 +226,7 @@
                     str(line_ofp))
     
             if len(line_ofp) > 1:
-                t0_ofp = int(float(obj[1])*1000)
+                t0_ofp = float(obj[1])*1000.0
             else:
                 main.log.error("Tshark output file for OFP"+
                         " returned unexpected results")
@@ -206,56 +241,212 @@
             json_str_1 = main.ONOS1cli.topology_events_metrics()
             json_str_2 = main.ONOS2cli.topology_events_metrics()
             json_str_3 = main.ONOS3cli.topology_events_metrics()
-    
-            #TESTING:
-            main.log.info(json_str_1)
-            main.log.info(json_str_2)
-            main.log.info(json_str_3)
 
             json_obj_1 = json.loads(json_str_1)
             json_obj_2 = json.loads(json_str_2)
             json_obj_3 = json.loads(json_str_3)
 
-            main.log.info(json_obj_1)
-            main.log.info(json_obj_2)
-            main.log.info(json_obj_3)
+            #Obtain graph timestamp. This timestsamp captures
+            #the epoch time at which the topology graph was updated.
+            graph_timestamp_1 = \
+                    json_obj_1[graphTimestamp]['value']
+            graph_timestamp_2 = \
+                    json_obj_2[graphTimestamp]['value']
+            graph_timestamp_3 = \
+                    json_obj_3[graphTimestamp]['value']
 
-            #TODO:
-            #Parse json object for timestamp
-            topo_timestamp_1 = 0
-            topo_timestamp_2 = 0
-            topo_timestamp_3 = 0
+            #Obtain device timestamp. This timestamp captures
+            #the epoch time at which the device event happened
+            device_timestamp_1 = \
+                    json_obj_1[deviceTimestamp]['value'] 
+            device_timestamp_2 = \
+                    json_obj_2[deviceTimestamp]['value'] 
+            device_timestamp_3 = \
+                    json_obj_3[deviceTimestamp]['value'] 
 
-            #ONOS processing latency
-            delta_of_1 = int(topo_timestamp_1) - int(t0_ofp)
-            delta_of_2 = int(topo_timestamp_2) - int(t0_ofp)
-            delta_of_3 = int(topo_timestamp_3) - int(t0_ofp)
-    
-            #End-to-end processing latency
-            delta_tcp_1 = int(topo_timestamp_1) - int(t0_tcp)
-            delta_tcp_2 = int(topo_timestamp_2) - int(t0_tcp)
-            delta_tcp_3 = int(topo_timestamp_3) - int(t0_tcp)
+            #t0 to device processing latency 
+            delta_device_1 = int(device_timestamp_1) - int(t0_tcp)
+            delta_device_2 = int(device_timestamp_2) - int(t0_tcp)
+            delta_device_3 = int(device_timestamp_3) - int(t0_tcp)
+        
+            #Get average of delta from all instances
+            avg_delta_device = \
+                    (int(delta_device_1)+\
+                     int(delta_device_2)+\
+                     int(delta_device_3)) / 3
+
+            #Ensure avg delta meets the threshold before appending
+            if avg_delta_device > 0.0 and avg_delta_device < 10000:
+                latency_t0_to_device_list.append(avg_delta_device)
+            else:
+                main.log.info("Results for t0-to-device ignored"+\
+                        "due to excess in threshold")
+
+            #t0 to graph processing latency (end-to-end)
+            delta_graph_1 = int(graph_timestamp_1) - int(t0_tcp)
+            delta_graph_2 = int(graph_timestamp_2) - int(t0_tcp)
+            delta_graph_3 = int(graph_timestamp_3) - int(t0_tcp)
+        
+            #Get average of delta from all instances
+            avg_delta_graph = \
+                    (int(delta_graph_1)+\
+                     int(delta_graph_2)+\
+                     int(delta_graph_3)) / 3
+
+            #Ensure avg delta meets the threshold before appending
+            if avg_delta_graph > 0.0 and avg_delta_graph < 10000:
+                latency_end_to_end_list.append(avg_delta_graph)
+            else:
+                main.log.info("Results for end-to-end ignored"+\
+                        "due to excess in threshold")
+
+            #ofp to graph processing latency (ONOS processing)
+            delta_ofp_graph_1 = int(graph_timestamp_1) - int(t0_ofp)
+            delta_ofp_graph_2 = int(graph_timestamp_2) - int(t0_ofp)
+            delta_ofp_graph_3 = int(graph_timestamp_3) - int(t0_ofp)
+            
+            avg_delta_ofp_graph = \
+                    (int(delta_ofp_graph_1)+\
+                     int(delta_ofp_graph_2)+\
+                     int(delta_ofp_graph_3)) / 3
+            
+            if avg_delta_ofp_graph > 0.0 and avg_delta_ofp_graph < 10000:
+                latency_ofp_to_graph_list.append(avg_delta_ofp_graph)
+            else:
+                main.log.info("Results for ofp-to-graph "+\
+                        "ignored due to excess in threshold")
+
+            #ofp to device processing latency (ONOS processing)
+            delta_ofp_device_1 = float(device_timestamp_1) - float(t0_ofp)
+            delta_ofp_device_2 = float(device_timestamp_2) - float(t0_ofp)
+            delta_ofp_device_3 = float(device_timestamp_3) - float(t0_ofp)
+            
+            avg_delta_ofp_device = \
+                    (float(delta_ofp_device_1)+\
+                     float(delta_ofp_device_2)+\
+                     float(delta_ofp_device_3)) / 3.0
+            
+            #NOTE: ofp - delta measurements are occasionally negative
+            #      due to system time misalignment.
+            #TODO: Implement ptp across all clusters
+            #Just add the calculation to list for now
+            latency_ofp_to_device_list.append(avg_delta_ofp_device)
 
             #TODO:
             #Fetch logs upon threshold excess
 
-            main.log.info("ONOS1 delta OFP: "+str(delta_of_1))
-            main.log.info("ONOS2 delta OFP: "+str(delta_of_2))
-            main.log.info("ONOS3 delta OFP: "+str(delta_of_3))
-
-            main.log.info("ONOS1 delta TCP: "+str(delta_tcp_1))
-            main.log.info("ONOS2 delta TCP: "+str(delta_tcp_2))
-            main.log.info("ONOS3 delta TCP: "+str(delta_tcp_3))
             
+            main.log.info("ONOS1 delta end-to-end: "+
+                    str(delta_graph_1) + " ms")
+            main.log.info("ONOS2 delta end-to-end: "+
+                    str(delta_graph_2) + " ms")
+            main.log.info("ONOS3 delta end-to-end: "+
+                    str(delta_graph_3) + " ms")
+
+            main.log.info("ONOS1 delta OFP - graph: "+
+                    str(delta_ofp_graph_1) + " ms")
+            main.log.info("ONOS2 delta OFP - graph: "+
+                    str(delta_ofp_graph_2) + " ms")
+            main.log.info("ONOS3 delta OFP - graph: "+
+                    str(delta_ofp_graph_3) + " ms")
+            
+            main.log.info("ONOS1 delta device - t0: "+
+                    str(delta_device_1) + " ms")
+            main.log.info("ONOS2 delta device - t0: "+
+                    str(delta_device_2) + " ms")
+            main.log.info("ONOS3 delta device - t0: "+
+                    str(delta_device_3) + " ms")
+          
+            main.log.info("ONOS1 delta OFP - device: "+
+                    str(delta_ofp_device_1) + " ms")
+            main.log.info("ONOS2 delta OFP - device: "+
+                    str(delta_ofp_device_2) + " ms")
+            main.log.info("ONOS3 delta OFP - device: "+
+                    str(delta_ofp_device_3) + " ms")
+
             main.step("Remove switch from controller")
             main.Mininet1.delete_sw_controller("s1")
 
             time.sleep(5)
 
+        #END of for loop iteration
+
+        #If there is at least 1 element in each list,
+        #pass the test case
+        if len(latency_end_to_end_list) > 0 and\
+           len(latency_ofp_to_graph_list) > 0 and\
+           len(latency_ofp_to_device_list) > 0 and\
+           len(latency_t0_to_device_list) > 0:
+            assertion = main.TRUE
+        elif len(latency_end_to_end_list) == 0:
+            #The appending of 0 here is to prevent 
+            #the min,max,sum functions from failing 
+            #below
+            latency_end_to_end_list.append(0)
+            assertion = main.FALSE
+        elif len(latency_ofp_to_graph_list) == 0:
+            latency_ofp_to_graph_list.append(0)
+            assertion = main.FALSE
+        elif len(latency_ofp_to_device_list) == 0:
+            latency_ofp_to_device_list.append(0)
+            assertion = main.FALSE
+        elif len(latency_t0_to_device_list) == 0:
+            latency_t0_to_device_list.append(0)
+            assertion = main.FALSE
+
+        #Calculate min, max, avg of latency lists
+        latency_end_to_end_max = \
+                int(max(latency_end_to_end_list))
+        latency_end_to_end_min = \
+                int(min(latency_end_to_end_list))
+        latency_end_to_end_avg = \
+                (int(sum(latency_end_to_end_list)) / \
+                 len(latency_end_to_end_list))
+   
+        latency_ofp_to_graph_max = \
+                int(max(latency_ofp_to_graph_list))
+        latency_ofp_to_graph_min = \
+                int(min(latency_ofp_to_graph_list))
+        latency_ofp_to_graph_avg = \
+                (int(sum(latency_ofp_to_graph_list)) / \
+                 len(latency_ofp_to_graph_list))
+
+        latency_ofp_to_device_max = \
+                int(max(latency_ofp_to_device_list))
+        latency_ofp_to_device_min = \
+                int(min(latency_ofp_to_device_list))
+        latency_ofp_to_device_avg = \
+                (int(sum(latency_ofp_to_device_list)) / \
+                 len(latency_ofp_to_device_list))
+
+        latency_t0_to_device_max = \
+                float(max(latency_t0_to_device_list))
+        latency_t0_to_device_min = \
+                float(min(latency_t0_to_device_list))
+        latency_t0_to_device_avg = \
+                (float(sum(latency_t0_to_device_list)) / \
+                 len(latency_ofp_to_device_list))
+
+        main.log.report("Switch add - End-to-end latency: \n"+\
+                "Min: "+str(latency_end_to_end_min)+"\n"+\
+                "Max: "+str(latency_end_to_end_max)+"\n"+\
+                "Avg: "+str(latency_end_to_end_avg))
+        main.log.report("Switch add - OFP-to-Graph latency: \n"+\
+                "Min: "+str(latency_ofp_to_graph_min)+"\n"+\
+                "Max: "+str(latency_ofp_to_graph_max)+"\n"+\
+                "Avg: "+str(latency_ofp_to_graph_avg))
+        main.log.report("Switch add - OFP-to-Device latency: \n"+\
+                "Min: "+str(latency_ofp_to_device_min)+"\n"+\
+                "Max: "+str(latency_ofp_to_device_max)+"\n"+\
+                "Avg: "+str(latency_ofp_to_device_avg))
+        main.log.report("Switch add - t0-to-Device latency: \n"+\
+                "Min: "+str(latency_t0_to_device_min)+"\n"+\
+                "Max: "+str(latency_t0_to_device_max)+"\n"+\
+                "Avg: "+str(latency_t0_to_device_avg))
+
         utilities.assert_equals(expect=main.TRUE, actual=assertion,
                 onpass="Switch latency test successful",
                 onfail="Switch latency test failed")
-        
 
     def CASE3(self, main):
         '''
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.topo b/TestON/tests/TopoPerfNext/TopoPerfNext.topo
index 9ff8136..9e928a6 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.topo
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.topo
@@ -2,7 +2,7 @@
     <COMPONENT>
         
         <ONOSbench>
-            <host>10.128.20.10</host>
+            <host>10.128.174.10</host>
             <user>admin</user>
             <password>onos_test</password>
             <type>OnosDriver</type>
@@ -11,7 +11,7 @@
         </ONOSbench>
 
         <ONOS1cli>
-            <host>10.128.20.10</host>
+            <host>10.128.174.10</host>
             <user>admin</user>
             <password>onos_test</password>
             <type>OnosCliDriver</type>
@@ -20,7 +20,7 @@
         </ONOS1cli>
 
         <ONOS2cli>
-            <host>10.128.20.10</host>
+            <host>10.128.174.10</host>
             <user>admin</user>
             <password>onos_test</password>
             <type>OnosCliDriver</type>
@@ -29,7 +29,7 @@
         </ONOS2cli>
         
         <ONOS3cli>
-            <host>10.128.20.10</host>
+            <host>10.128.174.10</host>
             <user>admin</user>
             <password>onos_test</password>
             <type>OnosCliDriver</type>