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 
     23 from vts.testcases.kernel.ltp import ltp_configs
     24 from vts.testcases.kernel.ltp import ltp_enums
     25 from vts.testcases.kernel.ltp import test_case
     26 
     27 
     28 class TestCasesParser(object):
     29     """Load a ltp vts testcase definition file and parse it into a generator.
     30 
     31     Attributes:
     32         _data_path: string, the vts data path on host side
     33         _filter_func: function, a filter method that will emit exception if a test is filtered
     34         disabled_tests: list of string
     35         staging_tests: list of string
     36     """
     37 
     38     def __init__(self, data_path, filter_func, disabled_tests, staging_tests):
     39         self._data_path = data_path
     40         self._filter_func = filter_func
     41         self._disabled_tests = disabled_tests
     42         self._staging_tests = staging_tests
     43 
     44     def ValidateDefinition(self, line):
     45         """Validate a tab delimited test case definition.
     46 
     47         Will check whether the given line of definition has three parts
     48         separated by tabs.
     49         It will also trim leading and ending white spaces for each part
     50         in returned tuple (if valid).
     51 
     52         Returns:
     53             A tuple in format (test suite, test name, test command) if
     54             definition is valid. None otherwise.
     55         """
     56         items = [
     57             item.strip()
     58             for item in line.split(ltp_enums.Delimiters.TESTCASE_DEFINITION)
     59         ]
     60         if not len(items) == 3 or not items:
     61             return None
     62         else:
     63             return items
     64 
     65     def Load(self, ltp_dir, n_bit, run_staging=False):
     66         """Read the definition file and yields a TestCase generator."""
     67         run_scritp = self.GenerateLtpRunScript()
     68 
     69         for line in run_scritp:
     70             items = self.ValidateDefinition(line)
     71             if not items:
     72                 continue
     73 
     74             testsuite, testname, command = items
     75 
     76             # Tests failed to build will have prefix "DISABLED_"
     77             if testname.startswith("DISABLED_"):
     78                 logging.info("[Parser] Skipping test case {}-{}. Reason: "
     79                              "not built".format(testsuite, testname))
     80                 continue
     81 
     82             # Some test cases contain semicolons in their commands,
     83             # and we replace them with &&
     84             command = command.replace(';', '&&')
     85 
     86             testcase = test_case.TestCase(
     87                 testsuite=testsuite, testname=testname, command=command)
     88 
     89             test_display_name = "{}_{}bit".format(str(testcase), n_bit)
     90 
     91             # Check runner's base_test filtering method
     92             try:
     93                 self._filter_func(test_display_name)
     94             except:
     95                 logging.info("[Parser] Skipping test case %s. Reason: "
     96                              "filtered" % testcase.fullname)
     97                 testcase.is_filtered = True
     98                 testcase.note = "filtered"
     99 
    100             # For skipping tests that are not designed or ready for Android
    101             if test_display_name in self._disabled_tests:
    102                 logging.info("[Parser] Skipping test case %s. Reason: "
    103                              "disabled" % testcase.fullname)
    104                 continue
    105 
    106             # For separating staging tests from stable tests
    107             if test_display_name in self._staging_tests:
    108                 if not run_staging:
    109                     # Skip staging tests in stable run
    110                     continue
    111                 else:
    112                     testcase.is_staging = True
    113                     testcase.note = "staging"
    114             else:
    115                 if run_staging:
    116                     # Skip stable tests in staging run
    117                     continue
    118 
    119             logging.info("[Parser] Adding test case %s." % testcase.fullname)
    120             yield testcase
    121 
    122     def ReadCommentedTxt(self, filepath):
    123         '''Read a lines of a file that are not commented by #.
    124 
    125         Args:
    126             filepath: string, path of file to read
    127 
    128         Returns:
    129             A set of string representing non-commented lines in given file
    130         '''
    131         if not filepath:
    132             logging.error('Invalid file path')
    133             return None
    134 
    135         with open(filepath, 'r') as f:
    136             lines_gen = (line.strip() for line in f)
    137             return set(
    138                 line for line in lines_gen
    139                 if line and not line.startswith('#'))
    140 
    141     def GenerateLtpTestCases(self, testsuite, disabled_tests_list):
    142         '''Generate test cases for each ltp test suite.
    143 
    144         Args:
    145             testsuite: string, test suite name
    146 
    147         Returns:
    148             A list of string
    149         '''
    150         testsuite_script = os.path.join(self._data_path,
    151                                         ltp_configs.LTP_RUNTEST_DIR, testsuite)
    152 
    153         result = []
    154         for line in open(testsuite_script, 'r'):
    155             line = line.strip()
    156             if not line or line.startswith('#'):
    157                 continue
    158 
    159             testname = line.split()[0]
    160             testname_prefix = ('DISABLED_'
    161                                if testname in disabled_tests_list else '')
    162             testname_modified = testname_prefix + testname
    163 
    164             result.append("\t".join([testsuite, testname_modified, line[len(
    165                 testname):].strip()]))
    166         return result
    167 
    168     def GenerateLtpRunScript(self):
    169         '''Given a scenario group generate test case script.
    170 
    171         Args:
    172             scenario_group: string, file path of scanerio group file
    173 
    174         Returns:
    175             A list of string
    176         '''
    177         disabled_tests_path = os.path.join(
    178             self._data_path, ltp_configs.LTP_DISABLED_BUILD_TESTS_CONFIG_PATH)
    179         disabled_tests_list = self.ReadCommentedTxt(disabled_tests_path)
    180 
    181         result = []
    182         for testsuite in ltp_configs.TEST_SUITES:
    183             result.extend(
    184                 self.GenerateLtpTestCases(testsuite, disabled_tests_list))
    185 
    186         #TODO(yuexima): remove duplicate
    187 
    188         return result
    189