We wanted to have a little more flexibility with test_importer.py for chromeos. 
 For example we wanted to import
 all tests from client/site_tests and server/site_tests but only some from 
client/tests and server/tests.  
 We've added the following:
 -The ability to pass a whitelist with -w that specifies a subset of tests 
within a tests/profilers/samples directory.
  This option is incompatible with -a because if you're using -a you're 
probably already managing your tests by 
  adding/deleting files.  The whitelist attribute does not clean anything so 
the pattern will be to run test_importer.py 
  with -C to clear all and then to run with -w.
 -The ability to adjust any test attributes as a site-specific extension.  We 
will use the file site_set_attributes.py
  if it exists and it should include  the function: 'def 
_set_attributes_custom(test, data)'.  
  We use this to adjust the following:
  -Use the directory name instead of control-file NAME (handles multiple 
control files (control.xx) as dirname.xx.
  -Globally set run_verify to 0

Signed-off-by: Mike Truty <[email protected]>

--- autotest/utils/test_importer.py     2010-03-25 11:20:10.000000000 -0700
+++ autotest/utils/test_importer.py     2010-03-25 11:20:10.000000000 -0700
@@ -30,78 +30,99 @@
 import logging, re, os, sys, optparse, compiler
 from autotest_lib.frontend import setup_django_environment
 from autotest_lib.frontend.afe import models
-from autotest_lib.client.common_lib import control_data
+from autotest_lib.client.common_lib import control_data, utils
 
 
-logging.basicConfig(level=logging.DEBUG)
+logging.basicConfig(level=logging.ERROR)
 # Global
 DRY_RUN = False
 DEPENDENCIES_NOT_FOUND = set()
 
 
-def update_all(autotest_dir, add_noncompliant, add_experimental, verbose):
-    """Function to scan through all tests and add them to the database."""
+def update_all(autotest_dir, add_noncompliant, add_experimental):
+    """
+    Function to scan through all tests and add them to the database.
+
+    This function invoked when no parameters supplied to the command line.
+    It 'synchronizes' the test database with the current contents of the
+    client and server test directories.  When test code is discovered
+    in the file system new tests may be added to the db.  Likewise,
+    if test code is not found in the filesystem, tests may be removed
+    from the db.  The base test directories are hard-coded to client/tests,
+    client/site_tests, server/tests and server/site_tests.
+
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
+    @param add_noncompliant: attempt adding test with invalid control files.
+    @param add_experimental: add tests with experimental attribute set.
+    """
     for path in [ 'server/tests', 'server/site_tests', 'client/tests',
                   'client/site_tests']:
         test_path = os.path.join(autotest_dir, path)
         if not os.path.exists(test_path):
             continue
-        if verbose:
-            print "Scanning " + test_path
+        logging.info("Scanning %s", test_path)
         tests = []
         tests = get_tests_from_fs(test_path, "^control.*",
                                  add_noncompliant=add_noncompliant)
         update_tests_in_db(tests, add_experimental=add_experimental,
                            add_noncompliant=add_noncompliant,
-                           autotest_dir=autotest_dir,
-                           verbose=verbose)
+                           autotest_dir=autotest_dir)
     test_suite_path = os.path.join(autotest_dir, 'test_suites')
     if os.path.exists(test_suite_path):
-        if verbose:
-            print "Scanning " + test_suite_path
+        logging.info("Scanning %s", test_suite_path)
         tests = get_tests_from_fs(test_suite_path, '.*',
                                  add_noncompliant=add_noncompliant)
         update_tests_in_db(tests, add_experimental=add_experimental,
                            add_noncompliant=add_noncompliant,
-                           autotest_dir=autotest_dir,
-                           verbose=verbose)
+                           autotest_dir=autotest_dir)
 
     profilers_path = os.path.join(autotest_dir, "client/profilers")
     if os.path.exists(profilers_path):
