build(browserstack): initial setup

Closes #4941
This commit is contained in:
mlaval 2015-10-27 16:09:09 +01:00 committed by Marc Laval
parent 84fe0c9d3e
commit 13447e3198
13 changed files with 164 additions and 22 deletions

View File

@ -19,6 +19,8 @@ env:
- LOGS_DIR=/tmp/angular-build/logs - LOGS_DIR=/tmp/angular-build/logs
- SAUCE_USERNAME=angular-ci - SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987 - SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- BROWSER_STACK_USERNAME=angularteam1
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
- ARCH=linux-x64 - ARCH=linux-x64
- DART_DEV_VERSION=latest - DART_DEV_VERSION=latest
- DART_STABLE_VERSION=latest - DART_STABLE_VERSION=latest
@ -36,6 +38,7 @@ env:
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION - MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION - MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION - MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION - MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION - MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION - MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
@ -45,6 +48,7 @@ env:
matrix: matrix:
allow_failures: allow_failures:
- env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION" - env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
- env: "MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION" - env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
addons: addons:

View File

@ -124,10 +124,17 @@ var customLaunchers = {
browserName: 'android', browserName: 'android',
platform: 'Linux', platform: 'Linux',
version: '5.1' version: '5.1'
},
'BS_Chrome': {
base: 'BrowserStack',
browser: 'chrome',
os: 'OS X',
os_version: 'Yosemite'
} }
}; };
var aliases = { var sauceAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}), 'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'], 'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'], 'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
@ -142,11 +149,19 @@ var aliases = {
'SL_CHROMEDEV', 'SL_FIREFOXBETA'] 'SL_CHROMEDEV', 'SL_FIREFOXBETA']
}; };
var browserstackAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
'DESKTOP': ['BS_Chrome'],
'CI': ['BS_Chrome'],
};
module.exports = { module.exports = {
customLaunchers: customLaunchers, customLaunchers: customLaunchers,
aliases: aliases sauceAliases: sauceAliases,
browserstackAliases: browserstackAliases
} }
if (process.env.TRAVIS) { if (process.env.TRAVIS) {
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join(''); process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
} }

View File

