Update: commiting the latest onosclidriver
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 5deb911..baed719 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -19,6 +19,8 @@
 import sys
 import pexpect
 import re
+import json
+import types
 sys.path.append( "../" )
 from drivers.common.clidriver import CLI
 
@@ -29,6 +31,9 @@
         """
         Initialize client
         """
+        self.name = None
+        self.home = None
+        self.handle = None
         super( CLI, self ).__init__()
 
     def connect( self, **connectargs ):
@@ -38,11 +43,13 @@
         try:
             for key in connectargs:
                 vars( self )[ key ] = connectargs[ key ]
-            self.home = "~/ONOS"
+            self.home = "~/onos"
             for key in self.options:
                 if key == "home":
                     self.home = self.options[ 'home' ]
                     break
+            if self.home is None or self.home == "":
+                self.home = "~/onos"
 
             self.name = self.options[ 'name' ]
             self.handle = super( OnosCliDriver, self ).connect(
@@ -67,7 +74,7 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -76,27 +83,25 @@
         """
         Called when Test is complete to disconnect the ONOS handle.
         """
-        response = ''
+        response = main.TRUE
         try:
-            self.handle.sendline( "" )
-            i = self.handle.expect( [ "onos>", "\$" ] )
-            if i == 0:
-                self.handle.sendline( "system:shutdown" )
-                self.handle.expect( "Confirm" )
-                self.handle.sendline( "yes" )
-                self.handle.expect( "\$" )
-            self.handle.sendline( "" )
-            self.handle.expect( "\$" )
-            self.handle.sendline( "exit" )
-            self.handle.expect( "closed" )
-
+            if self.handle:
+                i = self.logout()
+                if i == main.TRUE:
+                    self.handle.sendline( "" )
+                    self.handle.expect( "\$" )
+                    self.handle.sendline( "exit" )
+                    self.handle.expect( "closed" )
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
-            return None
+            response = main.FALSE
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":     " + self.handle.before )
-        except:
+        except ValueError:
+            main.log.exception( "Exception in discconect of " + self.name )
+            response = main.TRUE
+        except Exception:
             main.log.exception( self.name + ": Connection failed to the host" )
             response = main.FALSE
         return response
@@ -104,28 +109,38 @@
     def logout( self ):
         """
         Sends 'logout' command to ONOS cli
+        Returns main.TRUE if exited CLI and
+                main.FALSE on timeout (not guranteed you are disconnected)
+                None on TypeError
+                Exits test on unknown error or pexpect exits unexpectedly
         """
         try:
-            self.handle.sendline( "" )
-            i = self.handle.expect( [
-                "onos>",
-                "\$" ], timeout=10 )
-            if i == 0:
-                self.handle.sendline( "logout" )
-                self.handle.expect( "\$" )
-            elif i == 1:
+            if self.handle:
+                self.handle.sendline( "" )
+                i = self.handle.expect( [ "onos>", "\$", pexpect.TIMEOUT ],
+                                        timeout=10 )
+                if i == 0:  # In ONOS CLI
+                    self.handle.sendline( "logout" )
+                    self.handle.expect( "\$" )
+                    return main.TRUE
+                elif i == 1:  # not in CLI
+                    return main.TRUE
+                elif i == 3:  # Timeout
+                    return main.FALSE
+            else:
                 return main.TRUE
-
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
         except pexpect.EOF:
             main.log.error( self.name + ": eof exception found" )
-            main.log.error( self.name + ":    " +
-                            self.handle.before )
+            main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except ValueError:
+            main.log.error( self.name +
+                            "ValueError exception in logout method" )
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -146,12 +161,12 @@
                 # Expect the cellname in the ONOSCELL variable.
                 # Note that this variable name is subject to change
                 #   and that this driver will have to change accordingly
-                self.handle.expect( "ONOS_CELL=" + str( cellname ) )
+                self.handle.expect(str(cellname))
                 handleBefore = self.handle.before
                 handleAfter = self.handle.after
                 # Get the rest of the handle
