Initial tests for Transactional Maps

Work towards [ONOS-2108]
    - ONOS cli driver functions for Transactional Maps
    - Test steps to add and get using Transactional Maps for both
      partitioned and in-memory maps added to the HA Tests
    - minor refactoring of an exception handling block in teston.py
Still to come:
    - Test values after restarts
    - Induce failure during transactions( need additional supoort in
      ONOS )

Change-Id: Ia5e8d7459ef554b4191b27275e8d9797a6346748
diff --git a/TestON/core/teston.py b/TestON/core/teston.py
index ae6fc4e..c2cb118 100644
--- a/TestON/core/teston.py
+++ b/TestON/core/teston.py
@@ -39,7 +39,7 @@
 global path, drivers_path, core_path, tests_path,logs_path
 location = os.path.abspath( os.path.dirname( __file__ ) )
 path = re.sub( "(core|bin)$", "", location )
-drivers_path = path+"drivers/"
+drivers_path = path+"drivers"
 core_path = path+"core"
 tests_path = path+"tests"
 logs_path = path+"logs/"
@@ -527,9 +527,8 @@
             try :
                 import json
                 response_dict = json.loads(response)
-            except Exception, e:
-                self.log.exception( e )
-                self.log.error("Json Parser is unable to parse the string")
+            except Exception:
+                self.log.exception( "Json Parser is unable to parse the string" )
             return response_dict
         elif ini_match :
             self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index b33a5a9..7ff0cd1 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -3852,7 +3852,6 @@
             main.cleanup()
             main.exit()
 
