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

Side by Side Diff: build/android/pylib/base_test_runner.py

Issue 10689132: [android] Upstream / sync most of build/android and build/android/pylib. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « build/android/pylib/android_commands.py ('k') | build/android/pylib/base_test_sharder.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 import contextlib
6 import httplib
5 import logging 7 import logging
6 import os 8 import os
9 import tempfile
10 import time
7 11
8 import android_commands 12 import android_commands
9 from chrome_test_server_spawner import SpawningServer 13 from chrome_test_server_spawner import SpawningServer
14 import constants
10 from flag_changer import FlagChanger 15 from flag_changer import FlagChanger
16 from forwarder import Forwarder
11 import lighttpd_server 17 import lighttpd_server
12 import run_tests_helper 18 import ports
19 from valgrind_tools import CreateTool
13 20
14 FORWARDER_PATH = '/data/local/tmp/forwarder' 21
15 # These ports must match up with the constants in net/test/test_server.cc 22 # A file on device to store ports of net test server. The format of the file is
16 TEST_SERVER_SPAWNER_PORT = 8001 23 # test-spawner-server-port:test-server-port
17 TEST_SERVER_PORT = 8002 24 NET_TEST_SERVER_PORT_INFO_FILE = '/data/local/tmp/net-test-server-ports'
18 TEST_SYNC_SERVER_PORT = 8003
19 25
20 26
21 class BaseTestRunner(object): 27 class BaseTestRunner(object):
22 """Base class for running tests on a single device. 28 """Base class for running tests on a single device.
23 29
24 A subclass should implement RunTests() with no parameter, so that calling 30 A subclass should implement RunTests() with no parameter, so that calling
25 the Run() method will set up tests, run them and tear them down. 31 the Run() method will set up tests, run them and tear them down.
26 """ 32 """
27 33
28 def __init__(self, device, shard_index): 34 def __init__(self, device, tool, shard_index):
29 """ 35 """
30 Args: 36 Args:
31 device: Tests will run on the device of this ID. 37 device: Tests will run on the device of this ID.
32 shard_index: Index number of the shard on which the test suite will run. 38 shard_index: Index number of the shard on which the test suite will run.
33 """ 39 """
34 self.device = device 40 self.device = device
35 self.adb = android_commands.AndroidCommands(device=device) 41 self.adb = android_commands.AndroidCommands(device=device)
42 self.tool = CreateTool(tool, self.adb)
36 # Synchronize date/time between host and device. Otherwise same file on 43 # Synchronize date/time between host and device. Otherwise same file on
37 # host and device may have different timestamp which may cause 44 # host and device may have different timestamp which may cause
38 # AndroidCommands.PushIfNeeded failed, or a test which may compare timestamp 45 # AndroidCommands.PushIfNeeded failed, or a test which may compare timestamp
39 # got from http head and local time could be failed. 46 # got from http head and local time could be failed.
40 self.adb.SynchronizeDateTime() 47 self.adb.SynchronizeDateTime()
41 self._http_server = None 48 self._http_server = None
42 self._forwarder = None 49 self._forwarder = None
43 self._spawning_server = None
44 self._spawner_forwarder = None
45 self._forwarder_device_port = 8000 50 self._forwarder_device_port = 8000
46 self.forwarder_base_url = ('http://localhost:%d' % 51 self.forwarder_base_url = ('http://localhost:%d' %
47 self._forwarder_device_port) 52 self._forwarder_device_port)
48 self.flags = FlagChanger(self.adb) 53 self.flags = FlagChanger(self.adb)
49 self.shard_index = shard_index 54 self.shard_index = shard_index
55 self.flags.AddFlags(['--disable-fre'])
56 self._spawning_server = None
57 self._spawner_forwarder = None
58 # We will allocate port for test server spawner when calling method
59 # LaunchChromeTestServerSpawner and allocate port for test server when
60 # starting it in TestServerThread.
61 self.test_server_spawner_port = 0
62 self.test_server_port = 0
63
64 def _PushTestServerPortInfoToDevice(self):
65 """Pushes the latest port information to device."""
66 self.adb.SetFileContents(NET_TEST_SERVER_PORT_INFO_FILE,
67 '%d:%d' % (self.test_server_spawner_port,
68 self.test_server_port))
50 69
51 def Run(self): 70 def Run(self):
52 """Calls subclass functions to set up tests, run them and tear them down. 71 """Calls subclass functions to set up tests, run them and tear them down.
53 72
54 Returns: 73 Returns:
55 Test results returned from RunTests(). 74 Test results returned from RunTests().
56 """ 75 """
76 if not self.HasTests():
77 return True
57 self.SetUp() 78 self.SetUp()
58 try: 79 try:
59 return self.RunTests() 80 return self.RunTests()
60 finally: 81 finally:
61 self.TearDown() 82 self.TearDown()
62 83
63 def SetUp(self): 84 def SetUp(self):
64 """Called before tests run.""" 85 """Called before tests run."""
65 pass 86 pass
66 87
88 def HasTests(self):
89 """Whether the test suite has tests to run."""
90 return True
91
67 def RunTests(self): 92 def RunTests(self):
68 """Runs the tests. Need to be overridden.""" 93 """Runs the tests. Need to be overridden."""
69 raise NotImplementedError 94 raise NotImplementedError
70 95
71 def TearDown(self): 96 def TearDown(self):
72 """Called when tests finish running.""" 97 """Called when tests finish running."""
73 self.ShutdownHelperToolsForTestSuite() 98 self.ShutdownHelperToolsForTestSuite()
74 99
75 def CopyTestData(self, test_data_paths, dest_dir): 100 def CopyTestData(self, test_data_paths, dest_dir):
76 """Copies |test_data_paths| list of files/directories to |dest_dir|. 101 """Copies |test_data_paths| list of files/directories to |dest_dir|.
77 102
78 Args: 103 Args:
79 test_data_paths: A list of files or directories relative to |dest_dir| 104 test_data_paths: A list of files or directories relative to |dest_dir|
80 which should be copied to the device. The paths must exist in 105 which should be copied to the device. The paths must exist in
81 |CHROME_DIR|. 106 |CHROME_DIR|.
82 dest_dir: Absolute path to copy to on the device. 107 dest_dir: Absolute path to copy to on the device.
83 """ 108 """
84 for p in test_data_paths: 109 for p in test_data_paths:
85 self.adb.PushIfNeeded( 110 self.adb.PushIfNeeded(
86 os.path.join(run_tests_helper.CHROME_DIR, p), 111 os.path.join(constants.CHROME_DIR, p),
87 os.path.join(dest_dir, p)) 112 os.path.join(dest_dir, p))
88 113
89 def LaunchTestHttpServer(self, document_root, extra_config_contents=None): 114 def LinkSdCardPathsToTempDir(self, paths):
115 """Link |paths| which are under sdcard to /data/local/tmp.
116
117 For example, the test data '/sdcard/my_data' will be linked to
118 '/data/local/tmp/my_data'.
119
120 Args:
121 paths: A list of files and directories relative to /sdcard.
122 """
123 links = set()
124 for path in paths:
125 link_name = os.path.dirname(path)
126 assert link_name, 'Linked paths must be in a subdir of /sdcard/.'
127 link_name = link_name.split('/')[0]
128 if link_name not in links:
129 mapped_device_path = '/data/local/tmp/' + link_name
130 # Unlink the mapped_device_path at first in case it was mapped to
131 # a wrong path. Add option '-r' becuase the old path could be a dir.
132 self.adb.RunShellCommand('rm -r %s' % mapped_device_path)
133 self.adb.RunShellCommand(
134 'ln -s /sdcard/%s %s' % (link_name, mapped_device_path))
135 links.add(link_name)
136
137 def LaunchTestHttpServer(self, document_root, port=None,
138 extra_config_contents=None):
90 """Launches an HTTP server to serve HTTP tests. 139 """Launches an HTTP server to serve HTTP tests.
91 140
92 Args: 141 Args:
93 document_root: Document root of the HTTP server. 142 document_root: Document root of the HTTP server.
143 port: port on which we want to the http server bind.
94 extra_config_contents: Extra config contents for the HTTP server. 144 extra_config_contents: Extra config contents for the HTTP server.
95 """ 145 """
96 self._http_server = lighttpd_server.LighttpdServer( 146 self._http_server = lighttpd_server.LighttpdServer(
97 document_root, extra_config_contents=extra_config_contents) 147 document_root, port=port, extra_config_contents=extra_config_contents)
98 if self._http_server.StartupHttpServer(): 148 if self._http_server.StartupHttpServer():
99 logging.info('http server started: http://localhost:%s', 149 logging.info('http server started: http://localhost:%s',
100 self._http_server.port) 150 self._http_server.port)
101 else: 151 else:
102 logging.critical('Failed to start http server') 152 logging.critical('Failed to start http server')
103 # Root access needed to make the forwarder executable work.
104 self.adb.EnableAdbRoot()
105 self.StartForwarderForHttpServer() 153 self.StartForwarderForHttpServer()
106 154
155 def StartForwarder(self, port_pairs):
156 """Starts TCP traffic forwarding for the given |port_pairs|.
157
158 Args:
159 host_port_pairs: A list of (device_port, local_port) tuples to forward.
160 """
161 # Sometimes the forwarder device port may be already used. We have to kill
162 # all forwarder processes to ensure that the forwarder can be started since
163 # currently we can not associate the specified port to related pid.
164 self.adb.KillAll('forwarder')
165 if self._forwarder:
166 self._forwarder.Close()
167 self._forwarder = Forwarder(
168 self.adb, port_pairs, self.tool, '127.0.0.1')
169
107 def StartForwarderForHttpServer(self): 170 def StartForwarderForHttpServer(self):
108 """Starts a forwarder for the HTTP server. 171 """Starts a forwarder for the HTTP server.
109 172
110 The forwarder forwards HTTP requests and responses between host and device. 173 The forwarder forwards HTTP requests and responses between host and device.
111 """ 174 """
112 # Sometimes the forwarder device port may be already used. We have to kill 175 self.StartForwarder([(self._forwarder_device_port, self._http_server.port)])
113 # all forwarder processes to ensure that the forwarder can be started since
114 # currently we can not associate the specified port to related pid.
115 # TODO(yfriedman/wangxianzhu): This doesn't work as most of the time the
116 # port is in use but the forwarder is already dead. Killing all forwarders
117 # is overly destructive and breaks other tests which make use of forwarders.
118 # if IsDevicePortUsed(self.adb, self._forwarder_device_port):
119 # self.adb.KillAll('forwarder')
120 self._forwarder = run_tests_helper.ForwardDevicePorts(
121 self.adb, [(self._forwarder_device_port, self._http_server.port)])
122 176
123 def RestartHttpServerForwarderIfNecessary(self): 177 def RestartHttpServerForwarderIfNecessary(self):
124 """Restarts the forwarder if it's not open.""" 178 """Restarts the forwarder if it's not open."""
125 # Checks to see if the http server port is being used. If not forwards the 179 # Checks to see if the http server port is being used. If not forwards the
126 # request. 180 # request.
127 # TODO(dtrainor): This is not always reliable because sometimes the port 181 # TODO(dtrainor): This is not always reliable because sometimes the port
128 # will be left open even after the forwarder has been killed. 182 # will be left open even after the forwarder has been killed.
129 if not run_tests_helper.IsDevicePortUsed(self.adb, 183 if not ports.IsDevicePortUsed(self.adb,
130 self._forwarder_device_port): 184 self._forwarder_device_port):
131 self.StartForwarderForHttpServer() 185 self.StartForwarderForHttpServer()
132 186
133 def ShutdownHelperToolsForTestSuite(self): 187 def ShutdownHelperToolsForTestSuite(self):
134 """Shuts down the server and the forwarder.""" 188 """Shuts down the server and the forwarder."""
135 # Forwarders should be killed before the actual servers they're forwarding 189 # Forwarders should be killed before the actual servers they're forwarding
136 # to as they are clients potentially with open connections and to allow for 190 # to as they are clients potentially with open connections and to allow for
137 # proper hand-shake/shutdown. 191 # proper hand-shake/shutdown.
138 if self._forwarder or self._spawner_forwarder: 192 if self._forwarder or self._spawner_forwarder:
139 # Kill all forwarders on the device and then kill the process on the host 193 # Kill all forwarders on the device and then kill the process on the host
140 # (if it exists) 194 # (if it exists)
141 self.adb.KillAll('forwarder') 195 self.adb.KillAll('forwarder')
142 if self._forwarder: 196 if self._forwarder:
143 self._forwarder.kill() 197 self._forwarder.Close()
144 if self._spawner_forwarder: 198 if self._spawner_forwarder:
145 self._spawner_forwarder.kill() 199 self._spawner_forwarder.Close()
146 if self._http_server: 200 if self._http_server:
147 self._http_server.ShutdownHttpServer() 201 self._http_server.ShutdownHttpServer()
148 if self._spawning_server: 202 if self._spawning_server:
149 self._spawning_server.Stop() 203 self._spawning_server.Stop()
150 self.flags.Restore() 204 self.flags.Restore()
151 205
152 def LaunchChromeTestServerSpawner(self): 206 def LaunchChromeTestServerSpawner(self):
153 """Launches test server spawner.""" 207 """Launches test server spawner."""
154 self._spawning_server = SpawningServer(TEST_SERVER_SPAWNER_PORT, 208 server_ready = False
155 TEST_SERVER_PORT) 209 error_msgs = []
156 self._spawning_server.Start() 210 # Try 3 times to launch test spawner server.
157 # TODO(yfriedman): Ideally we'll only try to start up a port forwarder if 211 for i in xrange(0, 3):
158 # there isn't one already running but for now we just get an error message 212 # Do not allocate port for test server here. We will allocate
159 # and the existing forwarder still works. 213 # different port for individual test in TestServerThread.
160 self._spawner_forwarder = run_tests_helper.ForwardDevicePorts( 214 self.test_server_spawner_port = ports.AllocateTestServerPort()
161 self.adb, [(TEST_SERVER_SPAWNER_PORT, TEST_SERVER_SPAWNER_PORT), 215 self._spawning_server = SpawningServer(self.test_server_spawner_port,
162 (TEST_SERVER_PORT, TEST_SERVER_PORT)]) 216 self.adb,
217 self.tool)
218 self._spawning_server.Start()
219 server_ready, error_msg = ports.IsHttpServerConnectable(
220 '127.0.0.1', self.test_server_spawner_port, path='/ping',
221 expected_read='ready')
222 if server_ready:
223 break
224 else:
225 error_msgs.append(error_msg)
226 self._spawning_server.Stop()
227 # Wait for 2 seconds then restart.
228 time.sleep(2)
229 if not server_ready:
230 logging.error(';'.join(error_msgs))
231 raise Exception('Can not start the test spawner server.')
232 self._PushTestServerPortInfoToDevice()
233 self._spawner_forwarder = Forwarder(
234 self.adb,
235 [(self.test_server_spawner_port, self.test_server_spawner_port)],
236 self.tool, '127.0.0.1')
OLDNEW
« no previous file with comments | « build/android/pylib/android_commands.py ('k') | build/android/pylib/base_test_sharder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698