Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(637)

Side by Side Diff: build/android/pylib/host_driven/test_case.py

Issue 19537004: [Android] Converts host driven tests to common test_dispatcher (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sharding_refactoring
Patch Set: Merges instrumentation_test_case back into test_case Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Base class for Android Python-driven tests. 5 """Base class for host-driven test cases.
6 6
7 This test case is intended to serve as the base class for any Python-driven 7 This test case is intended to serve as the base class for any host-driven
8 tests. It is similar to the Python unitttest module in that the user's tests 8 test cases. It is similar to the Python unitttest module in that test cases
9 inherit from this case and add their tests in that case. 9 inherit from this class and add methods which will be run as tests.
10 10
11 When a PythonTestBase object is instantiated, its purpose is to run only one of 11 When a HostDrivenTestCase object is instantiated, its purpose is to run only one
12 its tests. The test runner gives it the name of the test the instance will 12 test method in the derived class. The test runner gives it the name of the test
13 run. The test runner calls SetUp with the Android device ID which the test will 13 method the instance will run. The test runner calls SetUp with the device ID
14 run against. The runner runs the test method itself, collecting the result, 14 which the test method will run against. The test runner runs the test method
15 and calls TearDown. 15 itself, collecting the result, and calls TearDown.
16
17 Tests can basically do whatever they want in the test methods, such as call
18 Java tests using _RunJavaTests. Those methods have the advantage of massaging
19 the Java test results into Python test results.
20 """ 16 """
21 17
22 import logging 18 import logging
23 import os 19 import os
24 import time 20 import time
25 21
26 from pylib import android_commands 22 from pylib import android_commands
27 from pylib.base import base_test_result 23 from pylib.base import base_test_result
28 from pylib.instrumentation import test_options
29 from pylib.instrumentation import test_package 24 from pylib.instrumentation import test_package
30 from pylib.instrumentation import test_result 25 from pylib.instrumentation import test_result
31 from pylib.instrumentation import test_runner 26 from pylib.instrumentation import test_runner
32 27
33
34 # aka the parent of com.google.android 28 # aka the parent of com.google.android
35 BASE_ROOT = 'src' + os.sep 29 BASE_ROOT = 'src' + os.sep
36 30
37 31
38 class PythonTestBase(object): 32 class HostDrivenTestCase(object):
39 """Base class for Python-driven tests.""" 33 """Base class for host-driven test cases."""
40 34
41 def __init__(self, test_name): 35 _HOST_DRIVEN_TAG = 'HostDriven'
42 # test_name must match one of the test methods defined on a subclass which 36
43 # inherits from this class. 37 def __init__(self, test_name, instrumentation_options=None):
44 # It's stored so we can do the attr lookup on demand, allowing this class 38 """Create a test case initialized to run |test_name|.
45 # to be pickled, a requirement for the multiprocessing module. 39
40 Args:
41 test_name: The name of the method to run as the test.
42 instrumentation_options: An InstrumentationOptions object.
43 """
46 self.test_name = test_name 44 self.test_name = test_name
47 class_name = self.__class__.__name__ 45 class_name = self.__class__.__name__
48 self.qualified_name = class_name + '.' + self.test_name 46 self.qualified_name = '%s.%s' % (class_name, self.test_name)
47 # Use tagged_name when creating results, so that we can identify host-driven
48 # tests in the overall results.
49 self.tagged_name = '%s_%s' % (self._HOST_DRIVEN_TAG, self.qualified_name)
49 50
50 def SetUp(self, options): 51 self.instrumentation_options = instrumentation_options
51 self.options = options 52 self.ports_to_forward = []
52 self.shard_index = self.options.shard_index 53
53 self.device_id = self.options.device_id 54 def SetUp(self, device, shard_index, build_type, push_deps,
55 cleanup_test_files):
56 self.device_id = device
57 self.shard_index = shard_index
58 self.build_type = build_type
54 self.adb = android_commands.AndroidCommands(self.device_id) 59 self.adb = android_commands.AndroidCommands(self.device_id)
55 self.ports_to_forward = [] 60 self.push_deps = push_deps
61 self.cleanup_test_files = cleanup_test_files
56 62
57 def TearDown(self): 63 def TearDown(self):
58 pass 64 pass
59 65
60 def GetOutDir(self): 66 def GetOutDir(self):
61 return os.path.join(os.environ['CHROME_SRC'], 'out', 67 return os.path.join(os.environ['CHROME_SRC'], 'out',
62 self.options.build_type) 68 self.build_type)
63 69
64 def Run(self): 70 def Run(self):
65 logging.warning('Running Python-driven test: %s', self.test_name) 71 logging.info('Running host-driven test: %s', self.test_name)
72 # Get the test method on the derived class and execute it
66 return getattr(self, self.test_name)() 73 return getattr(self, self.test_name)()
67 74
68 def _RunJavaTest(self, fname, suite, test): 75 # Instrumentation test case API.
69 """Runs a single Java test with a Java TestRunner. 76 #
77 # Test cases may make use of functions defined here internally to assist
78 # in running instrumentation tests. These functions rely on
79 # instrumentation_options being defined.
80 def _RunJavaTest(self, fname, test_case, test_method):
81 """Runs a single Java test method with a Java TestRunner.
70 82
71 Args: 83 Args:
72 fname: filename for the test (e.g. foo/bar/baz/tests/FooTest.py) 84 fname: Filename for the host-driven test case
73 suite: name of the Java test suite (e.g. FooTest) 85 (e.g. foo/bar/baz/tests/FooTest.py)
74 test: name of the test method to run (e.g. testFooBar) 86 test_case: Name of the Java test case (e.g. FooTest)
87 test_method: Name of the test method to run (e.g. testFooBar)
75 88
76 Returns: 89 Returns:
77 TestRunResults object with a single test result. 90 TestRunResults object with a single test result.
78 """ 91 """
79 test = self._ComposeFullTestName(fname, suite, test) 92 test = self._ComposeFullTestName(fname, test_case, test_method)
80 test_pkg = test_package.TestPackage( 93 test_pkg = test_package.TestPackage(
81 self.options.test_apk_path, self.options.test_apk_jar_path) 94 self.instrumentation_options.test_apk_path,
82 instrumentation_options = test_options.InstrumentationOptions( 95 self.instrumentation_options.test_apk_jar_path)
83 self.options.build_type, 96 java_test_runner = test_runner.TestRunner(self.instrumentation_options,
84 self.options.tool,
85 self.options.cleanup_test_files,
86 self.options.push_deps,
87 self.options.annotations,
88 self.options.exclude_annotations,
89 self.options.test_filter,
90 self.options.test_data,
91 self.options.save_perf_json,
92 self.options.screenshot_failures,
93 self.options.disable_assertions,
94 self.options.wait_for_debugger,
95 self.options.test_apk,
96 self.options.test_apk_path,
97 self.options.test_apk_jar_path)
98 java_test_runner = test_runner.TestRunner(instrumentation_options,
99 self.device_id, 97 self.device_id,
100 self.shard_index, test_pkg, 98 self.shard_index, test_pkg,
101 self.ports_to_forward) 99 self.ports_to_forward)
102 try: 100 try:
103 java_test_runner.SetUp() 101 java_test_runner.SetUp()
104 return java_test_runner.RunTest(test)[0] 102 return java_test_runner.RunTest(test)[0]
105 finally: 103 finally:
106 java_test_runner.TearDown() 104 java_test_runner.TearDown()
107 105
108 def _RunJavaTests(self, fname, tests): 106 def _RunJavaTests(self, fname, tests):
109 """Calls a list of tests and stops at the first test failure. 107 """Calls a list of tests and stops at the first test failure.
110 108
111 This method iterates until either it encounters a non-passing test or it 109 This method iterates until either it encounters a non-passing test or it
112 exhausts the list of tests. Then it returns the appropriate Python result. 110 exhausts the list of tests. Then it returns the appropriate overall result.
113 111
114 Args: 112 Args:
115 fname: filename for the Python test 113 fname: Filename for the host-driven test case
116 tests: a list of Java test names which will be run 114 tests: A list of Java test names which will be run
117 115
118 Returns: 116 Returns:
119 A TestRunResults object containing a result for this Python test. 117 A TestRunResults object containing an overall result for this set of Java
118 tests. If any Java tests do not pass, this is a fail overall.
120 """ 119 """
121 test_type = base_test_result.ResultType.PASS 120 test_type = base_test_result.ResultType.PASS
122 log = '' 121 log = ''
123 122
124 start_ms = int(time.time()) * 1000 123 start_ms = int(time.time()) * 1000
125 for test in tests: 124 for test in tests:
126 # We're only running one test at a time, so this TestRunResults object 125 # We're only running one test at a time, so this TestRunResults object
127 # will hold only one result. 126 # will hold only one result.
128 suite, test_name = test.split('.') 127 suite, test_name = test.split('.')
129 java_results = self._RunJavaTest(fname, suite, test_name) 128 java_result = self._RunJavaTest(fname, suite, test_name)
130 assert len(java_results.GetAll()) == 1 129 assert len(java_result.GetAll()) == 1
131 if not java_results.DidRunPass(): 130 if not java_result.DidRunPass():
132 result = java_results.GetNotPass().pop() 131 result = java_result.GetNotPass().pop()
133 log = result.GetLog() 132 log = result.GetLog()
134 test_type = result.GetType() 133 test_type = result.GetType()
135 break 134 break
136 duration_ms = int(time.time()) * 1000 - start_ms 135 duration_ms = int(time.time()) * 1000 - start_ms
137 136
138 python_results = base_test_result.TestRunResults() 137 overall_result = base_test_result.TestRunResults()
139 python_results.AddResult( 138 overall_result.AddResult(
140 test_result.InstrumentationTestResult( 139 test_result.InstrumentationTestResult(
141 self.qualified_name, test_type, start_ms, duration_ms, log=log)) 140 self.tagged_name, test_type, start_ms, duration_ms, log=log))
142 return python_results 141 return overall_result
143 142
144 def _ComposeFullTestName(self, fname, suite, test): 143 def _ComposeFullTestName(self, fname, test_case, test_method):
145 package_name = self._GetPackageName(fname) 144 """Composes a fully-qualified name for the test method.
146 return package_name + '.' + suite + '#' + test
147 145
148 def _GetPackageName(self, fname): 146 Args:
149 """Extracts the package name from the test file path.""" 147 fname: Filename for the host-driven test case
148 test_case: Name of the Java test case (e.g. FooTest)
149 test_method: Name of the test method to run (e.g. testFooBar)
150
151 Returns:
152 The fully qualified name for the test method on the Java test case.
153
154 Example:
155 _ComposeFullTestName('/src/foo/tests/FooTest.py', 'FooTest',
156 'testFooBar') => 'foo.tests.FooTest#testFooBar'
157 """
150 dirname = os.path.dirname(fname) 158 dirname = os.path.dirname(fname)
151 package = dirname[dirname.rfind(BASE_ROOT) + len(BASE_ROOT):] 159 package = dirname[dirname.rfind(BASE_ROOT) + len(BASE_ROOT):]
152 return package.replace(os.sep, '.') 160 package_name = package.replace(os.sep, '.')
161 return package_name + '.' + test_case + '#' + test_method
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698