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

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: Cleans up _RunJavaTest 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
bulach 2013/08/05 10:18:20 I think this bit should still remain, it's part of
gkanwar1 2013/08/05 17:35:49 Good point. I think I removed this when moving Jav
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.
bulach 2013/08/05 10:18:20 nit: I think 75 is not very descriptive, and 77-79
gkanwar1 2013/08/05 17:35:49 Fair enough. I think it makes sense to move this t
80 def _RunJavaTest(self, package_name, 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 package_name: Package name in which the java tests live
73 suite: name of the Java test suite (e.g. FooTest) 85 (e.g. foo.bar.baz.tests)
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 = '%s.%s#%s' % (package_name, 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, package_name, 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 package_name: Package name in which the java tests live
116 tests: a list of Java test names which will be run 114 (e.g. foo.bar.baz.tests)
115 tests: A list of Java test names which will be run
117 116
118 Returns: 117 Returns:
119 A TestRunResults object containing a result for this Python test. 118 A TestRunResults object containing an overall result for this set of Java
119 tests. If any Java tests do not pass, this is a fail overall.
120 """ 120 """
121 test_type = base_test_result.ResultType.PASS 121 test_type = base_test_result.ResultType.PASS
122 log = '' 122 log = ''
123 123
124 start_ms = int(time.time()) * 1000 124 start_ms = int(time.time()) * 1000
125 for test in tests: 125 for test in tests:
126 # We're only running one test at a time, so this TestRunResults object 126 # We're only running one test at a time, so this TestRunResults object
127 # will hold only one result. 127 # will hold only one result.
128 suite, test_name = test.split('.') 128 suite, test_name = test.split('.')
129 java_results = self._RunJavaTest(fname, suite, test_name) 129 java_result = self._RunJavaTest(package_name, suite, test_name)
130 assert len(java_results.GetAll()) == 1 130 assert len(java_result.GetAll()) == 1
131 if not java_results.DidRunPass(): 131 if not java_result.DidRunPass():
132 result = java_results.GetNotPass().pop() 132 result = java_result.GetNotPass().pop()
133 log = result.GetLog() 133 log = result.GetLog()
134 test_type = result.GetType() 134 test_type = result.GetType()
135 break 135 break
136 duration_ms = int(time.time()) * 1000 - start_ms 136 duration_ms = int(time.time()) * 1000 - start_ms
137 137
138 python_results = base_test_result.TestRunResults() 138 overall_result = base_test_result.TestRunResults()
139 python_results.AddResult( 139 overall_result.AddResult(
140 test_result.InstrumentationTestResult( 140 test_result.InstrumentationTestResult(
141 self.qualified_name, test_type, start_ms, duration_ms, log=log)) 141 self.tagged_name, test_type, start_ms, duration_ms, log=log))
142 return python_results 142 return overall_result
143
144 def _ComposeFullTestName(self, fname, suite, test):
145 package_name = self._GetPackageName(fname)
146 return package_name + '.' + suite + '#' + test
147
148 def _GetPackageName(self, fname):
149 """Extracts the package name from the test file path."""
150 dirname = os.path.dirname(fname)
151 package = dirname[dirname.rfind(BASE_ROOT) + len(BASE_ROOT):]
152 return package.replace(os.sep, '.')
OLDNEW
« no previous file with comments | « build/android/pylib/host_driven/setup.py ('k') | build/android/pylib/host_driven/test_info_collection.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698