Retries when doing UP4 flow verification

Also, improve logging on errors and a fix on the number of flows for UP4 and QoS tests.

Change-Id: I86f7be5565e04d641ba5ebd5723591c0779d5a43
diff --git a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
index 1b20ce8..9f35639 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
+++ b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
@@ -10,7 +10,8 @@
         # Generate traffic with Trex for the two UEs
         # --> no packet drop on RT flow, reasonable latency on RT flow
         try:
-            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4
+            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4, \
+                N_FLOWS_PER_UE
             from tests.USECASE.SegmentRouting.dependencies.trex import Trex
             from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
                 Testcaselib as run
@@ -19,6 +20,7 @@
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
+        n_switches = int(main.params["TOPO"]["switchNum"])
 
         run.initTest(main)
         main.log.info(main.Cluster.numCtrls)
@@ -43,7 +45,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                        len(up4.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         # Load traffic config for the current test case
diff --git a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.py b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.py
index 6615a25..8c657dd 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.py
+++ b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.py
@@ -6,23 +6,33 @@
     def CASE1(self):
         main.case("Leaf Edge with NON-Mobile Traffic Classification")
         try:
-            from tests.USECASE.SegmentRouting.QOSNonMobile.dependencies.QOSNonMobileTest import QOSNonMobileTest
+            from tests.USECASE.SegmentRouting.QOSNonMobile.dependencies.QOSNonMobileTest import \
+                QOSNonMobileTest
         except ImportError as e:
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
 
         test = QOSNonMobileTest()
-        test.runTest(main, test_idx=1, n_switches=2)
+        test.runTest(
+            main,
+            test_idx=1,
+            n_switches=int(main.params["TOPO"]["switchNum"])
+        )
 
     def CASE2(self):
         main.case("Leaf Pair Link with NON-Mobile Traffic Classification")
         try:
-            from tests.USECASE.SegmentRouting.QOSNonMobile.dependencies.QOSNonMobileTest import QOSNonMobileTest
+            from tests.USECASE.SegmentRouting.QOSNonMobile.dependencies.QOSNonMobileTest import \
+                QOSNonMobileTest
         except ImportError as e:
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
 
         test = QOSNonMobileTest()
-        test.runTest(main, test_idx=2, n_switches=2)
+        test.runTest(
+            main,
+            test_idx=2,
+            n_switches=int(main.params["TOPO"]["switchNum"])
+        )
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
index 1395671..a2838d2 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
@@ -16,13 +16,15 @@
         Verify removed PDRs and FARs
         """
         try:
-            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4
+            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4, \
+                N_FLOWS_PER_UE
             from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
                 Testcaselib as run
         except ImportError as e:
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
+        n_switches = int(main.params["TOPO"]["switchNum"])
 
         run.initTest(main)
         main.log.info(main.Cluster.numCtrls)
@@ -43,7 +45,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                    len(up4.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         # ------- Test Upstream traffic (enb->pdn)
@@ -82,13 +85,15 @@
         UE_PORT = 400
         PDN_PORT = 800
         try:
-            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4
+            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4, \
+                N_FLOWS_PER_UE
             from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
                 Testcaselib as run
         except ImportError as e:
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
+        n_switches = int(main.params["TOPO"]["switchNum"])
 
         run.initTest(main)
         main.log.info(main.Cluster.numCtrls)
@@ -119,7 +124,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                    len(up4.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         # ------------------- UPSTREAM -------------------
@@ -278,6 +284,7 @@
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
+        n_switches = int(main.params["TOPO"]["switchNum"])
 
         run.initTest(main)
         main.log.info(main.Cluster.numCtrls)
@@ -300,7 +307,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4_0.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                    len(up4_0.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         main.step("Verify PDRs and FARs number via UP4 P4RT on ONOS 1")
@@ -396,13 +404,15 @@
         Remove PDRs/FARs (cleanup)
         """
         try:
-            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4
+            from tests.USECASE.SegmentRouting.dependencies.up4 import UP4, \
+                N_FLOWS_PER_UE
             from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
                 Testcaselib as run
         except ImportError as e:
             main.log.error("Import not found. Exiting the test")
             main.log.error(e)
             main.cleanAndExit()
+        n_switches = int(main.params["TOPO"]["switchNum"])
 
         run.initTest(main)
         main.log.info(main.Cluster.numCtrls)
@@ -428,7 +438,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4_0.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                    len(up4_0.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         onosPod = main.params["UP4_delete_pod"]
@@ -470,7 +481,8 @@
         )
         up4_2.teardown()
 
-        main.step("Verify all active ONOS instances have the same number of flows")
+        main.step(
+            "Verify all active ONOS instances have the same number of flows")
         onos_1_flow_count = onos_cli_1.checkFlowCount()
         onos_2_flow_count = onos_cli_2.checkFlowCount()
         utilities.assert_equal(
@@ -549,7 +561,8 @@
 
         run.checkFlows(
             main,
-            minFlowCount=initial_flow_count+(len(up4_0.emulated_ues)*2)
+            minFlowCount=initial_flow_count + (
+                    len(up4_0.emulated_ues) * N_FLOWS_PER_UE * n_switches)
         )
 
         main.step("Verify PDRs and FARs via UP4 on ONOS 1")
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py b/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
index a4505d7..bc6a49a 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
@@ -13,6 +13,8 @@
 PDN_PORT = 800
 GPDU_PORT = 2152
 
+N_FLOWS_PER_UE = 4
+
 
 class UP4:
     """
@@ -141,7 +143,7 @@
         fail = False
         if len(self.emulated_ues) != packets.count('Ether'):
             fail = True
-            msg = "Failed to capture packets in PDN. "
+            msg = "Failed to capture packets in PDN.\n" + str(packets)
         else:
             msg = "Correctly captured packet in PDN. "
         # We expect exactly 1 packet per UE
@@ -149,9 +151,9 @@
                         for ue in self.emulated_ues.values()]
         if pktsFiltered.count(1) != len(pktsFiltered):
             fail = True
-            msg += "More than one packet per UE in downstream. "
+            msg += "\nError on the number of packets per UE in downstream.\n" + str(packets)
         else:
-            msg += "One packet per UE in upstream. "
+            msg += "\nOne packet per UE in upstream. "
 
         utilities.assert_equal(
             expect=False, actual=fail, onpass=msg, onfail=msg)
@@ -196,15 +198,15 @@
         fail = False
         if len(self.emulated_ues) != sum(pktsFiltered):
             fail = True
-            msg = "Failed to capture packets in eNodeB. "
+            msg = "Failed to capture packets in eNodeB.\n" + str(packets)
         else:
             msg = "Correctly captured packets in eNodeB. "
         # We expect exactly 1 packet per UE
         if pktsFiltered.count(1) != len(pktsFiltered):
             fail = True
-            msg += "More than one packet per GTP TEID in downstream. "
+            msg += "\nError on the number of packets per GTP TEID in downstream.\n" + str(packets)
         else:
-            msg += "One packet per GTP TEID in downstream. "
+            msg += "\nOne packet per GTP TEID in downstream. "
 
         utilities.assert_equal(
             expect=False, actual=fail, onpass=msg, onfail=msg)
@@ -277,18 +279,32 @@
                                 noExit=True, expectJson=False)
         return pdrs == "" and fars == ""
 
-    def verifyUp4Flow(self, onosCli):
+    def verifyUp4Flow(self, onosCli, retries=10):
         """
         Verify PDRs and FARs installed via UP4 using the ONOS CLI.
 
         :param onosCli: An instance of a OnosCliDriver
+        :param retries: Number of retries
         """
+        failString=""
+        retValue = utilities.retry(f=self.__internalVerifyUp4Flow,
+                                   retValue=False,
+                                   args=[onosCli, failString],
+                                   sleep=5,
+                                   attempts=retries)
+        utilities.assert_equal(
+            expect=True,
+            actual=retValue,
+            onpass="Correct PDRs and FARs in ONOS",
+            onfail="Wrong PDRs and FARs in ONOS. Missing PDR/FAR:\n" + failString
+        )
+
+    def __internalVerifyUp4Flow(self, onosCli, failMsg=""):
         pdrs = onosCli.sendline(cmdStr="up4:read-pdrs", showResponse=True,
                                 noExit=True, expectJson=False)
         fars = onosCli.sendline(cmdStr="up4:read-fars", showResponse=True,
                                 noExit=True, expectJson=False)
         fail = False
-        failMsg = ""
         for ue in self.emulated_ues.values():
             if pdrs.count(self.upPdrOnosString(**ue)) != 1:
                 failMsg += self.upPdrOnosString(**ue) + "\n"
@@ -302,9 +318,7 @@
             if fars.count(self.downFarOnosString(**ue)) != 1:
                 failMsg += self.downFarOnosString(**ue) + "\n"
                 fail = True
-        utilities.assert_equal(expect=False, actual=fail,
-                               onpass="Correct PDRs and FARs in ONOS",
-                               onfail="Wrong PDRs and FARs in ONOS. Missing PDR/FAR:\n" + failMsg)
+        return not fail
 
     def upPdrOnosString(self, pfcp_session_id, teid=None, up_id=None,
                         teid_up=None, far_id_up=None, ctr_id_up=None, qfi=None,