Upgrade T-rex to v2.22
[csit.git] / resources / tools / robot_output_parser.py
index ad1fbfa..b9ad8f8 100755 (executable)
 # limitations under the License.
 
 """Script parses the data taken by robot framework (output.xml) and dumps
-intereted values into XML output file."""
+interested values into XML output file."""
 
 import argparse
+import re
 import sys
 import xml.etree.ElementTree as ET
 
 from robot.api import ExecutionResult, ResultVisitor
 
 
-class ExecutionTestChecker(ResultVisitor):
+class ExecutionChecker(ResultVisitor):
     """Iterates through test cases."""
 
+    tc_regexp = re.compile(ur'^tc\d+-((\d+)B|IMIX)-(\d)t(\d)c-(.*)')
+    rate_regexp = re.compile(ur'^[\D\d]*FINAL_RATE:\s(\d+\.\d+)[\D\d]*')
+    lat_regexp = re.compile(ur'^[\D\d]*'\
+        ur'LAT_\d+%NDR:\s\[\'(-?\d+\/-?\d+\/-?\d+)\','\
+        ur'\s\'(-?\d+\/-?\d+\/-?\d+)\'\]\s\n'\
+        ur'LAT_\d+%NDR:\s\[\'(-?\d+\/-?\d+\/-?\d+)\','\
+        ur'\s\'(-?\d+\/-?\d+\/-?\d+)\'\]\s\n'\
+        ur'LAT_\d+%NDR:\s\[\'(-?\d+\/-?\d+\/-?\d+)\','\
+        ur'\s\'(-?\d+\/-?\d+\/-?\d+)\'\]')
+
     def __init__(self, args):
         self.root = ET.Element('build',
                                attrib={'vdevice': args.vdevice})
 
+    def visit_suite(self, suite):
+        """Implements traversing through the suite and its direct children.
+
+        :param suite: Suite to process.
+        :type suite: Suite
+        :return: Nothing.
+        """
+        if self.start_suite(suite) is not False:
+            suite.suites.visit(self)
+            suite.tests.visit(self)
+            self.end_suite(suite)
+
+    def start_suite(self, suite):
+        """Called when suite starts.
+
+        :param suite: Suite to process.
+        :type suite: Suite
+        :return: Nothing.
+        """
+        pass
+
+    def end_suite(self, suite):
+        """Called when suite ends.
+
+        :param suite: Suite to process.
+        :type suite: Suite
+        :return: Nothing.
+        """
+        pass
+
     def visit_test(self, test):
-        """Overloaded function. Called when test is found to process data.
+        """Implements traversing through the test.
 
         :param test: Test to process.
-        :type test: ExecutionTestChecker
+        :type test: Test
+        :return: Nothing.
         """
+        if self.start_test(test) is not False:
+            self.end_test(test)
+
+    def start_test(self, test):
+        """Called when test starts.
 
-        if any("PERFTEST_LONG" in tag for tag in test.tags):
+        :param test: Test to process.
+        :type test: Test
+        :return: Nothing.
+        """
+        if any("NDRPDRDISC" in tag for tag in test.tags):
             if test.status == 'PASS':
                 tags = []
                 for tag in test.tags:
                     tags.append(tag)
-                for keyword in test.keywords:
-                    for assign in keyword.assign:
-                        if assign == '${framesize}':
-                            framesize = keyword.args[0]
-                    if 'worker threads' in keyword.name:
-                        workers = keyword.name.split('\'')[1]
-                        workers_per_nic = keyword.name.split('\'')[3]
-
-                test_elem = ET.SubElement(self.root,
-                    test.longname.split('.')[3].replace(" ",""))
-                test_elem.attrib['name'] = test.longname.split('.')[3]
-                test_elem.attrib['workerthreads'] = workers
-                test_elem.attrib['workerspernic'] = workers_per_nic
-                test_elem.attrib['framesize'] = framesize
+
+                test_elem = ET.SubElement(
+                    self.root, "S" + test.parent.name.replace(" ", ""))
+                test_elem.attrib['name'] = test.parent.name
+                test_elem.attrib['framesize'] = str(re.search(
+                    self.tc_regexp, test.name).group(1))
+                test_elem.attrib['threads'] = str(re.search(
+                    self.tc_regexp, test.name).group(3))
+                test_elem.attrib['cores'] = str(re.search(
+                    self.tc_regexp, test.name).group(4))
+                if any("NDRDISC" in tag for tag in test.tags):
+                    try:
+                        test_elem.attrib['lat_100'] = str(re.search(
+                            self.lat_regexp, test.message).group(1)) + '/' +\
+                            str(re.search(self.lat_regexp, test.message).
+                                group(2))
+                    except AttributeError:
+                        test_elem.attrib['lat_100'] = "-1/-1/-1/-1/-1/-1"
+                    try:
+                        test_elem.attrib['lat_50'] = str(re.search(
+                            self.lat_regexp, test.message).group(3)) + '/' +\
+                            str(re.search(self.lat_regexp, test.message).
+                                group(4))
+                    except AttributeError:
+                        test_elem.attrib['lat_50'] = "-1/-1/-1/-1/-1/-1"
+                    try:
+                        test_elem.attrib['lat_10'] = str(re.search(
+                            self.lat_regexp, test.message).group(5)) + '/' +\
+                            str(re.search(self.lat_regexp, test.message).
+                                group(6))
+                    except AttributeError:
+                        test_elem.attrib['lat_10'] = "-1/-1/-1/-1/-1/-1"
                 test_elem.attrib['tags'] = ', '.join(tags)
-                test_elem.text = test.message.split(' ')[1]
+                try:
+                    test_elem.text = str(re.search(
+                        self.rate_regexp, test.message).group(1))
+                except AttributeError:
+                    test_elem.text = "-1"
+
+    def end_test(self, test):
+        """Called when test ends.
+
+        :param test: Test to process.
+        :type test: Test
+        :return: Nothing.
+        """
+        pass
 
 
 def parse_tests(args):
-    """Parser result of robot output file and return.
+    """Process data from robot output.xml file and return XML data.
 
     :param args: Parsed arguments.
     :type args: ArgumentParser
@@ -71,7 +153,7 @@ def parse_tests(args):
     """
 
     result = ExecutionResult(args.input)
-    checker = ExecutionTestChecker(args)
+    checker = ExecutionChecker(args)
     result.visit(checker)
 
     return checker.root
@@ -85,7 +167,7 @@ def print_error(msg):
     :return: nothing
     """
 
-    sys.stderr.write(msg+'\n')
+    sys.stderr.write(msg + '\n')
 
 
 def parse_args():
@@ -96,13 +178,18 @@ def parse_args():
     """
 
     parser = argparse.ArgumentParser()
-    parser.add_argument("-i", "--input", required=True,
+    parser.add_argument("-i", "--input",
+                        required=True,
                         type=argparse.FileType('r'),
                         help="Robot XML log file")
-    parser.add_argument("-o", "--output", required=True,
+    parser.add_argument("-o", "--output",
+                        required=True,
                         type=argparse.FileType('w'),
                         help="XML output file")
-    parser.add_argument("-v", "--vdevice", required=True,
+    parser.add_argument("-v", "--vdevice",
+                        required=False,
+                        default="",
+                        type=str,
                         help="VPP version")
 
     return parser.parse_args()