blob: d6203cccb397a0f8bdba7e33412ed2514fa46b71 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001# Copyright 2013 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"""Host driven test server controller.
6
7This class controls the startup and shutdown of a python driven test server that
8runs in a separate process.
9
10The server starts up automatically when the object is created.
11
12After it starts up, it is possible to retreive the hostname it started on
13through accessing the member field |host| and the port name through |port|.
14
15For shutting down the server, call TearDown().
16"""
17
18import logging
19import subprocess
20import os
21import os.path
22import time
23import urllib2
24
25from pylib import constants
26
27# NOTE: when adding or modifying these lines, omit any leading slashes!
28# Otherwise os.path.join() will (correctly) treat them as absolute paths
29# instead of relative paths, and will do nothing.
30_PYTHONPATH_DIRS = [
31 'net/tools/testserver/',
32 'third_party/',
33 'third_party/pyftpdlib/src/',
34 'third_party/pywebsocket/src',
35 'third_party/tlslite/',
36]
37
38# Python files in these directories are generated as part of the build.
39# These dirs are located in out/(Debug|Release) directory.
40# The correct path is determined based on the build type. E.g. out/Debug for
41# debug builds and out/Release for release builds.
42_GENERATED_PYTHONPATH_DIRS = [
43 'pyproto/sync/protocol/',
44 'pyproto/'
45]
46
47_TEST_SERVER_HOST = '127.0.0.1'
48# Paths for supported test server executables.
49TEST_NET_SERVER_PATH = 'net/tools/testserver/testserver.py'
50TEST_SYNC_SERVER_PATH = 'sync/tools/testserver/sync_testserver.py'
51# Parameters to check that the server is up and running.
52TEST_SERVER_CHECK_PARAMS = {
53 TEST_NET_SERVER_PATH: {
54 'url_path': '/',
55 'response': 'Default response given for path'
56 },
57 TEST_SYNC_SERVER_PATH: {
58 'url_path': 'chromiumsync/time',
59 'response': '0123456789'
60 },
61}
62
63class TestServer(object):
64 """Sets up a host driven test server on the host machine.
65
66 For shutting down the server, call TearDown().
67 """
68
69 def __init__(self, shard_index, test_server_port, test_server_path):
70 """Sets up a Python driven test server on the host machine.
71
72 Args:
73 shard_index: Index of the current shard.
74 test_server_port: Port to run the test server on. This is multiplexed with
75 the shard index. To retrieve the real port access the
76 member variable |port|.
77 test_server_path: The path (relative to the root src dir) of the server
78 """
79 self.host = _TEST_SERVER_HOST
80 self.port = test_server_port + shard_index
81
82 src_dir = constants.DIR_SOURCE_ROOT
83 # Make dirs into a list of absolute paths.
84 abs_dirs = [os.path.join(src_dir, d) for d in _PYTHONPATH_DIRS]
85 # Add the generated python files to the path
86 abs_dirs.extend([os.path.join(src_dir, constants.GetOutDirectory(), d)
87 for d in _GENERATED_PYTHONPATH_DIRS])
88 current_python_path = os.environ.get('PYTHONPATH')
89 extra_python_path = ':'.join(abs_dirs)
90 if current_python_path:
91 python_path = current_python_path + ':' + extra_python_path
92 else:
93 python_path = extra_python_path
94
95 # NOTE: A separate python process is used to simplify getting the right
96 # system path for finding includes.
97 cmd = ['python', os.path.join(src_dir, test_server_path),
98 '--log-to-console',
99 ('--host=%s' % self.host),
100 ('--port=%d' % self.port)]
101 self._test_server_process = subprocess.Popen(
102 cmd, env={'PYTHONPATH': python_path})
103 test_url = 'http://%s:%d/%s' % (self.host, self.port,
104 TEST_SERVER_CHECK_PARAMS[test_server_path]['url_path'])
105 expected_response = TEST_SERVER_CHECK_PARAMS[test_server_path]['response']
106 retries = 0
107 while retries < 5:
108 try:
109 d = urllib2.urlopen(test_url).read()
110 logging.info('URL %s GOT: %s' % (test_url, d))
111 if d.startswith(expected_response):
112 break
113 except Exception as e:
114 logging.info('URL %s GOT: %s' % (test_url, e))
115 time.sleep(retries * 0.1)
116 retries += 1
117
118 def TearDown(self):
119 self._test_server_process.kill()
120 self._test_server_process.wait()