Merge "vswitches: Affinitize vswitch threads for OVS-DPDK"
[vswitchperf.git] / vsperf
diff --git a/vsperf b/vsperf
index 0747a20..4510e12 100755 (executable)
--- a/vsperf
+++ b/vsperf
@@ -24,15 +24,20 @@ import argparse
 import time
 import datetime
 import shutil
+import unittest
+import xmlrunner
 
 sys.dont_write_bytecode = True
 
 from conf import settings
 from core.loader import Loader
 from testcases import TestCase
+from tools.report import report
 from tools import tasks
 from tools.collectors import collector
 from tools.pkt_gen import trafficgen
+from vswitches import vswitch
+from vnfs import vnf
 
 VERBOSITY_LEVELS = {
     'debug': logging.DEBUG,
@@ -115,6 +120,8 @@ def parse_arguments():
                         help='list all system metrics loggers and exit')
     parser.add_argument('--list-vswitches', action='store_true',
                         help='list all system vswitches and exit')
+    parser.add_argument('--list-vnfs', action='store_true',
+                        help='list all system vnfs and exit')
     parser.add_argument('--list-settings', action='store_true',
                         help='list effective settings configuration and exit')
     parser.add_argument('test', nargs='*', help='test specification(s)')
@@ -128,8 +135,14 @@ def parse_arguments():
     group.add_argument('--verbosity', choices=list_logging_levels(),
                        help='debug level')
     group.add_argument('--trafficgen', help='traffic generator to use')
+    group.add_argument('--vswitch', help='vswitch implementation to use')
+    group.add_argument('--vnf', help='vnf to use')
     group.add_argument('--sysmetrics', help='system metrics logger to use')
     group = parser.add_argument_group('test behavior options')
+    group.add_argument('--xunit', action='store_true',
+                       help='enable xUnit-formatted output')
+    group.add_argument('--xunit-dir', action=_ValidateDirAction,
+                       help='output directory of xUnit-formatted output')
     group.add_argument('--load-env', action='store_true',
                        help='enable loading of settings from the environment')
     group.add_argument('--conf-file', action=_ValidateFileAction,
@@ -231,6 +244,34 @@ def apply_filter(tests, tc_filter):
     return result
 
 
+class MockTestCase(unittest.TestCase):
+    """Allow use of xmlrunner to generate Jenkins compatible output without
+    using xmlrunner to actually run tests.
+
+    Usage:
+        suite = unittest.TestSuite()
+        suite.addTest(MockTestCase('Test1 passed ', True, 'Test1'))
+        suite.addTest(MockTestCase('Test2 failed because...', False, 'Test2'))
+        xmlrunner.XMLTestRunner(...).run(suite)
+    """
+
+    def __init__(self, msg, is_pass, test_name):
+        #remember the things
+        self.msg = msg
+        self.is_pass = is_pass
+
+        #dynamically create a test method with the right name
+        #but point the method at our generic test method
+        setattr(MockTestCase, test_name, self.generic_test)
+
+        super(MockTestCase, self).__init__(test_name)
+
+    def generic_test(self):
+        """Provide a generic function that raises or not based
+        on how self.is_pass was set in the constructor"""
+        self.assertTrue(self.is_pass, self.msg)
+
+
 def main():
     """Main function.
     """
@@ -267,6 +308,22 @@ def main():
                           settings.getValue('TRAFFICGEN_DIR'))
             sys.exit(1)
 
+    # configure vswitch
+    if args['vswitch']:
+        vswitches = Loader().get_vswitches()
+        if args['vswitch'] not in vswitches:
+            logging.error('There are no vswitches matching \'%s\' found in'
+                          ' \'%s\'. Exiting...', args['vswitch'],
+                          settings.getValue('VSWITCH_DIR'))
+            sys.exit(1)
+
+    if args['vnf']:
+        vnfs = Loader().get_vnfs()
+        if args['vnf'] not in vnfs:
+            logging.error('there are no vnfs matching \'%s\' found in'
+                          ' \'%s\'. exiting...', args['vnf'],
+                          settings.getValue('vnf_dir'))
+            sys.exit(1)
 
     # generate results directory name
     date = datetime.datetime.fromtimestamp(time.time())
@@ -308,28 +365,49 @@ def main():
         print(Loader().get_vswitches_printable())
         exit()
 
+    if args['list_vnfs']:
+        print(Loader().get_vnfs_printable())
+        exit()
+
     if args['list_settings']:
         print(str(settings))
         exit()
 
     # create results directory
-    if not os.path.exists(results_dir):
+    if not os.path.exists(results_path):
         logger.info("Creating result directory: "  + results_path)
         os.makedirs(results_path)
 
+    suite = unittest.TestSuite()
+
     # run tests
     for test in all_tests:
         try:
             test.run()
+            suite.addTest(MockTestCase('', True, test.name))
         #pylint: disable=broad-except
-        except (Exception) as _:
+        except (Exception) as ex:
             logger.exception("Failed to run test: %s", test.name)
+            suite.addTest(MockTestCase(str(ex), False, test.name))
             logger.info("Continuing with next test...")
 
+    if settings.getValue('XUNIT'):
+        xmlrunner.XMLTestRunner(
+            output=settings.getValue('XUNIT_DIR'), outsuffix="",
+            verbosity=0).run(suite)
+
     #remove directory if no result files were created.
     if os.path.exists(results_path):
-        if os.listdir(results_path) == []:
+        files_list = os.listdir(results_path)
+        if files_list == []:
             shutil.rmtree(results_path)
+        else:
+            for file in files_list:
+                # generate report from all csv files
+                if file[-3:] == 'csv':
+                    results_csv = os.path.join(results_path, file)
+                    if os.path.isfile(results_csv) and os.access(results_csv, os.R_OK):
+                        report.generate(testcases, results_csv)
 
 if __name__ == "__main__":
     main()