-        if verbose:
-            print "Scanning " + profilers_path
+        logging.info("Scanning %s", profilers_path)
         profilers = get_tests_from_fs(profilers_path, '.*py$')
-        update_profilers_in_db(profilers, verbose=verbose,
-                               add_noncompliant=add_noncompliant,
+        update_profilers_in_db(profilers, add_noncompliant=add_noncompliant,
                                description='NA')
     # Clean bad db entries
-    db_clean_broken(autotest_dir, verbose)
+    db_clean_broken(autotest_dir)
 
 
-def update_samples(autotest_dir, add_noncompliant, add_experimental, verbose):
+def update_samples(autotest_dir, add_noncompliant, add_experimental):
+    """
+    Add only sample tests to the database from the filesystem.
+
+    This function invoked when -S supplied on command line.
+    Only adds tests to the database - does not delete any.
+    Samples tests are formatted slightly differently than other tests.
+
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
+    @param add_noncompliant: attempt adding test with invalid control files.
+    @param add_experimental: add tests with experimental attribute set.
+    """
     sample_path = os.path.join(autotest_dir, 'server/samples')
     if os.path.exists(sample_path):
-        if verbose:
-            print "Scanning " + sample_path
+        logging.info("Scanning %s", sample_path)
         tests = get_tests_from_fs(sample_path, '.*srv$',
                                   add_noncompliant=add_noncompliant)
         update_tests_in_db(tests, add_experimental=add_experimental,
                            add_noncompliant=add_noncompliant,
-                           autotest_dir=autotest_dir,
-                           verbose=verbose)
+                           autotest_dir=autotest_dir)
+
 
+def db_clean_broken(autotest_dir):
+    """
+    Remove tests from autotest_web that do not have valid control files
 
-def db_clean_broken(autotest_dir, verbose):
-    """Remove tests from autotest_web that do not have valid control files
+    This function invoked when -c supplied on the command line and when
+    running update_all().  Removes tests from database which are not
+    found in the filesystem.  Also removes profilers which are just
+    a special case of tests.
 
