Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: appengine_apps/chromium_status/tests/local_gae.py

Issue 778533003: Moved chromium_status to appengine/ (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 """Setups a local GAE instance to test against a live server for integration
6 tests.
7
8 It makes sure Google AppEngine SDK is found and starts the server on a free
9 inbound TCP port.
10 """
11
12 import cookielib
13 import errno
14 import logging
15 import os
16 import re
17 import socket
18 import subprocess
19 import tempfile
20 import time
21 import sys
22 import urllib
23 import urllib2
24
25 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
26 GAE_SDK = None
27
28
29 def _load_modules():
30 """Loads all the necessary modules.
31
32 Update sys.path to be able to import chromium-status and GAE SDK.
33 """
34 global GAE_SDK
35 if GAE_SDK:
36 return
37 root_dir = BASE_DIR
38 # First, verify the Google AppEngine SDK is available.
39 while True:
40 if os.path.isfile(os.path.join(root_dir, 'google_appengine', 'VERSION')):
41 break
42 next_root = os.path.dirname(root_dir)
43 if next_root == root_dir:
44 raise Failure(
45 'Install google_appengine sdk in %s' % os.path.dirname(BASE_DIR))
46 root_dir = next_root
47 GAE_SDK = os.path.realpath(os.path.join(root_dir, 'google_appengine'))
48 # Need yaml later.
49 gae_sdk_lib = os.path.realpath(os.path.join(GAE_SDK, 'lib'))
50 sys.path.insert(0, os.path.realpath(os.path.join(gae_sdk_lib, 'yaml', 'lib')))
51
52
53 class Failure(Exception):
54 pass
55
56
57 def test_port(port):
58 s = socket.socket()
59 try:
60 return s.connect_ex(('127.0.0.1', port)) == 0
61 finally:
62 s.close()
63
64
65 def find_free_port(base_port=8080):
66 """Finds an available port starting at 8080."""
67 port = base_port
68 max_val = (2<<16)
69 while test_port(port) and port < max_val:
70 port += 1
71 if port == max_val:
72 raise Failure('Having issues finding an available port')
73 return port
74
75
76 class LocalGae(object):
77 """Wraps up starting a GAE local instance for integration tests."""
78
79 def __init__(self, base_dir=None):
80 """base_dir defaults to .. from the file's directory."""
81 # Paths
82 self.base_dir = base_dir
83 if not self.base_dir:
84 self.base_dir = os.path.dirname(os.path.abspath(__file__))
85 self.base_dir = os.path.realpath(os.path.join(self.base_dir, '..'))
86 self.test_server = None
87 self.port = None
88 self.admin_port = None
89 self.app_id = None
90 self.url = None
91 self.admin_url = None
92 self.tmp_db = None
93 self._xsrf_token = None
94 self._cookie_jar = cookielib.CookieJar()
95 cookie_processor = urllib2.HTTPCookieProcessor(self._cookie_jar)
96 redirect_handler = urllib2.HTTPRedirectHandler()
97 self._opener = urllib2.build_opener(redirect_handler, cookie_processor)
98
99 def install_prerequisites(self):
100 # Load GAE SDK.
101 _load_modules()
102
103 # Now safe to import GAE SDK modules.
104 # Unable to import 'yaml'
105 # pylint: disable=F0401
106
107 import yaml
108 self.app_id = yaml.load(
109 open(os.path.join(self.base_dir, 'app.yaml'), 'r'))['application']
110 logging.debug('Instance app id: %s' % self.app_id)
111 assert self.app_id
112
113 def start_server(self, verbose=False):
114 self.install_prerequisites()
115 self.port = find_free_port()
116 self.admin_port = find_free_port(base_port=self.port + 1)
117 if verbose:
118 stdout = None
119 stderr = None
120 else:
121 stdout = subprocess.PIPE
122 stderr = subprocess.PIPE
123 # Generate a friendly environment.
124 env = os.environ.copy()
125 env['LANGUAGE'] = 'en'
126 h, self.tmp_db = tempfile.mkstemp(prefix='local_gae')
127 os.close(h)
128 cmd = [
129 sys.executable,
130 os.path.join(GAE_SDK, 'dev_appserver.py'),
131 self.base_dir,
132 '--port', str(self.port),
133 '--admin_port', str(self.admin_port),
134 '--datastore_path', self.tmp_db,
135 '--datastore_consistency_policy', 'consistent',
136 '--skip_sdk_update_check',
137 ]
138 if verbose:
139 cmd.extend([
140 '--log_level', 'debug',
141 ])
142 self.test_server = subprocess.Popen(
143 cmd, stdout=stdout, stderr=stderr, env=env)
144 # Loop until port 127.0.0.1:port opens or the process dies.
145 while not test_port(self.port):
146 while not test_port(self.admin_port):
147 self.test_server.poll()
148 if self.test_server.returncode is not None:
149 raise Failure(
150 'Test GAE instance failed early on port %s' %
151 self.port)
152 time.sleep(0.001)
153 self.url = 'http://localhost:%d/' % self.port
154 self.admin_url = 'http://localhost:%d/' % self.admin_port
155
156 def stop_server(self):
157 if self.test_server:
158 try:
159 self.test_server.terminate()
160 except OSError as e:
161 if e.errno != errno.ESRCH:
162 raise
163 self.test_server = None
164 self.port = None
165 self.url = None
166 self.admin_url = None
167 if self.tmp_db:
168 try:
169 os.remove(self.tmp_db)
170 except OSError:
171 pass
172 self.tmp_db = None
173
174 def get(self, suburl, url=None):
175 if url is None:
176 url = self.url
177 logging.debug('GET: %r', url + suburl)
178 request = urllib2.Request(url + suburl)
179 f = self._opener.open(request)
180 data = f.read()
181 return data
182
183 def post(self, suburl, data, url=None):
184 if url is None:
185 url = self.url
186 logging.debug('POST(%r): %r', url + suburl, data)
187 request = urllib2.Request(url + suburl, urllib.urlencode(data))
188 f = self._opener.open(request)
189 return f.read()
190
191 def clear_cookies(self):
192 self._cookie_jar.clear()
193
194 def login(self, username, admin):
195 try:
196 self.get('_ah/login?email=%s&admin=%r&action=login&continue=/' % (
197 urllib.quote_plus(username), admin))
198 except urllib2.HTTPError:
199 # Ignore http errors as the continue url may be inaccessible.
200 pass
201
202 def query(self, cmd):
203 """Lame way to modify the db remotely on dev server.
204
205 Using remote_api inside the unit test is a bit too invasive.
206 """
207 data = {
208 'code': 'from google.appengine.ext import db\n' + cmd,
209 'module_name': 'default',
210 'xsrf_token': self.xsrf_token,
211 }
212 return self.post('console', data, url=self.admin_url)
213
214 @property
215 def xsrf_token(self):
216 if self._xsrf_token is None:
217 self.clear_cookies()
218 interactive = self.get('console', url=self.admin_url)
219 match = re.search(r"'xsrf_token': *'(.*?)'", interactive)
220 if not match:
221 logging.debug('interactive console output:\n%s', interactive)
222 raise Failure('could not find xsrf_token')
223 self._xsrf_token = match.group(1)
224 self.clear_cookies()
225 return self._xsrf_token
226
227 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « appengine_apps/chromium_status/tests/fill.py ('k') | appengine_apps/chromium_status/tests/main_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698