diff options
author | tejasshah@google.com <tejasshah@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-19 22:24:10 +0000 |
---|---|---|
committer | tejasshah@google.com <tejasshah@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-19 22:24:10 +0000 |
commit | 62c880ac8986131fcd1f1f49f854801b59a7cc1b (patch) | |
tree | 63bdf1adfebe3e3f95485f92f32f5b349486eee5 /chrome/test/live_sync | |
parent | 3f579584b420ced3178cedeb3a9a4616ada202fa (diff) | |
download | chromium_src-62c880ac8986131fcd1f1f49f854801b59a7cc1b.zip chromium_src-62c880ac8986131fcd1f1f49f854801b59a7cc1b.tar.gz chromium_src-62c880ac8986131fcd1f1f49f854801b59a7cc1b.tar.bz2 |
This script can be used by devs to run the sync integration test. Also, it will replace the original script which is used by buildbot to run sync test.
Review URL: http://codereview.chromium.org/172068
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23765 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/live_sync')
-rw-r--r-- | chrome/test/live_sync/sync_integration_test.py | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/chrome/test/live_sync/sync_integration_test.py b/chrome/test/live_sync/sync_integration_test.py new file mode 100644 index 0000000..3799468 --- /dev/null +++ b/chrome/test/live_sync/sync_integration_test.py @@ -0,0 +1,385 @@ +#!/usr/bin/python2.4
+#
+# Copyright 2009 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.
+
+
+"""A tool to run a chrome sync integration test, used by the buildbot slaves.
+
+ When this is run, the current directory (cwd) should be the outer build
+ directory (e.g., chrome-release/build/).
+
+ For a list of command-line options, call this script with '--help'.
+"""
+
+__author__ = 'tejasshah@chromium.org'
+
+
+import logging
+import optparse
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import time
+import urllib2
+
+
+USAGE = '%s [options] [test args]' % os.path.basename(sys.argv[0])
+HTTP_SERVER_URL = None
+HTTP_SERVER_PORT = None
+
+
+class PathNotFound(Exception): pass
+
+
+def ListSyncTests(test_exe_path):
+ """Returns list of the enabled live sync tests.
+
+ Args:
+ test_exe_path: Absolute path to test exe file.
+
+ Returns:
+ List of the tests that should be run.
+ """
+ command = [test_exe_path]
+ command.append('--gtest_list_tests')
+ proc = subprocess.Popen(
+ command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1)
+ proc.wait()
+ sys.stdout.flush()
+ test_list = []
+ for line in proc.stdout.readlines():
+ if not line.strip():
+ continue
+ elif line.count("."): # A new test collection
+ test_collection = line.split(".")[0].strip();
+ else: # An individual test to run
+ test_name = line.strip()
+ test_list.append("%s.%s" % (test_collection, test_name))
+ logging.info('List of tests to run: %s' % (test_list))
+ return test_list
+
+
+def GetUrl(command, port):
+ """Prepares the URL with appropriate command to send it to http server.
+
+ Args:
+ command: Command for HTTP server
+ port: Port number as a parameter to the command
+
+ Returns:
+ Formulated URL with the command and parameter.
+ """
+ command_url = (
+ '%s:%s/%s?port=%s'
+ % (HTTP_SERVER_URL, HTTP_SERVER_PORT, command, port))
+ return command_url
+
+
+def StartSyncServer(port=None):
+ """Starts a chrome sync server.
+
+ Args:
+ port: Port number on which sync server to start
+ (Default value none, in this case it uses random port).
+
+ Returns:
+ If success then port number on which sync server started, else None.
+ """
+ sync_port = None
+ if port:
+ start_sync_server_url = GetUrl('startsyncserver', port)
+ else:
+ start_sync_server_url = (
+ '%s:%s/%s' % (HTTP_SERVER_URL, HTTP_SERVER_PORT, 'startsyncserver'))
+ req = urllib2.Request(start_sync_server_url)
+ try:
+ response = urllib2.urlopen(req)
+ except urllib2.HTTPError, e:
+ logging.error(
+ 'Could not start sync server, something went wrong.'
+ 'Request URL: %s , Error Code: %s'% (start_sync_server_url, e.code))
+ return sync_port
+ except urllib2.URLError, e:
+ logging.error(
+ 'Failed to reach HTTP server.Request URL: %s , Error: %s'
+ % (start_sync_server_url, e.reason))
+ return sync_port
+ else:
+ # Let's read response and parse the sync server port number.
+ output = response.readlines()
+ # Regex to ensure that sync server started and extract the port number.
+ regex = re.compile(
+ ".*not.*running.*on.*port\s*:\s*(\d+).*started.*new.*sync.*server",
+ re.IGNORECASE|re.MULTILINE|re.DOTALL)
+ r = regex.search(output[0])
+ if r:
+ sync_port = r.groups()[0]
+ if sync_port:
+ logging.info(
+ 'Started Sync Server Successfully on Port:%s. Request URL: %s , '
+ 'Response: %s' % (sync_port, start_sync_server_url, output))
+ response.fp._sock.recv = None
+ response.close()
+ return sync_port
+
+
+def CheckIfSyncServerRunning(port):
+ """Check the healthz status of a chrome sync server.
+
+ Args:
+ port: Port number on which sync server is running
+
+ Returns:
+ True: If sync server running.
+ False: Otherwise.
+ """
+ sync_server_healthz_url = ('%s:%s/healthz' % (HTTP_SERVER_URL, port))
+ req = urllib2.Request(sync_server_healthz_url)
+ try:
+ response = urllib2.urlopen(req)
+ except urllib2.HTTPError, e:
+ logging.error(
+ 'It seems like Sync Server is not running, healthz check failed.'
+ 'Request URL: %s , Error Code: %s'% (sync_server_healthz_url, e.code))
+ return False
+ except urllib2.URLError, e:
+ logging.error(
+ 'Failed to reach Sync server, healthz check failed.'
+ 'Request URL: %s , Error: %s'% (sync_server_healthz_url, e.reason))
+ return False
+ else:
+ logging.info(
+ 'Sync Server healthz check Passed.Request URL: %s , Response: %s'
+ % (sync_server_healthz_url, response.readlines()))
+ response.fp._sock.recv = None
+ response.close()
+ return True
+
+
+def StopSyncServer(port):
+ """Stops a chrome sync server.
+
+ Args:
+ port: Port number on which sync server to Stop
+
+ Returns:
+ Success/Failure as a bool value.
+ """
+ stop_sync_server_url = GetUrl('stopsyncserver', port)
+ req = urllib2.Request(stop_sync_server_url)
+ logging.info("Stopping: %s" % stop_sync_server_url)
+ try:
+ response = urllib2.urlopen(req)
+ except urllib2.HTTPError, e:
+ logging.error(
+ 'Could not stop sync server, something went wrong.'
+ 'Request URL: %s , Error Code: %s'% (stop_sync_server_url, e.code))
+ return False
+ except urllib2.URLError, e:
+ logging.error(
+ 'Failed to reach HTTP server.Request URL: %s , Error: %s'
+ % (stop_sync_server_url, e.reason))
+ return False
+ else:
+ logging.info(
+ 'Stopped Sync Server Successfully.Request URL: %s , Response: %s'
+ % (stop_sync_server_url, response.readlines()))
+ response.fp._sock.recv = None
+ response.close()
+ return True
+
+
+def ShowGtestLikeFailure(test_exe_path, test_name):
+ """Show a gtest-like error when the test can't be run for some reason.
+
+ The scripts responsible for detecting test failures watch for this pattern.
+
+ Args:
+ test_exe_path: Absolute path to the test exe file.
+ test_name: The name of the test that wasn't run.
+ """
+ print '[ RUN ] %s.%s' % (os.path.basename(test_exe_path), test_name)
+ print '[ FAILED ] %s.%s' % (os.path.basename(test_exe_path), test_name)
+
+
+def RunCommand(command):
+ """Runs the command list, printing its output and returning its exit status.
+
+ Prints the given command (which should be a list of one or more strings),
+ then runs it and prints its stdout and stderr together to stdout,
+ line-buffered, converting line endings to CRLF (see note below). Waits for
+ the command to terminate and returns its status.
+
+ Args:
+ command: Command to run.
+
+ Returns:
+ Process exit code.
+ """
+ print '\n' + subprocess.list2cmdline(command) + '\n',
+ proc = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, bufsize=1)
+ last_flush_time = time.time()
+ while proc.poll() == None:
+ # Note that Windows Python converts \n to \r\n automatically whenever it
+ # encounters it written to a text file (including stdout). The only way
+ # around it is to write to a binary file, which isn't feasible for stdout.
+ # So we're stuck with \r\n here even though we explicitly write \n. (We
+ # could write \r instead, which doesn't get converted to \r\n, but that's
+ # probably more troublesome for people trying to read the files.)
+ line = proc.stdout.readline()
+ if line:
+ # The comma at the end tells python to not add \n, which is \r\n on
+ # Windows.
+ print line.rstrip() + '\n',
+ # Python on windows writes the buffer only when it reaches 4k. This is
+ # not fast enough. Flush each 10 seconds instead.
+ if time.time() - last_flush_time >= 10:
+ sys.stdout.flush()
+ last_flush_time = time.time()
+ sys.stdout.flush()
+ # Write the remaining buffer.
+ for line in proc.stdout.readlines():
+ print line.rstrip() + '\n',
+ sys.stdout.flush()
+ return proc.returncode
+
+
+def RunOneTest(test_exe_path, test_name, username, password):
+ """Run one live sync test after setting up a fresh server environment.
+
+ Args:
+ test_exe_path: Absolute path to test exe file.
+ test_name: the name of the one test to run.
+ username: test account username.
+ password: test account password.
+
+ Returns:
+ Zero for suceess.
+ Non-zero for failure.
+ """
+ def LogTestNotRun(message):
+ ShowGtestLikeFailure(test_exe_path, test_name)
+ logging.info('\n\n%s did not run because %s' % (test_name, message))
+
+ try:
+ logging.info('\n\n*************************************')
+ logging.info('%s Start' % (test_name))
+ sync_port = StartSyncServer()
+ if not sync_port:
+ LogTestNotRun('starting the sync server failed.')
+ return 1
+ if not CheckIfSyncServerRunning(sync_port):
+ LogTestNotRun('sync server running check failed.')
+ return 1
+ logging.info('Verified that sync server is running on port: %s', sync_port)
+ user_dir = GenericSetup(test_name)
+ logging.info('Created user data dir %s' % (user_dir))
+ command = [
+ test_exe_path,
+ '--gtest_filter='+ test_name,
+ '--user-data-dir=' + user_dir,
+ '--sync-user-for-test=' + username,
+ '--sync-password-for-test=' + password,
+ '--sync-url=' + HTTP_SERVER_URL,
+ '--sync-port=' + sync_port]
+ logging.info(
+ '%s will run with command: %s'
+ % (test_name, subprocess.list2cmdline(command)))
+ result = RunCommand(command)
+ StopSyncServer(sync_port)
+ return result
+ finally:
+ logging.info('%s End' % (test_name))
+
+
+def GenericSetup(test_name):
+ """Generic setup for running one test.
+
+ Args:
+ test_name: The name of a test that is about to be run.
+
+ Returns:
+ user_dir: Absolute path to user data dir created for the test.
+ """
+ user_dir = tempfile.mkdtemp(prefix=test_name + '.')
+ return user_dir
+
+
+def main_win(options, args):
+ """Main Function for win32 platform which drives the test here.
+
+ Using the target build configuration, run the executable given in the
+ first non-option argument, passing any following arguments to that
+ executable.
+
+ Args:
+ options: Option parameters.
+ args: Test arguments.
+
+ Returns:
+ Result: Zero for success/ Non-zero for failure.
+ """
+ final_result = 0
+ test_exe = 'sync_integration_tests.exe'
+ build_dir = os.path.abspath(options.build_dir)
+ test_exe_path = os.path.join(build_dir, options.target, test_exe)
+ if not os.path.exists(test_exe_path):
+ raise PathNotFound('Unable to find %s' % test_exe_path)
+ test_list = ListSyncTests(test_exe_path)
+ for test_name in test_list:
+ result = RunOneTest(
+ test_exe_path, test_name, options.sync_test_username,
+ options.sync_test_password)
+ # If any single test fails then final result should be failure
+ if result != 0:
+ final_result = result
+ return final_result
+
+if '__main__' == __name__:
+ # Initialize logging.
+ log_level = logging.INFO
+ logging.basicConfig(
+ level=log_level, format='%(asctime)s %(filename)s:%(lineno)-3d'
+ ' %(levelname)s %(message)s', datefmt='%y%m%d %H:%M:%S')
+
+ option_parser = optparse.OptionParser(usage=USAGE)
+
+ # Since the trailing program to run may have has command-line args of its
+ # own, we need to stop parsing when we reach the first positional argument.
+ option_parser.disable_interspersed_args()
+
+ option_parser.add_option(
+ '', '--target', default='Release', help='Build target (Debug or Release)'
+ ' Default value Release.')
+ option_parser.add_option(
+ '', '--build-dir', help='Path to main build directory'
+ '(the parent of the Release or Debug directory).')
+ option_parser.add_option(
+ '', '--http-server-url', help='Path to http server that can be used to'
+ ' start/stop sync server e.g. http://http_server_url_without_port')
+ option_parser.add_option(
+ '', '--http-server-port', help='Port on which http server is running'
+ ' e.g. 1010')
+ option_parser.add_option(
+ '', '--sync-test-username', help='Test username e.g. foo@gmail.com')
+ option_parser.add_option(
+ '', '--sync-test-password', help='Password for the test account')
+ options, args = option_parser.parse_args()
+ if (not options.build_dir or not options.http_server_url or
+ not options.http_server_port or not options.sync_test_username or
+ not options.sync_test_password):
+ sys.stderr.write('Missing required parameter, please fix it.\n')
+ option_parser.print_help()
+ sys.exit(1)
+ if sys.platform == 'win32':
+ HTTP_SERVER_URL = options.http_server_url
+ HTTP_SERVER_PORT = options.http_server_port
+ sys.exit(main_win(options, args))
+ else:
+ sys.stderr.write('Unknown sys.platform value %s\n' % repr(sys.platform))
+ sys.exit(1)
|