Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first shot at hpantomjs

  • Loading branch information...
commit f66deea4e8b1548fcb77e5605050b4bd153d664e 1 parent 14659b4
@zzo authored
View
114 backend/nodejute/jute/actions/phantomJS.js
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2011, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+module.exports = {
+ Create: function(hub) {
+ // Javascript is single threaded! We don't have to worry about concurrency!
+ var path = require('path'),
+ sys = require('sys'),
+ fs = require('fs'),
+ cache = hub.cache
+ ;
+
+ // Events I care about
+ hub.addListener('action:seleniumStart', startSelenium);
+
+ function startSelenium(selID, req, res) {
+ var soda = require('soda'), cb,
+ body = req.body,
+ browser
+ ;
+
+ try {
+ browser = soda.createClient({
+ url: 'http://' + (hub.config.host ? hub.config.host + ':' + hub.config.port : req.headers.host),
+ host: body.sel_host,
+ browser: body.sel_browser
+ })
+ } catch(e) {
+ hub.emit('action:seleniumDone', 'Cannot connect to Selenium server at ' + body.sel_host + ': ' + e, selID);
+ return;
+ }
+
+ // Give Selenium 1000 minutes to finish - should be good - 16 hours baby!
+ req.socket.setTimeout(60000000, function() {
+ hub.emit(hub.LOG, hub.ERROR, 'Selenium taking too long - giving up');
+ cb();
+ });
+
+ cache.connections[selID] = res; // our link back to the requesting client for status messages
+
+ // called when all Selenium tests are complete for this browser
+ // && keep track of requesting client for debug messages back...
+ // Callback for when the Selenium session is done
+ cb = function(err) {
+ if (!err) {
+ browser.chain.testComplete().end(function(err) {
+ delete cache.connections[selID]; // done with status updates
+ hub.emit('action:seleniumDone', err, selID);
+ });
+ } else {
+ hub.emit('action:seleniumDone', err, selID);
+ }
+ };
+ cb = hub.once(selID + 'finished', cb);
+
+ browser.
+ chain.
+ session().
+ open('/?selenium=' + selID).
+ waitForPageToLoad(10000).
+ end(function(err) {
+ if (err) {
+ var msg = 'Error starting/waiting for Selenium page to load: ' + err;
+ hub.emit('seleniumTestsFinished', err);
+ } else {
+ hub.emit(hub.LOG, hub.INFO, "Selenium up and running: " + browser.sid);
+ // If this is one of the tests that are going to run in the
+ // Selenium session, tag it with the Selenium token
+ cache.tests_to_run.forEach(function(test) {
+ if (test.browser === selID) {
+ test.seleniumID = browser.sid;
+ }
+ });
+
+ }
+ });
+ }
+ }
+
+};
+
View
55 backend/nodejute/jute/actions/runTest.js
@@ -95,7 +95,7 @@ module.exports = {
return;
}
- if (!Object.keys(cache.browsers).length && !obj.sel_host && capture && !obj.load) {
+ if (!Object.keys(cache.browsers).length && !obj.sel_host && !obj.phantomjs && capture && !obj.load) {
res.writeHead(412);
res.end("There are no currently captured browsers!");
return;
@@ -105,7 +105,7 @@ module.exports = {
requestKey = uuid(), seleniumIDs = [];
// Generate Selenium IDs
- if (obj.sel_host) {
+ if (obj.sel_host || obj.phantomjs) {
var seleniums = parseInt(obj.seleniums, 10) || 1;
for (var i = 0; i < seleniums; i++) {
seleniumIDs.push(uuid());
@@ -156,7 +156,26 @@ module.exports = {
cache.tests_to_run.push(test_obj);
pushed = true;
- } else {
+ } else if (obj.phantomjs) {
+ test_obj.phantomjs = obj.phantomjs;
+ if (obj.send_output) {
+ test_obj.sendOutput = 1;
+ }
+ if (obj.snapshot) {
+ test_obj.snapshot = 1;
+ }
+
+ // Only pass these tests out to phantomjs instances started by this
+ // this is how we keep track
+ // hand this off to next SeleniumID
+ console.log('choosing phantomjs id: ' + (i % seleniumIDs.length));
+ test_obj.browser = seleniumIDs[i % seleniumIDs.length];
+
+ common.addTestOutput(test_obj, 'PhantomJS test');
+
+ cache.tests_to_run.push(test_obj);
+ pushed = true;
+ }else {
if (multipleFromUI) {
// Only run these tests in THIS browser from the UI
@@ -222,7 +241,35 @@ module.exports = {
seleniumIDs.forEach(function(selID) {
hub.emit('action:seleniumStart', selID, req, res);
});
- } else {
+ } else if (obj.phantomjs) {
+ // Start up for a Selenium browser & Listen for results
+ var totalError = '';
+ hub.on('action:phantomjsDone', function(err, selID) {
+ seleniumIDs.pop(); // a selenium browser finished - we don't really care which one
+ // as we're just waiting for all to finish
+ var done = !seleniumIDs.length;
+ if (done) hub.removeListener('action:phantomjsDone', arguments.callee);
+
+ if (err) {
+ hub.emit(hub.LOG, hub.ERROR, 'ERROR running PhantomJS tests (' + selID + '): ' + err);
+ totalError += err;
+ if (done) {
+ res.end(totalError);
+ }
+ } else {
+ if (done) {
+ hub.once('action:checkedResults', function(results) {
+ res.end('Final PhantomJS Results: ' + JSON.stringify(results));
+ });
+ hub.emit('action:checkResults');
+ }
+ }
+ });
+
+ seleniumIDs.forEach(function(selID) {
+ hub.emit('action:phantomjsStart', selID, obj.phantomjs, obj.screen, req, res);
+ });
+ }else {
// UI wants to run multiple tests - redirect to it!
if (multipleFromUI) {
// Now tell browser to run the tests!
View
91 backend/nodejute/jute/actions/startPhantomjs.js
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2011, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+module.exports = {
+ Create: function(hub) {
+ // Javascript is single threaded! We don't have to worry about concurrency!
+ var path = require('path'),
+ sys = require('sys'),
+ fs = require('fs'),
+ child = require('child_process'),
+ cache = hub.cache
+ ;
+
+ // Events I care about
+ hub.addListener('action:phantomjsStart', startPhantomjs);
+
+ function Phantomjs(selID, phantomjs, screen, req, res) {
+ var cb, phantom, body = req.body,
+ url = 'http://' + (hub.config.host ? hub.config.host + ':' + hub.config.port : req.headers.host) + '/?selenium=' + selID
+ ;
+
+ try {
+ phantom = child.spawn(phantomjs, [url]);
+ phantom.stdout.on('data', function(data) {
+ hub.emit(hub.LOG, hub.INFO, "PhantomJS up and running: " + data);
+ });
+ phantom.stderr.on('data', function(data) {
+ });
+ phantom.on('exit', function() {
+ hub.emit(hub.LOG, hub.INFO, "PhantomJS up done");
+ });
+
+ } catch(e) {
+ hub.emit('action:phantomjsDone', 'Cannot start up phantomjs at ' + phantomjs + ': ' + e, selID);
+ return;
+ }
+
+ // Give Selenium 1000 minutes to finish - should be good - 16 hours baby!
+ req.socket.setTimeout(60000000, function() {
+ hub.emit(hub.LOG, hub.ERROR, 'Phantomjs taking too long - giving up');
+ cb();
+ });
+
+ cache.connections[selID] = res; // our link back to the requesting client for status messages
+
+ // called when all PhantomJS tests are complete for this instance
+ // && keep track of requesting client for debug messages back...
+ // Callback for when the phantomjs process is done
+ cb = function(err) {
+ delete cache.connections[selID]; // done with status updates
+ hub.emit('action:phantomjsDone', err, selID);
+ };
+ hub.once(selID + 'finished', cb);
+ }
+ }
+
+};
+
View
2  backend/nodejute/jute_backend.js
@@ -85,7 +85,7 @@ eventHub.on('configureDone', function() {
// Dump the config file for jute_v8 and submit_tests
console.log('DMPING: ' + JSON.stringify(eventHub.config));
- fs.writeFile('/tmp/jute.config', JSON.stringify(eventHub.config));
+ fs.writeFileSync('/tmp/jute.config', JSON.stringify(eventHub.config));
// Fire up server
eventHub.emit('startServer');
View
1  backend/nodejute/package.json
@@ -29,7 +29,6 @@
, "yui3": "~0.7"
, "xmlhttprequest" : "~1.2"
, "cookie-sessions" : "~0.0"
- , "jsdom": "~0.2"
, "mime" : "~1.2"
, "optimist" : "~0.2"
},
View
13 backend/nodejute/submit_test.js
@@ -41,7 +41,7 @@ var config = (require('./getConfig'))(),
events = require("events"),
eventHubF = function() { events.EventEmitter.call(this); },
args = opt
- .usage('Usage: $0 --test [testfile] [ --test [another testfile] ] [ --host [JUTE host] ] [ --port [JUTE host port] ] [ --sel_host [Selenium host] ] [ --sel_browser [Selenium browser spec] ] [ --seleniums # ] [ --load ] ] [ --send_output ] [ --wait ] [ --clear_results ] [ -v8 ] [ --status ] [ --snapshot ] [ --retry ]')
+ .usage('Usage: $0 --test [testfile] [ --test [another testfile] ] [ --host [JUTE host] ] [ --port [JUTE host port] ] [ --sel_host [Selenium host] ] [ --sel_browser [Selenium browser spec] ] [ --seleniums # ] [ --load ] ] [ --send_output ] [ --wait ] [ --clear_results ] [ -v8 ] [ --status ] [ --snapshot ] [ --retry ] [ --phantomjs <path> ] [ --screen # ]')
.alias('t', 'test')
.alias('h', 'host')
.alias('p', 'port')
@@ -54,6 +54,8 @@ var config = (require('./getConfig'))(),
.alias('c', 'clear_results')
.alias('w', 'wait')
.alias('r', 'retry')
+ .alias('ph', 'phantomjs')
+ .alias('sc', 'screen')
.default('host', (config && config.host) || os.hostname())
.default('port', (config && config.port) || 8080)
.default('send_output', false)
@@ -65,6 +67,7 @@ var config = (require('./getConfig'))(),
.default('seleniums', 1)
.default('sel_browser', '*firefox')
.default('retry', 0)
+ .default('screen', 0)
.describe('test', 'Test file to run - relative to docRoot/testDir (npm set jute.testDir) - can specify multiple of these')
.describe('host', 'Hostname of JUTE server')
.describe('port', 'Port of JUTE server')
@@ -79,6 +82,8 @@ var config = (require('./getConfig'))(),
.describe('v8', 'Run these test(s) using the V8 backend')
.describe('status', 'Just get status')
.describe('retry', 'Number of time to retry a failed test')
+ .describe('phantomjs', 'Path to phantomjs executable')
+ .describe('screen', 'X screen number where an X server is listening')
.argv,
sys = require('sys'),
qs = require('querystring'),
@@ -148,6 +153,12 @@ eventHub.on('tests', function(tests) {
juteArgs.retry = args.retry;
// Toss in Selenium stuff
+ if (args.phantomjs) {
+ juteArgs.phantomjs = args.phantomjs;
+ juteArgs.screen = args.screen;
+ }
+
+ // Toss in Selenium stuff
if (args.sel_host) {
juteArgs.sel_host = args.sel_host;
juteArgs.sel_browser = args.sel_browser;
Please sign in to comment.
Something went wrong with that request. Please try again.