OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Setups a local Rietveld instance to test against a live server for | 6 """Setups a local Rietveld instance to test against a live server for |
7 integration tests. | 7 integration tests. |
8 | 8 |
9 It makes sure Google AppEngine SDK is found, download Rietveld and Django code | 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. | 10 if necessary and starts the server on a free inbound TCP port. |
11 """ | 11 """ |
12 | 12 |
13 import optparse | 13 import optparse |
14 import os | 14 import os |
15 import socket | 15 import socket |
16 import subprocess | 16 import subprocess |
17 import time | 17 import time |
18 | 18 |
19 | 19 |
20 class Failure(Exception): | 20 class Failure(Exception): |
21 pass | 21 pass |
22 | 22 |
23 | 23 |
24 def test_port(port): | 24 def test_port(port): |
25 s = socket.socket() | 25 s = socket.socket() |
26 try: | 26 try: |
27 return s.connect_ex(('127.0.0.1', port)) == 0 | 27 return s.connect_ex(('127.0.0.1', port)) == 0 |
28 finally: | 28 finally: |
29 s.close() | 29 s.close() |
30 | 30 |
31 | 31 |
32 def find_free_port(): | 32 def find_free_port(): |
33 # Test to find an available port starting at 8080. | 33 # Test to find an available port starting at 8080. |
34 port = 8080 | 34 port = 8080 |
35 max_val = (2<<16) | 35 max_val = (2<<16) |
36 while test_port(port) and port < max_val: | 36 while test_port(port) and port < max_val: |
37 port += 1 | 37 port += 1 |
38 if port == max_val: | 38 if port == max_val: |
39 raise Failure('Having issues finding an available port') | 39 raise Failure('Having issues finding an available port') |
40 return port | 40 return port |
41 | 41 |
42 | 42 |
43 class LocalRietveld(object): | 43 class LocalRietveld(object): |
44 """Downloads everything needed to run a local instance of Rietveld.""" | 44 """Downloads everything needed to run a local instance of Rietveld.""" |
45 | 45 |
46 def __init__(self, base_dir=None): | 46 def __init__(self, base_dir=None): |
47 # Paths | 47 # Paths |
48 self.base_dir = base_dir | 48 self.base_dir = base_dir |
49 if not self.base_dir: | 49 if not self.base_dir: |
50 self.base_dir = os.path.dirname(os.path.abspath(__file__)) | 50 self.base_dir = os.path.dirname(os.path.abspath(__file__)) |
51 self.base_dir = os.path.realpath(os.path.join(self.base_dir, '..')) | 51 self.base_dir = os.path.realpath(os.path.join(self.base_dir, '..')) |
52 self.sdk_path = os.path.abspath( | 52 self.sdk_path = os.path.abspath( |
53 os.path.join(self.base_dir, '..', '..', 'google_appengine')) | 53 os.path.join(self.base_dir, '..', '..', 'google_appengine')) |
54 self.dev_app = os.path.join(self.sdk_path, 'dev_appserver.py') | 54 self.dev_app = os.path.join(self.sdk_path, 'dev_appserver.py') |
55 self.rietveld = os.path.join(self.base_dir, 'test', 'rietveld') | 55 self.rietveld = os.path.join(self.base_dir, 'test', 'rietveld') |
56 self.test_server = None | 56 self.test_server = None |
57 self.port = None | 57 self.port = None |
58 # Generate a friendly environment. | 58 # Generate a friendly environment. |
59 self.env = os.environ.copy() | 59 self.env = os.environ.copy() |
60 self.env['LANGUAGE'] = 'en' | 60 self.env['LANGUAGE'] = 'en' |
| 61 self.out = None |
| 62 self.err = None |
61 | 63 |
62 def install_prerequisites(self): | 64 def install_prerequisites(self): |
63 # First, verify the Google AppEngine SDK is available. | 65 # First, verify the Google AppEngine SDK is available. |
64 if not os.path.isfile(self.dev_app): | 66 if not os.path.isfile(self.dev_app): |
65 raise Failure('Install google_appengine sdk in %s' % self.sdk_path) | 67 raise Failure('Install google_appengine sdk in %s' % self.sdk_path) |
66 | 68 |
67 def call(*args, **kwargs): | 69 def call(*args, **kwargs): |
68 kwargs['env'] = self.env | 70 kwargs['env'] = self.env |
69 x = subprocess.Popen(*args, **kwargs) | 71 x = subprocess.Popen(*args, **kwargs) |
70 x.communicate() | 72 x.communicate() |
71 return x.returncode == 0 | 73 return x.returncode == 0 |
72 | 74 |
73 # Second, checkout rietveld if not available. | 75 # Second, checkout rietveld if not available. |
74 if not os.path.isdir(self.rietveld): | 76 if not os.path.isdir(self.rietveld): |
75 print('Checking out rietveld...') | 77 print('Checking out rietveld...') |
76 if not call( | 78 if not call( |
77 ['svn', 'co', '-q', | 79 ['svn', 'co', '-q', |
78 'http://rietveld.googlecode.com/svn/trunk@681', | 80 'http://rietveld.googlecode.com/svn/trunk@681', |
79 self.rietveld]): | 81 self.rietveld]): |
80 raise Failure('Failed to checkout rietveld') | 82 raise Failure('Failed to checkout rietveld') |
81 else: | 83 else: |
82 print('Syncing rietveld...') | 84 print('Syncing rietveld...') |
83 if not call(['svn', 'up', '-q', '-r', '681'], cwd=self.rietveld): | 85 if not call(['svn', 'up', '-q', '-r', '681'], cwd=self.rietveld): |
84 raise Failure('Failed to checkout rietveld') | 86 raise Failure('Failed to checkout rietveld') |
85 | 87 |
86 def start_server(self, verbose=False): | 88 def start_server(self, verbose=False): |
87 self.install_prerequisites() | 89 self.install_prerequisites() |
88 self.port = find_free_port() | 90 self.port = find_free_port() |
89 if verbose: | 91 if verbose: |
90 self.out = None | 92 self.out = None |
91 self.err = None | 93 self.err = None |
92 else: | 94 else: |
93 self.out = open(os.devnull, 'w') | 95 self.out = open(os.devnull, 'w') |
94 self.err = open(os.devnull, 'w') | 96 self.err = open(os.devnull, 'w') |
95 output = [] | 97 cmd = [ |
96 cmd = [ | 98 self.dev_app, |
97 self.dev_app, | 99 '--skip_sdk_update_check', |
98 '--skip_sdk_update_check', | 100 '.', |
99 '.', | 101 '--port=%d' % self.port, |
100 '--port=%d' % self.port, | 102 '--datastore_path=' + os.path.join(self.rietveld, 'tmp.db'), |
101 '--datastore_path=' + os.path.join(self.rietveld, 'tmp.db'), | 103 '-c'] |
102 '-c'] | 104 self.test_server = subprocess.Popen( |
103 self.test_server = subprocess.Popen( | 105 cmd, stdout=self.out, stderr=self.err, env=self.env, |
104 cmd, stdout=self.out, stderr=self.err, env=self.env, | 106 cwd=self.rietveld) |
105 cwd=self.rietveld) | 107 # Loop until port 127.0.0.1:port opens or the process dies. |
106 # Loop until port 127.0.0.1:port opens or the process dies. | 108 while not test_port(self.port): |
107 while not test_port(self.port): | 109 self.test_server.poll() |
108 self.test_server.poll() | 110 if self.test_server.returncode is not None: |
109 if self.test_server.returncode is not None: | 111 raise Failure( |
110 raise Failure( | 112 'Test rietveld instance failed early on port %s' % |
111 'Test rietveld instance failed early on port %s' % | 113 self.port) |
112 self.port) | 114 time.sleep(0.001) |
113 time.sleep(0.001) | |
114 | 115 |
115 def stop_server(self): | 116 def stop_server(self): |
116 if self.test_server: | 117 if self.test_server: |
117 self.test_server.kill() | 118 self.test_server.kill() |
118 self.test_server = None | 119 self.test_server = None |
119 self.port = None | 120 self.port = None |
120 if self.out: | 121 if self.out: |
121 self.out.close() | 122 self.out.close() |
122 self.out = None | 123 self.out = None |
123 if self.err: | 124 if self.err: |
124 self.err.close() | 125 self.err.close() |
125 self.err = None | 126 self.err = None |
126 | 127 |
127 | 128 |
128 def main(): | 129 def main(): |
129 parser = optparse.OptionParser() | 130 parser = optparse.OptionParser() |
130 parser.add_option('-v', '--verbose', action='store_true') | 131 parser.add_option('-v', '--verbose', action='store_true') |
131 options, args = parser.parse_args() | 132 options, args = parser.parse_args() |
132 if args: | 133 if args: |
133 parser.error('Unknown arguments: %s' % ' '.join(args)) | 134 parser.error('Unknown arguments: %s' % ' '.join(args)) |
134 instance = LocalRietveld() | 135 instance = LocalRietveld() |
135 try: | 136 try: |
136 instance.start_server(verbose=options.verbose) | 137 instance.start_server(verbose=options.verbose) |
137 print 'Local rietveld instance started on port %d' % instance.port | 138 print 'Local rietveld instance started on port %d' % instance.port |
138 while True: | 139 while True: |
139 time.sleep(0.1) | 140 time.sleep(0.1) |
140 finally: | 141 finally: |
141 instance.stop_server() | 142 instance.stop_server() |
142 | 143 |
143 | 144 |
144 if __name__ == '__main__': | 145 if __name__ == '__main__': |
145 main() | 146 main() |
146 | |
147 # vim: ts=4:sw=4:tw=80:et: | |
OLD | NEW |