-       Arguments:
-        tests: a list of control file relative paths used as keys for deletion.
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
     """
     for test in models.Test.objects.all():
         full_path = os.path.join(autotest_dir, test.path)
         if not os.path.isfile(full_path):
-            if verbose:
-                print "Removing " + test.path
+            logging.info("Removing %s", test.path)
             _log_or_execute(repr(test), test.delete)
 
     # Find profilers that are no longer present
@@ -109,21 +130,52 @@
         full_path = os.path.join(autotest_dir, "client", "profilers",
                                  profiler.name)
         if not os.path.exists(full_path):
-            if verbose:
-                print "Removing " + profiler.name
+            logging.info("Removing %s", profiler.name)
             _log_or_execute(repr(profiler), profiler.delete)
 
 
-def update_profilers_in_db(profilers, verbose=False, description='NA',
+def db_clean_all(autotest_dir):
+    """
+    Remove all tests from autotest_web - very destructive
+
+    This function invoked when -C supplied on the command line.
+    Removes ALL tests from the database.
+
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
+    """
+    for test in models.Test.objects.all():
+        full_path = os.path.join(autotest_dir, test.path)
+        logging.info("Removing %s", test.path)
+        _log_or_execute(repr(test), test.delete)
+
+    # Find profilers that are no longer present
+    for profiler in models.Profiler.objects.all():
+        full_path = os.path.join(autotest_dir, "client", "profilers",
+                                 profiler.name)
+        logging.info("Removing %s", profiler.name)
+        _log_or_execute(repr(profiler), profiler.delete)
+
+
+def update_profilers_in_db(profilers, description='NA',
                            add_noncompliant=False):
-    """Update profilers in autotest_web database"""
+    """
+    Add only profilers to the database from the filesystem.
+
+    This function invoked when -p supplied on command line.
+    Only adds profilers to the database - does not delete any.
+    Profilers are formatted slightly differently than tests.
+
+    @param profilers: list of profilers found in the file system.
+    @param description: simple text to satisfy docstring.
+    @param add_noncompliant: attempt adding test with invalid control files.
+    """
     for profiler in profilers:
         name = os.path.basename(profiler).rstrip(".py")
         if not profilers[profiler]:
             if add_noncompliant:
                 doc = description
             else:
-                print "Skipping %s, missing docstring" % profiler
+                logging.info("Skipping %s, missing docstring", profiler)
         else:
             doc = profilers[profiler]
 
@@ -133,19 +185,35 @@
 
 
 def update_tests_in_db(tests, dry_run=False, add_experimental=False,
-                       add_noncompliant=False, verbose=False,
-                       autotest_dir=None):
-    """Update or add each test to the database"""
+                       add_noncompliant=False, autotest_dir=None):
+    """
+    Scans through all tests and add them to the database.
+
+    This function invoked when -t supplied and for update_all.
+    When test code is discovered in the file system new tests may be added
+
+    @param tests: list of tests found in the filesystem.
+    @param dry_run: not used at this time.
+    @param add_experimental: add tests with experimental attribute set.
+    @param add_noncompliant: attempt adding test with invalid control files.
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
+    """
+    site_set_attributes_module = utils.import_site_module(
+        __file__, 'autotest_lib.utils.site_test_importer_attributes')
+
     for test in tests:
         new_test = models.Test.objects.get_or_create(
                 path=test.replace(autotest_dir, '').lstrip('/'))[0]
-        if verbose:
-            print "Processing " + new_test.path
+        logging.info("Processing %s", new_test.path)
 
         # Set the test's attributes
         data = tests[test]
         _set_attributes_clean(new_test, data)
 
+        # Custom Attribute Update
+        if site_set_attributes_module:
+            site_set_attributes_module._set_attributes_custom(new_test, data)
+
         # This only takes place if --add-noncompliant is provided on the CLI
         if not new_test.name:
             test_new_test = test.split('/')
@@ -166,8 +234,12 @@
 
 
 def _set_attributes_clean(test, data):
-    """Sets the attributes of the Test object"""
+    """
+    First pass sets the attributes of the Test object from file system.
 
+    @param test: a test object to be populated for the database.
+    @param data: object with test data from the file system.
+    """
     test_type = { 'client' : 1,
                   'server' : 2, }
     test_time = { 'short' : 1,
@@ -209,9 +281,11 @@
 
 def add_label_dependencies(test):
     """
-    Look at the DEPENDENCIES field for each test and add the proper 
many-to-many
-    relationships.
+    Add proper many-to-many relationships from DEPENDENCIES field.
+
+    @param test: test object for the database.
     """
+
     # clear out old relationships
     _log_or_execute(repr(test), test.dependency_labels.clear,
                     subject='clear dependencies from')
@@ -232,18 +306,26 @@
 
 
 def log_dependency_not_found(label_name):
+    """
+    Exception processing when label not found in database.
+
+    @param label_name: from test dependencies.
+    """
     if label_name in DEPENDENCIES_NOT_FOUND:
         return
-    print 'Dependency %s not found' % label_name
+    logging.info("Dependency %s not found", label_name)
     DEPENDENCIES_NOT_FOUND.add(label_name)
 
 
 def get_tests_from_fs(parent_dir, control_pattern, add_noncompliant=False):
-    """Find control jobs in location and create one big job
-       Returns:
-        dictionary of the form:
-            tests[file_path] = parsed_object
+    """
+    Find control files in file system and load a list with their info.
 
+    @param parent_dir: directory to search recursively.
+    @param control_pattern: name format of control file.
+    @param add_noncompliant: ignore control file parse errors.
+
+    @return: dictionary of the form: tests[file_path] = parsed_object
     """
     tests = {}
     profilers = False
@@ -261,7 +343,7 @@
                                                             
raise_warnings=True)
                         tests[file] = found_test
                     except control_data.ControlVariableException, e:
