From 5b78c7262b4c6a640917650a5cfb139b30eb113c Mon Sep 17 00:00:00 2001 From: "maruel@chromium.org" Date: Fri, 11 Feb 2011 17:27:18 +0000 Subject: [PATCH] Move rietveld local server setup in a separate file. This makes the code more comprehensible and reusable. BUG=none TEST=none Review URL: http://codereview.chromium.org/6460015 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@74623 0039d316-1c4b-4281-b951-d872f2087c98 --- git_cl/PRESUBMIT.py | 116 ++++++++---------------------- git_cl/test/__init__.py | 0 git_cl/test/local_rietveld.py | 132 ++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 85 deletions(-) create mode 100644 git_cl/test/__init__.py create mode 100644 git_cl/test/local_rietveld.py diff --git a/git_cl/PRESUBMIT.py b/git_cl/PRESUBMIT.py index 6c7506929..aaeafaf38 100644 --- a/git_cl/PRESUBMIT.py +++ b/git_cl/PRESUBMIT.py @@ -19,106 +19,52 @@ def CheckChangeOnCommit(input_api, output_api): def RunTests(input_api, output_api): """Run all the shells scripts in the directory test. - - Also verify the GAE python SDK is available, fetches Rietveld if necessary and - start a test instance to test against. """ - # They are not exposed from InputApi. - from os import listdir, pathsep - import socket - import time - - # Shortcuts - join = input_api.os_path.join - error = output_api.PresubmitError - - # Paths - sdk_path = input_api.os_path.abspath(join('..', '..', 'google_appengine')) - dev_app = join(sdk_path, 'dev_appserver.py') - rietveld = join('test', 'rietveld') - django_path = join(rietveld, 'django') - - # Generate a friendly environment. - env = input_api.environ.copy() - env['LANGUAGE'] = 'en' - if env.get('PYTHONPATH'): - env['PYTHONPATH'] = (env['PYTHONPATH'].rstrip(pathsep) + pathsep + - django_path) - else: - env['PYTHONPATH'] = django_path - - def call(*args, **kwargs): - kwargs['env'] = env - x = input_api.subprocess.Popen(*args, **kwargs) - x.communicate() - return x.returncode == 0 - - def test_port(port): - s = socket.socket() - try: - return s.connect_ex(('127.0.0.1', port)) == 0 - finally: - s.close() + # Not exposed from InputApi. + from os import listdir - # First, verify the Google AppEngine SDK is available. - if not input_api.os_path.isfile(dev_app): - return [error('Install google_appengine sdk in %s' % sdk_path)] - - # Second, checkout rietveld and django if not available. - if not input_api.os_path.isdir(rietveld): - print('Checking out rietveld...') - if not call(['svn', 'co', '-q', - 'http://rietveld.googlecode.com/svn/trunk@563', - rietveld]): - return [error('Failed to checkout rietveld')] - if not input_api.os_path.isdir(django_path): - print('Checking out django...') - if not call( - ['svn', 'co', '-q', - 'http://code.djangoproject.com/' - 'svn/django/branches/releases/1.0.X/django@13637', - django_path]): - return [error('Failed to checkout django')] - - - # Test to find an available port starting at 8080. - port = 8080 - while test_port(port) and port < 65000: - port += 1 - if port == 65000: - return [error('Having issues finding an available port')] + # First loads a local Rietveld instance. + import sys + old_sys_path = sys.path + try: + sys.path = [input_api.PresubmitLocalPath()] + sys.path + from test import local_rietveld + server = local_rietveld.LocalRietveld() + finally: + sys.path = old_sys_path + # Set to True for testing. verbose = False if verbose: stdout = None stderr = None else: stdout = input_api.subprocess.PIPE - stderr = input_api.subprocess.PIPE + stderr = input_api.subprocess.STDOUT output = [] - test_server = input_api.subprocess.Popen( - [dev_app, rietveld, '--port=%d' % port, - '--datastore_path=' + join(rietveld, 'tmp.db'), '-c'], - stdout=stdout, stderr=stderr, env=env) try: - # Loop until port 127.0.0.1:port opens or the process dies. - while not test_port(port): - test_server.poll() - if test_server.returncode is not None: - output.append(error('Test rietveld instance failed early')) - break - time.sleep(0.001) - - test_path = input_api.os_path.abspath('test') + # Start a local rietveld instance to test against. + server.start_server() + test_path = input_api.os_path.abspath( + input_api.os_path.join(input_api.PresubmitLocalPath(), 'test')) for test in listdir(test_path): - # push-from-logs and rename fails for now. Remove from this list once they - # work. + # push-from-logs and rename fails for now. Remove from this list once + # they work. if (test in ('push-from-logs.sh', 'rename.sh', 'test-lib.sh') or not test.endswith('.sh')): continue + print('Running %s' % test) - if not call([join(test_path, test)], cwd=test_path, stdout=stdout): - output.append(error('%s failed' % test)) + proc = input_api.subprocess.Popen( + [input_api.os_path.join(test_path, test)], + cwd=test_path, + stdout=stdout, + stderr=stderr) + proc.communicate() + if proc.returncode != 0: + output.append(output_api.PresubmitError('%s failed' % test)) + except setup_mock.Failure, e: + output.append(output_api.PresubmitError('\n'.join(str(i) for i in e.args))) finally: - test_server.kill() + server.stop_server() return output diff --git a/git_cl/test/__init__.py b/git_cl/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/git_cl/test/local_rietveld.py b/git_cl/test/local_rietveld.py new file mode 100644 index 000000000..95e27b60b --- /dev/null +++ b/git_cl/test/local_rietveld.py @@ -0,0 +1,132 @@ +# 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. + +"""Setups a local Rietveld instance to test against a live server for +integration tests. + +It makes sure Google AppEngine SDK is found, download Rietveld and Django code +if necessary and starts the server on a free inbound TCP port. +""" + +import os +import socket +import subprocess +import time + + +class Failure(Exception): + pass + + +def test_port(port): + s = socket.socket() + try: + return s.connect_ex(('127.0.0.1', port)) == 0 + finally: + s.close() + + +def find_free_port(): + # Test to find an available port starting at 8080. + port = 8080 + max_val = (2<<16) + while test_port(port) and port < max_val: + port += 1 + if port == max_val: + raise Failure('Having issues finding an available port') + return port + + +class LocalRietveld(object): + """Downloads everything needed to run a local instance of Rietveld.""" + + def __init__(self, base_dir=None): + # Paths + self.base_dir = base_dir + if not self.base_dir: + self.base_dir = os.path.dirname(os.path.abspath(__file__)) + self.base_dir = os.path.realpath(os.path.join(self.base_dir, '..')) + self.sdk_path = os.path.abspath( + os.path.join(self.base_dir, '..', '..', 'google_appengine')) + self.dev_app = os.path.join(self.sdk_path, 'dev_appserver.py') + self.rietveld = os.path.join(self.base_dir, 'test', 'rietveld') + self.django_path = os.path.join(self.rietveld, 'django') + self.test_server = None + self.port = None + # Generate a friendly environment. + self.env = os.environ.copy() + self.env['LANGUAGE'] = 'en' + if self.env.get('PYTHONPATH'): + self.env['PYTHONPATH'] = ( + self.env['PYTHONPATH'].rstrip(os.pathsep) + os.pathsep + + self.django_path) + else: + self.env['PYTHONPATH'] = self.django_path + + def install_prerequisites(self): + # First, verify the Google AppEngine SDK is available. + if not os.path.isfile(self.dev_app): + raise Failure('Install google_appengine sdk in %s' % self.sdk_path) + + def call(*args, **kwargs): + kwargs['env'] = self.env + x = subprocess.Popen(*args, **kwargs) + x.communicate() + return x.returncode == 0 + + # Second, checkout rietveld and django if not available. + if not os.path.isdir(self.rietveld): + print('Checking out rietveld...') + if not call( + ['svn', 'co', '-q', + 'http://rietveld.googlecode.com/svn/trunk@563', + self.rietveld]): + raise Failure('Failed to checkout rietveld') + if not os.path.isdir(self.django_path): + print('Checking out django...') + if not call( + ['svn', 'co', '-q', + 'http://code.djangoproject.com/' + 'svn/django/branches/releases/1.0.X/django@13637', + self.django_path]): + raise Failure('Failed to checkout django') + + def start_server(self, verbose=False): + self.install_prerequisites() + self.port = find_free_port() + if verbose: + stdout = None + stderr = None + else: + stdout = subprocess.PIPE + stderr = subprocess.PIPE + output = [] + self.test_server = subprocess.Popen( + [self.dev_app, self.rietveld, '--port=%d' % self.port, + '--datastore_path=' + os.path.join(self.rietveld, 'tmp.db'), '-c'], + stdout=stdout, stderr=stderr, env=self.env) + # Loop until port 127.0.0.1:port opens or the process dies. + while not test_port(self.port): + self.test_server.poll() + if self.test_server.returncode is not None: + raise Failure( + 'Test rietveld instance failed early on port %s' % + self.port) + time.sleep(0.001) + + def stop_server(self): + if self.test_server: + self.test_server.kill() + self.test_server = None + self.port = None + + +def main(): + print LocalRietveld().start_server() + + +if __name__ == '__main__': + main() + +# vim: ts=4:sw=4:tw=80:et: