1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/build/android/pylib/run_python_tests.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,207 @@ 1.4 +# Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +# Use of this source code is governed by a BSD-style license that can be 1.6 +# found in the LICENSE file. 1.7 + 1.8 +"""Runs the Python tests (relies on using the Java test runner).""" 1.9 + 1.10 +import logging 1.11 +import os 1.12 +import sys 1.13 +import types 1.14 + 1.15 +import android_commands 1.16 +import apk_info 1.17 +import constants 1.18 +import python_test_base 1.19 +from python_test_caller import CallPythonTest 1.20 +from python_test_sharder import PythonTestSharder 1.21 +import run_java_tests 1.22 +from run_java_tests import FatalTestException 1.23 +from test_info_collection import TestInfoCollection 1.24 +from test_result import TestResults 1.25 + 1.26 + 1.27 +def _GetPythonFiles(root, files): 1.28 + """Returns all files from |files| that end in 'Test.py'. 1.29 + 1.30 + Args: 1.31 + root: A directory name with python files. 1.32 + files: A list of file names. 1.33 + 1.34 + Returns: 1.35 + A list with all Python driven test file paths. 1.36 + """ 1.37 + return [os.path.join(root, f) for f in files if f.endswith('Test.py')] 1.38 + 1.39 + 1.40 +def _InferImportNameFromFile(python_file): 1.41 + """Given a file, infer the import name for that file. 1.42 + 1.43 + Example: /usr/foo/bar/baz.py -> baz. 1.44 + 1.45 + Args: 1.46 + python_file: path to the Python file, ostensibly to import later. 1.47 + 1.48 + Returns: 1.49 + The module name for the given file. 1.50 + """ 1.51 + return os.path.splitext(os.path.basename(python_file))[0] 1.52 + 1.53 + 1.54 +def DispatchPythonTests(options): 1.55 + """Dispatches the Python tests. If there are multiple devices, use sharding. 1.56 + 1.57 + Args: 1.58 + options: command line options. 1.59 + 1.60 + Returns: 1.61 + A list of test results. 1.62 + """ 1.63 + 1.64 + attached_devices = android_commands.GetAttachedDevices() 1.65 + if not attached_devices: 1.66 + raise FatalTestException('You have no devices attached or visible!') 1.67 + if options.device: 1.68 + attached_devices = [options.device] 1.69 + 1.70 + test_collection = TestInfoCollection() 1.71 + all_tests = _GetAllTests(options.python_test_root, options.official_build) 1.72 + test_collection.AddTests(all_tests) 1.73 + test_names = [t.qualified_name for t in all_tests] 1.74 + logging.debug('All available tests: ' + str(test_names)) 1.75 + 1.76 + available_tests = test_collection.GetAvailableTests( 1.77 + options.annotation, options.test_filter) 1.78 + 1.79 + if not available_tests: 1.80 + logging.warning('No Python tests to run with current args.') 1.81 + return TestResults() 1.82 + 1.83 + available_tests *= options.number_of_runs 1.84 + test_names = [t.qualified_name for t in available_tests] 1.85 + logging.debug('Final list of tests to run: ' + str(test_names)) 1.86 + 1.87 + # Copy files to each device before running any tests. 1.88 + for device_id in attached_devices: 1.89 + logging.debug('Pushing files to device %s', device_id) 1.90 + apks = [apk_info.ApkInfo(options.test_apk_path, options.test_apk_jar_path)] 1.91 + test_files_copier = run_java_tests.TestRunner(options, device_id, 1.92 + None, False, 0, apks, []) 1.93 + test_files_copier.CopyTestFilesOnce() 1.94 + 1.95 + # Actually run the tests. 1.96 + if len(attached_devices) > 1 and options.wait_for_debugger: 1.97 + logging.warning('Debugger can not be sharded, ' 1.98 + 'using first available device') 1.99 + attached_devices = attached_devices[:1] 1.100 + logging.debug('Running Python tests') 1.101 + sharder = PythonTestSharder(attached_devices, available_tests, options) 1.102 + test_results = sharder.RunShardedTests() 1.103 + 1.104 + return test_results 1.105 + 1.106 + 1.107 +def _GetTestModules(python_test_root, is_official_build): 1.108 + """Retrieve a sorted list of pythonDrivenTests. 1.109 + 1.110 + Walks the location of pythonDrivenTests, imports them, and provides the list 1.111 + of imported modules to the caller. 1.112 + 1.113 + Args: 1.114 + python_test_root: the path to walk, looking for pythonDrivenTests 1.115 + is_official_build: whether to run only those tests marked 'official' 1.116 + 1.117 + Returns: 1.118 + A list of Python modules which may have zero or more tests. 1.119 + """ 1.120 + # By default run all python tests under pythonDrivenTests. 1.121 + python_test_file_list = [] 1.122 + for root, _, files in os.walk(python_test_root): 1.123 + if (root.endswith('pythonDrivenTests') 1.124 + or (is_official_build 1.125 + and root.endswith('pythonDrivenTests/official'))): 1.126 + python_test_file_list += _GetPythonFiles(root, files) 1.127 + python_test_file_list.sort() 1.128 + 1.129 + test_module_list = [_GetModuleFromFile(test_file) 1.130 + for test_file in python_test_file_list] 1.131 + return test_module_list 1.132 + 1.133 + 1.134 +def _GetModuleFromFile(python_file): 1.135 + """Gets the module associated with a file by importing it. 1.136 + 1.137 + Args: 1.138 + python_file: file to import 1.139 + 1.140 + Returns: 1.141 + The module object. 1.142 + """ 1.143 + sys.path.append(os.path.dirname(python_file)) 1.144 + import_name = _InferImportNameFromFile(python_file) 1.145 + return __import__(import_name) 1.146 + 1.147 + 1.148 +def _GetTestsFromClass(test_class): 1.149 + """Create a list of test objects for each test method on this class. 1.150 + 1.151 + Test methods are methods on the class which begin with 'test'. 1.152 + 1.153 + Args: 1.154 + test_class: class object which contains zero or more test methods. 1.155 + 1.156 + Returns: 1.157 + A list of test objects, each of which is bound to one test. 1.158 + """ 1.159 + test_names = [m for m in dir(test_class) 1.160 + if _IsTestMethod(m, test_class)] 1.161 + return map(test_class, test_names) 1.162 + 1.163 + 1.164 +def _GetTestClassesFromModule(test_module): 1.165 + tests = [] 1.166 + for name in dir(test_module): 1.167 + attr = getattr(test_module, name) 1.168 + if _IsTestClass(attr): 1.169 + tests.extend(_GetTestsFromClass(attr)) 1.170 + return tests 1.171 + 1.172 + 1.173 +def _IsTestClass(test_class): 1.174 + return (type(test_class) is types.TypeType and 1.175 + issubclass(test_class, python_test_base.PythonTestBase) and 1.176 + test_class is not python_test_base.PythonTestBase) 1.177 + 1.178 + 1.179 +def _IsTestMethod(attrname, test_case_class): 1.180 + """Checks whether this is a valid test method. 1.181 + 1.182 + Args: 1.183 + attrname: the method name. 1.184 + test_case_class: the test case class. 1.185 + 1.186 + Returns: 1.187 + True if test_case_class.'attrname' is callable and it starts with 'test'; 1.188 + False otherwise. 1.189 + """ 1.190 + attr = getattr(test_case_class, attrname) 1.191 + return callable(attr) and attrname.startswith('test') 1.192 + 1.193 + 1.194 +def _GetAllTests(test_root, is_official_build): 1.195 + """Retrieve a list of Python test modules and their respective methods. 1.196 + 1.197 + Args: 1.198 + test_root: path which contains Python-driven test files 1.199 + is_official_build: whether this is an official build 1.200 + 1.201 + Returns: 1.202 + List of test case objects for all available test methods. 1.203 + """ 1.204 + if not test_root: 1.205 + return [] 1.206 + all_tests = [] 1.207 + test_module_list = _GetTestModules(test_root, is_official_build) 1.208 + for module in test_module_list: 1.209 + all_tests.extend(_GetTestClassesFromModule(module)) 1.210 + return all_tests