-                        print "Skipping %s\n%s" % (file, e)
+                        logging.info("Skipping %s\n%s", file, e)
                         pass
                 else:
                     found_test = control_data.parse_control(file)
@@ -273,9 +355,15 @@
 
 
 def recursive_walk(path, wildcard):
-    """Recurisvely go through a directory.
-        Returns:
-        A list of files that match wildcard
+    """
+    Recursively go through a directory.
+
+    This function invoked by get_tests_from_fs().
+
+    @param path: base directory to start search.
+    @param wildcard: name format to match.
+
+    @return: A list of files that match wildcard
     """
     files = []
     directories = [ path ]
@@ -293,29 +381,86 @@
 
 
 def _log_or_execute(content, func, *args, **kwargs):
-    """Log a message if dry_run is enabled, or execute the given function
+    """
+    Log a message if dry_run is enabled, or execute the given function.
 
-    @param content the actual log message
-    @param func function to execute if dry_run is not enabled
-    @param subject (Optional) The type of log being written. Defaults to the
-                   name of the provided function.
+    Relies on the DRY_RUN global variable.
+
+    @param content: the actual log message.
+    @param func: function to execute if dry_run is not enabled.
+    @param subject: (Optional) The type of log being written. Defaults to
+                     the name of the provided function.
     """
     subject = kwargs.get('subject', func.__name__)
 
     if DRY_RUN:
-        print 'Would %s: %s' % (subject, content)
+        logging.info("Would %s: %s",  subject, content)
     else:
         func(*args)
 
 
+def _create_whitelist_set(whitelist_path):
+    """
+    Create a set with contents from a whitelist file for membership testing.
+
+    @param whitelist_path: full path to the whitelist file.
+
+    @return: set with files listed one/line - newlines included.
+    """
+    f = open(whitelist_path, 'r')
+    whitelist_set = set([line.strip() for line in f])
+    f.close()
+    return whitelist_set
+
+
+def update_from_whitelist(whitelist_set, add_experimental, add_noncompliant,
+                          autotest_dir):
+    """
+    Scans through all tests in the whitelist and add them to the database.
+
+    This function invoked when -w supplied.
+
+    @param whitelist_set: set of tests in full-path form from a whitelist.
+    @param add_experimental: add tests with experimental attribute set.
+    @param add_noncompliant: attempt adding test with invalid control files.
+    @param autotest_dir: prepended to path strings (/usr/local/autotest).
+    """
+    tests = {}
+    profilers = {}
+    for file_path in whitelist_set:
+        if file_path.find('client/profilers') == -1:
+            try:
+                found_test = control_data.parse_control(file_path,
+                                                        raise_warnings=True)
+                tests[file_path] = found_test
+            except control_data.ControlVariableException, e:
+                logging.info("Skipping %s\n%s", file, e)
+                pass
+        else:
+            profilers[file_path] = compiler.parseFile(file_path).doc
+
+    if len(tests) > 0:
+        update_tests_in_db(tests, add_experimental=add_experimental,
+                           add_noncompliant=add_noncompliant,
+                           autotest_dir=autotest_dir)
+    if len(profilers) > 0:
+        update_profilers_in_db(profilers, add_noncompliant=add_noncompliant,
+                               description='NA')
+
+
 def main(argv):
     """Main function"""
+
     global DRY_RUN
     parser = optparse.OptionParser()
