| OLD | NEW |
| (Empty) |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import logging | |
| 6 import os | |
| 7 | |
| 8 import android_commands | |
| 9 from chrome_test_server_spawner import SpawningServer | |
| 10 from flag_changer import FlagChanger | |
| 11 import lighttpd_server | |
| 12 import run_tests_helper | |
| 13 | |
| 14 FORWARDER_PATH = '/data/local/tmp/forwarder' | |
| 15 # These ports must match up with the constants in net/test/test_server.cc | |
| 16 TEST_SERVER_SPAWNER_PORT = 8001 | |
| 17 TEST_SERVER_PORT = 8002 | |
| 18 TEST_SYNC_SERVER_PORT = 8003 | |
| 19 | |
| 20 | |
| 21 class BaseTestRunner(object): | |
| 22 """Base class for running tests on a single device. | |
| 23 | |
| 24 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. | |
| 26 """ | |
| 27 | |
| 28 def __init__(self, device, shard_index): | |
| 29 """ | |
| 30 Args: | |
| 31 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. | |
| 33 """ | |
| 34 self.device = device | |
| 35 self.adb = android_commands.AndroidCommands(device=device) | |
| 36 # Synchronize date/time between host and device. Otherwise same file on | |
| 37 # host and device may have different timestamp which may cause | |
| 38 # AndroidCommands.PushIfNeeded failed, or a test which may compare timestamp | |
| 39 # got from http head and local time could be failed. | |
| 40 self.adb.SynchronizeDateTime() | |
| 41 self._http_server = None | |
| 42 self._forwarder = None | |
| 43 self._spawning_server = None | |
| 44 self._spawner_forwarder = None | |
| 45 self._forwarder_device_port = 8000 | |
| 46 self.forwarder_base_url = ('http://localhost:%d' % | |
| 47 self._forwarder_device_port) | |
| 48 self.flags = FlagChanger(self.adb) | |
| 49 self.shard_index = shard_index | |
| 50 | |
| 51 def Run(self): | |
| 52 """Calls subclass functions to set up tests, run them and tear them down. | |
| 53 | |
| 54 Returns: | |
| 55 Test results returned from RunTests(). | |
| 56 """ | |
| 57 self.SetUp() | |
| 58 try: | |
| 59 return self.RunTests() | |
| 60 finally: | |
| 61 self.TearDown() | |
| 62 | |
| 63 def SetUp(self): | |
| 64 """Called before tests run.""" | |
| 65 pass | |
| 66 | |
| 67 def RunTests(self): | |
| 68 """Runs the tests. Need to be overridden.""" | |
| 69 raise NotImplementedError | |
| 70 | |
| 71 def TearDown(self): | |
| 72 """Called when tests finish running.""" | |
| 73 self.ShutdownHelperToolsForTestSuite() | |
| 74 | |
| 75 def CopyTestData(self, test_data_paths, dest_dir): | |
| 76 """Copies |test_data_paths| list of files/directories to |dest_dir|. | |
| 77 | |
| 78 Args: | |
| 79 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 | |
| 81 |CHROME_DIR|. | |
| 82 dest_dir: Absolute path to copy to on the device. | |
| 83 """ | |
| 84 for p in test_data_paths: | |
| 85 self.adb.PushIfNeeded( | |
| 86 os.path.join(run_tests_helper.CHROME_DIR, p), | |
| 87 os.path.join(dest_dir, p)) | |
| 88 | |
| 89 def LaunchTestHttpServer(self, document_root, extra_config_contents=None): | |
| 90 """Launches an HTTP server to serve HTTP tests. | |
| 91 | |
| 92 Args: | |
| 93 document_root: Document root of the HTTP server. | |
| 94 extra_config_contents: Extra config contents for the HTTP server. | |
| 95 """ | |
| 96 self._http_server = lighttpd_server.LighttpdServer( | |
| 97 document_root, extra_config_contents=extra_config_contents) | |
| 98 if self._http_server.StartupHttpServer(): | |
| 99 logging.info('http server started: http://localhost:%s', | |
| 100 self._http_server.port) | |
| 101 else: | |
| 102 logging.critical('Failed to start http server') | |
| 103 # Root access needed to make the forwarder executable work. | |
| 104 self.adb.EnableAdbRoot() | |
| 105 self.StartForwarderForHttpServer() | |
| 106 | |
| 107 def StartForwarderForHttpServer(self): | |
| 108 """Starts a forwarder for the HTTP server. | |
| 109 | |
| 110 The forwarder forwards HTTP requests and responses between host and device. | |
| 111 """ | |
| 112 # Sometimes the forwarder device port may be already used. We have to kill | |
| 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 | |
| 123 def RestartHttpServerForwarderIfNecessary(self): | |
| 124 """Restarts the forwarder if it's not open.""" | |
| 125 # Checks to see if the http server port is being used. If not forwards the | |
| 126 # request. | |
| 127 # TODO(dtrainor): This is not always reliable because sometimes the port | |
| 128 # will be left open even after the forwarder has been killed. | |
| 129 if not run_tests_helper.IsDevicePortUsed(self.adb, | |
| 130 self._forwarder_device_port): | |
| 131 self.StartForwarderForHttpServer() | |
| 132 | |
| 133 def ShutdownHelperToolsForTestSuite(self): | |
| 134 """Shuts down the server and the forwarder.""" | |
| 135 # 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 | |
| 137 # proper hand-shake/shutdown. | |
| 138 if self._forwarder or self._spawner_forwarder: | |
| 139 # Kill all forwarders on the device and then kill the process on the host | |
| 140 # (if it exists) | |
| 141 self.adb.KillAll('forwarder') | |
| 142 if self._forwarder: | |
| 143 self._forwarder.kill() | |
| 144 if self._spawner_forwarder: | |
| 145 self._spawner_forwarder.kill() | |
| 146 if self._http_server: | |
| 147 self._http_server.ShutdownHttpServer() | |
| 148 if self._spawning_server: | |
| 149 self._spawning_server.Stop() | |
| 150 self.flags.Restore() | |
| 151 | |
| 152 def LaunchChromeTestServerSpawner(self): | |
| 153 """Launches test server spawner.""" | |
| 154 self._spawning_server = SpawningServer(TEST_SERVER_SPAWNER_PORT, | |
| 155 TEST_SERVER_PORT) | |
| 156 self._spawning_server.Start() | |
| 157 # TODO(yfriedman): Ideally we'll only try to start up a port forwarder if | |
| 158 # there isn't one already running but for now we just get an error message | |
| 159 # and the existing forwarder still works. | |
| 160 self._spawner_forwarder = run_tests_helper.ForwardDevicePorts( | |
| 161 self.adb, [(TEST_SERVER_SPAWNER_PORT, TEST_SERVER_SPAWNER_PORT), | |
| 162 (TEST_SERVER_PORT, TEST_SERVER_PORT)]) | |
| OLD | NEW |