Add Apps.AppListSearchQueryLength UMA histogram.
[chromium-blink-merge.git] / build / android / pylib / host_driven / test_case.py
blob6ff4c5fec5353b5388c8c053e54327b724b08faf
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Base class for host-driven test cases.
7 This test case is intended to serve as the base class for any host-driven
8 test cases. It is similar to the Python unitttest module in that test cases
9 inherit from this class and add methods which will be run as tests.
11 When a HostDrivenTestCase object is instantiated, its purpose is to run only one
12 test method in the derived class. The test runner gives it the name of the test
13 method the instance will run. The test runner calls SetUp with the device ID
14 which the test method will run against. The test runner runs the test method
15 itself, collecting the result, and calls TearDown.
17 Tests can perform arbitrary Python commands and asserts in test methods. Tests
18 that run instrumentation tests can make use of the _RunJavaTestFilters helper
19 function to trigger Java tests and convert results into a single host-driven
20 test result.
21 """
23 import logging
24 import os
25 import time
27 from pylib import constants
28 from pylib import forwarder
29 from pylib import valgrind_tools
30 from pylib.base import base_test_result
31 from pylib.device import device_utils
32 from pylib.instrumentation import test_package
33 from pylib.instrumentation import test_result
34 from pylib.instrumentation import test_runner
36 # aka the parent of com.google.android
37 BASE_ROOT = 'src' + os.sep
40 class HostDrivenTestCase(object):
41 """Base class for host-driven test cases."""
43 _HOST_DRIVEN_TAG = 'HostDriven'
45 def __init__(self, test_name, instrumentation_options=None):
46 """Create a test case initialized to run |test_name|.
48 Args:
49 test_name: The name of the method to run as the test.
50 instrumentation_options: An InstrumentationOptions object.
51 """
52 class_name = self.__class__.__name__
53 self.device = None
54 self.device_id = ''
55 self.has_forwarded_ports = False
56 self.instrumentation_options = instrumentation_options
57 self.ports_to_forward = []
58 self.shard_index = 0
60 # Use tagged_name when creating results, so that we can identify host-driven
61 # tests in the overall results.
62 self.test_name = test_name
63 self.qualified_name = '%s.%s' % (class_name, self.test_name)
64 self.tagged_name = '%s_%s' % (self._HOST_DRIVEN_TAG, self.qualified_name)
66 # TODO(bulach): make ports_to_forward not optional and move the Forwarder
67 # mapping here.
68 def SetUp(self, device, shard_index, ports_to_forward=None):
69 if not ports_to_forward:
70 ports_to_forward = []
71 self.device = device
72 self.shard_index = shard_index
73 self.device_id = str(self.device)
74 if ports_to_forward:
75 self.ports_to_forward = ports_to_forward
77 def TearDown(self):
78 pass
80 # TODO(craigdh): Remove GetOutDir once references have been removed
81 # downstream.
82 @staticmethod
83 def GetOutDir():
84 return constants.GetOutDirectory()
86 def Run(self):
87 logging.info('Running host-driven test: %s', self.tagged_name)
88 # Get the test method on the derived class and execute it
89 return getattr(self, self.test_name)()
91 @staticmethod
92 def __GetHostForwarderLog():
93 return ('-- Begin Full HostForwarder log\n'
94 '%s\n'
95 '--End Full HostForwarder log\n' % forwarder.Forwarder.GetHostLog())
97 def __StartForwarder(self):
98 logging.warning('Forwarding %s %s', self.ports_to_forward,
99 self.has_forwarded_ports)
100 if self.ports_to_forward and not self.has_forwarded_ports:
101 self.has_forwarded_ports = True
102 tool = valgrind_tools.CreateTool(None, self.device)
103 forwarder.Forwarder.Map([(port, port) for port in self.ports_to_forward],
104 self.device, tool)
106 def __RunJavaTest(self, test, test_pkg, additional_flags=None):
107 """Runs a single Java test in a Java TestRunner.
109 Args:
110 test: Fully qualified test name (ex. foo.bar.TestClass#testMethod)
111 test_pkg: TestPackage object.
112 additional_flags: A list of additional flags to add to the command line.
114 Returns:
115 TestRunResults object with a single test result.
117 # TODO(bulach): move this to SetUp() stage.
118 self.__StartForwarder()
120 java_test_runner = test_runner.TestRunner(
121 self.instrumentation_options, self.device, self.shard_index,
122 test_pkg, additional_flags=additional_flags)
123 try:
124 java_test_runner.SetUp()
125 return java_test_runner.RunTest(test)[0]
126 finally:
127 java_test_runner.TearDown()
129 def _RunJavaTestFilters(self, test_filters, additional_flags=None):
130 """Calls a list of tests and stops at the first test failure.
132 This method iterates until either it encounters a non-passing test or it
133 exhausts the list of tests. Then it returns the appropriate overall result.
135 Test cases may make use of this method internally to assist in running
136 instrumentation tests. This function relies on instrumentation_options
137 being defined.
139 Args:
140 test_filters: A list of Java test filters.
141 additional_flags: A list of addition flags to add to the command line.
143 Returns:
144 A TestRunResults object containing an overall result for this set of Java
145 tests. If any Java tests do not pass, this is a fail overall.
147 test_type = base_test_result.ResultType.PASS
148 log = ''
150 test_pkg = test_package.TestPackage(
151 self.instrumentation_options.test_apk_path,
152 self.instrumentation_options.test_apk_jar_path,
153 self.instrumentation_options.test_support_apk_path)
155 start_ms = int(time.time()) * 1000
156 done = False
157 for test_filter in test_filters:
158 tests = test_pkg.GetAllMatchingTests(None, None, test_filter)
159 # Filters should always result in >= 1 test.
160 if len(tests) == 0:
161 raise Exception('Java test filter "%s" returned no tests.'
162 % test_filter)
163 for test in tests:
164 # We're only running one test at a time, so this TestRunResults object
165 # will hold only one result.
166 java_result = self.__RunJavaTest(test, test_pkg, additional_flags)
167 assert len(java_result.GetAll()) == 1
168 if not java_result.DidRunPass():
169 result = java_result.GetNotPass().pop()
170 log = result.GetLog()
171 log += self.__GetHostForwarderLog()
172 test_type = result.GetType()
173 done = True
174 break
175 if done:
176 break
177 duration_ms = int(time.time()) * 1000 - start_ms
179 overall_result = base_test_result.TestRunResults()
180 overall_result.AddResult(
181 test_result.InstrumentationTestResult(
182 self.tagged_name, test_type, start_ms, duration_ms, log=log))
183 return overall_result
185 def __str__(self):
186 return self.tagged_name
188 def __repr__(self):
189 return self.tagged_name