Skip to content
This repository was archived by the owner on Apr 14, 2021. It is now read-only.

Commit 471fb71

Browse files
committed
saucerunner
1 parent 36158d3 commit 471fb71

File tree

3 files changed

+312
-3
lines changed

3 files changed

+312
-3
lines changed

.travis.yml

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
language: node_js
22
node_js:
3-
- "0.10"
4-
- "0.11"
3+
- '0.10'
4+
- '0.11'
5+
addons:
6+
sauce_connect:
7+
username: drewfish
8+
access_key:
9+
secure: ilQt8gfe2HLG7FemtevQCsvBMMK9ggcfjTSMiiDQuu10hI184IJNlX8a/4Ug9H9oMK4sBe8bNI8lS5ItpOgTWGIMv29DT/+1ri4YqM9/FXlZPgBKzfmTMbgJumvhiPYqHlMRaJsZrrLxnXI3u/R3O3kw5qCucMF7TVeorfzQRmI=

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"scripts": {
1818
"build": "grunt",
1919
"lint": "jshint Intl.js",
20-
"test": "cd tests && node noderunner.js"
20+
"test": "cd tests && node noderunner.js && node saucelabs.js"
2121
},
2222
"repository": {
2323
"type": "git",

tests/saucelabs.js

+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
2+
Error.stackTraceLimit = 50;
3+
4+
var LIBS = {
5+
async: require('async'),
6+
child: require('child_process'),
7+
fs: require('fs'),
8+
path: require('path'),
9+
util: require('util'),
10+
wd: require('wd')
11+
},
12+
TEST_DIR = LIBS.path.resolve(__dirname, 'test262', 'pages'),
13+
BROWSER_CONCURRENCY = 4,
14+
BROWSERS = [
15+
// hand-chosen from https://saucelabs.com/platforms
16+
{
17+
browserName: "iphone",
18+
version: "7",
19+
platform: "OS X 10.9",
20+
"device-orientation": "portrait"
21+
},
22+
{
23+
browserName: "android",
24+
version: "4.0",
25+
platform: "Linux",
26+
"device-orientation": "portrait"
27+
},
28+
{
29+
browserName: "firefox",
30+
version: "26",
31+
platform: "Windows 8.1"
32+
},
33+
{
34+
browserName: "chrome",
35+
version: "31",
36+
platform: "OS X 10.9"
37+
},
38+
{
39+
browserName: "internet explorer",
40+
version: "11",
41+
platform: "Windows 8.1"
42+
},
43+
{
44+
browserName: "internet explorer",
45+
version: "10",
46+
platform: "Windows 8"
47+
},
48+
{
49+
browserName: "safari",
50+
version: "7",
51+
platform: "OS X 10.9"
52+
},
53+
];
54+
55+
56+
function listTests() {
57+
var tests = [],
58+
todo = ['.'],
59+
doing,
60+
path,
61+
stat;
62+
while (todo.length) {
63+
doing = todo.shift();
64+
path = LIBS.path.resolve(TEST_DIR, doing);
65+
stat = LIBS.fs.statSync(path);
66+
if (stat.isFile()) {
67+
tests.push(doing);
68+
continue;
69+
}
70+
if (stat.isDirectory()) {
71+
todo = todo.concat(LIBS.fs.readdirSync(path).map(function(a) {
72+
return LIBS.path.join(doing, a);
73+
}));
74+
}
75+
}
76+
return tests;
77+
}
78+
79+
80+
function runCommand(command, done) {
81+
var cmd = command.shift(),
82+
stdout = '',
83+
stderr = '',
84+
err,
85+
pid;
86+
pid = LIBS.child.spawn(cmd, command, {
87+
cwd: process.cwd(),
88+
env: process.env
89+
});
90+
pid.stdout.on('data', function(data) {
91+
stdout += data;
92+
});
93+
pid.stderr.on('data', function(data) {
94+
stderr += data;
95+
});
96+
pid.on('exit', function(code) {
97+
done(err, code, stdout, stderr);
98+
});
99+
pid.on('error', function(err) {
100+
done(err, err.code, stdout, stderr);
101+
});
102+
pid.on('uncaughtException', function(err) {
103+
done(err, err.code || 1, stdout, stderr);
104+
});
105+
}
106+
107+
108+
function calculateGitDetails(state, done) {
109+
state.git = {};
110+
LIBS.async.series([
111+
function(taskDone) {
112+
runCommand(['git', 'rev-parse', 'HEAD'], function(err, code, stdout, stderr) {
113+
state.git.shasum = stdout.trim();
114+
taskDone(err);
115+
});
116+
},
117+
function(taskDone) {
118+
runCommand(['git', 'for-each-ref', "--format='%(refname) %(objectname)'"], function(err, code, stdout, stderr) {
119+
var matches;
120+
if (err) {
121+
taskDone(err);
122+
return;
123+
}
124+
matches = stdout.match(new RegExp('refs\\/remotes\\/([^\\/]+)\\/([^\\/\\n\\s]+)\\s+' + state.git.shasum, 'm'));
125+
if (matches) {
126+
state.git.remote = matches[1];
127+
state.git.branch = matches[2];
128+
taskDone();
129+
return;
130+
}
131+
taskDone(new Error('failed to find relevant remote for ' + state.git.shasum));
132+
});
133+
},
134+
function(taskDone) {
135+
runCommand(['git', 'config', '--get', ['remote', state.git.remote, 'url'].join('.')], function(err, code, stdout, stderr) {
136+
var matches;
137+
if (err) {
138+
taskDone(err);
139+
return;
140+
}
141+
matches = stdout.trim().match(/([^:\/]+)\/(.+)\.git$/);
142+
if (matches) {
143+
state.git.user = matches[1];
144+
state.git.repo = matches[2];
145+
state.git.rawURL = 'https://rawgithub.com/' + state.git.user + '/' + state.git.repo + '/' + state.git.shasum + '/tests/test262/pages/';
146+
taskDone();
147+
return;
148+
}
149+
taskDone(new Error('failed to find repository URL for remote ' + state.git.remote));
150+
});
151+
}
152+
], function(err) {
153+
console.log(JSON.stringify(state.git, null, 4));
154+
done(err);
155+
});
156+
}
157+
158+
159+
function runTestsInBrowser(state, browserConfig, done) {
160+
var tasks = [],
161+
caps = {},
162+
browserString = LIBS.util.inspect(browserConfig, {depth: null}).replace(/\n\s*/g, ' '),
163+
browser,
164+
failures = 0;
165+
console.log('================================================ START', browserString);
166+
167+
Object.keys(state.capabilities).forEach(function(key) {
168+
caps[key] = state.capabilities[key];
169+
});
170+
Object.keys(browserConfig).forEach(function(key) {
171+
caps[key] = browserConfig[key];
172+
});
173+
caps.name = [browserConfig.browserName, browserConfig.version, browserConfig.platform].join(' - ');
174+
175+
function saveResults(test, out, err) {
176+
if (err) {
177+
if (err.cause) { err = err.cause; }
178+
if (err.value) { err = err.value; }
179+
if (err.message) { err = err.message; }
180+
err = err.toString().split('\n')[0];
181+
}
182+
if (out === 'passed') {
183+
state.results.passCount++;
184+
} else {
185+
failures++;
186+
state.results.failCount++;
187+
if (!state.results.failures[test]) {
188+
state.results.failures[test] = {}
189+
}
190+
state.results.failures[test][browserString] = err || out || 'FAILED no results';
191+
console.log('FAILED', test, browserString, (err || out || 'FAILED no results'));
192+
}
193+
}
194+
195+
// open browser
196+
tasks.push(function(taskDone) {
197+
var sauceConfig = {
198+
hostname: "ondemand.saucelabs.com",
199+
port: 80,
200+
user: state.sauce.username,
201+
pwd: state.sauce.access_key
202+
};
203+
if (process.env.TRAVIS) {
204+
// "sauce connect" travis addon
205+
// http://about.travis-ci.org/docs/user/gui-and-headless-browsers/#Using-Sauce-Labs
206+
sauceConfig.hostname = 'localhost';
207+
sauceConfig.port = 4445;
208+
}
209+
browser = LIBS.wd.remote(sauceConfig);
210+
browser.init(caps, taskDone);
211+
});
212+
213+
// for each page, get and test page
214+
state.tests.forEach(function(test) {
215+
tasks.push(function(taskDone) {
216+
var url = state.git.rawURL + test;
217+
console.log(test, browserString);
218+
browser.get(url, function() {
219+
browser.elementById('results', function(err, el) {
220+
if (err) {
221+
saveResults(test, null, err);
222+
taskDone();
223+
return;
224+
}
225+
el.text(function(err, out) {
226+
saveResults(test, out, err);
227+
taskDone();
228+
});
229+
});
230+
});
231+
});
232+
});
233+
234+
// quit browser
235+
tasks.push(function(taskDone) {
236+
browser.quit(function() {
237+
browser.sauceJobStatus(failures === 0, taskDone);
238+
});
239+
});
240+
241+
LIBS.async.series(tasks, function() {
242+
console.log('================================================ DONE', browserString);
243+
done();
244+
});
245+
}
246+
247+
248+
function runTests(state, done) {
249+
var q;
250+
// saucelabs FLOSS account has a low concurrency
251+
q = LIBS.async.queue(function(browser, browserDone) {
252+
runTestsInBrowser(state, browser, browserDone);
253+
}, BROWSER_CONCURRENCY);
254+
q.drain = done;
255+
q.push(BROWSERS);
256+
}
257+
258+
259+
function main() {
260+
var state = {};
261+
state.tests = listTests();
262+
state.sauce = {
263+
username: process.env.SAUCE_USERNAME,
264+
access_key: process.env.SAUCE_ACCESS_KEY
265+
};
266+
state.results = {
267+
passCount: 0,
268+
failCount: 0,
269+
failures: {} // key is test, value is hash of browser:error
270+
};
271+
272+
state.capabilities = {
273+
tags: []
274+
};
275+
if (process.env.TRAVIS_JOB_NUMBER) {
276+
state.capabilities['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER;
277+
}
278+
if (process.env.TRAVIS_NODE_VERSION) {
279+
state.capabilities.tags.push('CI');
280+
state.capabilities.tags.push(process.env.TRAVIS_NODE_VERSION);
281+
}
282+
state.capabilities.build = process.env.TRAVIS_BUILD_NUMBER || process.pid;
283+
284+
console.log(JSON.stringify(state, null, 4));
285+
console.log('================================================ START');
286+
287+
LIBS.async.series([
288+
calculateGitDetails.bind(null, state),
289+
runTests.bind(null, state)
290+
], function(err) {
291+
console.log('================================================ DONE');
292+
if (err) {
293+
console.error(err);
294+
process.exit(2);
295+
}
296+
console.log(JSON.stringify(state.results, null, 4));
297+
if (state.results.failCount) {
298+
process.exit(1);
299+
}
300+
});
301+
}
302+
main();
303+
304+

0 commit comments

Comments
 (0)