Home | History | Annotate | Download | only in ltp
      1 #
      2 # Copyright (C) 2016 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 
     17 import os
     18 import logging
     19 import itertools
     20 
     21 from vts.runners.host import const
     22 from vts.testcases.kernel.ltp import ltp_configs
     23 from vts.testcases.kernel.ltp import ltp_enums
     24 from vts.testcases.kernel.ltp import test_case
     25 from vts.testcases.kernel.ltp.configs import stable_tests
     26 from vts.testcases.kernel.ltp.configs import disabled_tests
     27 from vts.utils.python.common import filter_utils
     28 
     29 
     30 class TestCasesParser(object):
     31     """Load a ltp vts testcase definition file and parse it into a generator.
     32 
     33     Attributes:
     34         _data_path: string, the vts data path on host side
     35         _filter_func: function, a filter method that will emit exception if a test is filtered
     36         _ltp_tests_filter: list of string, filter for tests that are stable and disabled
     37     """
     38 
     39     def __init__(self, data_path, filter_func):
     40         self._data_path = data_path
     41         self._filter_func = filter_func
     42         self._ltp_tests_filter = filter_utils.Filter(
     43             stable_tests.STABLE_TESTS,
     44             disabled_tests.DISABLED_TESTS,
     45             enable_regex=True)
     46 
     47     def ValidateDefinition(self, line):
     48         """Validate a tab delimited test case definition.
     49 
     50         Will check whether the given line of definition has three parts
     51         separated by tabs.
     52         It will also trim leading and ending white spaces for each part
     53         in returned tuple (if valid).
     54 
     55         Returns:
     56             A tuple in format (test suite, test name, test command) if
     57             definition is valid. None otherwise.
     58         """
     59         items = [
     60             item.strip()
     61             for item in line.split(ltp_enums.Delimiters.TESTCASE_DEFINITION)
     62         ]
     63         if not len(items) == 3 or not items:
     64             return None
     65         else:
     66             return items
     67 
     68     def Load(self,
     69              ltp_dir,
     70              n_bit,
     71              test_filter,
     72              run_staging=False,
     73              is_low_mem=False):
     74         """Read the definition file and yields a TestCase generator.
     75 
     76         Args:
     77             ltp_dir: string, directory that contains ltp binaries and scripts
     78             n_bit: int, bitness
     79             test_filter: Filter object, test name filter from base_test
     80             run_staging: bool, whether to use staging configuration
     81             is_low_mem: bool, whether to use low memory device configuration
     82         """
     83         scenario_groups = (ltp_configs.TEST_SUITES_LOW_MEM
     84                            if is_low_mem else ltp_configs.TEST_SUITES)
     85         logging.info('LTP scenario groups: %s', scenario_groups)
     86 
     87         run_scritp = self.GenerateLtpRunScript(scenario_groups)
     88 
     89         for line in run_scritp:
     90             items = self.ValidateDefinition(line)
     91             if not items:
     92                 continue
     93 
     94             testsuite, testname, command = items
     95             if is_low_mem and testsuite.endswith(
     96                     ltp_configs.LOW_MEMORY_SCENARIO_GROUP_SUFFIX):
     97                 testsuite = testsuite[:-len(
     98                     ltp_configs.LOW_MEMORY_SCENARIO_GROUP_SUFFIX)]
     99 
    100             # Tests failed to build will have prefix "DISABLED_"
    101             if testname.startswith("DISABLED_"):
    102                 logging.info("[Parser] Skipping test case {}-{}. Reason: "
    103                              "not built".format(testsuite, testname))
    104                 continue
    105 
    106             # Some test cases contain semicolons in their commands,
    107             # and we replace them with &&
    108             command = command.replace(';', '&&')
    109 
    110             testcase = test_case.TestCase(
    111                 testsuite=testsuite, testname=testname, command=command)
    112 
    113             test_display_name = "{}_{}bit".format(str(testcase), n_bit)
    114 
    115             # Check runner's base_test filtering method
    116             try:
    117                 self._filter_func(test_display_name)
    118             except:
    119                 logging.info("[Parser] Skipping test case %s. Reason: "
    120                              "filtered" % testcase.fullname)
    121                 testcase.is_filtered = True
    122                 testcase.note = "filtered"
    123 
    124             # For skipping tests that are not designed or ready for Android
    125             if (self._ltp_tests_filter.IsInExcludeFilter(test_display_name) and
    126                     not test_filter.IsInIncludeFilter(test_display_name)):
    127                 logging.info("[Parser] Skipping test case %s. Reason: "
    128                              "disabled" % testcase.fullname)
    129                 continue
    130 
    131             # For separating staging tests from stable tests
    132             if not self._ltp_tests_filter.IsInIncludeFilter(test_display_name):
    133                 if not run_staging and not test_filter.IsInIncludeFilter(
    134                         test_display_name):
    135                     # Skip staging tests in stable run
    136                     continue
    137                 else:
    138                     testcase.is_staging = True
    139                     testcase.note = "staging"
    140             else:
    141                 if run_staging:
    142                     # Skip stable tests in staging run
    143                     continue
    144 
    145             logging.info("[Parser] Adding test case %s." % testcase.fullname)
    146             yield testcase
    147 
    148     def ReadCommentedTxt(self, filepath):
    149         '''Read a lines of a file that are not commented by #.
    150 
    151         Args:
    152             filepath: string, path of file to read
    153 
    154         Returns:
    155             A set of string representing non-commented lines in given file
    156         '''
    157         if not filepath:
    158             logging.error('Invalid file path')
    159             return None
    160 
    161         with open(filepath, 'r') as f:
    162             lines_gen = (line.strip() for line in f)
    163             return set(
    164                 line for line in lines_gen
    165                 if line and not line.startswith('#'))
    166 
    167     def GenerateLtpTestCases(self, testsuite, disabled_tests_list):
    168         '''Generate test cases for each ltp test suite.
    169 
    170         Args:
    171             testsuite: string, test suite name
    172 
    173         Returns:
    174             A list of string
    175         '''
    176         testsuite_script = os.path.join(self._data_path,
    177                                         ltp_configs.LTP_RUNTEST_DIR, testsuite)
    178 
    179         result = []
    180         for line in open(testsuite_script, 'r'):
    181             line = line.strip()
    182             if not line or line.startswith('#'):
    183                 continue
    184 
    185             testname = line.split()[0]
    186             testname_prefix = ('DISABLED_'
    187                                if testname in disabled_tests_list else '')
    188             testname_modified = testname_prefix + testname
    189 
    190             result.append("\t".join(
    191                 [testsuite, testname_modified, line[len(testname):].strip()]))
    192         return result
    193 
    194     def GenerateLtpRunScript(self, scenario_groups):
    195         '''Given a scenario group generate test case script.
    196 
    197         Args:
    198             scenario_groups: list of string, name of test scenario groups to use
    199 
    200         Returns:
    201             A list of string
    202         '''
    203         disabled_tests_path = os.path.join(
    204             self._data_path, ltp_configs.LTP_DISABLED_BUILD_TESTS_CONFIG_PATH)
    205         disabled_tests_list = self.ReadCommentedTxt(disabled_tests_path)
    206 
    207         result = []
    208         for testsuite in scenario_groups:
    209             result.extend(
    210                 self.GenerateLtpTestCases(testsuite, disabled_tests_list))
    211 
    212         #TODO(yuexima): remove duplicate
    213 
    214         return result
    215