-                self.handle.sendline( "" )
-                self.handle.expect( "\$" )
+                self.handle.sendline("")
+                self.handle.expect("\$")
                 handleMore = self.handle.before
 
                 main.log.info( "Cell call returned: " + handleBefore +
@@ -167,14 +182,14 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def startOnosCli( self, ONOSIp, karafTimeout="" ):
         """
-        karafTimeout is an optional arugument. karafTimeout value passed
+        karafTimeout is an optional argument. karafTimeout value passed
         by user would be used to set the current karaf shell idle timeout.
         Note that when ever this property is modified the shell will exit and
         the subsequent login would reflect new idle timeout.
@@ -245,7 +260,40 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def log( self, cmdStr, level="" ):
+        """
+            log  the commands in the onos CLI.
+            returns main.TRUE on success
+            returns main.FALSE if Error occurred
+            Available level: DEBUG, TRACE, INFO, WARN, ERROR
+            Level defaults to INFO
+        """
+        try:
+            lvlStr = ""
+            if level:
+                lvlStr = "--level=" + level
+
+            self.handle.sendline( "" )
+            self.handle.expect( "onos>" )
+            self.handle.sendline( "log:log " + lvlStr + " " + cmdStr )
+            self.handle.expect( "onos>" )
+
+            response = self.handle.before
+            if re.search( "Error", response ):
+                return main.FALSE
+            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 Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -260,28 +308,31 @@
         sent using this method.
         """
         try:
-            self.handle.sendline( "" )
-            self.handle.expect( "onos>" )
-
-            self.handle.sendline( "log:log \"Sending CLI command: '"
-                                  + cmdStr + "'\"" )
-            self.handle.expect( "onos>" )
+            logStr = "\"Sending CLI command: '" + cmdStr + "'\""
+            self.log( logStr )
             self.handle.sendline( cmdStr )
-            self.handle.expect( "onos>" )
+            i = self.handle.expect( ["onos>", "\$", pexpect.TIMEOUT] )
+            response = self.handle.before
+            if i == 2:
+                self.handle.sendline()
+                self.handle.expect( "\$" )
+                response += self.handle.before
+                print response
+                try:
+                    print self.handle.after
+                except:
+                    pass
+            # TODO: do something with i
             main.log.info( "Command '" + str( cmdStr ) + "' sent to "
                            + self.name + "." )
-
-            handle = self.handle.before
             # Remove control strings from output
             ansiEscape = re.compile( r'\x1b[^m]*m' )
-            handle = ansiEscape.sub( '', handle )
-            #Remove extra return chars that get added
-            handle = re.sub(  r"\s\r", "", handle )
-            handle = handle.strip()
-            # parse for just the output, remove the cmd from handle
-            output = handle.split( cmdStr, 1 )[1]
-
-
+            response = ansiEscape.sub( '', response )
+            # Remove extra return chars that get added
+            response = re.sub(  r"\s\r", "", response )
+            response = response.strip()
+            # parse for just the output, remove the cmd from response
+            output = response.split( cmdStr, 1 )[1]
             return output
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
@@ -291,7 +342,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -331,7 +382,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -359,21 +410,29 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
-    def nodes( self ):
+    def nodes( self, jsonFormat=True):
         """
         List the nodes currently visible
         Issues command: 'nodes'
-        Returns: entire handle of list of nodes
+        Optional argument:
+            * jsonFormat - boolean indicating if you want output in json
         """
         try:
-            cmdStr = "nodes"
-            handle = self.sendline( cmdStr )
-            return handle
+            if jsonFormat:
+                cmdStr = "nodes -j"
+                output = self.sendline( cmdStr )
+                ansiEscape = re.compile( r'\r\r\n\x1b[^m]*m' )
+                parsedOutput = ansiEscape.sub( '', output )
+                return parsedOutput
+            else:
+                cmdStr = "nodes"
+                output = self.sendline( cmdStr )
+                return output
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -382,21 +441,24 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def topology( self ):
         """
-        Shows the current state of the topology
-        by issusing command: 'onos> onos:topology'
+        Definition:
+            Returns the ouput of topology command.
+        Return:
+            topology = current ONOS topology
         """
+        import json
         try:
             # either onos:topology or 'topology' will work in CLI
-            cmdStr = "onos:topology"
+            cmdStr = "topology -j"
             handle = self.sendline( cmdStr )
-            main.log.info( "onos:topology returned: " + str( handle ) )
+            main.log.info( "topology -j returned: " + str( handle ) )
             return handle
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
@@ -406,7 +468,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -431,7 +493,7 @@
             main.log.report( "Exiting test" )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.log.report( "Failed to install feature" )
             main.log.report( "Exiting test" )
@@ -444,9 +506,15 @@
         by issuing command: 'onos> feature:uninstall <feature_str>'
         """
         try:
-            cmdStr = "feature:uninstall " + str( featureStr )
-            self.sendline( cmdStr )
-            # TODO: Check for possible error responses from karaf
+            cmdStr = 'feature:list -i | grep "' + featureStr + '"'
+            handle = self.sendline( cmdStr )
+            if handle != '':
+                cmdStr = "feature:uninstall " + str( featureStr )
+                self.sendline( cmdStr )
+                # TODO: Check for possible error responses from karaf
+            else:
+                main.log.info( "Feature needs to be installed before " +
+                               "uninstalling it" )
             return main.TRUE
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
@@ -456,11 +524,36 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
+    def deviceRemove( self, deviceId ):
+        """
+        Removes particular device from storage
+
+        TODO: refactor this function
+        """
+        try:
+            cmdStr = "device-remove "+str(deviceId)
+            handle = self.sendline( cmdStr )
+            return main.TRUE
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            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 Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+        
+
+
     def devices( self, jsonFormat=True ):
         """
         Lists all infrastructure devices or switches
@@ -499,7 +592,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -523,7 +616,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -566,7 +659,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -589,7 +682,7 @@
                 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 the following commads:
+                sequence using the following commands:
 
                 ansiEscape = re.compile( r'\r\r\n\x1b[^m]*m' )
                 handle1 = ansiEscape.sub( '', handle )
@@ -610,7 +703,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -656,7 +749,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -673,7 +766,6 @@
         None if no match
         """
         try:
-            import json
             if deviceId is None:
                 return None
             else:
@@ -693,7 +785,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -705,7 +797,6 @@
                  main.FALSE any device has no master
         """
         try:
-            import json
             rawRoles = self.roles()
             rolesJson = json.loads( rawRoles )
             # search json for the device with id then return the device
@@ -724,7 +815,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -752,7 +843,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -795,7 +886,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -804,12 +895,11 @@
         """
         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
+        Note: mac must be a colon separated mac address, but could be a
               partial mac address
 
         Return None if there is no match
         """
-        import json
         try:
             if mac is None:
                 return None
@@ -833,7 +923,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -875,7 +965,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -886,8 +976,10 @@
             * hostIdOne: ONOS host id for host1
             * hostIdTwo: ONOS host id for host2
         Description:
-            Adds a host-to-host intent ( bidrectional ) by
+            Adds a host-to-host intent ( bidirectional ) by
             specifying the two hosts.
+        Returns:
+            A string of the intent id or None on Error
         """
         try:
             cmdStr = "add-host-intent " + str( hostIdOne ) +\
@@ -895,12 +987,19 @@
             handle = self.sendline( cmdStr )
             if re.search( "Error", handle ):
                 main.log.error( "Error in adding Host intent" )
-                return handle
+                main.log.debug( "Response from ONOS was: " + repr( handle ) )
+                return None
             else:
                 main.log.info( "Host intent installed between " +
-                           str( hostIdOne ) + " and " + str( hostIdTwo ) )
-                return main.TRUE
-
+                               str( hostIdOne ) + " and " + str( hostIdTwo ) )
+                match = re.search('id=0x([\da-f]+),', handle)
+                if match:
+                    return match.group()[3:-1]
+                else:
+                    main.log.error( "Error, intent ID not found" )
+                    main.log.debug( "Response from ONOS was: " +
+                                    repr( handle ) )
+                    return None
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -909,7 +1008,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -921,6 +1020,10 @@
             * egressDevice: device id of egress device
         Optional:
             TODO: Still needs to be implemented via dev side
+        Description:
+            Adds an optical intent by specifying an ingress and egress device
+        Returns:
+            A string of the intent id or None on error
         """
         try:
             cmdStr = "add-optical-intent " + str( ingressDevice ) +\
@@ -928,9 +1031,18 @@
             handle = self.sendline( cmdStr )
             # If error, return error message
             if re.search( "Error", handle ):
-                return handle
+                main.log.error( "Error in adding Optical intent" )
+                return None
             else:
-                return main.TRUE
+                main.log.info( "Optical intent installed between " +
+                               str( ingressDevice ) + " and " +
+                               str( egressDevice ) )
+                match = re.search('id=0x([\da-f]+),', handle)
+                if match:
+                    return match.group()[3:-1]
+                else:
+                    main.log.error( "Error, intent ID not found" )
+                    return None
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -939,7 +1051,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -979,14 +1091,14 @@
         Description:
             Adds a point-to-point intent ( uni-directional ) by
             specifying device id's and optional fields
+        Returns:
+            A string of the intent id or None on error
 
         NOTE: This function may change depending on the
               options developers provide for point-to-point
               intent via cli
         """
         try:
-            cmd = ""
-
             # If there are no optional arguments
             if not ethType and not ethSrc and not ethDst\
                     and not bandwidth and not lambdaAlloc \
@@ -1024,10 +1136,11 @@
                 cmd += " " + str( ingressDevice )
             else:
                 if not portIngress:
-                    main.log.error( "You must specify " +
-                                    "the ingress port" )
+                    main.log.error( "You must specify the ingress port" )
                     # TODO: perhaps more meaningful return
-                    return main.FALSE
+                    #       Would it make sense to throw an exception and exit
+                    #       the test?
+                    return None
 
                 cmd += " " + \
                     str( ingressDevice ) + "/" +\
@@ -1037,20 +1150,29 @@
                 cmd += " " + str( egressDevice )
             else:
                 if not portEgress:
-                    main.log.error( "You must specify " +
-                                    "the egress port" )
-                    return main.FALSE
+                    main.log.error( "You must specify the egress port" )
+                    return None
 
                 cmd += " " +\
                     str( egressDevice ) + "/" +\
                     str( portEgress )
 
             handle = self.sendline( cmd )
+            # If error, return error message
             if re.search( "Error", handle ):
                 main.log.error( "Error in adding point-to-point intent" )
-                return main.FALSE
+                return None
             else:
-                return main.TRUE
+                # TODO: print out all the options in this message?
+                main.log.info( "Point-to-point intent installed between " +
+                               str( ingressDevice ) + " and " +
+                               str( egressDevice ) )
+                match = re.search('id=0x([\da-f]+),', handle)
+                if match:
+                    return match.group()[3:-1]
+                else:
+                    main.log.error( "Error, intent ID not found" )
+                    return None
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -1059,17 +1181,16 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def addMultipointToSinglepointIntent(
             self,
-            ingressDevice1,
-            ingressDevice2,
+            ingressDeviceList,
             egressDevice,
-            portIngress="",
+            portIngressList=None,
             portEgress="",
             ethType="",
             ethSrc="",
@@ -1085,12 +1206,13 @@
             setEthDst="" ):
         """
         Note:
-            This function assumes that there would be 2 ingress devices and
-            one egress device. For more number of ingress devices, this
-            function needs to be modified
+            This function assumes the format of all ingress devices
+            is same. That is, all ingress devices include port nos 
+            with a "/" or all ingress devices could specify device 
+            ids and port nos seperately.
         Required:
-            * ingressDevice1: device id of ingress device1
-            * ingressDevice2: device id of ingress device2
+            * ingressDeviceList: List of device ids of ingress device 
+                ( Atleast 2 ingress devices required in the list )
             * egressDevice: device id of egress device
         Optional:
             * ethType: specify ethType
@@ -1109,14 +1231,14 @@
         Description:
             Adds a multipoint-to-singlepoint intent ( uni-directional ) by
             specifying device id's and optional fields
+        Returns:
+            A string of the intent id or None on error
 
         NOTE: This function may change depending on the
-              options developers provide for multipointpoint-to-singlepoint
+              options developers provide for multipoint-to-singlepoint
               intent via cli
         """
         try:
-            cmd = ""
-
             # If there are no optional arguments
             if not ethType and not ethSrc and not ethDst\
                     and not bandwidth and not lambdaAlloc\
@@ -1155,31 +1277,22 @@
 
             # Check whether the user appended the port
             # or provided it as an input
-            if "/" in ingressDevice1:
-                cmd += " " + str( ingressDevice1 )
+
+            if portIngressList is None:
+                for ingressDevice in ingressDeviceList:
+                    if "/" in ingressDevice:
+                        cmd += " " + str( ingressDevice )
+                    else:
+                        main.log.error( "You must specify " +
+                                    "the ingress port" )
+                        # TODO: perhaps more meaningful return
+                        return main.FALSE
             else:
-                if not portIngress1:
-                    main.log.error( "You must specify " +
-                                    "the ingress port1" )
-                    # TODO: perhaps more meaningful return
-                    return main.FALSE
-
-                cmd += " " + \
-                    str( ingressDevice1 ) + "/" +\
-                    str( portIngress1 ) + " "
-
-            if "/" in ingressDevice2:
-                cmd += " " + str( ingressDevice2 )
-            else:
-                if not portIngress2:
-                    main.log.error( "You must specify " +
-                                    "the ingress port2" )
-                    # TODO: perhaps more meaningful return
-                    return main.FALSE
-
-                cmd += " " + \
-                    str( ingressDevice2 ) + "/" +\
-                    str( portIngress2 ) + " "
+                if len( ingressDeviceList ) == len( portIngressList ):
+                    for ingressDevice,portIngress in zip( ingressDeviceList,portIngressList ):
+                        cmd += " " + \
+                            str( ingressDevice ) + "/" +\
+                            str( portIngress ) + " "
 
             if "/" in egressDevice:
                 cmd += " " + str( egressDevice )
@@ -1192,13 +1305,25 @@
                 cmd += " " +\
                     str( egressDevice ) + "/" +\
                     str( portEgress )
+
             print "cmd= ", cmd
             handle = self.sendline( cmd )
+            # If error, return error message
             if re.search( "Error", handle ):
-                main.log.error( "Error in adding point-to-point intent" )
-                return self.handle
+                main.log.error( "Error in adding multipoint-to-singlepoint " +
+                                "intent" )
+                return None
             else:
-                return main.TRUE
+                # TODO: print out all the options in this message?
+                main.log.info( "Multipoint-to-singlepoint intent installed" +
+                               " failed " )
+                return None
+                #match = re.search('id=0x([\da-f]+),', handle)
+                #if match:
+                    #return match.group()[3:-1]
+                #else:
+                    #main.log.error( "Error, intent ID not found" )
+                    #return None
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -1207,21 +1332,31 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
-    def removeIntent( self, intentId ):
+    def removeIntent( self, intentId, app='org.onosproject.cli',
+                      purge=False, sync=False ):
         """
-        Remove intent for specified intent id
+        Remove intent for specified application id and intent id
+        Optional args:-
+        -s or --sync: Waits for the removal before returning
+        -p or --purge: Purge the intent from the store after removal
 
         Returns:
             main.False on error and
             cli output otherwise
         """
         try:
-            cmdStr = "remove-intent " + str( intentId )
+            cmdStr = "remove-intent "
+            if purge:
+                cmdStr += " -p"
+            if sync:
+                cmdStr += " -s"
+
+            cmdStr += " " + app + " " + str( intentId )
             handle = self.sendline( cmdStr )
             if re.search( "Error", handle ):
                 main.log.error( "Error in removing intent" )
@@ -1237,7 +1372,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1269,7 +1404,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1299,7 +1434,66 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def getIntentState(self, intentsId, intentsJson=None):
+        """
+            Check intent state.
+            Accepts a single intent ID (string type) or a list of intent IDs.
+            Returns the state(string type) of the id if a single intent ID is
+            accepted.
+            Returns a dictionary with intent IDs as the key and its
+            corresponding states as the values
+            Parameters:
+            intentId: intent ID (string type)
+            intentsJson: parsed json object from the onos:intents api
+            Returns:
+            state = An intent's state- INSTALL,WITHDRAWN etc.
+            stateDict = Dictionary of intent's state. intent ID as the keys and
+            state as the values.
+        """
+        try:
+            state = "State is Undefined"
+            if not intentsJson:
+                intentsJsonTemp = json.loads( self.intents() )
+            else:
+                intentsJsonTemp = json.loads( intentsJson )
+            if isinstance( intentsId, types.StringType ):
+                for intent in intentsJsonTemp:
+                    if intentsId == intent['id']:
+                        state = intent['state']
+                        return state
+                main.log.info( "Cannot find intent ID" + str( intentsId ) +
+                               " on the list" )
+                return state
+            elif isinstance( intentsId, types.ListType ):
+                dictList = []
+                for ID in intentsId:
+                    stateDict = {}
+                    for intents in intentsJsonTemp:
+                        if ID == intents['id']:
+                            stateDict['state'] = intents['state']
+                            stateDict['id'] = ID
+                            dictList.append( stateDict )
+                            break
+                if len( intentsId ) != len( dictList ):
+                    main.log.info( "Cannot find some of the intent ID state" )
+                return dictList
+            else:
+                main.log.info("Invalid intents ID entry")
+                return None
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            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 Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1320,7 +1514,7 @@
             else:
                 cmdStr = "flows"
                 handle = self.sendline( cmdStr )
-            if re.search( "Error\sexecuting\scommand:", handle ):
+            if re.search( "Error:", handle ):
                 main.log.error( self.name + ".flows() response: " +
                                 str( handle ) )
             return handle
@@ -1332,13 +1526,13 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def pushTestIntents( self, dpidSrc, dpidDst, numIntents,
-                          numMult="", appId="", report=True ):
+                         numMult="", appId="", report=True ):
         """
         Description:
             Push a number of intents in a batch format to
@@ -1391,7 +1585,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1421,7 +1615,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1442,7 +1636,11 @@
             else:
                 cmdStr = "topology-events-metrics"
                 handle = self.sendline( cmdStr )
-            return handle
+            if handle:
+                return handle
+            else:
+                # Return empty json 
+                return '{}'
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -1451,7 +1649,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1470,29 +1668,16 @@
         """
         try:
             # Obtain output of intents function
-            intentsStr = self.intents()
-            allIntentList = []
+            intentsStr = self.intents(jsonFormat=False)
             intentIdList = []
 
             # Parse the intents output for ID's
             intentsList = [ s.strip() for s in intentsStr.splitlines() ]
             for intents in intentsList:
-                if "onos>" in intents:
-                    continue
-                elif "intents" in intents:
-                    continue
-                else:
-                    lineList = intents.split( " " )
-                    allIntentList.append( lineList[ 0 ] )
-
-            allIntentList = allIntentList[ 1:-2 ]
-
-            for intents in allIntentList:
-                if not intents:
-                    continue
-                else:
-                    intentIdList.append( intents )
-
+                match = re.search('id=0x([\da-f]+),', intents)
+                if match:
+                    tmpId = match.group()[3:-1]
+                    intentIdList.append( tmpId )
             return intentIdList
 
         except TypeError:
@@ -1503,7 +1688,27 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def FlowAddedCount( self, deviceId ):
+        """
+        Determine the number of flow rules for the given device id that are
+        in the added state
+        """
+        try:
+            cmdStr = "flows any " + str( deviceId ) + " | " +\
+                     "grep 'state=ADDED' | wc -l"
+            handle = self.sendline( cmdStr )
+            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 Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1549,7 +1754,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1563,22 +1768,15 @@
             list of node id's
         """
         try:
-            nodesStr = self.nodes()
+            nodesStr = self.nodes( jsonFormat=True )
             idList = []
-
+            # Sample nodesStr output
+            # id=local, address=127.0.0.1:9876, state=ACTIVE *
             if not nodesStr:
                 main.log.info( "There are no nodes to get id from" )
                 return idList
-
-            # Sample nodesStr output
-            # id=local, address=127.0.0.1:9876, state=ACTIVE *
-
-            # Split the string into list by comma
-            nodesList = nodesStr.split( "," )
-            tempList = [ node for node in nodesList if "id=" in node ]
-            for arg in tempList:
-                idList.append( arg.split( "id=" )[ 1 ] )
-
+            nodesJson = json.loads( nodesStr )
+            idList = [ node.get('id') for node in nodesJson ]
             return idList
 
         except TypeError:
@@ -1589,7 +1787,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1599,7 +1797,6 @@
         Return the first device from the devices api whose 'id' contains 'dpid'
         Return None if there is no match
         """
-        import json
         try:
             if dpid is None:
                 return None
@@ -1621,28 +1818,28 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def checkStatus( self, ip, numoswitch, numolink, logLevel="info" ):
         """
-        Checks the number of swithes & links that ONOS sees against the
+        Checks the number of switches & links that ONOS sees against the
         supplied values. By default this will report to main.log, but the
-        log level can be specifid.
+        log level can be specified.
 
         Params: ip = ip used for the onos cli
                 numoswitch = expected number of switches
-                numlink = expected number of links
+                numolink = expected number of links
                 logLevel = level to log to. Currently accepts
                 'info', 'warn' and 'report'
 
 
         logLevel can
 
-        Returns: main.TRUE if the number of switchs and links are correct,
-                 main.FALSE if the numer of switches and links is incorrect,
+        Returns: main.TRUE if the number of switches and links are correct,
+                 main.FALSE if the number of switches and links is incorrect,
                  and main.ERROR otherwise
         """
         try:
@@ -1653,20 +1850,19 @@
             # 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:
+            if devices is False or links is False:
                 return main.ERROR
             switchCheck = ( int( devices ) == int( numoswitch ) )
             # Is the number of links is what we expected
             linkCheck = ( int( links ) == int( numolink ) )
             if ( switchCheck and linkCheck ):
                 # We expected the correct numbers
-                output = output + "The number of links and switches match "\
-                    + "what was expected"
+                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 matc\
-                    h what was expected"
+                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)" % (
@@ -1687,7 +1883,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1730,7 +1926,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1773,7 +1969,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1825,7 +2021,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1866,7 +2062,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1907,7 +2103,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1933,7 +2129,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1959,7 +2155,7 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
@@ -1984,19 +2180,61 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
+        except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
-    def testExceptions( self, obj ):
+    def intentSummary( self ):
         """
-        Test exception logging
+        Returns a dictionary containing the current intent states and the count
         """
-        # FIXME: Remove this before you commit
-
         try:
-            return obj[ 'dedf' ]
+            intents = self.intents( )
+            intentStates = []
+            for intent in json.loads( intents ):
+                intentStates.append( intent.get( 'state', None ) )
+            out = [ (i, intentStates.count( i ) ) for i in set( intentStates ) ]
+            main.log.info( dict( out ) )
+            return dict( out )
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            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 Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def leaders( self, jsonFormat=True ):
+        """
+        Returns the output of the leaders command.
+        Optional argument:
+            * jsonFormat - boolean indicating if you want output in json
+        """
+        # FIXME: add json output
+        # Sample JSON
+        # {
+        #     "electedTime": "13m ago",
+        #     "epoch": 4,
+        #     "leader": "10.128.30.17",
+        #     "topic": "intent-partition-3"
+        #  },
+        try:
+            if jsonFormat:
+                cmdStr = "onos:leaders -j"
+                output = self.sendline( cmdStr )
+                ansiEscape = re.compile( r'\r\r\n\x1b[^m]*m' )
+                cleanedOutput = ansiEscape.sub( '', output )
+                return cleanedOutput
+            else:
+                cmdStr = "onos:leaders"
+                output = self.sendline( cmdStr )
+                return output
         except TypeError:
             main.log.exception( self.name + ": Object not as expected" )
             return None
@@ -2009,3 +2247,71 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
+
+    def pendingMap( self, jsonFormat=True ):
+        """
+        Returns the output of the intent Pending map.
+        """
+        try:
+            if jsonFormat:
+                cmdStr = "onos:intents -p -j"
+                output = self.sendline( cmdStr )
+                ansiEscape = re.compile( r'\r\r\n\x1b[^m]*m' )
+                cleanedOutput = ansiEscape.sub( '', output )
+                return cleanedOutput
+            else:
+                cmdStr = "onos:intents -p"
+                output = self.sendline( cmdStr )
+                return output
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            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.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def partitions( self, jsonFormat=True ):
+        """
+        Returns the output of the raft partitions command for ONOS.
+        """
+        # Sample JSON
+        # {
+        #     "leader": "tcp://10.128.30.11:7238",
+        #     "members": [
+        #         "tcp://10.128.30.11:7238",
+        #         "tcp://10.128.30.17:7238",
+        #         "tcp://10.128.30.13:7238",
+        #     ],
+        #     "name": "p1",
+        #     "term": 3
+        # },
+        try:
+            if jsonFormat:
+                cmdStr = "onos:partitions -j"
+                output = self.sendline( cmdStr )
+                ansiEscape = re.compile( r'\r\r\n\x1b[^m]*m' )
+                cleanedOutput = ansiEscape.sub( '', output )
+                return cleanedOutput
+            else:
+                cmdStr = "onos:partitions"
+                output = self.sendline( cmdStr )
+                return output
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            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.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+