1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/build/android/pylib/base_test_runner.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,210 @@ 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 +import contextlib 1.9 +import httplib 1.10 +import logging 1.11 +import os 1.12 +import tempfile 1.13 +import time 1.14 + 1.15 +import android_commands 1.16 +import constants 1.17 +from chrome_test_server_spawner import SpawningServer 1.18 +import constants 1.19 +from flag_changer import FlagChanger 1.20 +from forwarder import Forwarder 1.21 +import lighttpd_server 1.22 +import ports 1.23 +from valgrind_tools import CreateTool 1.24 + 1.25 + 1.26 +# A file on device to store ports of net test server. The format of the file is 1.27 +# test-spawner-server-port:test-server-port 1.28 +NET_TEST_SERVER_PORT_INFO_FILE = 'net-test-server-ports' 1.29 + 1.30 + 1.31 +class BaseTestRunner(object): 1.32 + """Base class for running tests on a single device. 1.33 + 1.34 + A subclass should implement RunTests() with no parameter, so that calling 1.35 + the Run() method will set up tests, run them and tear them down. 1.36 + """ 1.37 + 1.38 + def __init__(self, device, tool, shard_index, build_type): 1.39 + """ 1.40 + Args: 1.41 + device: Tests will run on the device of this ID. 1.42 + shard_index: Index number of the shard on which the test suite will run. 1.43 + build_type: 'Release' or 'Debug'. 1.44 + """ 1.45 + self.device = device 1.46 + self.adb = android_commands.AndroidCommands(device=device) 1.47 + self.tool = CreateTool(tool, self.adb) 1.48 + self._http_server = None 1.49 + self._forwarder = None 1.50 + self._forwarder_device_port = 8000 1.51 + self.forwarder_base_url = ('http://localhost:%d' % 1.52 + self._forwarder_device_port) 1.53 + self.flags = FlagChanger(self.adb) 1.54 + self.shard_index = shard_index 1.55 + self.flags.AddFlags(['--disable-fre']) 1.56 + self._spawning_server = None 1.57 + self._spawner_forwarder = None 1.58 + # We will allocate port for test server spawner when calling method 1.59 + # LaunchChromeTestServerSpawner and allocate port for test server when 1.60 + # starting it in TestServerThread. 1.61 + self.test_server_spawner_port = 0 1.62 + self.test_server_port = 0 1.63 + self.build_type = build_type 1.64 + 1.65 + def _PushTestServerPortInfoToDevice(self): 1.66 + """Pushes the latest port information to device.""" 1.67 + self.adb.SetFileContents(self.adb.GetExternalStorage() + '/' + 1.68 + NET_TEST_SERVER_PORT_INFO_FILE, 1.69 + '%d:%d' % (self.test_server_spawner_port, 1.70 + self.test_server_port)) 1.71 + 1.72 + def Run(self): 1.73 + """Calls subclass functions to set up tests, run them and tear them down. 1.74 + 1.75 + Returns: 1.76 + Test results returned from RunTests(). 1.77 + """ 1.78 + if not self.HasTests(): 1.79 + return True 1.80 + self.SetUp() 1.81 + try: 1.82 + return self.RunTests() 1.83 + finally: 1.84 + self.TearDown() 1.85 + 1.86 + def SetUp(self): 1.87 + """Called before tests run.""" 1.88 + pass 1.89 + 1.90 + def HasTests(self): 1.91 + """Whether the test suite has tests to run.""" 1.92 + return True 1.93 + 1.94 + def RunTests(self): 1.95 + """Runs the tests. Need to be overridden.""" 1.96 + raise NotImplementedError 1.97 + 1.98 + def TearDown(self): 1.99 + """Called when tests finish running.""" 1.100 + self.ShutdownHelperToolsForTestSuite() 1.101 + 1.102 + def CopyTestData(self, test_data_paths, dest_dir): 1.103 + """Copies |test_data_paths| list of files/directories to |dest_dir|. 1.104 + 1.105 + Args: 1.106 + test_data_paths: A list of files or directories relative to |dest_dir| 1.107 + which should be copied to the device. The paths must exist in 1.108 + |CHROME_DIR|. 1.109 + dest_dir: Absolute path to copy to on the device. 1.110 + """ 1.111 + for p in test_data_paths: 1.112 + self.adb.PushIfNeeded( 1.113 + os.path.join(constants.CHROME_DIR, p), 1.114 + os.path.join(dest_dir, p)) 1.115 + 1.116 + def LaunchTestHttpServer(self, document_root, port=None, 1.117 + extra_config_contents=None): 1.118 + """Launches an HTTP server to serve HTTP tests. 1.119 + 1.120 + Args: 1.121 + document_root: Document root of the HTTP server. 1.122 + port: port on which we want to the http server bind. 1.123 + extra_config_contents: Extra config contents for the HTTP server. 1.124 + """ 1.125 + self._http_server = lighttpd_server.LighttpdServer( 1.126 + document_root, port=port, extra_config_contents=extra_config_contents) 1.127 + if self._http_server.StartupHttpServer(): 1.128 + logging.info('http server started: http://localhost:%s', 1.129 + self._http_server.port) 1.130 + else: 1.131 + logging.critical('Failed to start http server') 1.132 + self.StartForwarderForHttpServer() 1.133 + return (self._forwarder_device_port, self._http_server.port) 1.134 + 1.135 + def StartForwarder(self, port_pairs): 1.136 + """Starts TCP traffic forwarding for the given |port_pairs|. 1.137 + 1.138 + Args: 1.139 + host_port_pairs: A list of (device_port, local_port) tuples to forward. 1.140 + """ 1.141 + if self._forwarder: 1.142 + self._forwarder.Close() 1.143 + self._forwarder = Forwarder( 1.144 + self.adb, port_pairs, self.tool, '127.0.0.1', self.build_type) 1.145 + 1.146 + def StartForwarderForHttpServer(self): 1.147 + """Starts a forwarder for the HTTP server. 1.148 + 1.149 + The forwarder forwards HTTP requests and responses between host and device. 1.150 + """ 1.151 + self.StartForwarder([(self._forwarder_device_port, self._http_server.port)]) 1.152 + 1.153 + def RestartHttpServerForwarderIfNecessary(self): 1.154 + """Restarts the forwarder if it's not open.""" 1.155 + # Checks to see if the http server port is being used. If not forwards the 1.156 + # request. 1.157 + # TODO(dtrainor): This is not always reliable because sometimes the port 1.158 + # will be left open even after the forwarder has been killed. 1.159 + if not ports.IsDevicePortUsed(self.adb, 1.160 + self._forwarder_device_port): 1.161 + self.StartForwarderForHttpServer() 1.162 + 1.163 + def ShutdownHelperToolsForTestSuite(self): 1.164 + """Shuts down the server and the forwarder.""" 1.165 + # Forwarders should be killed before the actual servers they're forwarding 1.166 + # to as they are clients potentially with open connections and to allow for 1.167 + # proper hand-shake/shutdown. 1.168 + if self._forwarder or self._spawner_forwarder: 1.169 + # Kill all forwarders on the device and then kill the process on the host 1.170 + # (if it exists) 1.171 + self.adb.KillAll('device_forwarder') 1.172 + if self._forwarder: 1.173 + self._forwarder.Close() 1.174 + if self._spawner_forwarder: 1.175 + self._spawner_forwarder.Close() 1.176 + if self._http_server: 1.177 + self._http_server.ShutdownHttpServer() 1.178 + if self._spawning_server: 1.179 + self._spawning_server.Stop() 1.180 + self.flags.Restore() 1.181 + 1.182 + def LaunchChromeTestServerSpawner(self): 1.183 + """Launches test server spawner.""" 1.184 + server_ready = False 1.185 + error_msgs = [] 1.186 + # Try 3 times to launch test spawner server. 1.187 + for i in xrange(0, 3): 1.188 + # Do not allocate port for test server here. We will allocate 1.189 + # different port for individual test in TestServerThread. 1.190 + self.test_server_spawner_port = ports.AllocateTestServerPort() 1.191 + self._spawning_server = SpawningServer(self.test_server_spawner_port, 1.192 + self.adb, 1.193 + self.tool, 1.194 + self.build_type) 1.195 + self._spawning_server.Start() 1.196 + server_ready, error_msg = ports.IsHttpServerConnectable( 1.197 + '127.0.0.1', self.test_server_spawner_port, path='/ping', 1.198 + expected_read='ready') 1.199 + if server_ready: 1.200 + break 1.201 + else: 1.202 + error_msgs.append(error_msg) 1.203 + self._spawning_server.Stop() 1.204 + # Wait for 2 seconds then restart. 1.205 + time.sleep(2) 1.206 + if not server_ready: 1.207 + logging.error(';'.join(error_msgs)) 1.208 + raise Exception('Can not start the test spawner server.') 1.209 + self._PushTestServerPortInfoToDevice() 1.210 + self._spawner_forwarder = Forwarder( 1.211 + self.adb, 1.212 + [(self.test_server_spawner_port, self.test_server_spawner_port)], 1.213 + self.tool, '127.0.0.1', self.build_type)