@ -43,7 +43,7 @@ var buildRouter = require('./modules/angular1_router/build');
var uglify = require('gulp-uglify'); var uglify = require('gulp-uglify');
var shouldLog = require('./tools/build/logging'); var shouldLog = require('./tools/build/logging');
var dartSdk = require('./tools/build/dart'); var dartSdk = require('./tools/build/dart');
var sauceConf = require('./sauce.conf'); var browserProvidersConf = require('./browser-providers.conf.js');
var os = require('os'); var os = require('os');
require('./tools/check-environment')({ require('./tools/check-environment')({
@ -463,17 +463,17 @@ function getBrowsersFromCLI() {
for (var i = 0; i < inputList.length; i++) { for (var i = 0; i < inputList.length; i++) {
var input = inputList[i]; var input = inputList[i];
var karmaChromeLauncher = require('karma-chrome-launcher'); var karmaChromeLauncher = require('karma-chrome-launcher');
if (sauceConf.customLaunchers.hasOwnProperty(input) || karmaChromeLauncher.hasOwnProperty("launcher:" + input)) { if (browserProvidersConf.customLaunchers.hasOwnProperty(input) || karmaChromeLauncher.hasOwnProperty("launcher:" + input)) {
// In case of non-sauce browsers, or browsers defined in karma-chrome-launcher (Chrome, ChromeCanary and Dartium): // In case of non-sauce browsers, or browsers defined in karma-chrome-launcher (Chrome, ChromeCanary and Dartium):
// overrides everything, ignoring other options // overrides everything, ignoring other options
outputList = [input]; outputList = [input];
isSauce = false; isSauce = false;
break; break;
} else if (sauceConf.customLaunchers.hasOwnProperty("SL_" + input.toUpperCase())) { } else if (browserProvidersConf.customLaunchers.hasOwnProperty("SL_" + input.toUpperCase())) {
isSauce = true; isSauce = true;
outputList.push("SL_" + input.toUpperCase()); outputList.push("SL_" + input.toUpperCase());
} else if (sauceConf.aliases.hasOwnProperty(input.toUpperCase())) { } else if (browserProvidersConf.sauceAliases.hasOwnProperty(input.toUpperCase())) {
outputList = outputList.concat(sauceConf.aliases[input]); outputList = outputList.concat(browserProvidersConf.sauceAliases[input]);
isSauce = true; isSauce = true;
} else { } else {
throw new Error('ERROR: unknown browser found in getBrowsersFromCLI()'); throw new Error('ERROR: unknown browser found in getBrowsersFromCLI()');
@ -661,12 +661,25 @@ gulp.task('test.unit.js.sauce/ci', function (done) {
browserNoActivityTimeout: 240000, browserNoActivityTimeout: 240000,
captureTimeout: 120000, captureTimeout: 120000,
reporters: ['dots', 'saucelabs'], reporters: ['dots', 'saucelabs'],
browsers: sauceConf.aliases.CI browsers: browserProvidersConf.sauceAliases.CI
}, },
function(err) {done(); process.exit(err ? 1 : 0);} function(err) {done(); process.exit(err ? 1 : 0);}
).start(); ).start();
}); });
gulp.task('test.unit.js.browserstack/ci', function (done) {
new karma.Server({
configFile: __dirname + '/karma-js.conf.js',
singleRun: true,
browserNoActivityTimeout: 240000,
captureTimeout: 120000,
reporters: ['dots'],
browsers: browserProvidersConf.browserstackAliases.CI
},
function(err) {done(); process.exit(err ? 1 : 0);}
).start();
});
gulp.task('test.unit.dart/ci', function (done) { gulp.task('test.unit.dart/ci', function (done) {
var browserConf = getBrowsersFromCLI(); var browserConf = getBrowsersFromCLI();
new karma.Server({ new karma.Server({

View File

@ -1,4 +1,4 @@
var sauceConf = require('./sauce.conf'); var browserProvidersConf = require('./browser-providers.conf.js');
var packageSources = { var packageSources = {
// Dependencies installed with `pub install`. // Dependencies installed with `pub install`.
@ -67,7 +67,7 @@ module.exports = function(config) {
// Map packages to the correct urls where Karma serves them. // Map packages to the correct urls where Karma serves them.
proxies: proxyPaths, proxies: proxyPaths,
customLaunchers: sauceConf.customLaunchers, customLaunchers: browserProvidersConf.customLaunchers,
browsers: ['DartiumWithWebPlatform'], browsers: ['DartiumWithWebPlatform'],
port: 9877, port: 9877,

View File

@ -1,4 +1,4 @@
var sauceConf = require('./sauce.conf'); var browserProvidersConf = require('./browser-providers.conf.js');
// Karma configuration // Karma configuration
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT) // Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
@ -33,7 +33,7 @@ module.exports = function(config) {
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'], exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
customLaunchers: sauceConf.customLaunchers, customLaunchers: browserProvidersConf.customLaunchers,
sauceLabs: { sauceLabs: {
testName: 'Angular2', testName: 'Angular2',
@ -48,18 +48,33 @@ module.exports = function(config) {
} }
}, },
browserStack: {
project: 'Angular2',
startTunnel: false,
retryLimit: 1,
timeout: 600
},
browsers: ['Chrome'], browsers: ['Chrome'],
port: 9876 port: 9876
}); });
if (process.env.TRAVIS && process.env.MODE === 'saucelabs') { if (process.env.TRAVIS) {
config.sauceLabs.build = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')'; var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; if (process.env.MODE === 'saucelabs') {
config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
// TODO(mlaval): remove once SauceLabs supports websockets. // TODO(mlaval): remove once SauceLabs supports websockets.
// This speeds up the capturing a bit, as browsers don't even try to use websocket. // This speeds up the capturing a bit, as browsers don't even try to use websocket.
console.log('>>>> setting socket.io transport to polling <<<<'); console.log('>>>> setting socket.io transport to polling <<<<');
config.transports = ['polling']; config.transports = ['polling'];
}
if (process.env.MODE === 'browserstack') {
config.browserStack.build = buildId;
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
}
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
var sauceConf = require('../../sauce.conf'); var browserProvidersConf = require('../../browser-providers.conf.js');
// This runs the tests for the router in Angular 1.x // This runs the tests for the router in Angular 1.x
@ -20,7 +20,7 @@ module.exports = function (config) {
'test/**/*_spec.js' 'test/**/*_spec.js'
], ],
customLaunchers: sauceConf.customLaunchers, customLaunchers: browserProvidersConf.customLaunchers,
browsers: ['ChromeCanary'] browsers: ['ChromeCanary']
}; };

View File

@ -0,0 +1,50 @@
'use strict';
var fs = require('fs');
var http = require('http');
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
var HOSTNAME = 'localhost';
var PORTS = [9876, 9877];
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
var READY_FILE = process.env.BROWSER_PROVIDER_READY_FILE;
var TUNNEL_IDENTIFIER = process.env.TRAVIS_JOB_NUMBER;
// We need to start fake servers, otherwise the tunnel does not start.
var fakeServers = [];
var hosts = [];
PORTS.forEach(function(port) {
fakeServers.push(http.createServer(function() {}).listen(port));
hosts.push({
name: HOSTNAME,
port: port,
sslFlag: 0
});
});
var tunnel = new BrowserStackTunnel({
key: ACCESS_KEY,
localIdentifier: TUNNEL_IDENTIFIER,
hosts: hosts
});
console.log('Starting tunnel on ports', PORTS.join(', '));
tunnel.start(function(error) {
if (error) {
console.error('Can not establish the tunnel', error);
} else {
console.log('Tunnel established.');
fakeServers.forEach(function(server) {
server.close();
});
if (READY_FILE) {
fs.writeFile(READY_FILE, '');
}
}
});
tunnel.on('error', function(error) {
console.error(error);
});

View File

@ -0,0 +1,3 @@
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
node ./scripts/browserstack/start_tunnel.js &

View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e -o pipefail
echo "Shutting down Browserstack tunnel"
echo "TODO: implement me"
exit 1

View File

@ -0,0 +1,19 @@
#!/bin/bash
# Wait for Connect to be ready before exiting
# Time out if we wait for more than 2 minutes, so that we can print logs.
let "counter=0"
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
let "counter++"
if [ $counter -gt 240 ]; then
echo "Timed out after 2 minutes waiting for browser provider ready file"
# We must manually print logs here because travis will not run
# after_script commands if the failure occurs before the script
# phase.
./scripts/ci/print-logs.sh
exit 5
fi
sleep .5
done

View File

@ -8,6 +8,9 @@ echo '*******************'
if [ "$MODE" = "saucelabs" ]; then if [ "$MODE" = "saucelabs" ]; then
./scripts/sauce/sauce_connect_teardown.sh ./scripts/sauce/sauce_connect_teardown.sh
fi fi
if [ "$MODE" = "browserstack" ]; then
./scripts/browserstack/teardown_tunnel.sh
fi
echo '---------------------' echo '---------------------'

View File

@ -10,7 +10,7 @@ cd $SCRIPT_DIR/../..
if [ "$MODE" = "dart_experimental" ]; then if [ "$MODE" = "dart_experimental" ]; then
${SCRIPT_DIR}/build_$MODE.sh ${SCRIPT_DIR}/build_$MODE.sh
elif [ "$MODE" = "saucelabs" ]; then elif [ "$MODE" = "saucelabs" ] || [ "$MODE" = "browserstack" ] ; then
${SCRIPT_DIR}/test_$MODE.sh ${SCRIPT_DIR}/test_$MODE.sh
elif [ "$MODE" = "lint" ]; then elif [ "$MODE" = "lint" ]; then
./node_modules/.bin/gulp static-checks ./node_modules/.bin/gulp static-checks

12
scripts/ci/test_browserstack.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e
echo =============================================================================
# go to project dir
SCRIPT_DIR=$(dirname $0)
cd $SCRIPT_DIR/../..
./scripts/browserstack/start_tunnel.sh
./scripts/browserstack/waitfor_tunnel.sh
./node_modules/.bin/gulp build.js.dev
./node_modules/.bin/gulp test.unit.js.browserstack/ci