generate html report for interop tests
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 84262aa..2170824 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -161,7 +161,7 @@
       if os.path.isfile(binary):
         out.append(config.job_spec([binary], [binary]))
       else:
-        print "\nWARNING: binary not found, skipping", binary
+        print '\nWARNING: binary not found, skipping', binary
     return sorted(out)
 
   def make_targets(self):
@@ -516,7 +516,7 @@
         if n <= 0: raise ValueError
         return n
     except:
-        msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
+        msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
         raise argparse.ArgumentTypeError(msg)
 
 # parse command line
@@ -555,14 +555,14 @@
                   default=False,
                   action='store_const',
                   const=True,
-                  help="Run all the tests under docker. That provides " +
-                  "additional isolation and prevents the need to install " +
-                  "language specific prerequisites. Only available on Linux.")
+                  help='Run all the tests under docker. That provides ' +
+                  'additional isolation and prevents the need to install ' +
+                  'language specific prerequisites. Only available on Linux.')
 argp.add_argument('--allow_flakes',
                   default=False,
                   action='store_const',
                   const=True,
-                  help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
+                  help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
 argp.add_argument('-a', '--antagonists', default=0, type=int)
 argp.add_argument('-x', '--xml_report', default=None, type=str,
         help='Generates a JUnit-compatible XML report')
@@ -578,7 +578,7 @@
     time.sleep(5)
 
   child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
-  run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
+  run_tests_cmd = 'tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
 
   # TODO(jtattermusch): revisit if we need special handling for arch here
   # set arch command prefix in case we are working with different arch.
@@ -625,9 +625,9 @@
     # better do parallel compilation
     # empirically /m:2 gives the best performance/price and should prevent
     # overloading the windows workers.
-    extra_args.extend(["/m:2"])
+    extra_args.extend(['/m:2'])
     # disable PDB generation: it's broken, and we don't need it during CI
-    extra_args.extend(["/p:Jenkins=true"])
+    extra_args.extend(['/p:Jenkins=true'])
     return [
       jobset.JobSpec(['vsprojects\\build.bat',
                       'vsprojects\\%s.sln' % target,
@@ -802,8 +802,10 @@
     check_cancelled, newline_on_success, travis, cache, xml_report=None):
   """Do one pass of building & running tests."""
   # build latest sequentially
-  if not jobset.run(build_steps, maxjobs=1, stop_on_failure=True,
-                    newline_on_success=newline_on_success, travis=travis):
+  num_failures, _ = jobset.run(
+      build_steps, maxjobs=1, stop_on_failure=True,
+      newline_on_success=newline_on_success, travis=travis)
+  if num_failures:
     return 1
 
   # start antagonists