mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
[infra] Remove obsolete webdriver/selenium support from testing
After this removal, the only thing in tools/testing is the checked-in jsshell (Mozilla command-line JavaScript runner) executable. Discussions for removing that as well have been started. Change-Id: I28505154de9fa7df3a2d5f84f3f778c596f52fcc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106087 Reviewed-by: Bob Nystrom <rnystrom@google.com>
This commit is contained in:
parent
770675b668
commit
707d3ccd14
|
@ -1,20 +0,0 @@
|
||||||
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
||||||
# for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
# BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
|
|
||||||
import test_runner
|
|
||||||
import utils
|
|
||||||
|
|
||||||
|
|
||||||
# Constants used for test outcomes
|
|
||||||
SKIP = 'skip'
|
|
||||||
FAIL = 'fail'
|
|
||||||
PASS = 'pass'
|
|
||||||
OKAY = 'okay'
|
|
||||||
TIMEOUT = 'timeout'
|
|
||||||
CRASH = 'crash'
|
|
||||||
SLOW = 'slow'
|
|
||||||
|
|
||||||
HOST_CPUS = utils.GuessCpus()
|
|
||||||
USE_DEFAULT_CPUS = -1
|
|
|
@ -1,29 +0,0 @@
|
||||||
Overview:
|
|
||||||
These are the instructions to run a wide variety of browser tests using
|
|
||||||
test.dart or dart/tools/testing/perf_testing/run_perf_tests.py. Currently
|
|
||||||
the results of run_perf_tests are uploaded to
|
|
||||||
https://dartperf.googleplex.com/.
|
|
||||||
|
|
||||||
========= General Browser Setup ==========
|
|
||||||
|
|
||||||
See instructions on:
|
|
||||||
https://code.google.com/p/dart/wiki/BrowserTestSetup
|
|
||||||
|
|
||||||
========= Proceed further only if you also want to run performance tests.======
|
|
||||||
|
|
||||||
1) Pull down benchmarks from internal repo (Google only): goto/dartbrowsersetup
|
|
||||||
|
|
||||||
2) Create a directory in called appengine-python in third_party. Download the
|
|
||||||
Linux/Other Platforms .zip file, and place the contents in the directory
|
|
||||||
you just created.
|
|
||||||
http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Python
|
|
||||||
|
|
||||||
3) Run the tests! While standing in dart/tools/testing/perf_testing, run
|
|
||||||
$> python run_perf_tests.py --forever --verbose
|
|
||||||
to run all the tests (browser performance, language correctness in the
|
|
||||||
browser, command line performance, and self-hosted compile time and compiled
|
|
||||||
code size).
|
|
||||||
|
|
||||||
You can run individual tests by adding the particular option (such as
|
|
||||||
--language) when running create_graph.py. Type "create_graph.py -h" for a
|
|
||||||
full list of the options.
|
|
Binary file not shown.
|
@ -1,90 +0,0 @@
|
||||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the background window. It can access the necessary APIs to get
|
|
||||||
* at the console messages. It can only communicate with the content
|
|
||||||
* window through message passing.
|
|
||||||
*
|
|
||||||
* There is no way to query the console messages, as such, but we can
|
|
||||||
* set up a handler that is called when there are console messages. This
|
|
||||||
* will be called with any console messages already present, so it can be set
|
|
||||||
* up after the fact. However, if there are no messages it won't be called.
|
|
||||||
* To handle the end of the messages (or no messages) we have to use a
|
|
||||||
* sentinel message that is logged by the content page.
|
|
||||||
*/
|
|
||||||
var version = "1.0";
|
|
||||||
var messages = []; // An array that we can put messages in.
|
|
||||||
var debuggeeId; // An object that identifies the browser tab we are talking to.
|
|
||||||
var callback; // For passing back the response to the content window.
|
|
||||||
var timer; // To time out if no messages are available.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When we have collected all the messages, we send them back to the
|
|
||||||
* content page via the callback, turn off message collection, and
|
|
||||||
* detach the debugger from the browser tab.
|
|
||||||
*/
|
|
||||||
function allDone() {
|
|
||||||
callback(messages);
|
|
||||||
chrome.debugger.sendCommand(debuggeeId, "Console.clearMessages", {},
|
|
||||||
function() {
|
|
||||||
chrome.debugger.sendCommand(debuggeeId, "Console.disable", {},
|
|
||||||
function() {});
|
|
||||||
chrome.debugger.detach(debuggeeId, function() {});
|
|
||||||
});
|
|
||||||
messages = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debugger event handler. We only care about console.messageAdded
|
|
||||||
* events, in which case we add a new message object with the fields
|
|
||||||
* we care about to our messages array.
|
|
||||||
*/
|
|
||||||
function onEvent(debuggeeId, method, params) {
|
|
||||||
var tabId = debuggeeId.tabId;
|
|
||||||
if (method == "Console.messageAdded") {
|
|
||||||
var msg = params.message;
|
|
||||||
// More fields are available if we want them later. See
|
|
||||||
// https://developers.google.com/chrome-developer-tools/docs/protocol/1.0/console#type-ConsoleMessage
|
|
||||||
if (msg.text == 'getMessages/end') {
|
|
||||||
allDone();
|
|
||||||
} else {
|
|
||||||
messages.push({"source":msg.url, "line": msg.line,
|
|
||||||
"category":msg.source, "message":msg.text });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle requests sent by the content script. We save the callback,
|
|
||||||
* get the window and tab that is currently active, attach the
|
|
||||||
* debugger to that tab, and then turn on console message event
|
|
||||||
* handling, which will result in onEvent calls for each console
|
|
||||||
* message, including the ones that are already present in the console.
|
|
||||||
*/
|
|
||||||
function onRequest(request, sender, sendResponse) {
|
|
||||||
if (request.command == "getMessages") {
|
|
||||||
callback = sendResponse;
|
|
||||||
chrome.windows.getCurrent(function(win) {
|
|
||||||
chrome.tabs.getSelected(win.id, function(tab) {
|
|
||||||
debuggeeId = {tabId:tab.id};
|
|
||||||
chrome.debugger.attach(debuggeeId, version, function() {
|
|
||||||
if (chrome.extension.lastError) {
|
|
||||||
// Attach failed; send an empty response.
|
|
||||||
callback([]);
|
|
||||||
} else {
|
|
||||||
chrome.debugger.sendCommand(debuggeeId, "Console.enable", {},
|
|
||||||
function() {});
|
|
||||||
//timer = setTimeout(allDone, 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up the general handler for debug events.
|
|
||||||
chrome.debugger.onEvent.addListener(onEvent);
|
|
||||||
// Listen for the content script to send a message to the background page.
|
|
||||||
chrome.extension.onRequest.addListener(onRequest);
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the content page script. This runs in the context of the browser
|
|
||||||
* page, and communicates with the background page by relaying a getMessages
|
|
||||||
* request, and the forwarding the messages back to the browser page as a
|
|
||||||
* gotMessages message.
|
|
||||||
*/
|
|
||||||
window.addEventListener("message", function(event) {
|
|
||||||
if (event.source == window && event.data == "getMessages") {
|
|
||||||
// Log a special sentinel message to mark the end of the messages.
|
|
||||||
console.log('getMessages/end');
|
|
||||||
chrome.extension.sendRequest({command: "getMessages"}, function(messages) {
|
|
||||||
window.postMessage({ "type": "gotMessages", "messages" : messages}, "*");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, false);
|
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Console Collector",
|
|
||||||
"version": "1.0",
|
|
||||||
"manifest_version": 2,
|
|
||||||
"description": "Allow querying of the Javascript console.",
|
|
||||||
"browser_action": {
|
|
||||||
"name": "ConsoleCollector"
|
|
||||||
},
|
|
||||||
"background": {
|
|
||||||
"scripts": ["background.js"],
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"content_scripts": [
|
|
||||||
{
|
|
||||||
"matches": ["http://*/*", "file://*" ],
|
|
||||||
"js": [ "content.js" ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"permissions": [
|
|
||||||
"tabs", "http://*/*", "file://*", "debugger"
|
|
||||||
]
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,2 +0,0 @@
|
||||||
../ConsoleCollector.xpi: chrome.manifest install.rdf chrome/content/console.js chrome/content/overlay.xul
|
|
||||||
zip -r ../ConsoleCollector.xpi chrome.manifest install.rdf chrome/content/console.js chrome/content/overlay.xul
|
|
|
@ -1,2 +0,0 @@
|
||||||
content ConsoleCollector chrome/content/
|
|
||||||
overlay chrome://browser/content/browser.xul chrome://ConsoleCollector/content/overlay.xul
|
|
|
@ -1,104 +0,0 @@
|
||||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// This Firefox add-on exposes the Javascript console contents to Javascript
|
|
||||||
// running in the browser. Once this is installed there will be a new
|
|
||||||
// window.ConsoleCollector object with read() and clear() functions.
|
|
||||||
|
|
||||||
var ConsoleCollector = {};
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
// An array for collecting the messages.
|
|
||||||
var messages = [];
|
|
||||||
|
|
||||||
// Add a console message to the collection.
|
|
||||||
this.add = function(message) {
|
|
||||||
messages.push(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read the message collection. As a side effect we clear the message list.
|
|
||||||
this.read = function(type) {
|
|
||||||
var rtn = [];
|
|
||||||
for (var i = 0; i < messages.length; i++) {
|
|
||||||
var message = messages[i];
|
|
||||||
if (message.errorMessage) {
|
|
||||||
rtn.push({ 'time' : message.timeStamp,
|
|
||||||
'source' : message.sourceName,
|
|
||||||
'line': message.lineNumber,
|
|
||||||
'column': message.columnNumber,
|
|
||||||
'category': message.category,
|
|
||||||
'message' : message.errorMessage });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
messages = [];
|
|
||||||
return rtn;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear the message list.
|
|
||||||
this.clear = function() {
|
|
||||||
messages = [];
|
|
||||||
};
|
|
||||||
}).apply(ConsoleCollector);
|
|
||||||
|
|
||||||
// A Console Listener.
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Console_service for
|
|
||||||
// details.
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
var consoleService;
|
|
||||||
|
|
||||||
var consoleListener = {
|
|
||||||
observe: function(e) {
|
|
||||||
try {
|
|
||||||
var message = e.QueryInterface(Components.interfaces.nsIScriptError);
|
|
||||||
ConsoleCollector.add(message);
|
|
||||||
} catch (exception) {
|
|
||||||
ConsoleCollector.add(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
QueryInterface: function (iid) {
|
|
||||||
if (!iid.equals(Components.interfaces.nsIConsoleListener) &&
|
|
||||||
!iid.equals(Components.interfaces.nsISupports)) {
|
|
||||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start collecting console messages.
|
|
||||||
function initialize(event) {
|
|
||||||
consoleService = Components.classes['@mozilla.org/consoleservice;1']
|
|
||||||
.getService(Components.interfaces.nsIConsoleService);
|
|
||||||
if (consoleService) {
|
|
||||||
consoleService.registerListener(consoleListener);
|
|
||||||
}
|
|
||||||
// Add the handler for hooking in to each page's DOM. This handler
|
|
||||||
// is for each "gBrowser", representing a tab/window.
|
|
||||||
window.getBrowser().addEventListener("load", onPageLoad, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop collecting console messages.
|
|
||||||
function shutdown(event) {
|
|
||||||
window.getBrowser().removeEventListener("load", onPageLoad);
|
|
||||||
consoleService.unregisterListener(consoleListener);
|
|
||||||
ConsoleCollector.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook the ConsoleCollector into the DOM as window.ConsoleCollector.
|
|
||||||
var onPageLoad = function(e) {
|
|
||||||
var win = e.originalTarget.defaultView;
|
|
||||||
if (win) {
|
|
||||||
win.wrappedJSObject.ConsoleCollector = ConsoleCollector;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the handlers to initialize the add-on and shut it down.
|
|
||||||
// These handlers are for the application as a whole.
|
|
||||||
window.addEventListener('load', initialize, false);
|
|
||||||
window.addEventListener('unload', shutdown, false);
|
|
||||||
}());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<overlay id="ConsoleCollector-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
||||||
<script src="console.js"/>
|
|
||||||
</overlay>
|
|
|
@ -1,20 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
|
||||||
<Description about="urn:mozilla:install-manifest">
|
|
||||||
<em:id>ConsoleCollector@google.com</em:id>
|
|
||||||
<em:name>Console collector</em:name>
|
|
||||||
<em:version>0.2</em:version>
|
|
||||||
<em:description>Exposes the Javascript console to each browser window.
|
|
||||||
</em:description>
|
|
||||||
<em:creator>Graham Wheeler</em:creator>
|
|
||||||
<em:homepageURL>http://www.dartlang.org</em:homepageURL>
|
|
||||||
<em:targetApplication>
|
|
||||||
<Description>
|
|
||||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
|
|
||||||
<em:minVersion>3.0</em:minVersion>
|
|
||||||
<em:maxVersion>15.0</em:maxVersion>
|
|
||||||
</Description>
|
|
||||||
</em:targetApplication>
|
|
||||||
</Description>
|
|
||||||
</RDF>
|
|
|
@ -1,390 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
||||||
# for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
# BSD-style license that can be found in the LICENSE file.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""Script to actually open a browser and perform the test, and reports back with
|
|
||||||
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
|
|
||||||
import optparse
|
|
||||||
import platform
|
|
||||||
import selenium
|
|
||||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
|
||||||
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
|
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
|
||||||
import shutil
|
|
||||||
import signal
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import urllib2
|
|
||||||
import threading
|
|
||||||
|
|
||||||
TIMEOUT_ERROR_MSG = 'FAIL (timeout)'
|
|
||||||
CRASH_ERROR_MSG = 'CRASH'
|
|
||||||
|
|
||||||
def correctness_test_done(source):
|
|
||||||
"""Checks if test has completed."""
|
|
||||||
return ('PASS' in source) or ('FAIL' in source)
|
|
||||||
|
|
||||||
def perf_test_done(source):
|
|
||||||
"""Tests to see if our performance test is done by printing a score."""
|
|
||||||
#This code is written this way to work around a current instability in the
|
|
||||||
# python webdriver bindings if you call driver.get_element_by_id.
|
|
||||||
#TODO(efortuna): Access these elements in a nicer way using DOM parser.
|
|
||||||
string = '<div id="status">'
|
|
||||||
index = source.find(string)
|
|
||||||
end_index = source.find('</div>', index+1)
|
|
||||||
source = source[index + len(string):end_index]
|
|
||||||
return 'Score:' in source
|
|
||||||
|
|
||||||
# TODO(vsm): Ideally, this wouldn't live in this file.
|
|
||||||
CONFIGURATIONS = {
|
|
||||||
'correctness': correctness_test_done,
|
|
||||||
'perf': perf_test_done
|
|
||||||
}
|
|
||||||
|
|
||||||
def run_test_in_browser(browser, html_out, timeout, mode, refresh):
|
|
||||||
"""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)."""
|
|
||||||
|
|
||||||
if isinstance(browser, selenium.selenium):
|
|
||||||
return run_test_in_browser_selenium_rc(browser, html_out, timeout, mode,
|
|
||||||
refresh)
|
|
||||||
|
|
||||||
browser.get(html_out)
|
|
||||||
if refresh:
|
|
||||||
browser.refresh()
|
|
||||||
try:
|
|
||||||
def pythonTimeout():
|
|
||||||
# The builtin quit call for chrome will call close on the RemoteDriver
|
|
||||||
# which may hang. Explicitly call browser.service.stop()
|
|
||||||
if (type(browser) is selenium.webdriver.chrome.webdriver.WebDriver):
|
|
||||||
# Browser may be dead
|
|
||||||
try:
|
|
||||||
browser.service.stop()
|
|
||||||
except:
|
|
||||||
print("Trying to close browser that has already been closed")
|
|
||||||
# If the browser is crashing selenium may not time out.
|
|
||||||
# Explicitly catch this case with a python timer.
|
|
||||||
t = threading.Timer(timeout, pythonTimeout)
|
|
||||||
t.start()
|
|
||||||
test_done = CONFIGURATIONS[mode]
|
|
||||||
element = WebDriverWait(browser, float(timeout)).until(
|
|
||||||
lambda driver: test_done(driver.page_source))
|
|
||||||
t.cancel()
|
|
||||||
return browser.page_source
|
|
||||||
except selenium.common.exceptions.TimeoutException:
|
|
||||||
return TIMEOUT_ERROR_MSG
|
|
||||||
except:
|
|
||||||
return CRASH_ERROR_MSG
|
|
||||||
|
|
||||||
def run_test_in_browser_selenium_rc(sel, html_out, timeout, mode, refresh):
|
|
||||||
""" 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(html_out)
|
|
||||||
if refresh:
|
|
||||||
sel.refresh()
|
|
||||||
source = sel.get_html_source()
|
|
||||||
end_condition = CONFIGURATIONS[mode]
|
|
||||||
|
|
||||||
elapsed = 0
|
|
||||||
while (not end_condition(source)) and elapsed <= timeout:
|
|
||||||
sec = .25
|
|
||||||
time.sleep(sec)
|
|
||||||
elapsed += sec
|
|
||||||
source = sel.get_html_source()
|
|
||||||
return source
|
|
||||||
|
|
||||||
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)',
|
|
||||||
action = 'store', default = 'chrome')
|
|
||||||
parser.add_option('--executable', dest='executable',
|
|
||||||
help = 'The browser executable path (only for browser=dartium)',
|
|
||||||
action = 'store', default = None)
|
|
||||||
# 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',
|
|
||||||
action = 'store', default=58)
|
|
||||||
parser.add_option('--mode', dest = 'mode',
|
|
||||||
help = 'The type of test we are running',
|
|
||||||
action = 'store', default='correctness')
|
|
||||||
parser.add_option('--force-refresh', dest='refresh',
|
|
||||||
help='Force the browser to refresh before getting results from this test '
|
|
||||||
'(used for browser multitests).', action='store_true', default=False)
|
|
||||||
args, _ = parser.parse_args(args=args)
|
|
||||||
args.out = args.out.strip('"')
|
|
||||||
if args.executable and args.browser != 'dartium':
|
|
||||||
print 'Executable path only supported when browser=dartium.'
|
|
||||||
sys.exit(1)
|
|
||||||
return (args.out, args.browser, args.executable, args.timeout, args.mode,
|
|
||||||
args.refresh)
|
|
||||||
|
|
||||||
def print_server_error():
|
|
||||||
"""Provide the user an informative error message if we attempt to connect to
|
|
||||||
the Selenium remote control server, but cannot access it. Then exit the
|
|
||||||
program."""
|
|
||||||
print ('ERROR: Could not connect to Selenium RC server. Are you running'
|
|
||||||
' java -jar tools/testing/selenium-server-standalone-*.jar? If not, '
|
|
||||||
'start it before running this test.')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def start_browser(browser, executable_path, html_out):
|
|
||||||
if browser == 'chrome' or browser == 'dartium':
|
|
||||||
# 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.
|
|
||||||
options = selenium.webdriver.chrome.options.Options()
|
|
||||||
if browser == 'dartium':
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
dartium_dir = os.path.join(script_dir, '..', '..', 'client', 'tests',
|
|
||||||
'dartium')
|
|
||||||
# enable ShadowDOM and style scoped for Dartium
|
|
||||||
options.add_argument('--enable-shadow-dom')
|
|
||||||
options.add_argument('--enable-style-scoped')
|
|
||||||
if executable_path is not None:
|
|
||||||
options.binary_location = executable_path
|
|
||||||
elif platform.system() == 'Windows':
|
|
||||||
options.binary_location = os.path.join(dartium_dir, 'chrome.exe')
|
|
||||||
elif platform.system() == 'Darwin':
|
|
||||||
options.binary_location = os.path.join(dartium_dir, 'Chromium.app',
|
|
||||||
'Contents', 'MacOS', 'Chromium')
|
|
||||||
else:
|
|
||||||
options.binary_location = os.path.join(dartium_dir, 'chrome')
|
|
||||||
return selenium.webdriver.Chrome(chrome_options=options)
|
|
||||||
elif browser == 'ff':
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
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)
|
|
||||||
profile.set_preference('app.update.auto', True)
|
|
||||||
profile.set_preference('app.update.enabled', True)
|
|
||||||
return selenium.webdriver.Firefox(firefox_profile=profile)
|
|
||||||
elif ((browser == 'ie9' or browser == 'ie10') and
|
|
||||||
platform.system() == 'Windows'):
|
|
||||||
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,
|
|
||||||
# timeouts). Come up with a less hacky way to do this.
|
|
||||||
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", html_out)
|
|
||||||
try:
|
|
||||||
sel.start()
|
|
||||||
return sel
|
|
||||||
except socket.error:
|
|
||||||
print_server_error()
|
|
||||||
elif browser == 'opera':
|
|
||||||
try:
|
|
||||||
driver = RemoteWebDriver(desired_capabilities=DesiredCapabilities.OPERA)
|
|
||||||
# By default, Opera sets their script timeout (the amount of time they
|
|
||||||
# expect to hear back from the JavaScript file) to be 10 seconds. We just
|
|
||||||
# make it an impossibly large number so that it doesn't time out for this
|
|
||||||
# reason, so it behaves like all of the other browser drivers.
|
|
||||||
driver.set_script_timeout(9000)
|
|
||||||
# If the webpage contains document.onreadystatechanged = function() {...}
|
|
||||||
# page load event does not correctly get fired and caught (OperaDriver
|
|
||||||
# bug). This is a band-aid.
|
|
||||||
driver.set_page_load_timeout(1)
|
|
||||||
return driver
|
|
||||||
except urllib2.URLError:
|
|
||||||
print_server_error()
|
|
||||||
else:
|
|
||||||
raise Exception('Incompatible browser and platform combination.')
|
|
||||||
|
|
||||||
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 (type(browser) is not selenium.webdriver.chrome.webdriver.WebDriver and
|
|
||||||
type(browser) is not selenium.webdriver.ie.webdriver.WebDriver):
|
|
||||||
browser.close()
|
|
||||||
|
|
||||||
browser.quit()
|
|
||||||
|
|
||||||
def report_results(mode, source, browser):
|
|
||||||
if mode != 'correctness':
|
|
||||||
# We're running a performance test.
|
|
||||||
print source.encode('utf8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
if 'NaN' in source:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
# We're running a correctness test. Mark test as passing if all individual
|
|
||||||
# test cases pass.
|
|
||||||
if 'FAIL' not in source and 'PASS' in source:
|
|
||||||
print 'Content-Type: text/plain\nPASS'
|
|
||||||
return 0
|
|
||||||
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('</body')
|
|
||||||
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:
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
line = sys.stdin.readline()
|
|
||||||
if line == '--terminate\n':
|
|
||||||
print("Terminating selenium driver")
|
|
||||||
break
|
|
||||||
|
|
||||||
(html_out, browser_name, executable_path,
|
|
||||||
timeout, mode, refresh) = parse_args(line.split())
|
|
||||||
|
|
||||||
# Sanity checks that test.dart is passing flags we can handle.
|
|
||||||
if mode != 'correctness':
|
|
||||||
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, executable_path, html_out)
|
|
||||||
|
|
||||||
source = run_test_in_browser(browser, html_out, timeout, mode, refresh)
|
|
||||||
|
|
||||||
# Test is done. Write end token to stderr and flush.
|
|
||||||
sys.stderr.write('>>> EOF STDERR\n')
|
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
# print one of:
|
|
||||||
# >>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}
|
|
||||||
status = report_results(mode, source, browser)
|
|
||||||
if status == 0:
|
|
||||||
print '>>> TEST PASS'
|
|
||||||
elif source == TIMEOUT_ERROR_MSG:
|
|
||||||
print '>>> TEST TIMEOUT'
|
|
||||||
elif source == CRASH_ERROR_MSG:
|
|
||||||
print '>>> TEST CRASH'
|
|
||||||
# The browser crashed, set the browser to None so that we will
|
|
||||||
# create a new instance on next iteration.
|
|
||||||
browser = None
|
|
||||||
else:
|
|
||||||
print '>>> TEST FAIL'
|
|
||||||
sys.stdout.flush()
|
|
||||||
except:
|
|
||||||
type, value, traceback = sys.exc_info()
|
|
||||||
print "run_selenium.py: Unexpected exception occured: "
|
|
||||||
print " type: ", type
|
|
||||||
print " value: ", value
|
|
||||||
print " traceback: ", traceback
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
sys.stdin.close()
|
|
||||||
print("Closing browser");
|
|
||||||
|
|
||||||
def close_output_streams():
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stdout.close()
|
|
||||||
sys.stderr.flush()
|
|
||||||
sys.stderr.close()
|
|
||||||
|
|
||||||
def close_and_exit():
|
|
||||||
print("Timed out waiting for browser to close")
|
|
||||||
close_output_streams()
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
timer = threading.Timer(5.0, close_and_exit)
|
|
||||||
timer.start()
|
|
||||||
try:
|
|
||||||
close_browser(browser)
|
|
||||||
timer.cancel()
|
|
||||||
finally:
|
|
||||||
close_output_streams()
|
|
||||||
|
|
||||||
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, executable_path, timeout, mode, refresh = parse_args()
|
|
||||||
browser = start_browser(browser_name, executable_path, html_out)
|
|
||||||
|
|
||||||
try:
|
|
||||||
output = run_test_in_browser(browser, html_out, timeout, mode, refresh)
|
|
||||||
return report_results(mode, output, browser)
|
|
||||||
finally:
|
|
||||||
close_browser(browser)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main(sys.argv))
|
|
|
@ -1,434 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
||||||
# for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
# BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
# Run to install the necessary components to run webdriver on the buildbots or
|
|
||||||
# on your local machine.
|
|
||||||
# Note: The setup steps can be done fairly easily by hand. This script is
|
|
||||||
# intended to simply and reduce the time for setup since there are a fair number
|
|
||||||
# of steps.
|
|
||||||
|
|
||||||
# TODO(efortuna): Rewrite this script in Dart when the Process module has a
|
|
||||||
# better high level API.
|
|
||||||
import HTMLParser
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import string
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
def run_cmd(cmd, stdin=None):
|
|
||||||
"""Run the command on the command line in the shell. We print the output of
|
|
||||||
the command.
|
|
||||||
"""
|
|
||||||
print cmd
|
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
||||||
stdin=subprocess.PIPE, shell=True)
|
|
||||||
output, stderr = p.communicate(input=stdin)
|
|
||||||
if output:
|
|
||||||
print output
|
|
||||||
if stderr:
|
|
||||||
print stderr
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
parser.add_option('--firefox', '-f', dest='firefox',
|
|
||||||
help="Don't install Firefox", action='store_true', default=False)
|
|
||||||
parser.add_option('--opera', '-o', dest='opera', default=False,
|
|
||||||
help="Don't install Opera", action='store_true')
|
|
||||||
parser.add_option('--chromedriver', '-c', dest='chromedriver',
|
|
||||||
help="Don't install chromedriver.", action='store_true', default=False)
|
|
||||||
parser.add_option('--iedriver', '-i', dest='iedriver',
|
|
||||||
help="Don't install iedriver (only used on Windows).",
|
|
||||||
action='store_true', default=False)
|
|
||||||
parser.add_option('--seleniumrc', '-s', dest='seleniumrc',
|
|
||||||
help="Don't install the Selenium RC server (used for Safari and Opera "
|
|
||||||
"tests).", action='store_true', default=False)
|
|
||||||
parser.add_option('--python', '-p', dest='python',
|
|
||||||
help="Don't install Selenium python bindings.", action='store_true',
|
|
||||||
default=False)
|
|
||||||
parser.add_option('--buildbot', '-b', dest='buildbot', action='store_true',
|
|
||||||
help='Perform a buildbot selenium setup (buildbots have a different' +
|
|
||||||
'location for their python executable).', default=False)
|
|
||||||
args, _ = parser.parse_args()
|
|
||||||
return args
|
|
||||||
|
|
||||||
def find_depot_tools_location(is_buildbot):
|
|
||||||
"""Depot_tools is our default install location for chromedriver, so we find
|
|
||||||
its location on the filesystem.
|
|
||||||
Arguments:
|
|
||||||
is_buildbot - True if we are running buildbot machine setup (we can't detect
|
|
||||||
this automatically because this script is not run at build time).
|
|
||||||
"""
|
|
||||||
if is_buildbot:
|
|
||||||
depot_tools = os.sep + os.path.join('b', 'depot_tools')
|
|
||||||
if 'win32' in sys.platform or 'cygwin' in sys.platform:
|
|
||||||
depot_tools = os.path.join('e:', depot_tools)
|
|
||||||
return depot_tools
|
|
||||||
else:
|
|
||||||
path = os.environ['PATH'].split(os.pathsep)
|
|
||||||
for loc in path:
|
|
||||||
if 'depot_tools' in loc:
|
|
||||||
return loc
|
|
||||||
raise Exception("Could not find depot_tools in your path.")
|
|
||||||
|
|
||||||
class GoogleBasedInstaller(object):
|
|
||||||
"""Install a project from a Google source, pulling latest version."""
|
|
||||||
|
|
||||||
def __init__(self, project_name, destination, download_path_func):
|
|
||||||
"""Create an object that will install the project.
|
|
||||||
Arguments:
|
|
||||||
project_name - Google code name of the project, such as "selenium" or
|
|
||||||
"chromedriver."
|
|
||||||
destination - Where to download the desired file on our filesystem.
|
|
||||||
download_path_func - A function that takes a dictionary (currently with keys
|
|
||||||
"os" and "version", but more can be added) that calculates the string
|
|
||||||
representing the path of the download we want.
|
|
||||||
"""
|
|
||||||
self.project_name = project_name
|
|
||||||
self.destination = destination
|
|
||||||
self.download_path_func = download_path_func
|
|
||||||
|
|
||||||
@property
|
|
||||||
def get_os_str(self):
|
|
||||||
"""The strings to indicate what OS a download is for."""
|
|
||||||
os_str = 'win'
|
|
||||||
if 'darwin' in sys.platform:
|
|
||||||
os_str = 'mac'
|
|
||||||
elif 'linux' in sys.platform:
|
|
||||||
os_str = 'linux32'
|
|
||||||
if '64bit' in platform.architecture()[0]:
|
|
||||||
os_str = 'linux64'
|
|
||||||
if self.project_name == 'chromedriver' and (
|
|
||||||
os_str == 'mac' or os_str == 'win'):
|
|
||||||
os_str += '32'
|
|
||||||
return os_str
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""Download and install the project."""
|
|
||||||
print 'Installing %s' % self.project_name
|
|
||||||
os_str = self.get_os_str
|
|
||||||
version = self.find_latest_version()
|
|
||||||
download_path = self.download_path_func({'os': os_str, 'version': version})
|
|
||||||
download_name = os.path.basename(download_path)
|
|
||||||
urllib.urlretrieve(os.path.join(self.source_path(), download_path),
|
|
||||||
os.path.join(self.destination, download_name))
|
|
||||||
if download_name.endswith('.zip'):
|
|
||||||
if platform.system() != 'Windows':
|
|
||||||
# The Python zip utility does not preserve executable permissions, but
|
|
||||||
# this does not seem to be a problem for Windows, which does not have a
|
|
||||||
# built in zip utility. :-/
|
|
||||||
run_cmd('unzip -u %s -d %s' % (os.path.join(self.destination,
|
|
||||||
download_name), self.destination), stdin='y')
|
|
||||||
else:
|
|
||||||
z = zipfile.ZipFile(os.path.join(self.destination, download_name))
|
|
||||||
z.extractall(self.destination)
|
|
||||||
z.close()
|
|
||||||
os.remove(os.path.join(self.destination, download_name))
|
|
||||||
chrome_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
||||||
'orig-chromedriver')
|
|
||||||
if self.project_name == 'chromedriver' and os.path.exists(chrome_path):
|
|
||||||
# We have one additional location to make sure chromedriver is updated.
|
|
||||||
# TODO(efortuna): Remove this. See move_chrome_driver_if_needed in
|
|
||||||
# perf_testing/run_perf_tests.py
|
|
||||||
driver = 'chromedriver'
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
driver += '.exe'
|
|
||||||
shutil.copy(os.path.join(self.destination, driver),
|
|
||||||
os.path.join(chrome_path, driver))
|
|
||||||
|
|
||||||
class ChromeDriverInstaller(GoogleBasedInstaller):
|
|
||||||
"""Install chromedriver from Google Storage."""
|
|
||||||
|
|
||||||
def __init__(self, destination):
|
|
||||||
"""Create an object to install ChromeDriver
|
|
||||||
destination - Where to download the desired file on our filesystem.
|
|
||||||
"""
|
|
||||||
super(ChromeDriverInstaller, self).__init__('chromedriver', destination,
|
|
||||||
lambda x: '%(version)s/chromedriver_%(os)s.zip' % x)
|
|
||||||
|
|
||||||
def find_latest_version(self):
|
|
||||||
"""Find the latest version number of ChromeDriver."""
|
|
||||||
source_page = urllib2.urlopen(self.source_path())
|
|
||||||
source_text = source_page.read()
|
|
||||||
regex = re.compile('(?:<Key>)(\d+\.\d+)')
|
|
||||||
latest = max(regex.findall(source_text))
|
|
||||||
return latest
|
|
||||||
|
|
||||||
def source_path(self):
|
|
||||||
return 'http://chromedriver.storage.googleapis.com'
|
|
||||||
|
|
||||||
class GoogleCodeInstaller(GoogleBasedInstaller):
|
|
||||||
"""Install a project from Google Code."""
|
|
||||||
|
|
||||||
def google_code_downloads_page(self):
|
|
||||||
return 'http://code.google.com/p/%s/downloads/list' % self.project_name
|
|
||||||
|
|
||||||
def find_latest_version(self):
|
|
||||||
"""Find the latest version number of some code available for download on a
|
|
||||||
Google code page. This was unfortunately done in an ad hoc manner because
|
|
||||||
Google Code does not seem to have an API for their list of current
|
|
||||||
downloads(!).
|
|
||||||
"""
|
|
||||||
google_code_site = self.google_code_downloads_page()
|
|
||||||
f = urllib2.urlopen(google_code_site)
|
|
||||||
latest = ''
|
|
||||||
|
|
||||||
download_regex_str = self.download_path_func({'os': self.get_os_str,
|
|
||||||
'version': '.+'})
|
|
||||||
|
|
||||||
for line in f.readlines():
|
|
||||||
if re.search(download_regex_str, line):
|
|
||||||
suffix_index = line.find(
|
|
||||||
download_regex_str[download_regex_str.rfind('.'):])
|
|
||||||
name_end = download_regex_str.rfind('.+')
|
|
||||||
name = self.download_path_func({'os': self.get_os_str, 'version': ''})
|
|
||||||
name = name[:name.rfind('.')]
|
|
||||||
version_str = line[line.find(name) + len(name) : suffix_index]
|
|
||||||
orig_version_str = version_str
|
|
||||||
if version_str.count('.') == 0:
|
|
||||||
version_str = version_str.replace('_', '.')
|
|
||||||
version_str = re.compile(r'[^\d.]+').sub('', version_str)
|
|
||||||
if latest == '':
|
|
||||||
latest = '0.' * version_str.count('.')
|
|
||||||
latest += '0'
|
|
||||||
orig_latest_str = latest
|
|
||||||
else:
|
|
||||||
orig_latest_str = latest
|
|
||||||
latest = latest.replace('_', '.')
|
|
||||||
latest = re.compile(r'[^\d.]+').sub('', latest)
|
|
||||||
nums = version_str.split('.')
|
|
||||||
latest_nums = latest.split('.')
|
|
||||||
for (num, latest_num) in zip(nums, latest_nums):
|
|
||||||
if int(num) > int(latest_num):
|
|
||||||
latest = orig_version_str
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
latest = orig_latest_str
|
|
||||||
if latest == '':
|
|
||||||
raise Exception("Couldn't find the desired download on " + \
|
|
||||||
' %s.' % google_code_site)
|
|
||||||
return latest
|
|
||||||
|
|
||||||
def source_path(self):
|
|
||||||
return 'http://%s.googlecode.com/files/' % self.project_name
|
|
||||||
|
|
||||||
|
|
||||||
class FirefoxInstaller(object):
|
|
||||||
"""Installs the latest version of Firefox on the machine."""
|
|
||||||
|
|
||||||
def ff_download_site(self, os_name):
|
|
||||||
return 'http://releases.mozilla.org/pub/mozilla.org/firefox/releases/' + \
|
|
||||||
'latest/%s/en-US/' % os_name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def get_os_str(self):
|
|
||||||
"""Returns the string that Mozilla uses to denote which operating system a
|
|
||||||
Firefox binary is for."""
|
|
||||||
os_str = ('win32', '.exe')
|
|
||||||
if 'darwin' in sys.platform:
|
|
||||||
os_str = ('mac', '.dmg')
|
|
||||||
elif 'linux' in sys.platform:
|
|
||||||
os_str = ('linux-i686', '.tar.bz2')
|
|
||||||
if '64bit' in platform.architecture()[0]:
|
|
||||||
os_str = ('linux-x86_64', '.tar.bz2')
|
|
||||||
return os_str
|
|
||||||
|
|
||||||
def get_download_url(self):
|
|
||||||
"""Parse the html on the page to determine what is the latest download
|
|
||||||
appropriate for our system."""
|
|
||||||
f = urllib2.urlopen(self.ff_download_site(self.get_os_str[0]))
|
|
||||||
download_name = ''
|
|
||||||
for line in f.readlines():
|
|
||||||
suffix = self.get_os_str[1]
|
|
||||||
if (suffix + '"') in line:
|
|
||||||
link_str = '<a href="'
|
|
||||||
download_name = line[line.find(link_str) + len(link_str) : \
|
|
||||||
line.find(suffix) + len(suffix)]
|
|
||||||
break
|
|
||||||
return '%s%s' % (self.ff_download_site(self.get_os_str[0]), download_name)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
print 'Installing Firefox'
|
|
||||||
if 'darwin' in sys.platform:
|
|
||||||
urllib.urlretrieve(self.get_download_url(), 'firefox.dmg')
|
|
||||||
run_cmd('hdiutil mount firefox.dmg')
|
|
||||||
run_cmd('sudo cp -R /Volumes/firefox/Firefox.app /Applications')
|
|
||||||
run_cmd('hdiutil unmount /Volumes/firefox/')
|
|
||||||
elif 'win' in sys.platform:
|
|
||||||
urllib.urlretrieve(self.get_download_url(), 'firefox_install.exe')
|
|
||||||
run_cmd('firefox_install.exe -ms')
|
|
||||||
else:
|
|
||||||
run_cmd('wget -O - %s | tar -C ~ -jxv' % self.get_download_url())
|
|
||||||
|
|
||||||
|
|
||||||
class SeleniumBindingsInstaller(object):
|
|
||||||
"""Install the Selenium Webdriver bindings for Python."""
|
|
||||||
|
|
||||||
SETUPTOOLS_SITE = 'http://python-distribute.org/distribute_setup.py'
|
|
||||||
PIP_SITE = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
|
|
||||||
def __init__(self, is_buildbot):
|
|
||||||
self.is_buildbot = is_buildbot
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
print 'Installing Selenium Python Bindings'
|
|
||||||
admin_keyword = ''
|
|
||||||
python_cmd = 'python'
|
|
||||||
pip_cmd = 'pip'
|
|
||||||
if 'win32' not in sys.platform and 'cygwin' not in sys.platform:
|
|
||||||
admin_keyword = 'sudo'
|
|
||||||
pip_cmd = '/usr/local/bin/pip'
|
|
||||||
else:
|
|
||||||
# The python installation is "special" on Windows buildbots.
|
|
||||||
if self.is_buildbot:
|
|
||||||
python_loc = os.path.join(
|
|
||||||
find_depot_tools_location(self.is_buildbot), 'python_bin')
|
|
||||||
python_cmd = os.path.join(python_loc, 'python')
|
|
||||||
pip_cmd = os.path.join(python_loc, 'Scripts', pip_cmd)
|
|
||||||
else:
|
|
||||||
path = os.environ['PATH'].split(os.pathsep)
|
|
||||||
for loc in path:
|
|
||||||
if 'python' in loc or 'Python' in loc:
|
|
||||||
pip_cmd = os.path.join(loc, 'Scripts', pip_cmd)
|
|
||||||
break
|
|
||||||
page = urllib2.urlopen(self.SETUPTOOLS_SITE)
|
|
||||||
run_cmd('%s %s' % (admin_keyword, python_cmd), page.read())
|
|
||||||
page = urllib2.urlopen(self.PIP_SITE)
|
|
||||||
run_cmd('%s %s' % (admin_keyword, python_cmd), page.read())
|
|
||||||
run_cmd('%s %s install -U selenium' % (admin_keyword, pip_cmd))
|
|
||||||
|
|
||||||
class OperaHtmlParser(HTMLParser.HTMLParser):
|
|
||||||
"""A helper class to parse Opera pages listing available downloads to find the
|
|
||||||
correct download we want."""
|
|
||||||
|
|
||||||
def initialize(self, rejection_func, accept_func):
|
|
||||||
"""Initialize some state for our parser.
|
|
||||||
Arguments:
|
|
||||||
rejection_func: A function that accepts the value of the URL and determines
|
|
||||||
if it is of the type we are looking for.
|
|
||||||
accept_func: A function that takes the URL and the "current best" URL and
|
|
||||||
determines if it is better than our current download url."""
|
|
||||||
self.latest = 0
|
|
||||||
self.rejection_func = rejection_func
|
|
||||||
self.accept_func = accept_func
|
|
||||||
|
|
||||||
def handle_starttag(self, tag, attrs):
|
|
||||||
"""Find the latest version."""
|
|
||||||
if (tag == 'a' and attrs[0][0] == 'href' and
|
|
||||||
self.rejection_func(attrs[0][1])):
|
|
||||||
self.latest = self.accept_func(attrs[0][1], self.latest)
|
|
||||||
|
|
||||||
class OperaInstaller(object):
|
|
||||||
"""Install from the Opera FTP website."""
|
|
||||||
|
|
||||||
def find_latest_version(self, download_page, rejection_func, accept_func):
|
|
||||||
"""Get the latest non-beta version.
|
|
||||||
Arguments:
|
|
||||||
download_page: The initial page that lists all the download options.
|
|
||||||
rejection_func: A function that accepts the value of the URL and determines
|
|
||||||
if it is of the type we are looking for.
|
|
||||||
accept_func: A function that takes the URL and the "current best" URL and
|
|
||||||
determines if it is better than our current download url."""
|
|
||||||
f = urllib2.urlopen(download_page)
|
|
||||||
parser = OperaHtmlParser()
|
|
||||||
parser.initialize(rejection_func, accept_func)
|
|
||||||
parser.feed(f.read())
|
|
||||||
return str(parser.latest)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""Download and install Opera."""
|
|
||||||
print 'Installing Opera'
|
|
||||||
os_str = self.get_os_str
|
|
||||||
download_name = 'http://ftp.opera.com/pub/opera/%s/' % os_str
|
|
||||||
|
|
||||||
def higher_revision(new_version_str, current):
|
|
||||||
version_string = new_version_str[:-1]
|
|
||||||
if int(version_string) > current:
|
|
||||||
return int(version_string)
|
|
||||||
return current
|
|
||||||
|
|
||||||
version = self.find_latest_version(
|
|
||||||
download_name,
|
|
||||||
lambda x: x[0] in string.digits and 'b' not in x and 'rc' not in x,
|
|
||||||
higher_revision)
|
|
||||||
download_name += version
|
|
||||||
if ('linux' in sys.platform and
|
|
||||||
platform.linux_distribution()[0] == 'Ubuntu'):
|
|
||||||
# Last time I tried, the .deb file you download directly from opera was
|
|
||||||
# not installing correctly on Ubuntu. This installs Opera more nicely.
|
|
||||||
os.system("sudo sh -c 'wget -O - http://deb.opera.com/archive.key | "
|
|
||||||
"apt-key add -'")
|
|
||||||
os.system("""sudo sh -c 'echo "deb http://deb.opera.com/opera/ """
|
|
||||||
"""stable non-free" > /etc/apt/sources.list.d/opera.list'""")
|
|
||||||
run_cmd('sudo apt-get update')
|
|
||||||
run_cmd('sudo apt-get install opera', stdin='y')
|
|
||||||
else:
|
|
||||||
if 'darwin' in sys.platform:
|
|
||||||
dotted_version = '%s.%s' % (version[:2], version[2:])
|
|
||||||
download_name += '/Opera_%s_Setup_Intel.dmg' % dotted_version
|
|
||||||
urllib.urlretrieve(download_name, 'opera.dmg')
|
|
||||||
run_cmd('hdiutil mount opera.dmg', stdin='qY\n')
|
|
||||||
run_cmd('sudo cp -R /Volumes/Opera/Opera.app /Applications')
|
|
||||||
run_cmd('hdiutil unmount /Volumes/Opera/')
|
|
||||||
elif 'win' in sys.platform:
|
|
||||||
download_name += '/en/Opera_%s_en_Setup.exe' % version
|
|
||||||
urllib.urlretrieve(download_name, 'opera_install.exe')
|
|
||||||
run_cmd('opera_install.exe -ms')
|
|
||||||
else:
|
|
||||||
# For all other flavors of linux, download the tar.
|
|
||||||
download_name += '/'
|
|
||||||
extension = '.tar.bz2'
|
|
||||||
if '64bit' in platform.architecture()[0]:
|
|
||||||
platform_str = '.x86_64'
|
|
||||||
else:
|
|
||||||
platform_str = '.i386'
|
|
||||||
def get_acceptable_file(new_version_str, current):
|
|
||||||
return new_version_str
|
|
||||||
latest = self.find_latest_version(
|
|
||||||
download_name,
|
|
||||||
lambda x: x.startswith('opera') and x.endswith(extension)
|
|
||||||
and platform_str in x,
|
|
||||||
get_acceptable_file)
|
|
||||||
download_name += latest
|
|
||||||
run_cmd('wget -O - %s | tar -C ~ -jxv' % download_name)
|
|
||||||
print ('PLEASE MANUALLY RUN "~/%s/install" TO COMPLETE OPERA '
|
|
||||||
'INSTALLATION' %
|
|
||||||
download_name[download_name.rfind('/') + 1:-len(extension)])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def get_os_str(self):
|
|
||||||
"""The strings to indicate what OS a download is."""
|
|
||||||
os_str = 'win'
|
|
||||||
if 'darwin' in sys.platform:
|
|
||||||
os_str = 'mac'
|
|
||||||
elif 'linux' in sys.platform:
|
|
||||||
os_str = 'linux'
|
|
||||||
return os_str
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = parse_args()
|
|
||||||
if not args.python:
|
|
||||||
SeleniumBindingsInstaller(args.buildbot).run()
|
|
||||||
if not args.chromedriver:
|
|
||||||
ChromeDriverInstaller(find_depot_tools_location(args.buildbot)).run()
|
|
||||||
if not args.seleniumrc:
|
|
||||||
GoogleCodeInstaller('selenium', os.path.dirname(os.path.abspath(__file__)),
|
|
||||||
lambda x: 'selenium-server-standalone-%(version)s.jar' % x).run()
|
|
||||||
if not args.iedriver and platform.system() == 'Windows':
|
|
||||||
GoogleCodeInstaller('selenium', find_depot_tools_location(args.buildbot),
|
|
||||||
lambda x: 'IEDriverServer_Win32_%(version)s.zip' % x).run()
|
|
||||||
if not args.firefox:
|
|
||||||
FirefoxInstaller().run()
|
|
||||||
if not args.opera:
|
|
||||||
OperaInstaller().run()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
Loading…
Reference in a new issue