Home | History | Annotate | Download | only in host_driven
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Module containing information about the host-driven tests."""
      6 
      7 import logging
      8 import os
      9 import sys
     10 
     11 from pylib.host_driven import tests_annotations
     12 
     13 from pylib import constants
     14 
     15 sys.path.insert(0,
     16                 os.path.join(constants.DIR_SOURCE_ROOT,
     17                              'build', 'util', 'lib', 'common'))
     18 
     19 import unittest_util # pylint: disable=F0401
     20 
     21 class TestInfo(object):
     22   """An object containing and representing a test function, plus metadata."""
     23 
     24   def __init__(self, runnable, set_up=None, tear_down=None):
     25     # The actual test function/method.
     26     self.runnable = runnable
     27     # Qualified name of test function/method (e.g. FooModule.testBar).
     28     self.qualified_name = self._GetQualifiedName(runnable)
     29     # setUp and teardown functions, if any.
     30     self.set_up = set_up
     31     self.tear_down = tear_down
     32 
     33   @staticmethod
     34   def _GetQualifiedName(runnable):
     35     """Helper method to infer a runnable's name and module name.
     36 
     37     Many filters and lists presuppose a format of module_name.testMethodName.
     38     To make this easy on everyone, we use some reflection magic to infer this
     39     name automatically.
     40 
     41     Args:
     42       runnable: the test method to get the qualified name for
     43 
     44     Returns:
     45       qualified name for this runnable, incl. module name and method name.
     46     """
     47     runnable_name = runnable.__name__
     48     # See also tests_annotations.
     49     module_name = os.path.splitext(
     50         os.path.basename(runnable.__globals__['__file__']))[0]
     51     return '.'.join([module_name, runnable_name])
     52 
     53   def __str__(self):
     54     return self.qualified_name
     55 
     56 
     57 class TestInfoCollection(object):
     58   """A collection of TestInfo objects which facilitates filtering."""
     59 
     60   def __init__(self):
     61     """Initialize a new TestInfoCollection."""
     62     # Master list of all valid tests.
     63     self.all_tests = []
     64 
     65   def AddTests(self, test_infos):
     66     """Adds a set of tests to this collection.
     67 
     68     The user may then retrieve them, optionally according to criteria, via
     69     GetAvailableTests().
     70 
     71     Args:
     72       test_infos: a list of TestInfos representing test functions/methods.
     73     """
     74     self.all_tests = test_infos
     75 
     76   def GetAvailableTests(self, annotations, exclude_annotations, name_filter):
     77     """Get a collection of TestInfos which match the supplied criteria.
     78 
     79     Args:
     80       annotations: List of annotations. Each test in the returned list is
     81         annotated with atleast one of these annotations.
     82       exclude_annotations: List of annotations. The tests in the returned
     83         list are not annotated with any of these annotations.
     84       name_filter: name filter which tests must match, if any
     85 
     86     Returns:
     87       List of available tests.
     88     """
     89     available_tests = self.all_tests
     90 
     91     # Filter out tests which match neither the requested annotation, nor the
     92     # requested name filter, if any.
     93     available_tests = [t for t in available_tests if
     94                        self._AnnotationIncludesTest(t, annotations)]
     95     if annotations and len(annotations) == 1 and annotations[0] == 'SmallTest':
     96       tests_without_annotation = [
     97           t for t in self.all_tests if
     98           not tests_annotations.AnnotatedFunctions.GetTestAnnotations(
     99               t.qualified_name)]
    100       test_names = [t.qualified_name for t in tests_without_annotation]
    101       logging.warning('The following tests do not contain any annotation. '
    102                       'Assuming "SmallTest":\n%s',
    103                       '\n'.join(test_names))
    104       available_tests += tests_without_annotation
    105     if exclude_annotations:
    106       excluded_tests = [t for t in available_tests if
    107                         self._AnnotationIncludesTest(t, exclude_annotations)]
    108       available_tests = list(set(available_tests) - set(excluded_tests))
    109 
    110     if name_filter:
    111       available_test_names = unittest_util.FilterTestNames(
    112           [t.qualified_name for t in available_tests], name_filter)
    113       available_tests = [
    114           t for t in available_tests if
    115           t.qualified_name in available_test_names]
    116     return available_tests
    117 
    118   @staticmethod
    119   def _AnnotationIncludesTest(test_info, annotation_filter_list):
    120     """Checks whether a given test represented by test_info matches annotation.
    121 
    122     Args:
    123       test_info: TestInfo object representing the test
    124       annotation_filter_list: list of annotation filters to match (e.g. Smoke)
    125 
    126     Returns:
    127       True if no annotation was supplied or the test matches; false otherwise.
    128     """
    129     if not annotation_filter_list:
    130       return True
    131     for annotation_filter in annotation_filter_list:
    132       filters = annotation_filter.split('=')
    133       if len(filters) == 2:
    134         key = filters[0]
    135         value_list = filters[1].split(',')
    136         for value in value_list:
    137           if tests_annotations.AnnotatedFunctions.IsAnnotated(
    138               key + ':' + value, test_info.qualified_name):
    139             return True
    140       elif tests_annotations.AnnotatedFunctions.IsAnnotated(
    141           annotation_filter, test_info.qualified_name):
    142         return True
    143     return False
    144 
    145