blob: bb0316bb146ec7deab831c75472983a0b9f12b7f [file] [log] [blame]
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
import android_commands
from chrome_test_server_spawner import SpawningServer
from flag_changer import FlagChanger
import lighttpd_server
import run_tests_helper
FORWARDER_PATH = '/data/local/tmp/forwarder'
# These ports must match up with the constants in net/test/test_server.cc
TEST_SERVER_SPAWNER_PORT = 8001
TEST_SERVER_PORT = 8002
TEST_SYNC_SERVER_PORT = 8003
class BaseTestRunner(object):
"""Base class for running tests on a single device."""
def __init__(self, device):
"""
Args:
device: Tests will run on the device of this ID.
"""
self.device = device
self.adb = android_commands.AndroidCommands(device=device)
# Synchronize date/time between host and device. Otherwise same file on
# host and device may have different timestamp which may cause
# AndroidCommands.PushIfNeeded failed, or a test which may compare timestamp
# got from http head and local time could be failed.
self.adb.SynchronizeDateTime()
self._http_server = None
self._forwarder = None
self._spawning_server = None
self._spawner_forwarder = None
self._forwarder_device_port = 8000
self.forwarder_base_url = ('http://localhost:%d' %
self._forwarder_device_port)
self.flags = FlagChanger(self.adb)
def RunTests(self):
# TODO(bulach): this should actually do SetUp / RunTestsInternal / TearDown.
# Refactor the various subclasses to expose a RunTestsInternal without
# any params.
raise NotImplementedError
def SetUp(self):
"""Called before tests run."""
pass
def TearDown(self):
"""Called when tests finish running."""
self.ShutdownHelperToolsForTestSuite()
def CopyTestData(self, test_data_paths, dest_dir):
"""Copies |test_data_paths| list of files/directories to |dest_dir|.
Args:
test_data_paths: A list of files or directories relative to |dest_dir|
which should be copied to the device. The paths must exist in
|CHROME_DIR|.
dest_dir: Absolute path to copy to on the device.
"""
for p in test_data_paths:
self.adb.PushIfNeeded(
os.path.join(run_tests_helper.CHROME_DIR, p),
os.path.join(dest_dir, p))
def LaunchTestHttpServer(self, document_root, extra_config_contents=None):
"""Launches an HTTP server to serve HTTP tests.
Args:
document_root: Document root of the HTTP server.
extra_config_contents: Extra config contents for the HTTP server.
"""
self._http_server = lighttpd_server.LighttpdServer(
document_root, extra_config_contents=extra_config_contents)
if self._http_server.StartupHttpServer():
logging.info('http server started: http://localhost:%s',
self._http_server.port)
else:
logging.critical('Failed to start http server')
# Root access needed to make the forwarder executable work.
self.adb.EnableAdbRoot()
self.StartForwarderForHttpServer()
def StartForwarderForHttpServer(self):
"""Starts a forwarder for the HTTP server.
The forwarder forwards HTTP requests and responses between host and device.
"""
# Sometimes the forwarder device port may be already used. We have to kill
# all forwarder processes to ensure that the forwarder can be started since
# currently we can not associate the specified port to related pid.
# TODO(yfriedman/wangxianzhu): This doesn't work as most of the time the
# port is in use but the forwarder is already dead. Killing all forwarders
# is overly destructive and breaks other tests which make use of forwarders.
# if IsDevicePortUsed(self.adb, self._forwarder_device_port):
# self.adb.KillAll('forwarder')
self._forwarder = run_tests_helper.ForwardDevicePorts(
self.adb, [(self._forwarder_device_port, self._http_server.port)])
def RestartHttpServerForwarderIfNecessary(self):
"""Restarts the forwarder if it's not open."""
# Checks to see if the http server port is being used. If not forwards the
# request.
# TODO(dtrainor): This is not always reliable because sometimes the port
# will be left open even after the forwarder has been killed.
if not run_tests_helper.IsDevicePortUsed(self.adb,
self._forwarder_device_port):
self.StartForwarderForHttpServer()
def ShutdownHelperToolsForTestSuite(self):
"""Shuts down the server and the forwarder."""
# Forwarders should be killed before the actual servers they're forwarding
# to as they are clients potentially with open connections and to allow for
# proper hand-shake/shutdown.
if self._forwarder or self._spawner_forwarder:
# Kill all forwarders on the device and then kill the process on the host
# (if it exists)
self.adb.KillAll('forwarder')
if self._forwarder:
self._forwarder.kill()
if self._spawner_forwarder:
self._spawner_forwarder.kill()
if self._http_server:
self._http_server.ShutdownHttpServer()
if self._spawning_server:
self._spawning_server.Stop()
self.flags.Restore()
def LaunchChromeTestServerSpawner(self):
"""Launches test server spawner."""
self._spawning_server = SpawningServer(TEST_SERVER_SPAWNER_PORT,
TEST_SERVER_PORT)
self._spawning_server.Start()
# TODO(yfriedman): Ideally we'll only try to start up a port forwarder if
# there isn't one already running but for now we just get an error message
# and the existing forwarder still works.
self._spawner_forwarder = run_tests_helper.ForwardDevicePorts(
self.adb, [(TEST_SERVER_SPAWNER_PORT, TEST_SERVER_SPAWNER_PORT),
(TEST_SERVER_PORT, TEST_SERVER_PORT)])