SearchCases.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. # Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http:#www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """ search test cases from a given file or path """
  15. import copy
  16. import fnmatch
  17. import os
  18. import types
  19. from . import load_source
  20. class Search(object):
  21. TEST_CASE_FILE_PATTERN = '*_test.py'
  22. SUPPORT_REPLICATE_CASES_KEY = ['target']
  23. @classmethod
  24. def _search_cases_from_file(cls, file_name):
  25. """ get test cases from test case .py file """
  26. print('Try to get cases from: ' + file_name)
  27. test_functions = []
  28. try:
  29. mod = load_source(file_name)
  30. for func in [mod.__getattribute__(x) for x in dir(mod)
  31. if isinstance(mod.__getattribute__(x), types.FunctionType)]:
  32. try:
  33. # test method decorator will add test_method attribute to test function
  34. if func.test_method:
  35. test_functions.append(func)
  36. except AttributeError:
  37. continue
  38. except ImportError as e:
  39. print('ImportError: \r\n\tFile:' + file_name + '\r\n\tError:' + str(e))
  40. test_functions_out = []
  41. for case in test_functions:
  42. test_functions_out += cls.replicate_case(case)
  43. for i, test_function in enumerate(test_functions_out):
  44. print('\t{}. {} <{}>'.format(i + 1, test_function.case_info['name'], test_function.case_info['target']))
  45. test_function.case_info['app_dir'] = os.path.dirname(file_name)
  46. return test_functions_out
  47. @classmethod
  48. def _search_test_case_files(cls, test_case, file_pattern):
  49. """ search all test case files recursively of a path """
  50. if not os.path.exists(test_case):
  51. raise OSError('test case path not exist')
  52. if os.path.isdir(test_case):
  53. test_case_files = []
  54. for root, _, file_names in os.walk(test_case):
  55. for filename in fnmatch.filter(file_names, file_pattern):
  56. test_case_files.append(os.path.join(root, filename))
  57. else:
  58. test_case_files = [test_case]
  59. return test_case_files
  60. @classmethod
  61. def replicate_case(cls, case):
  62. """
  63. Replicate cases according to its filter values.
  64. If one case has specified filter chip=(ESP32, ESP32C),
  65. it will create 2 cases, one for ESP32 and on for ESP32C.
  66. Once the cases are replicated, it's easy to filter those we want to execute.
  67. :param case: the original case
  68. :return: a list of replicated cases
  69. """
  70. replicate_config = []
  71. for key in case.case_info:
  72. if key == 'ci_target': # ci_target is used to filter target, should not be duplicated.
  73. continue
  74. if isinstance(case.case_info[key], (list, tuple)):
  75. replicate_config.append(key)
  76. def _replicate_for_key(cases, replicate_key, replicate_list):
  77. def deepcopy_func(f, name=None):
  78. fn = types.FunctionType(f.__code__, f.__globals__, name if name else f.__name__,
  79. f.__defaults__, f.__closure__)
  80. fn.__dict__.update(copy.deepcopy(f.__dict__))
  81. return fn
  82. case_out = []
  83. for inner_case in cases:
  84. for value in replicate_list:
  85. new_case = deepcopy_func(inner_case)
  86. new_case.case_info[replicate_key] = value
  87. case_out.append(new_case)
  88. return case_out
  89. replicated_cases = [case]
  90. while replicate_config:
  91. if not replicate_config:
  92. break
  93. key = replicate_config.pop()
  94. if key in cls.SUPPORT_REPLICATE_CASES_KEY:
  95. replicated_cases = _replicate_for_key(replicated_cases, key, case.case_info[key])
  96. # mark the cases with targets not in ci_target
  97. for case in replicated_cases:
  98. ci_target = case.case_info['ci_target']
  99. if not ci_target or case.case_info['target'] in ci_target:
  100. case.case_info['supported_in_ci'] = True
  101. else:
  102. case.case_info['supported_in_ci'] = False
  103. return replicated_cases
  104. @classmethod
  105. def search_test_cases(cls, test_case_paths, test_case_file_pattern=None):
  106. """
  107. search all test cases from a folder or file, and then do case replicate.
  108. :param test_case_paths: test case file(s) paths
  109. :param test_case_file_pattern: unix filename pattern
  110. :return: a list of replicated test methods
  111. """
  112. if not isinstance(test_case_paths, list):
  113. test_case_paths = [test_case_paths]
  114. test_case_files = []
  115. for path in test_case_paths:
  116. test_case_files.extend(cls._search_test_case_files(path, test_case_file_pattern or cls.TEST_CASE_FILE_PATTERN))
  117. test_cases = []
  118. for test_case_file in test_case_files:
  119. test_cases += cls._search_cases_from_file(test_case_file)
  120. return test_cases