Functionality for counting buckets in an ecmp group.

Function takes as argument a dictionary of ip-subnet -> number of groups
in ecmp group. It parses flows and groups to match the number of
expected groups with actual groups.

Usage :

  subnets = {}
  subnets["10.0.1.0/24"] = 10
  lib.checkGroupsForBuckets(main, "of:0000000000000001",subnets)

Change-Id: I373eb967d9ca41e4e2355569595a6509a28c2b92
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 439ba80..3b57cb2 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -2505,7 +2505,7 @@
             else:
                 main.cleanAndExit()
 
-    def flows( self, state="", jsonFormat=True, timeout=60, noExit=False, noCore=False ):
+    def flows( self, state="any", jsonFormat=True, timeout=60, noExit=False, noCore=False, device=""):
         """
         Optional:
             * jsonFormat: enable output formatting in json
@@ -2516,10 +2516,11 @@
         try:
             cmdStr = "flows"
             if jsonFormat:
-                cmdStr += " -j "
+                cmdStr += " -j"
             if noCore:
-                cmdStr += " -n "
-            cmdStr += state
+                cmdStr += " -n"
+            cmdStr += " " + state
+            cmdStr += " " + device
             handle = self.sendline( cmdStr, timeout=timeout, noExit=noExit )
             assert handle is not None, "Error in sendline"
             assert "Command not found:" not in handle, handle
@@ -2942,6 +2943,33 @@
         main.log.debug( "found {} groups".format( count ) )
         return count if ((count > expectedGroupCount) if (comparison == 0) else (count == expectedGroupCount)) else main.FALSE
 
+    def getGroups( self, deviceId, group_type="any"):
+        """
+        Retrieve groups from a specific device.
+        group_type = Type of group
+        """
+
+        try:
+            group_cmd = "groups -t {0} any {1}".format(group_type, deviceId)
+            self.sendline(group_cmd, showResponse=False)
+            handle = self.sendline( group_cmd )
+            assert handle is not None, "Error in sendline"
+            assert "Command not found:" not in handle, handle
+            return handle
+        except AssertionError:
+            main.log.exception( "" )
+            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.cleanAndExit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanAndExit()
+
     def checkFlowAddedCount( self, deviceId, expectedFlowCount=0, core=False, comparison=0):
         """
         Description:
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index ce6d20c..08d190a 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -22,6 +22,7 @@
 import time
 import json
 import urllib
+import re
 from core import utilities
 
 
@@ -309,6 +310,36 @@
                                  onfail="route-add command failed")
 
     @staticmethod
+    def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30):
+        """
+        Check number of groups for each subnet on device deviceId and matches
+        it with an expected value. subnetDict is a dictionarty containing values
+        of the type "10.0.1.0/24" : 5.
+        """
+        main.step("Checking if number of groups for subnets in device {0} is as expected.".format(deviceId))
+        groups = main.Cluster.active( 0 ).CLI.getGroups(deviceId, group_type="select")
+        flows = main.Cluster.active( 0 ).CLI.flows(jsonFormat=False, device=deviceId)
+
+        for subnet, number_in_select in subnetDict.iteritems():
+            for flow in flows.splitlines():
+                if "tableId={0}".format(routingTable) in flow and subnet in flow:
+
+                    # this will match the group id that this flow entry points to, for example :
+                    # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
+                    group_id = re.search(r".*GROUP:(0x.*)], transition.*", flow).groups()[0]
+
+                    count = 0
+                    for group in groups.splitlines():
+                        if 'id={0}'.format(group_id) in group:
+                            count += 1
+
+                    utilities.assert_equals( expect=True, actual=(count-1 == number_in_select),
+                                             onpass="Number of buckets in select group is correct",
+                                             onfail="Mismatch in number of buckets of select group, found {0}, expected {1} for subnet {2} on device {3}".format(count - 1, number_in_select, subnet, deviceId))
+                else:
+                    continue
+
+    @staticmethod
     def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
         main.step(
                 "Check whether the flow count is bigger than %s" % minFlowCount )