- add sources.
[platform/framework/web/crosswalk.git] / src / build / android / pylib / base / base_test_runner.py
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 """Base class for running tests on a single device."""
6
7 import contextlib
8 import httplib
9 import logging
10 import os
11 import tempfile
12 import time
13
14 from pylib import android_commands
15 from pylib import constants
16 from pylib import ports
17 from pylib.chrome_test_server_spawner import SpawningServer
18 from pylib.forwarder import Forwarder
19 from pylib.valgrind_tools import CreateTool
20 # TODO(frankf): Move this to pylib/utils
21 import lighttpd_server
22
23
24 # A file on device to store ports of net test server. The format of the file is
25 # test-spawner-server-port:test-server-port
26 NET_TEST_SERVER_PORT_INFO_FILE = 'net-test-server-ports'
27
28
29 class BaseTestRunner(object):
30   """Base class for running tests on a single device."""
31
32   def __init__(self, device, tool, push_deps=True, cleanup_test_files=False):
33     """
34       Args:
35         device: Tests will run on the device of this ID.
36         tool: Name of the Valgrind tool.
37         push_deps: If True, push all dependencies to the device.
38         cleanup_test_files: Whether or not to cleanup test files on device.
39     """
40     self.device = device
41     self.adb = android_commands.AndroidCommands(device=device)
42     self.tool = CreateTool(tool, self.adb)
43     self._http_server = None
44     self._forwarder_device_port = 8000
45     self.forwarder_base_url = ('http://localhost:%d' %
46         self._forwarder_device_port)
47     self._spawning_server = None
48     # We will allocate port for test server spawner when calling method
49     # LaunchChromeTestServerSpawner and allocate port for test server when
50     # starting it in TestServerThread.
51     self.test_server_spawner_port = 0
52     self.test_server_port = 0
53     self._push_deps = push_deps
54     self._cleanup_test_files = cleanup_test_files
55
56   def _PushTestServerPortInfoToDevice(self):
57     """Pushes the latest port information to device."""
58     self.adb.SetFileContents(self.adb.GetExternalStorage() + '/' +
59                              NET_TEST_SERVER_PORT_INFO_FILE,
60                              '%d:%d' % (self.test_server_spawner_port,
61                                         self.test_server_port))
62
63   def RunTest(self, test):
64     """Runs a test. Needs to be overridden.
65
66     Args:
67       test: A test to run.
68
69     Returns:
70       Tuple containing:
71         (base_test_result.TestRunResults, tests to rerun or None)
72     """
73     raise NotImplementedError
74
75   def InstallTestPackage(self):
76     """Installs the test package once before all tests are run."""
77     pass
78
79   def PushDataDeps(self):
80     """Push all data deps to device once before all tests are run."""
81     pass
82
83   def SetUp(self):
84     """Run once before all tests are run."""
85     self.InstallTestPackage()
86     push_size_before = self.adb.GetPushSizeInfo()
87     if self._push_deps:
88       logging.warning('Pushing data files to device.')
89       self.PushDataDeps()
90       push_size_after = self.adb.GetPushSizeInfo()
91       logging.warning(
92           'Total data: %0.3fMB' %
93           ((push_size_after[0] - push_size_before[0]) / float(2 ** 20)))
94       logging.warning(
95           'Total data transferred: %0.3fMB' %
96           ((push_size_after[1] - push_size_before[1]) / float(2 ** 20)))
97     else:
98       logging.warning('Skipping pushing data to device.')
99
100   def TearDown(self):
101     """Run once after all tests are run."""
102     self.ShutdownHelperToolsForTestSuite()
103     if self._cleanup_test_files:
104       self.adb.RemovePushedFiles()
105
106   def LaunchTestHttpServer(self, document_root, port=None,
107                            extra_config_contents=None):
108     """Launches an HTTP server to serve HTTP tests.
109
110     Args:
111       document_root: Document root of the HTTP server.
112       port: port on which we want to the http server bind.
113       extra_config_contents: Extra config contents for the HTTP server.
114     """
115     self._http_server = lighttpd_server.LighttpdServer(
116         document_root, port=port, extra_config_contents=extra_config_contents)
117     if self._http_server.StartupHttpServer():
118       logging.info('http server started: http://localhost:%s',
119                    self._http_server.port)
120     else:
121       logging.critical('Failed to start http server')
122     self._ForwardPortsForHttpServer()
123     return (self._forwarder_device_port, self._http_server.port)
124
125   def _ForwardPorts(self, port_pairs):
126     """Forwards a port."""
127     Forwarder.Map(port_pairs, self.adb, self.tool)
128
129   def _UnmapPorts(self, port_pairs):
130     """Unmap previously forwarded ports."""
131     for (device_port, _) in port_pairs:
132       Forwarder.UnmapDevicePort(device_port, self.adb)
133
134   # Deprecated: Use ForwardPorts instead.
135   def StartForwarder(self, port_pairs):
136     """Starts TCP traffic forwarding for the given |port_pairs|.
137
138     Args:
139       host_port_pairs: A list of (device_port, local_port) tuples to forward.
140     """
141     self._ForwardPorts(port_pairs)
142
143   def _ForwardPortsForHttpServer(self):
144     """Starts a forwarder for the HTTP server.
145
146     The forwarder forwards HTTP requests and responses between host and device.
147     """
148     self._ForwardPorts([(self._forwarder_device_port, self._http_server.port)])
149
150   def _RestartHttpServerForwarderIfNecessary(self):
151     """Restarts the forwarder if it's not open."""
152     # Checks to see if the http server port is being used.  If not forwards the
153     # request.
154     # TODO(dtrainor): This is not always reliable because sometimes the port
155     # will be left open even after the forwarder has been killed.
156     if not ports.IsDevicePortUsed(self.adb, self._forwarder_device_port):
157       self._ForwardPortsForHttpServer()
158
159   def ShutdownHelperToolsForTestSuite(self):
160     """Shuts down the server and the forwarder."""
161     if self._http_server:
162       self._UnmapPorts([(self._forwarder_device_port, self._http_server.port)])
163       self._http_server.ShutdownHttpServer()
164     if self._spawning_server:
165       self._spawning_server.Stop()
166
167   def CleanupSpawningServerState(self):
168     """Tells the spawning server to clean up any state.
169
170     If the spawning server is reused for multiple tests, this should be called
171     after each test to prevent tests affecting each other.
172     """
173     if self._spawning_server:
174       self._spawning_server.CleanupState()
175
176   def LaunchChromeTestServerSpawner(self):
177     """Launches test server spawner."""
178     server_ready = False
179     error_msgs = []
180     # TODO(pliard): deflake this function. The for loop should be removed as
181     # well as IsHttpServerConnectable(). spawning_server.Start() should also
182     # block until the server is ready.
183     # Try 3 times to launch test spawner server.
184     for i in xrange(0, 3):
185       self.test_server_spawner_port = ports.AllocateTestServerPort()
186       self._ForwardPorts(
187           [(self.test_server_spawner_port, self.test_server_spawner_port)])
188       self._spawning_server = SpawningServer(self.test_server_spawner_port,
189                                              self.adb,
190                                              self.tool)
191       self._spawning_server.Start()
192       server_ready, error_msg = ports.IsHttpServerConnectable(
193           '127.0.0.1', self.test_server_spawner_port, path='/ping',
194           expected_read='ready')
195       if server_ready:
196         break
197       else:
198         error_msgs.append(error_msg)
199       self._spawning_server.Stop()
200       # Wait for 2 seconds then restart.
201       time.sleep(2)
202     if not server_ready:
203       logging.error(';'.join(error_msgs))
204       raise Exception('Can not start the test spawner server.')
205     self._PushTestServerPortInfoToDevice()