Home | History | Annotate | Download | only in health
      1 #!/usr/bin/python
      2 #
      3 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 
      8 import argparse, datetime, sys
      9 
     10 import common
     11 from autotest_lib.frontend import setup_django_readonly_environment
     12 from autotest_lib.server.cros.dynamic_suite import reporting
     13 
     14 # Django and the models are only setup after
     15 # the setup_django_readonly_environment module is imported.
     16 from autotest_lib.frontend.afe import models as afe_models
     17 from autotest_lib.frontend.health import utils as test_health_utils
     18 
     19 
     20 # Keep tests that have not failed for at least this many days.
     21 _MIN_DAYS_SINCE_FAILURE = 30
     22 # Ignore any tests that have not passed in this many days.
     23 _MAX_DAYS_SINCE_LAST_PASS = 30
     24 
     25 
     26 def get_experimental_tests():
     27     """
     28     Get all the tests marked experimental from the afe_autotests table.
     29 
     30     @return the set of experimental test names.
     31 
     32     """
     33     entries = afe_models.Test.objects.values('name').filter(experimental=True)
     34     return {entry['name'] for entry in entries}
     35 
     36 
     37 def find_long_passing_tests(pass_times, fail_times, valid_names):
     38     """
     39     Determine the experimental tests that have been passsing for a long time.
     40 
     41     @param pass_times: The dictionary of test_name:pass_time pairs.
     42     @param fail_times: The dictionary of test_name:fail_time pairs.
     43     @param valid_names: An iterable of experimental test names.
     44 
     45     @return the list of experimental test names that have been passing for a
     46         long time.
     47 
     48     """
     49     failure_cutoff_date = (datetime.datetime.today() -
     50                            datetime.timedelta(_MIN_DAYS_SINCE_FAILURE))
     51     pass_cutoff_date = (datetime.datetime.today() -
     52                         datetime.timedelta(_MAX_DAYS_SINCE_LAST_PASS))
     53 
     54     valid_passes = {test for test in valid_names if test in pass_times}
     55     valid_failures = {test for test in valid_names if test in fail_times}
     56 
     57     recent_passes = {test for test in valid_passes
     58                      if (pass_times[test] > pass_cutoff_date)}
     59     recent_fails = {test for test in valid_failures
     60                     if (fail_times[test] > failure_cutoff_date)}
     61 
     62     return recent_passes - recent_fails
     63 
     64 
     65 def parse_options(args):
     66     """Parse the command line options."""
     67 
     68     description = ('Collects information about which experimental tests '
     69                    'have been passing for a long time and creates a bug '
     70                    'report for each one.')
     71     parser = argparse.ArgumentParser(description=description)
     72     parser.parse_args(args)
     73 
     74 
     75 def submit_bug_reports(tests):
     76     """
     77     Submits bug reports to make the long passing tests as not experimental.
     78 
     79     @param tests: The tests that need to be marked as not experimental.
     80     """
     81 
     82     for test in tests:
     83         title = '%s should be promoted to non-experimental.' % test
     84         summary = ('This bug has been automatically filed to track the '
     85                    'following issue:\n\n'
     86                    'Test: %s\n'
     87                    'Issue: Promote to non-experimental as it has been passing '
     88                    'for at least %d days.\n'
     89                    'Suggested Actions: Navigate to the test\'s control file '
     90                    'and remove the EXPERIMENTAL flag.\n'
     91                    '\tSee http://www.chromium.org/chromium-os/testing/'
     92                    'autotest-best-practices#TOC-Control-files' %
     93                    (test, _MIN_DAYS_SINCE_FAILURE))
     94         search_marker = 'PassingExperimental(%s)' % test
     95         reporting.submit_generic_bug_report(title=title, summary=summary,
     96                                             search_marker=search_marker)
     97 
     98 
     99 def main(args=None):
    100     """
    101     The script code.
    102 
    103     Allows other python code to import and run this code. This will be more
    104     important if a nice way to test this code can be determined.
    105 
    106     @param args: The command line arguments being passed in.
    107 
    108     """
    109     args = [] if args is None else args
    110     parse_options(args)
    111 
    112     experimental_tests = get_experimental_tests()
    113     pass_times = test_health_utils.get_last_pass_times()
    114     fail_times = test_health_utils.get_last_fail_times()
    115 
    116     long_passers = find_long_passing_tests(pass_times, fail_times,
    117                                            experimental_tests)
    118 
    119     submit_bug_reports(long_passers)
    120 
    121     return 0
    122 
    123 
    124 if __name__ == '__main__':
    125     sys.exit(main(sys.argv[1:]))
    126