|  | @@ -801,6 +801,23 @@ def _start_port_server(port_server_port):
 | 
	
		
			
				|  |  |          raise
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +def _calculate_num_runs_failures(list_of_results):
 | 
	
		
			
				|  |  | +  """Caculate number of runs and failures for a particular test.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Args:
 | 
	
		
			
				|  |  | +    list_of_results: (List) of JobResult object.
 | 
	
		
			
				|  |  | +  Returns:
 | 
	
		
			
				|  |  | +    A tuple of total number of runs and failures.
 | 
	
		
			
				|  |  | +  """
 | 
	
		
			
				|  |  | +  num_runs = len(list_of_results)  # By default, there is 1 run per JobResult.
 | 
	
		
			
				|  |  | +  num_failures = 0
 | 
	
		
			
				|  |  | +  for jobresult in list_of_results:
 | 
	
		
			
				|  |  | +    if jobresult.retries > 0:
 | 
	
		
			
				|  |  | +      num_runs += jobresult.retries
 | 
	
		
			
				|  |  | +    if jobresult.num_failures > 0:
 | 
	
		
			
				|  |  | +      num_failures += jobresult.num_failures
 | 
	
		
			
				|  |  | +  return num_runs, num_failures
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  def _build_and_run(
 | 
	
		
			
				|  |  |      check_cancelled, newline_on_success, travis, cache, xml_report=None):
 | 
	
		
			
				|  |  |    """Do one pass of building & running tests."""
 | 
	
	
		
			
				|  | @@ -842,13 +859,24 @@ def _build_and_run(
 | 
	
		
			
				|  |  |      root = ET.Element('testsuites') if xml_report else None
 | 
	
		
			
				|  |  |      testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    number_failures, _ = jobset.run(
 | 
	
		
			
				|  |  | -        all_runs, check_cancelled, newline_on_success=newline_on_success,
 | 
	
		
			
				|  |  | +    number_failures, resultset = jobset.run(
 | 
	
		
			
				|  |  | +        all_runs, check_cancelled, newline_on_success=newline_on_success, 
 | 
	
		
			
				|  |  |          travis=travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
 | 
	
		
			
				|  |  |          stop_on_failure=args.stop_on_failure,
 | 
	
		
			
				|  |  |          cache=cache if not xml_report else None,
 | 
	
		
			
				|  |  |          xml_report=testsuite,
 | 
	
		
			
				|  |  |          add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
 | 
	
		
			
				|  |  | +    if resultset:
 | 
	
		
			
				|  |  | +      for k, v in resultset.iteritems():
 | 
	
		
			
				|  |  | +        num_runs, num_failures = _calculate_num_runs_failures(v)
 | 
	
		
			
				|  |  | +        if num_failures == num_runs:  # what about infinite_runs???
 | 
	
		
			
				|  |  | +          jobset.message('FAILED', k, do_newline=True)
 | 
	
		
			
				|  |  | +        elif num_failures > 0:
 | 
	
		
			
				|  |  | +          jobset.message(
 | 
	
		
			
				|  |  | +              'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
 | 
	
		
			
				|  |  | +              do_newline=True)
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +          jobset.message('PASSED', k, do_newline=True)
 | 
	
		
			
				|  |  |      if number_failures:
 | 
	
		
			
				|  |  |        return 2
 | 
	
		
			
				|  |  |    finally:
 | 
	
	
		
			
				|  | @@ -880,9 +908,9 @@ if forever:
 | 
	
		
			
				|  |  |      have_files_changed = lambda: dw.most_recent_change() != initial_time
 | 
	
		
			
				|  |  |      previous_success = success
 | 
	
		
			
				|  |  |      success = _build_and_run(check_cancelled=have_files_changed,
 | 
	
		
			
				|  |  | -                             newline_on_success=False,
 | 
	
		
			
				|  |  | -                             travis=args.travis,
 | 
	
		
			
				|  |  | -                             cache=test_cache) == 0
 | 
	
		
			
				|  |  | +                                        newline_on_success=False,
 | 
	
		
			
				|  |  | +                                        travis=args.travis,
 | 
	
		
			
				|  |  | +                                        cache=test_cache) == 0
 | 
	
		
			
				|  |  |      if not previous_success and success:
 | 
	
		
			
				|  |  |        jobset.message('SUCCESS',
 | 
	
		
			
				|  |  |                       'All tests are now passing properly',
 |