-    parser.add_option('-c', '--db-clear-tests',
-                      dest='clear_tests', action='store_true',
+    parser.add_option('-c', '--db-clean-tests',
+                      dest='clean_tests', action='store_true',
                       default=False,
-                help='Clear client and server tests with invalid control 
files')
+                help='Clean client and server tests with invalid control 
files')
+    parser.add_option('-C', '--db-clear-all-tests',
+                      dest='clear_all_tests', action='store_true',
+                      default=False,
+                help='Clear ALL client and server tests')
     parser.add_option('-d', '--dry-run',
                       dest='dry_run', action='store_true', default=False,
                       help='Dry run for operation')
@@ -346,7 +491,9 @@
     parser.add_option('-v', '--verbose',
                       dest='verbose', action='store_true', default=False,
                       help='Run in verbose mode')
-    parser.add_option('-z', '--autotest_dir', dest='autotest_dir',
+    parser.add_option('-w', '--whitelist-file', dest='whitelist_file',
+                      help='Filename for list of test names that must match')
+    parser.add_option('-z', '--autotest-dir', dest='autotest_dir',
                       default=os.path.join(os.path.dirname(__file__), '..'),
                       help='Autotest directory root')
     options, args = parser.parse_args()
@@ -355,37 +502,63 @@
     options.autotest_dir = os.path.abspath(options.autotest_dir)
 
     if len(args) > 0:
-        print "Invalid option(s) provided: ", args
+        logging.error("Invalid option(s) provided: %s", args)
         parser.print_help()
         return 1
 
-    if len(argv) == 1:
+    if options.verbose:
+        logging.getLogger().setLevel(logging.DEBUG)
+
+    if len(argv) == 1 or (len(argv) == 2 and options.verbose):
         update_all(options.autotest_dir, options.add_noncompliant,
-                   options.add_experimental, options.verbose)
-        db_clean_broken(options.autotest_dir, options.verbose)
+                   options.add_experimental)
+        db_clean_broken(options.autotest_dir)
         return 0
 
+    if options.clear_all_tests:
+        if (options.clean_tests or options.add_all or options.add_samples or
+            options.add_noncompliant):
+            logging.error(
+                "Can only pass --autotest-dir, --dry-run and --verbose with "
+                "--db-clear-all-tests")
+            return 1
+        db_clean_all(options.autotest_dir)
+
+    whitelist_set = None
+    if options.whitelist_file:
+        if options.add_all:
+            logging.error("Cannot pass both --add-all and --whitelist-file")
+            return 1
+        whitelist_path = os.path.abspath(options.whitelist_file)
+        if not os.path.isfile(whitelist_path):
+            logging.error("--whitelist-file (%s) not found", whitelist_path)
+            return 1
+        logging.info("Using whitelist file %s", whitelist_path)
+        whitelist_set =  _create_whitelist_set(whitelist_path)
+        update_from_whitelist(whitelist_set,
+                              add_experimental=options.add_experimental,
+                              add_noncompliant=options.add_noncompliant,
+                              autotest_dir=options.autotest_dir)
     if options.add_all:
         update_all(options.autotest_dir, options.add_noncompliant,
-                   options.add_experimental, options.verbose)
+                   options.add_experimental)
     if options.add_samples:
         update_samples(options.autotest_dir, options.add_noncompliant,
-                       options.add_experimental, options.verbose)
-    if options.clear_tests:
-        db_clean_broken(options.autotest_dir, options.verbose)
+                       options.add_experimental)
     if options.tests_dir:
         options.tests_dir = os.path.abspath(options.tests_dir)
         tests = get_tests_from_fs(options.tests_dir, options.control_pattern,
                                   add_noncompliant=options.add_noncompliant)
         update_tests_in_db(tests, add_experimental=options.add_experimental,
                            add_noncompliant=options.add_noncompliant,
-                           autotest_dir=options.autotest_dir,
-                           verbose=options.verbose)
+                           autotest_dir=options.autotest_dir)
     if options.profile_dir:
         profilers = get_tests_from_fs(options.profile_dir, '.*py$')
-        update_profilers_in_db(profilers, verbose=options.verbose,
+        update_profilers_in_db(profilers,
                                add_noncompliant=options.add_noncompliant,
                                description='NA')
+    if options.clean_tests:
+        db_clean_broken(options.autotest_dir)
 
 
 if __name__ == "__main__":
_______________________________________________
Autotest mailing list
[email protected]
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

Reply via email to