Fix missing IP_PROTO in slicing classifier flows

Also update traffic selector comparison logic to account for different
ordering of criteria (since we now send more than one criterion for each
selector)

Also 2, remove dead code related to adding/removing slices and traffic
classes.

Change-Id: I25ff416c8413e24f641da35f50c69cda78a77e77
diff --git a/TestON/drivers/common/api/controller/onosrestdriver.py b/TestON/drivers/common/api/controller/onosrestdriver.py
index 7ce7749..927cd25 100755
--- a/TestON/drivers/common/api/controller/onosrestdriver.py
+++ b/TestON/drivers/common/api/controller/onosrestdriver.py
@@ -2465,7 +2465,7 @@
         self.__slicingClassifierFlow( slice_id, traffic_class, traffic_selector,
                                      ip, port, debug, method="DELETE" )
 
-    def getSlicingClassifierFlow( self, slice_id, traffic_class, ip="DEFAULT",
+    def getSlicingClassifierFlows( self, slice_id, traffic_class, ip="DEFAULT",
                                   port="DEFAULT", debug=False ):
         try:
             if ip == "DEFAULT":
@@ -2482,9 +2482,11 @@
                     output = response[ 1 ]
                     if debug:
                         main.log.debug(self.name + ": read: " + output)
-                    traffic_selector = json.loads( output ).get( 'TrafficSelector' )
-                    assert traffic_selector is not None, "Error parsing json object"
-                    return json.dumps( traffic_selector )
+                    # FIXME: use plural in slicing service API
+                    #  TrafficSelector actually points to an array of selectors.
+                    traffic_selectors = json.loads( output ).get( 'TrafficSelector' )
+                    assert traffic_selectors is not None, "Error parsing json object"
+                    return json.dumps( traffic_selectors )
                 else:
                     main.log.error( "Error with REST request, response was: %s: %s" %
                                     ( response[ 0 ], response[ 1 ] ) )
@@ -2496,75 +2498,6 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanAndExit()
 
-    def __slices( self, slice_id, ip="DEFAULT", port="DEFAULT", debug=False,
-                  method="POST" ):
-        try:
-            if debug:
-                main.log.debug( self.name + ": %s Slice" % method )
-                main.log.debug( self.name + ": Slice ID: %d" % slice_id )
-            if ip == "DEFAULT":
-                main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
-                ip = self.ip_address
-            if port == "DEFAULT":
-                main.log.warn( self.name + ": No port given, reverting to port " +
-                               "from topo file" )
-                port = self.port
-            url = "/fabrictna/slicing/slice/%d" % slice_id
-            response = self.send( method=method,
-                                  url=url, ip = ip, port = port,
-                                  base="/onos", data = {} )
-            if response:
-                if "200" in str( response[ 0 ] ):
-                    main.log.info( self.name + ": Successfully %s Slice ID: %d " % ( method, slice_id ) )
-                    return main.TRUE
-                else:
-                    main.log.error( "Error with REST request, response was: %s: %s" %
-                                    ( response[ 0 ], response[ 1 ] ) )
-                    return main.FALSE
-        except NotImplementedError as e:
-            raise # Inform the caller
-        except ( AttributeError, TypeError ):
-            main.log.exception( self.name + ": Object not as expected" )
-            return None
-        except Exception:
-            main.log.exception( self.name + ": Uncaught exception!" )
-            main.cleanAndExit()
-
-    def __trafficClass( self, slice_id, traffic_class, ip="DEFAULT", port="DEFAULT",
-                        debug=False, method="POST" ):
-        try:
-            if debug:
-                main.log.debug( self.name + ": %s Traffic Class" % method )
-                main.log.debug( self.name + ": Slice ID: %d, Traffic Class: %s" % ( slice_id, traffic_class ) )
-            if ip == "DEFAULT":
-                main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
-                ip = self.ip_address
-            if port == "DEFAULT":
-                main.log.warn( self.name + ": No port given, reverting to port " +
-                               "from topo file" )
-                port = self.port
-            url = "/fabrictna/slicing/tc/%d/%s" % ( slice_id, traffic_class )
-            response = self.send( method=method,
-                                  url=url, ip = ip, port = port,
-                                  base="/onos", data = {} )
-            if response:
-                if "200" in str( response[ 0 ] ):
-                    main.log.info( self.name + ": Successfully %s " % method +
-                                   "Slice ID: %d, Traffic Class: %s" % ( slice_id, traffic_class ) )
-                    return main.TRUE
-                else:
-                    main.log.error( "Error with REST request, response was: %s: %s" %
-                                    ( response[ 0 ], response[ 1 ] ) )
-                    return main.FALSE
-        except NotImplementedError as e:
-            raise # Inform the caller
-        except ( AttributeError, TypeError ):
-            main.log.exception( self.name + ": Object not as expected" )
-            return None
-        except Exception:
-            main.log.exception( self.name + ": Uncaught exception!" )
-            main.cleanAndExit()
-
     def __slicingClassifierFlow( self, slice_id, traffic_class, traffic_selector,
                                  ip="DEFAULT", port="DEFAULT", debug=False,
                                  method="POST" ):
diff --git a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
index 56e859a..51c916e 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
+++ b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
@@ -41,20 +41,28 @@
                 <slice_id>1</slice_id>
                 <traffic_class>BEST_EFFORT</traffic_class>
                 <traffic_selector>
-                    <criteria1>
+                    <ipProto>
+                        <type>IP_PROTO</type>
+                        <protocol>17</protocol>
+                    </ipProto>
+                    <udpDst>
                         <type>UDP_DST</type>
                         <udpPort>100</udpPort>
-                    </criteria1>
+                    </udpDst>
                 </traffic_selector>
             </slice_1_be>
             <slice_1_rt>
                 <slice_id>1</slice_id>
                 <traffic_class>REAL_TIME</traffic_class>
                 <traffic_selector>
-                    <criteria1>
+                    <ipProto>
+                        <type>IP_PROTO</type>
+                        <protocol>17</protocol>
+                    </ipProto>
+                    <udpDst>
                         <type>UDP_DST</type>
                         <udpPort>200</udpPort>
-                    </criteria1>
+                    </udpDst>
                 </traffic_selector>
             </slice_1_rt>
         </traffic_classification>
diff --git a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
index faaeb04..d53b3f8 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
@@ -70,7 +70,7 @@
                 flow_config = main.params["SLICING"]["traffic_classification"][
                     flow_name]
 
-                traffic_selector = self.__cleanupTrafficSelector(flow_config.get("traffic_selector", []))
+                traffic_selector = self.__normalizeTrafficSelector(flow_config.get("traffic_selector"))
                 onos_rest.addSlicingClassifierFlow(
                     slice_id=int(flow_config.get("slice_id")),
                     traffic_class=flow_config.get("traffic_class"),
@@ -78,14 +78,14 @@
                     debug=True
                 )
 
-                onos_flows = json.loads(onos_rest.getSlicingClassifierFlow(
+                actual_selectors = json.loads(onos_rest.getSlicingClassifierFlows(
                     slice_id=int(flow_config.get("slice_id")),
                     traffic_class=flow_config.get("traffic_class"),
                     debug=True
                 ))
                 utilities.assert_equal(
                     expect=True,
-                    actual=traffic_selector in onos_flows,
+                    actual=self.__containsTrafficSelector(actual_selectors, traffic_selector),
                     onpass="Classifier flow %s installed" % flow_name,
                     onfail="Classifier flow %s not found after insert" % flow_name
                 )
@@ -120,21 +120,21 @@
                 flow_config = main.params["SLICING"]["traffic_classification"][
                     flow_name]
 
-                traffic_selector = self.__cleanupTrafficSelector(flow_config.get("traffic_selector", []))
+                traffic_selector = self.__normalizeTrafficSelector(flow_config.get("traffic_selector"))
                 onos_rest.removeSlicingClassifierFlow(
                     slice_id=int(flow_config.get("slice_id")),
                     traffic_class=flow_config.get("traffic_class"),
                     traffic_selector=traffic_selector,
                     debug=True
                 )
-                onos_flow = onos_rest.getSlicingClassifierFlow(
+                actual_selectors = json.loads(onos_rest.getSlicingClassifierFlows(
                     slice_id=int(flow_config.get("slice_id")),
                     traffic_class=flow_config.get("traffic_class"),
                     debug=True
-                )
+                ))
                 utilities.assert_equal(
-                    expect="[]",
-                    actual=onos_flow,
+                    expect=False,
+                    actual=self.__containsTrafficSelector(actual_selectors, traffic_selector),
                     onpass="Classifier flow %s removed from slicing service" % flow_name,
                     onfail="Unable to remove classifier flow %s from slicing service" % flow_name
                 )
@@ -145,14 +145,32 @@
             trex.teardown()
             run.cleanup(main)
 
-    def __cleanupTrafficSelector(self, traffic_selector):
+    def __normalizeTrafficSelector(self, traffic_selector):
         ts = {
-            "criteria": [traffic_selector[criteria] for criteria in
+            "criteria": [traffic_selector[criterion] for criterion in
                          traffic_selector]}
-        # Cleanup the traffic selector, by converting into integer the
-        # required fields, conversion is required for checking the result
-        # from ONOS
-        for criteria in ts["criteria"]:
-            if "udpPort" in criteria:
-                criteria["udpPort"] = int(criteria["udpPort"])
+        # Converts the required fields into integer, required to compare them
+        # with the API result from ONOS.
+        for criterion in ts["criteria"]:
+            if "udpPort" in criterion:
+                criterion["udpPort"] = int(criterion["udpPort"])
+            elif "protocol" in criterion:
+                criterion["protocol"] = int(criterion["protocol"])
         return ts
+
+    def __containsTrafficSelector(self, actual_selectors, expected_selector):
+        # actual_selectors = [{"criteria":[{"type":"IP_PROTO","protocol":17},{"type":"UDP_DST","udpPort":200}]}]
+        expected_criteria = expected_selector["criteria"]
+        for actual_selector in actual_selectors:
+            actual_criteria = actual_selector["criteria"]
+            if len(actual_criteria) != len(expected_criteria):
+                continue
+            for actual_criterion in actual_criteria:
+                # actual_criterion = {"type":"IP_PROTO","protocol":17}
+                if actual_criterion not in expected_criteria:
+                    # Next selector
+                    break
+            else:
+                # We found all criteria in this selector.
+                return True
+        return False