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

Unified Diff: tools/testing/run_selenium.py

Issue 9420037: reuse the same browser when running webdriver tests (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: added comment about processQueue Created 8 years, 10 months 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 side-by-side diff with in-line comments
Download patch
« tools/testing/dart/test_runner.dart ('K') | « tools/testing/dart/test_suite.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/testing/run_selenium.py
diff --git a/tools/testing/run_selenium.py b/tools/testing/run_selenium.py
index 93f2c1b723a8c90afd47e294d4925bf8c15d1582..8f129fb759ae4be580a392e317634ccd7bf6acfa 100755
--- a/tools/testing/run_selenium.py
+++ b/tools/testing/run_selenium.py
@@ -6,7 +6,25 @@
#
"""Script to actually open a browser and perform the test, and reports back with
-the result.
+the result. It uses Selenium WebDriver when possible for running the tests. It
+uses Selenium RC for Safari.
+
+If started with --batch this script runs a batch of in-browser tests in
+the same browser process.
+
+Normal mode:
+$ python run_selenium.py --browser=ff --timeout=60 path/to/test.html
+
+Exit code indicates pass or fail
+
+Batch mode:
+$ python run_selenium.py --batch
+stdin: --browser=ff --timeout=60 path/to/test.html
+stdout: >>> TEST PASS
+stdin: --browser=ff --timeout=60 path/to/test2.html
+stdout: >>> TEST FAIL
+stdin: --terminate
+$
"""
import os
@@ -18,6 +36,9 @@ import shutil
import socket
import sys
import time
+import signal
+
+TIMEOUT_ERROR_MSG = 'FAIL (timeout)'
def perf_test_done(driver):
"""Checks if the performance test has completed."""
@@ -35,10 +56,13 @@ def perf_test_done_helper(source):
return 'Score:' in source
def run_test_in_browser(browser, html_out, timeout, is_perf):
- """Run the desired test in the browser using Selenium 2.0 WebDriver syntax,
+ """Run the desired test in the browser using Selenium 2.0 WebDriver syntax,
and wait for the test to complete. This is the newer syntax, that currently
supports Firefox, Chrome, IE, Opera (and some mobile browsers)."""
- browser.get("file://" + html_out)
+ if isinstance(browser, selenium.selenium):
+ return run_test_in_browser_selenium_rc(browser, html_out, timeout, is_perf)
+
+ browser.get("file://" + html_out)
source = ''
try:
if is_perf:
@@ -50,25 +74,16 @@ def run_test_in_browser(browser, html_out, timeout, is_perf):
('FAIL' in driver.page_source))
source = browser.page_source
except selenium.common.exceptions.TimeoutException:
- source = 'FAIL (timeout)'
- finally:
- # A timeout exception is thrown if nothing happens within the time limit.
- if browser != 'chrome':
- browser.close()
- try:
- browser.quit()
- except selenium.common.exceptions.WebDriverException:
- #TODO(efortuna): figure out why this crashes.... and avoid?
- pass
+ source = TIMEOUT_ERROR_MSG
return source
-def run_test_in_browser_selenium1(sel, html_out, timeout, is_perf):
+def run_test_in_browser_selenium_rc(sel, html_out, timeout, is_perf):
""" Run the desired test in the browser using Selenium 1.0 syntax, and wait
for the test to complete. This is used for Safari, since it is not currently
supported on Selenium 2.0."""
sel.open('file://' + html_out)
source = sel.get_html_source()
- def end_condition(source):
+ def end_condition(source):
return 'PASS' in source or 'FAIL' in source
if is_perf:
end_condition = perf_test_done_helper
@@ -79,66 +94,78 @@ def run_test_in_browser_selenium1(sel, html_out, timeout, is_perf):
time.sleep(sec)
elapsed += sec
source = sel.get_html_source()
- sel.stop()
return source
-def parse_args():
+def parse_args(args=None):
parser = optparse.OptionParser()
- parser.add_option('--out', dest='out',
- help = 'The path for html output file that we will running our test from',
- action = 'store', default = '')
- parser.add_option('--browser', dest='browser',
- help = 'The browser type (default = chrome)',
+ parser.add_option('--out', dest='out',
+ help = 'The path for html output file that we will running our test from',
+ action = 'store', default = '')
+ parser.add_option('--browser', dest='browser',
+ help = 'The browser type (default = chrome)',
action = 'store', default = 'chrome')
- # TODO(efortuna): Put this back up to be more than the default timeout in
- # test.dart. Right now it needs to be less than 60 so that when test.dart
+ # TODO(efortuna): Put this back up to be more than the default timeout in
+ # test.dart. Right now it needs to be less than 60 so that when test.dart
# times out, this script also closes the browser windows.
- parser.add_option('--timeout', dest = 'timeout',
- help = 'Amount of time (seconds) to wait before timeout', type = 'int',
+ parser.add_option('--timeout', dest = 'timeout',
+ help = 'Amount of time (seconds) to wait before timeout', type = 'int',
action = 'store', default=58)
- parser.add_option('--perf', dest = 'is_perf',
- help = 'Add this flag if we are running a browser performance test',
+ parser.add_option('--perf', dest = 'is_perf',
+ help = 'Add this flag if we are running a browser performance test',
action = 'store_true', default=False)
- args, ignored = parser.parse_args()
+ args, ignored = parser.parse_args(args=args)
return args.out, args.browser, args.timeout, args.is_perf
-def Main():
- # Note: you need ChromeDriver *in your path* to run Chrome, in addition to
- # installing Chrome.
- browser = None
- html_out, browser, timeout, is_perf = parse_args()
-
+def start_browser(browser, html_out):
if browser == 'chrome':
- browser = selenium.webdriver.Chrome()
+ # Note: you need ChromeDriver *in your path* to run Chrome, in addition to
+ # installing Chrome. Also note that the build bot runs have a different path
+ # from a normal user -- check the build logs.
+ return selenium.webdriver.Chrome()
elif browser == 'ff':
profile = selenium.webdriver.firefox.firefox_profile.FirefoxProfile()
profile.set_preference('dom.max_script_run_time', 0)
profile.set_preference('dom.max_chrome_script_run_time', 0)
- browser = selenium.webdriver.Firefox(firefox_profile=profile)
+ return selenium.webdriver.Firefox(firefox_profile=profile)
elif browser == 'ie' and platform.system() == 'Windows':
- browser = selenium.webdriver.Ie()
+ return selenium.webdriver.Ie()
elif browser == 'safari' and platform.system() == 'Darwin':
- # TODO(efortuna): Ensure our preferences (no pop-up blocking) file is the
- # same (Safari auto-deletes when it has too many "crashes," or in our case,
+ # TODO(efortuna): Ensure our preferences (no pop-up blocking) file is the
+ # same (Safari auto-deletes when it has too many "crashes," or in our case,
# timeouts). Come up with a less hacky way to do this.
- shutil.copy(os.path.dirname(__file__) + '/com.apple.Safari.plist',
- '/Library/Preferences/com.apple.Safari.plist')
+ backup_safari_prefs = os.path.dirname(__file__) + '/com.apple.Safari.plist'
+ if os.path.exists(backup_safari_prefs):
+ shutil.copy(backup_safari_prefs,
+ '/Library/Preferences/com.apple.Safari.plist')
sel = selenium.selenium('localhost', 4444, "*safari", 'file://' + html_out)
try:
sel.start()
+ return sel
except socket.error:
print 'ERROR: Could not connect to Selenium RC server. Are you running' +\
' java -jar selenium-server-standalone-2.15.0.jar? If not, start ' + \
'it before running this test.'
- return 1
+ sys.exit(1)
else:
raise Exception('Incompatible browser and platform combination.')
- source = ''
- if browser == 'safari':
- source = run_test_in_browser_selenium1(sel, html_out, timeout, is_perf)
- else:
- source = run_test_in_browser(browser, html_out, timeout, is_perf)
+def close_browser(browser):
+ if browser is None:
+ return
+ if isinstance(browser, selenium.selenium):
+ browser.stop()
+ return
+
+ # A timeout exception is thrown if nothing happens within the time limit.
+ if browser != 'chrome':
+ browser.close()
+ try:
+ browser.quit()
+ except selenium.common.exceptions.WebDriverException:
+ # TODO(efortuna): Figure out why this crashes.... and avoid?
+ pass
+
+def report_results(is_perf, source):
if is_perf:
# We're running a performance test.
print source
@@ -152,16 +179,98 @@ def Main():
if 'FAIL' not in source and 'PASS' in source:
print 'Content-Type: text/plain\nPASS'
return 0
- else:
+ else:
#The hacky way to get document.getElementById('body').innerHTML for this
# webpage, without the JavaScript.
#TODO(efortuna): Access these elements in a nicer way using DOM parser.
index = source.find('<body>')
index += len('<body>')
end_index = source.find('<script')
- print source[index : end_index]
+ print unicode(source[index : end_index]).encode("utf-8")
return 1
+def run_batch_tests():
+ '''
+ Runs a batch of in-browser tests in the same browser process. Batching
+ gives faster throughput and makes tests less subject to browser starting
+ flakiness, issues with too many browser processes running, etc.
+
+ When running this function, stdin/stdout is used to communicate with the test
+ framework. See BatchRunnerProcess in test_runner.dart for the other side of
+ this communication channel
+
+ Example of usage:
+ $ python run_selenium.py --batch
+ stdin: --browser=ff --timeout=60 path/to/test.html
+ stdout: >>> TEST PASS
+ stdin: --browser=ff --timeout=60 path/to/test2.html
+ stdout: >>> TEST FAIL
+ stdin: --terminate
+ $
+ '''
+
+ print '>>> BATCH START'
+ browser = None
+ current_browser_name = None
+
+ # TODO(jmesserly): It'd be nice to shutdown gracefully in the event of a
+ # SIGTERM. Unfortunately dart:io cannot send SIGTERM, see dartbug.com/1756.
+ signal.signal(signal.SIGTERM, lambda number, frame: close_browser(browser))
+
+ try:
+ while True:
+ line = sys.stdin.readline()
+ if line == '--terminate\n':
+ break
+
+ html_out, browser_name, timeout, is_perf = parse_args(line.split())
+
+ # Sanity checks that test.dart is passing flags we can handle.
+ if is_perf:
+ print 'Batch test runner not compatible with perf testing'
+ return 1
+ if browser and current_browser_name != browser_name:
+ print('Batch test runner got multiple browsers: %s and %s'
+ % (current_browser_name, browser_name))
+ return 1
+
+ # Start the browser on the first run
+ if browser is None:
+ current_browser_name = browser_name
+ browser = start_browser(browser_name, html_out)
+
+ source = run_test_in_browser(browser, html_out, timeout, is_perf)
+
+ # print one of:
+ # >>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}
+ status = report_results(is_perf, source)
+ if status == 0:
+ print '>>> TEST PASS'
+ elif source == TIMEOUT_ERROR_MSG:
+ print '>>> TEST TIMEOUT'
+ else:
+ print '>>> TEST FAIL'
+ sys.stdout.flush()
+ finally:
+ close_browser(browser)
+
+
+def main(args):
+ # Run in batch mode if the --batch flag is passed.
+ # TODO(jmesserly): reconcile with the existing args parsing
+ if '--batch' in args:
+ return run_batch_tests()
+
+ # Run a single test
+ html_out, browser_name, timeout, is_perf = parse_args()
+ browser = start_browser(browser_name, html_out)
+
+ try:
+ output = run_test_in_browser(browser, html_out, timeout, is_perf)
+ return report_results(is_perf, output)
+ finally:
+ close_browser(browser)
+
if __name__ == "__main__":
- sys.exit(Main())
+ sys.exit(main(sys.argv))
« tools/testing/dart/test_runner.dart ('K') | « tools/testing/dart/test_suite.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698