-
     def summary( self, jsonFormat=True ):
         """
         Description: Execute summary command in onos
@@ -3886,3 +3885,128 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
+
+    def transactionalMapGet( self, keyName, inMemory=False ):
+        """
+        CLI command to get the value of a key in a consistent map using
+        transactions. This a test function and can only get keys from the
+        test map hard coded into the cli command
+        Required arguments:
+            keyName - The name of the key to get
+        Optional arguments:
+            inMemory - use in memory map for the counter
+        returns:
+            The string value of the key or
+            None on Error
+        """
+        try:
+            keyName = str( keyName )
+            cmdStr = "transactional-map-test-get "
+            if inMemory:
+                cmdStr += "-i "
+            cmdStr += keyName
+            output = self.sendline( cmdStr )
+            try:
+                # TODO: Maybe make this less hardcoded
+                # ConsistentMap Exceptions
+                assert "org.onosproject.store.service" not in output
+                # Node not leader
+                assert "java.lang.IllegalStateException" not in output
+            except AssertionError:
+                main.log.error( "Error in processing '" + cmdStr + "' " +
+                                "command: " + str( output ) )
+                return None
+            pattern = "Key-value pair \(" + keyName + ", (?P<value>.+)\) found."
+            if "Key " + keyName + " not found." in output:
+                return None
+            else:
+                match = re.search( pattern, output )
+                if match:
+                    return match.groupdict()[ 'value' ]
+                else:
+                    main.log.error( self.name + ": transactionlMapGet did not" +
+                                    " match expected output." )
+                    main.log.debug( self.name + " expected: " + pattern )
+                    main.log.debug( self.name + " actual: " + repr( output ) )
+                    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()
+
+    def transactionalMapPut( self, numKeys, value, inMemory=False ):
+        """
+        CLI command to put a value into 'numKeys' number of keys in a
+        consistent map using transactions. This a test function and can only
+        put into keys named 'Key#' of the test map hard coded into the cli command
+        Required arguments:
+            numKeys - Number of keys to add the value to
+            value - The string value to put into the keys
+        Optional arguments:
+            inMemory - use in memory map for the counter
+        returns:
+            A dictionary whose keys are the name of the keys put into the map
+            and the values of the keys are dictionaries whose key-values are
+            'value': value put into map and optionaly
+            'oldValue': Previous value in the key or
+            None on Error
+
+            Example output
+            { 'Key1': {'oldValue': 'oldTestValue', 'value': 'Testing'},
+              'Key2': {'value': 'Testing'} }
+        """
+        try:
+            numKeys = str( numKeys )
+            value = str( value )
+            cmdStr = "transactional-map-test-put "
+            if inMemory:
+                cmdStr += "-i "
+            cmdStr += numKeys + " " + value
+            output = self.sendline( cmdStr )
+            try:
+                # TODO: Maybe make this less hardcoded
+                # ConsistentMap Exceptions
+                assert "org.onosproject.store.service" not in output
+                # Node not leader
+                assert "java.lang.IllegalStateException" not in output
+            except AssertionError:
+                main.log.error( "Error in processing '" + cmdStr + "' " +
+                                "command: " + str( output ) )
+                return None
+            newPattern = 'Created Key (?P<key>(\w)+) with value (?P<value>(.)+)\.'
+            updatedPattern = "Put (?P<value>(.)+) into key (?P<key>(\w)+)\. The old value was (?P<oldValue>(.)+)\."
+            results = {}
+            for line in output.splitlines():
+                new = re.search( newPattern, line )
+                updated = re.search( updatedPattern, line )
+                if new:
+                    results[ new.groupdict()[ 'key' ] ] = { 'value': new.groupdict()[ 'value' ] }
+                elif updated:
+                    results[ updated.groupdict()[ 'key' ] ] = { 'value': updated.groupdict()[ 'value' ],
+                                                            'oldValue': updated.groupdict()[ 'oldValue' ] }
+                else:
+                    main.log.error( self.name + ": transactionlMapGet did not" +
+                                    " match expected output." )
+                    main.log.debug( self.name + " expected: " + pattern )
+                    main.log.debug( self.name + " actual: " + repr( output ) )
+            return results
+        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()
diff --git a/TestON/tests/HAclusterRestart/HAclusterRestart.py b/TestON/tests/HAclusterRestart/HAclusterRestart.py
index d138096..fe15573 100644
--- a/TestON/tests/HAclusterRestart/HAclusterRestart.py
+++ b/TestON/tests/HAclusterRestart/HAclusterRestart.py
@@ -4284,3 +4284,94 @@
                                  onpass="Set retain correct",
                                  onfail="Set retain was incorrect" )
 
+        # Transactional maps
+        main.step( "Partitioned Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="Partitioned Transactional Map put successful",
+                                 onfail="Partitioned Transactional Map put values are incorrect" )
+
+        main.step( "Partitioned Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ] )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="Partitioned Transactional Map get values were correct",
+                                 onfail="Partitioned Transactional Map values incorrect" )
+
+        main.step( "In-memory Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue, inMemory=True )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="In-Memory Transactional Map put successful",
+                                 onfail="In-Memory Transactional Map put values are incorrect" )
+
+        main.step( "In-Memory Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ],
+                                 kwargs={ "inMemory": True } )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="In-Memory Transactional Map get values were correct",
+                                 onfail="In-Memory Transactional Map values incorrect" )
diff --git a/TestON/tests/HAminorityRestart/HAminorityRestart.py b/TestON/tests/HAminorityRestart/HAminorityRestart.py
index c9d3e6d..5fee9b1 100644
--- a/TestON/tests/HAminorityRestart/HAminorityRestart.py
+++ b/TestON/tests/HAminorityRestart/HAminorityRestart.py
@@ -4215,3 +4215,94 @@
                                  onpass="Set retain correct",
                                  onfail="Set retain was incorrect" )
 
+        # Transactional maps
+        main.step( "Partitioned Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="Partitioned Transactional Map put successful",
+                                 onfail="Partitioned Transactional Map put values are incorrect" )
+
+        main.step( "Partitioned Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ] )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="Partitioned Transactional Map get values were correct",
+                                 onfail="Partitioned Transactional Map values incorrect" )
+
+        main.step( "In-memory Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue, inMemory=True )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="In-Memory Transactional Map put successful",
+                                 onfail="In-Memory Transactional Map put values are incorrect" )
+
+        main.step( "In-Memory Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ],
+                                 kwargs={ "inMemory": True } )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="In-Memory Transactional Map get values were correct",
+                                 onfail="In-Memory Transactional Map values incorrect" )
diff --git a/TestON/tests/HAsanity/HAsanity.py b/TestON/tests/HAsanity/HAsanity.py
index c2a1872..e404da4 100644
--- a/TestON/tests/HAsanity/HAsanity.py
+++ b/TestON/tests/HAsanity/HAsanity.py
@@ -4178,3 +4178,94 @@
                                  onpass="Set retain correct",
                                  onfail="Set retain was incorrect" )
 
+        # Transactional maps
+        main.step( "Partitioned Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="Partitioned Transactional Map put successful",
+                                 onfail="Partitioned Transactional Map put values are incorrect" )
+
+        main.step( "Partitioned Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ] )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="Partitioned Transactional Map get values were correct",
+                                 onfail="Partitioned Transactional Map values incorrect" )
+
+        main.step( "In-memory Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue, inMemory=True )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="In-Memory Transactional Map put successful",
+                                 onfail="In-Memory Transactional Map put values are incorrect" )
+
+        main.step( "In-Memory Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ],
+                                 kwargs={ "inMemory": True } )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="In-Memory Transactional Map get values were correct",
+                                 onfail="In-Memory Transactional Map values incorrect" )
diff --git a/TestON/tests/HAsingleInstanceRestart/HAsingleInstanceRestart.py b/TestON/tests/HAsingleInstanceRestart/HAsingleInstanceRestart.py
index 14a90af..70bd0f2 100644
--- a/TestON/tests/HAsingleInstanceRestart/HAsingleInstanceRestart.py
+++ b/TestON/tests/HAsingleInstanceRestart/HAsingleInstanceRestart.py
@@ -3293,3 +3293,94 @@
                                  onpass="Set retain correct",
                                  onfail="Set retain was incorrect" )
 
+        # Transactional maps
+        main.step( "Partitioned Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="Partitioned Transactional Map put successful",
+                                 onfail="Partitioned Transactional Map put values are incorrect" )
+
+        main.step( "Partitioned Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ] )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="Partitioned Transactional Map get values were correct",
+                                 onfail="Partitioned Transactional Map values incorrect" )
+
+        main.step( "In-memory Transactional maps put" )
+        tMapValue = "Testing"
+        numKeys = 100
+        putResult = True
+        putResponses = main.CLIs[ 0 ].transactionalMapPut( numKeys, tMapValue, inMemory=True )
+        if len( putResponses ) == 100:
+            for i in putResponses:
+                if putResponses[ i ][ 'value' ] != tMapValue:
+                    putResult = False
+        else:
+            putResult = False
+        if not putResult:
+            main.log.debug( "Put response values: " + str( putResponses ) )
+        utilities.assert_equals( expect=True,
+                                 actual=putResult,
+                                 onpass="In-Memory Transactional Map put successful",
+                                 onfail="In-Memory Transactional Map put values are incorrect" )
+
+        main.step( "In-Memory Transactional maps get" )
+        getCheck = True
+        for n in range( 1, numKeys + 1 ):
+            getResponses = []
+            threads = []
+            valueCheck = True
+            for i in range( main.numCtrls ):
+                t = main.Thread( target=main.CLIs[i].transactionalMapGet,
+                                 name="TMap-get-" + str( i ),
+                                 args=[ "Key" + str ( n ) ],
+                                 kwargs={ "inMemory": True } )
+                threads.append( t )
+                t.start()
+            for t in threads:
+                t.join()
+                getResponses.append( t.result )
+            for node in getResponses:
+                if node != tMapValue:
+                    valueCheck = False
+            if not valueCheck:
+                main.log.warn( "Values for key 'Key" + str( n ) + "' do not match:" )
+                main.log.warn( getResponses )
+            getCheck = getCheck and valueCheck
+        utilities.assert_equals( expect=True,
+                                 actual=getCheck,
+                                 onpass="In-Memory Transactional Map get values were correct",
+                                 onfail="In-Memory Transactional Map values incorrect" )