oft: Add support for XML output

Add support for xUnit-format XML output by utilising the 'xmlrunner'
package. This feature is optional, and is disabled by default.

Resolves issue #123.

Signed-off-by: Stephen Finucane <stephenfinucane@hotmail.com>
diff --git a/oft b/oft
index 9d5df6a..a3756da 100755
--- a/oft
+++ b/oft
@@ -78,6 +78,8 @@
     "log_dir"            : None,
     "debug"              : "verbose",
     "profile"            : False,
+    "xunit"              : False,
+    "xunit_dir"          : "xunit",
 
     # Test behavior options
     "relax"              : False,
@@ -182,6 +184,8 @@
     group.add_option("-q", "--quiet", action="store_const", dest="debug",
                      const="warning", help="Shortcut for --debug=warning")
     group.add_option("--profile", action="store_true", help="Write Python profile to profile.out")
+    group.add_option("--xunit", action="store_true", help="Enable xUnit-formatted results")
+    group.add_option("--xunit-dir", help="Output directory for xUnit-formatted results")
     parser.add_option_group(group)
 
     group = optparse.OptionGroup(parser, "Test behavior options")
@@ -240,6 +244,20 @@
 
     oftest.open_logfile('main')
 
+def xunit_setup(config):
+    """
+    Set up xUnit output based on config
+    """
+
+    if not config["xunit"]:
+        return
+
+    if config["xunit"] != None:
+        if os.path.exists(config["xunit_dir"]):
+            import shutil
+            shutil.rmtree(config["xunit_dir"])
+        os.makedirs(config["xunit_dir"])
+
 def pcap_setup(config):
     """
     Set up dataplane packet capturing based on config
@@ -371,6 +389,7 @@
 oftest.config.update(new_config)
 
 logging_setup(config)
+xunit_setup(config)
 logging.info("++++++++ " + time.asctime() + " ++++++++")
 
 # Pick an OpenFlow protocol module based on the configured version
@@ -530,7 +549,15 @@
         oftest.dataplane_instance.port_add(ifname, of_port)
 
     logging.info("*** TEST RUN START: " + time.asctime())
-    result = unittest.TextTestRunner(verbosity=2).run(suite)
+    if config["xunit"]:
+        import xmlrunner  # fail-fast if module missing
+
+        runner = xmlrunner.XMLTestRunner(output=config["xunit_dir"],
+                                         outsuffix="",
+                                         verbosity=2)
+        result = runner.run(suite)
+    else:
+        result = unittest.TextTestRunner(verbosity=2).run(suite)
     oftest.open_logfile('main')
     if oftest.testutils.skipped_test_count > 0:
         ts = " tests"