OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Setups a local Rietveld instance to test against a live server for | |
7 integration tests. | |
8 | |
9 It makes sure Google AppEngine SDK is found, download Rietveld and Django code | |
10 if necessary and starts the server on a free inbound TCP port. | |
11 """ | |
12 | |
13 import logging | |
14 import optparse | |
15 import os | |
16 import shutil | |
17 import socket | |
18 import sys | |
19 import tempfile | |
20 import time | |
21 | |
22 try: | |
23 import subprocess2 | |
24 except ImportError: | |
25 sys.path.append( | |
26 os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) | |
27 import subprocess2 | |
iannucci
2015/02/19 00:22:39
this implies that this file should also go into in
pgervais
2015/02/19 00:45:57
This file is also not used by the CQ, removing.
| |
28 | |
29 | |
30 class Failure(Exception): | |
31 pass | |
32 | |
33 | |
34 def test_port(port): | |
35 s = socket.socket() | |
36 try: | |
37 return s.connect_ex(('127.0.0.1', port)) == 0 | |
38 finally: | |
39 s.close() | |
40 | |
41 | |
42 def find_free_port(start_port): | |
43 """Search for a free port starting at specified port.""" | |
44 for port in xrange(start_port, (2<<16)): | |
45 if not test_port(port): | |
46 return port | |
47 raise Failure('Having issues finding an available port') | |
48 | |
49 | |
50 class LocalRietveld(object): | |
51 """Downloads everything needed to run a local instance of Rietveld.""" | |
52 | |
53 def __init__(self, base_dir=None): | |
54 # Paths | |
55 self.base_dir = base_dir | |
56 if not self.base_dir: | |
57 self.base_dir = os.path.dirname(os.path.abspath(__file__)) | |
58 # TODO(maruel): This should be in /tmp but that would mean having to fetch | |
59 # everytime. This test is already annoyingly slow. | |
60 self.rietveld = os.path.join(self.base_dir, '_rietveld') | |
61 self.test_server = None | |
62 self.port = None | |
63 self.tempdir = None | |
64 | |
65 # Find the GAE SDK | |
66 previous_dir = '' | |
67 self.sdk_path = '' | |
68 base_dir = self.base_dir | |
69 while base_dir != previous_dir: | |
70 previous_dir = base_dir | |
71 self.sdk_path = os.path.join(base_dir, 'google_appengine') | |
72 if not os.path.isfile(os.path.join(self.sdk_path, 'VERSION')): | |
73 base_dir = os.path.dirname(base_dir) | |
74 self.dev_app = os.path.join(self.sdk_path, 'dev_appserver.py') | |
75 | |
76 def install_prerequisites(self): | |
77 # First, verify the Google AppEngine SDK is available. | |
78 if not os.path.isfile(self.dev_app): | |
79 raise Failure( | |
80 'Install google_appengine sdk in %s or higher up' % self.base_dir) | |
81 | |
82 if os.path.isdir(os.path.join(self.rietveld, '.svn')): | |
83 # Left over from subversion. Delete it. | |
84 shutil.rmtree(self.rietveld) | |
85 | |
86 # Second, checkout rietveld if not available. | |
87 rev = '9349cab9a3bb' | |
88 if not os.path.isdir(self.rietveld): | |
89 print('Checking out rietveld...') | |
90 try: | |
91 subprocess2.check_call( | |
92 [ 'hg', 'clone', '-q', '-u', rev, '-r', rev, | |
93 'https://code.google.com/p/rietveld/', self.rietveld]) | |
94 except (OSError, subprocess2.CalledProcessError), e: | |
95 raise Failure( | |
96 'Failed to checkout rietveld. Do you have mercurial installed?\n' | |
97 '%s' % e) | |
98 else: | |
99 print('Syncing rietveld...') | |
100 try: | |
101 subprocess2.check_call( | |
102 ['hg', 'co', '-q', '-C', rev], cwd=self.rietveld) | |
103 except (OSError, subprocess2.CalledProcessError), e: | |
104 raise Failure('Failed to sync rietveld\n%s' % e) | |
105 | |
106 def start_server(self, verbose=False): | |
107 self.install_prerequisites() | |
108 assert not self.tempdir | |
109 self.tempdir = tempfile.mkdtemp(prefix='rietveld_test') | |
110 self.port = find_free_port(10000) | |
111 admin_port = find_free_port(self.port + 1) | |
112 if verbose: | |
113 stdout = stderr = None | |
114 else: | |
115 stdout = subprocess2.PIPE | |
116 stderr = subprocess2.STDOUT | |
117 cmd = [ | |
118 sys.executable, | |
119 self.dev_app, | |
120 '.', | |
121 '--port', str(self.port), | |
122 '--admin_port', str(admin_port), | |
123 '--storage', self.tempdir, | |
124 '--clear_search_indexes', | |
125 '--skip_sdk_update_check', | |
126 ] | |
127 | |
128 # CHEAP TRICK | |
129 # By default you only want to bind on loopback but I'm testing over a | |
130 # headless computer so it's useful to be able to access the test instance | |
131 # remotely. | |
132 if os.environ.get('GAE_LISTEN_ALL', '') == 'true': | |
133 cmd.extend(('-a', '0.0.0.0')) | |
134 logging.info(' '.join(cmd)) | |
135 self.test_server = subprocess2.Popen( | |
136 cmd, stdout=stdout, stderr=stderr, cwd=self.rietveld) | |
137 # Loop until port 127.0.0.1:port opens or the process dies. | |
138 while not test_port(self.port): | |
139 self.test_server.poll() | |
140 if self.test_server.returncode is not None: | |
141 if not verbose: | |
142 out = self.test_server.communicate()[0] | |
143 shutil.rmtree(self.tempdir) | |
144 self.tempdir = None | |
145 raise Failure( | |
146 'Test rietveld instance failed early on port %s\n%s' % | |
147 (self.port, out)) | |
148 time.sleep(0.01) | |
149 | |
150 def stop_server(self): | |
151 if self.test_server: | |
152 try: | |
153 self.test_server.kill() | |
154 except OSError: | |
155 pass | |
156 self.test_server.wait() | |
157 self.test_server = None | |
158 self.port = None | |
159 if self.tempdir: | |
160 shutil.rmtree(self.tempdir) | |
161 self.tempdir = None | |
162 | |
163 | |
164 def main(): | |
165 parser = optparse.OptionParser() | |
166 parser.add_option('-v', '--verbose', action='store_true') | |
167 options, args = parser.parse_args() | |
168 if args: | |
169 parser.error('Unknown arguments: %s' % ' '.join(args)) | |
170 instance = LocalRietveld() | |
171 try: | |
172 instance.start_server(verbose=options.verbose) | |
173 print 'Local rietveld instance started on port %d' % instance.port | |
174 while True: | |
175 time.sleep(0.1) | |
176 finally: | |
177 instance.stop_server() | |
178 | |
179 | |
180 if __name__ == '__main__': | |
181 main() | |
OLD | NEW |