moved devServer into a module so that it can be used programmatically
This commit is contained in:
parent
c4c8af0675
commit
7ace826b63
0
.creds.json
Normal file
0
.creds.json
Normal file
10
package.json
10
package.json
|
@ -6,22 +6,22 @@
|
||||||
"main": "Gulpfile.js",
|
"main": "Gulpfile.js",
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"bluebird": "~2.0.7",
|
||||||
|
"connect": "~2.19.5",
|
||||||
|
"event-stream": "~3.1.5",
|
||||||
"expect.js": "~0.2.0",
|
"expect.js": "~0.2.0",
|
||||||
"grunt": "~0.4.2",
|
"grunt": "~0.4.2",
|
||||||
"grunt-cli": "~0.1.13",
|
|
||||||
"grunt-contrib-connect": "~0.6.0",
|
|
||||||
"grunt-contrib-jade": "~0.10.0",
|
"grunt-contrib-jade": "~0.10.0",
|
||||||
"grunt-contrib-jshint": "~0.8.0",
|
"grunt-contrib-jshint": "~0.8.0",
|
||||||
"grunt-contrib-less": "~0.10.0",
|
"grunt-contrib-less": "~0.10.0",
|
||||||
"grunt-contrib-requirejs": "~0.4.4",
|
"grunt-contrib-requirejs": "~0.4.4",
|
||||||
"grunt-contrib-watch": "~0.5.3",
|
"grunt-contrib-watch": "~0.5.3",
|
||||||
"grunt-mocha": "~0.4.10",
|
"grunt-mocha": "~0.4.10",
|
||||||
|
"http-proxy": "~1.1.4",
|
||||||
"istanbul": "~0.2.4",
|
"istanbul": "~0.2.4",
|
||||||
"load-grunt-config": "~0.7.0",
|
"load-grunt-config": "~0.7.0",
|
||||||
"lodash": "~2.4.1",
|
"lodash": "~2.4.1",
|
||||||
"bluebird": "~1.2.4",
|
"mocha": "~1.17.1"
|
||||||
"mocha": "~1.17.1",
|
|
||||||
"event-stream": "~3.1.5"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "grunt test",
|
"test": "grunt test",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
.thumbnail > img,
|
.thumbnail > img,
|
||||||
.thumbnail a > img,
|
.thumbnail a > img,
|
||||||
.carousel-inner > .item > img,
|
.carousel-inner > .item > img,
|
||||||
|
|
|
@ -323,8 +323,6 @@ define(function (require) {
|
||||||
};
|
};
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
if (!indexPattern) return;
|
|
||||||
|
|
||||||
var columnObjects = arrayToKeys($state.columns);
|
var columnObjects = arrayToKeys($state.columns);
|
||||||
|
|
||||||
$scope.fields = [];
|
$scope.fields = [];
|
||||||
|
@ -332,6 +330,8 @@ define(function (require) {
|
||||||
$scope.formatsByName = {};
|
$scope.formatsByName = {};
|
||||||
$state.columns = $state.columns || [];
|
$state.columns = $state.columns || [];
|
||||||
|
|
||||||
|
if (!indexPattern) return;
|
||||||
|
|
||||||
// Inject source into list;
|
// Inject source into list;
|
||||||
//$scope.fields.push({name: '_source', type: 'source', display: false});
|
//$scope.fields.push({name: '_source', type: 'source', display: false});
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ define(function (require) {
|
||||||
template: headerHtml,
|
template: headerHtml,
|
||||||
controller: function ($scope) {
|
controller: function ($scope) {
|
||||||
$scope.headerClass = function (column) {
|
$scope.headerClass = function (column) {
|
||||||
|
if (!$scope.mapping) return;
|
||||||
if ($scope.mapping[column] && !$scope.mapping[column].indexed) return;
|
if ($scope.mapping[column] && !$scope.mapping[column].indexed) return;
|
||||||
|
|
||||||
var sorting = $scope.sorting;
|
var sorting = $scope.sorting;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
.thumbnail > img,
|
.thumbnail > img,
|
||||||
.thumbnail a > img,
|
.thumbnail a > img,
|
||||||
.carousel-inner > .item > img,
|
.carousel-inner > .item > img,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
.thumbnail > img,
|
.thumbnail > img,
|
||||||
.thumbnail a > img,
|
.thumbnail a > img,
|
||||||
.carousel-inner > .item > img,
|
.carousel-inner > .item > img,
|
||||||
|
|
|
@ -66,10 +66,12 @@ define(function (require) {
|
||||||
var row = rowStack.slice(0);
|
var row = rowStack.slice(0);
|
||||||
var metric = bucket.value == null ? bucket.doc_count : bucket.value;
|
var metric = bucket.value == null ? bucket.doc_count : bucket.value;
|
||||||
|
|
||||||
if (revColStack.length) [].push.apply(row, new Array(revColStack.length));
|
if (!revColStack.length) {
|
||||||
|
// we have a full row, minus the final metric
|
||||||
// we have a full row, minus the final metric
|
row.push(metric);
|
||||||
row.push(metric);
|
} else {
|
||||||
|
[].push.apply(row, new Array(revColStack.length + 1));
|
||||||
|
}
|
||||||
|
|
||||||
chartData.rows.push(row);
|
chartData.rows.push(row);
|
||||||
};
|
};
|
||||||
|
@ -184,8 +186,6 @@ define(function (require) {
|
||||||
rows: []
|
rows: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// debugger;
|
|
||||||
|
|
||||||
(function cleanup(obj) {
|
(function cleanup(obj) {
|
||||||
if (obj.rows && obj.columns) {
|
if (obj.rows && obj.columns) {
|
||||||
// this obj is a chart
|
// this obj is a chart
|
||||||
|
@ -196,10 +196,11 @@ define(function (require) {
|
||||||
|
|
||||||
var rows = obj.rows;
|
var rows = obj.rows;
|
||||||
var cols = obj.columns;
|
var cols = obj.columns;
|
||||||
|
|
||||||
delete obj.rows;
|
delete obj.rows;
|
||||||
delete obj.columns;
|
delete obj.columns;
|
||||||
obj.label = [].concat(labelStack, obj.label).filter(Boolean).join(' > ');
|
|
||||||
|
|
||||||
|
obj.label = [].concat(labelStack, obj.label).filter(Boolean).join(' > ');
|
||||||
rows.forEach(function (row) {
|
rows.forEach(function (row) {
|
||||||
raw.rows.push([].concat(raw.splitValStack, row));
|
raw.rows.push([].concat(raw.splitValStack, row));
|
||||||
});
|
});
|
||||||
|
@ -210,6 +211,7 @@ define(function (require) {
|
||||||
delete obj.splits;
|
delete obj.splits;
|
||||||
|
|
||||||
labelStack.push(obj.label);
|
labelStack.push(obj.label);
|
||||||
|
|
||||||
_.forOwn(splits, function (split) {
|
_.forOwn(splits, function (split) {
|
||||||
raw.splitColumns.push(split.column);
|
raw.splitColumns.push(split.column);
|
||||||
raw.splitValStack.push(split.value);
|
raw.splitValStack.push(split.value);
|
||||||
|
|
|
@ -100,15 +100,6 @@ define(function (require) {
|
||||||
custom: true
|
custom: true
|
||||||
};
|
};
|
||||||
|
|
||||||
agg.params.min_doc_count = {
|
|
||||||
hide: true,
|
|
||||||
custom: true,
|
|
||||||
default: 0,
|
|
||||||
write: function (selection, output) {
|
|
||||||
output.aggParams.min_doc_count = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
agg.params.extended_bounds = {
|
agg.params.extended_bounds = {
|
||||||
hide: true,
|
hide: true,
|
||||||
default: {},
|
default: {},
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
.thumbnail > img,
|
.thumbnail > img,
|
||||||
.thumbnail a > img,
|
.thumbnail a > img,
|
||||||
.carousel-inner > .item > img,
|
.carousel-inner > .item > img,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
.thumbnail > img,
|
.thumbnail > img,
|
||||||
.thumbnail a > img,
|
.thumbnail a > img,
|
||||||
.carousel-inner > .item > img,
|
.carousel-inner > .item > img,
|
||||||
|
|
|
@ -56,8 +56,6 @@ define(function (require) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPage === oldPage) return;
|
|
||||||
|
|
||||||
// setup the list of the other pages to link to
|
// setup the list of the other pages to link to
|
||||||
$scope.otherPages = [];
|
$scope.otherPages = [];
|
||||||
var width = +getOtherWidth($scope) || 5;
|
var width = +getOtherWidth($scope) || 5;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
|
||||||
@import "icon_font.css";
|
@import "icon_font.css";
|
||||||
/*!
|
/*!
|
||||||
* Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome
|
* Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Bootswatch
|
// Bootswatch
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
// @import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||||
|
|
||||||
// Navbar =====================================================================
|
// Navbar =====================================================================
|
||||||
|
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
module.exports = function (grunt) {
|
|
||||||
var instrumentationMiddleware = require('../utils/instrumentation');
|
|
||||||
var amdRapperMiddleware = require('../utils/amd_rapper');
|
|
||||||
|
|
||||||
return {
|
|
||||||
dev: {
|
|
||||||
options: {
|
|
||||||
hostname: '0.0.0.0',
|
|
||||||
middleware: function (connect, options, stack) {
|
|
||||||
stack = stack || [];
|
|
||||||
|
|
||||||
var root = grunt.config.get('root');
|
|
||||||
|
|
||||||
// when a request for an intrumented file comes in (?instrument=true)
|
|
||||||
// and it is included in `pattern`, it will be handled
|
|
||||||
// by this middleware
|
|
||||||
stack.push(instrumentationMiddleware({
|
|
||||||
// root that files should be served from
|
|
||||||
root: root,
|
|
||||||
|
|
||||||
// make file names easier to read
|
|
||||||
displayRoot: grunt.config.get('src'),
|
|
||||||
|
|
||||||
// filter the filenames that will be served
|
|
||||||
filter: function (filename) {
|
|
||||||
// return true if the filename should be
|
|
||||||
// included in the coverage report (results are cached)
|
|
||||||
return grunt.file.isMatch([
|
|
||||||
'**/src/**/*.js',
|
|
||||||
'!**/src/bower_components/**/*',
|
|
||||||
'!**/src/kibana/utils/{event_emitter,next_tick}.js'
|
|
||||||
], filename);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// minimize code duplication (especially in the istanbul reporter)
|
|
||||||
// by allowing node_modules to be requested in an AMD rapper
|
|
||||||
stack.push(amdRapperMiddleware({
|
|
||||||
root: root
|
|
||||||
}));
|
|
||||||
|
|
||||||
// standard static middleware reading from the root
|
|
||||||
stack.push(connect.static(root));
|
|
||||||
|
|
||||||
stack.push(function (req, res, next) {
|
|
||||||
if (req.method !== 'HEAD' || req.url !== '/') return next();
|
|
||||||
res.statusCode === 200;
|
|
||||||
res.setHeader('Pong', 'Kibana 4 Dev Server');
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
// redirect requests for '/' to '/src/'
|
|
||||||
stack.push(function (req, res, next) {
|
|
||||||
if (req.url !== '/') return next();
|
|
||||||
res.statusCode = 303;
|
|
||||||
res.setHeader('Location', '/src/');
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
// allow browsing directories
|
|
||||||
stack.push(
|
|
||||||
function (req, res, next) {
|
|
||||||
// prevent chrome's stupid "this page is in spanish"
|
|
||||||
res.setHeader('Content-Language', 'en');
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
connect.directory(root)
|
|
||||||
);
|
|
||||||
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -19,7 +19,7 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError() {
|
function onError() {
|
||||||
grunt.task.run(['connect:dev']);
|
grunt.task.run(['server']);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
module.exports = function (grunt) {
|
module.exports = function (grunt) {
|
||||||
grunt.registerTask('server', ['connect:dev:keepalive']);
|
grunt.registerTask('server', function () {
|
||||||
|
var done = this.async();
|
||||||
|
var DevServer = require('../test/utils/dev_server');
|
||||||
|
var server = new DevServer();
|
||||||
|
server.listen(8000, function () {
|
||||||
|
console.log('visit http://localhost:8000');
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
31
test.js
Normal file
31
test.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
var Proxy = require('./test/utils/proxy');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
var configfile = require('fs').readFileSync(__dirname + '/src/config.js', 'utf8').replace(
|
||||||
|
/elasticsearch:[^\n]+/,
|
||||||
|
'elasticsearch: \'http://\' + window.location.host + \'/es-proxy\','
|
||||||
|
);
|
||||||
|
|
||||||
|
var p = new Proxy();
|
||||||
|
p.on('/es-proxy', {
|
||||||
|
target: 'http://localhost:9200',
|
||||||
|
middleware: function (req, res) {
|
||||||
|
// strip the prefix
|
||||||
|
req.url = req.url.replace(/^\/es-proxy/, '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
p.on('/src/config.js', {
|
||||||
|
target: 'http://localhost:8000',
|
||||||
|
middleware: function (req, res) {
|
||||||
|
// overwrite the contents of the file
|
||||||
|
res.end(configfile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// send all other requests to localhost:8000
|
||||||
|
p.on('*', 'http://localhost:8000');
|
||||||
|
|
||||||
|
p.listen()
|
||||||
|
.then(console.log.bind(console, 'listening on %s'))
|
||||||
|
.catch(console.error.bind(console));
|
66
test/e2e/index.js
Normal file
66
test/e2e/index.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* jshint node:true */
|
||||||
|
var _ = require('lodash');
|
||||||
|
var Proxy = require('./test/utils/proxy');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var readFileSync = require('fs').readFileSync;
|
||||||
|
var rel = require('path').join.bind(null, __dirname);
|
||||||
|
|
||||||
|
|
||||||
|
var soda = require('soda');
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
|
||||||
|
// array of async fns that will be called when we need to close up
|
||||||
|
var closers = [];
|
||||||
|
|
||||||
|
connectSauceLabs({
|
||||||
|
username: SAUCE_USERNAME,
|
||||||
|
accessKey: SAUCE_ACCESSKEY,
|
||||||
|
verbose: true,
|
||||||
|
//optionally change sauce connect logfile location
|
||||||
|
logfile: null,
|
||||||
|
// optionally identity the tunnel for concurrent tunnels
|
||||||
|
tunnelIdentifier: null,
|
||||||
|
logger: function () {
|
||||||
|
console.log(' \x1b[33mSauce Connect\x1b[0m: %s', [].join.call(arguments, ', '));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (connectProc) {
|
||||||
|
closers.push(function () {
|
||||||
|
return Promise.promisify(connectProc.close, connectProc)()
|
||||||
|
.then(console.log.bind(console, 'Closed Sauce Connect'));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Started Sauce Connect');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
var browser = soda.createSauceClient({
|
||||||
|
'url': 'http://localhost:8000',
|
||||||
|
'username': SAUCE_USERNAME,
|
||||||
|
'access-key': SAUCE_ACCESSKEY,
|
||||||
|
'os': 'Windows 2003',
|
||||||
|
'browser': 'firefox',
|
||||||
|
'browser-version': '7',
|
||||||
|
'name': 'This is an example test'
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.on('command', function(cmd, args){
|
||||||
|
console.log(' \x1b[33m%s\x1b[0m: %s', cmd, args.join(', '));
|
||||||
|
});
|
||||||
|
|
||||||
|
browser
|
||||||
|
.chain
|
||||||
|
.session()
|
||||||
|
.open('/src/#/visualize')
|
||||||
|
.waitForPageToLoad(8000)
|
||||||
|
.select('//ng-model="indexPattern.selection"')
|
||||||
|
.end(function(err){
|
||||||
|
this.queue = null;
|
||||||
|
this.setContext('sauce:job-info={"passed": ' + (err === null) + '}', function(){
|
||||||
|
browser.testComplete(function(){
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(closers.map(function (fn) { return fn(); }));
|
||||||
|
});
|
||||||
|
});
|
41
test/utils/automated_browser/_connector.js
Normal file
41
test/utils/automated_browser/_connector.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var connectSauceLabs = Promise.promisify(require('sauce-connect-launcher'));
|
||||||
|
|
||||||
|
var creds = require('../../../.creds');
|
||||||
|
|
||||||
|
module.exports = function SauceLabsConnector() {
|
||||||
|
var proc;
|
||||||
|
|
||||||
|
var pickPort = function () {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var server = require('http').createServer();
|
||||||
|
server.listen(0, function () {
|
||||||
|
var port = server.address().port;
|
||||||
|
server.once('close', function () {
|
||||||
|
resolve(port);
|
||||||
|
});
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.listen = function () {
|
||||||
|
connectSauceLabs({
|
||||||
|
username: creds.SAUCE_USERNAME,
|
||||||
|
accessKey: creds.SAUCE_ACCESSKEY,
|
||||||
|
verbose: true,
|
||||||
|
tunnelIdentifier: null,
|
||||||
|
logger: function () {
|
||||||
|
console.log(' \x1b[33mSauce Connect\x1b[0m: %s', [].join.call(arguments, ', '));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (connectProc) {
|
||||||
|
proc = connectProc;
|
||||||
|
return proc;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.close = function () {
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
50
test/utils/automated_browser/_example.js
Normal file
50
test/utils/automated_browser/_example.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
var wd = require('wd');
|
||||||
|
var chai = require('chai');
|
||||||
|
var chaiAsPromised = require('chai-as-promised');
|
||||||
|
var asserters = wd.asserters;
|
||||||
|
var mocha = require('mocha');
|
||||||
|
|
||||||
|
chai.use(chaiAsPromised);
|
||||||
|
chai.should();
|
||||||
|
chaiAsPromised.transferPromiseness = wd.transferPromiseness;
|
||||||
|
|
||||||
|
var url = 'http://localhost:8000';
|
||||||
|
var access_key = '1770de66-20c2-4f3c-9d3e-3ecf01d768f4';
|
||||||
|
var username = 'ccowan';
|
||||||
|
var remotePort = (process.env.SAUCE) ? 4445 : 4444;
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
browserName: 'firefox',
|
||||||
|
name: 'Example Marvel Test'
|
||||||
|
};
|
||||||
|
|
||||||
|
before(function (done) {
|
||||||
|
this.browser = wd.promiseChainRemote('localhost', remotePort, username, access_key)
|
||||||
|
.init(options)
|
||||||
|
.then(function () { done(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function (done) {
|
||||||
|
this.browser.quit()
|
||||||
|
.then(function () { done(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Welcome Screen', function () {
|
||||||
|
describe('click "Continue Free Trial"', function() {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
this.browser
|
||||||
|
.get(url+'/kibana/index.html#/dashboard/elasticsearch/marvel.overview.json')
|
||||||
|
.then(function () { done(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the marvelOpts trialTimestamp attribute in localStorage', function(done) {
|
||||||
|
this.browser
|
||||||
|
.waitForElementByCss('div > .modal-body > p > a:nth-child(3)', asserters.isDisplayed, 1000)
|
||||||
|
.click()
|
||||||
|
.waitForConditionInBrowser('JSON.parse(localStorage.getItem("marvelOpts")).status === "trial"', 1000)
|
||||||
|
.then(function () { done(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
108
test/utils/automated_browser/_proxy.js
Normal file
108
test/utils/automated_browser/_proxy.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/* jshint node:true */
|
||||||
|
var _ = require('lodash');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
var portOptions = (
|
||||||
|
'4000,4001,4040,4321,4502,4503,4567,5000,5001,5050,5555,5432,6000,6001,6060,' +
|
||||||
|
'6666,6543,7000,7070,7774,7777,8000,8001,8003,8031,8080,8081,8443,8765,8777,' +
|
||||||
|
'8888,9000,9001,9031,9080,9090,9876,9877,9999,49221,55001'
|
||||||
|
).split(',').map(function (p) { return _.parseInt(p); });
|
||||||
|
|
||||||
|
module.exports = function SauceLabsProxy(opts) {
|
||||||
|
if (!(this instanceof SauceLabsProxy)) return new SauceLabsProxy(opts);
|
||||||
|
|
||||||
|
var proxy = this;
|
||||||
|
var pass = require('http-proxy').createProxyServer({});
|
||||||
|
|
||||||
|
var routes = [];
|
||||||
|
|
||||||
|
var send404 = function (req, res) {
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.end('unable to find ' + req.url);
|
||||||
|
};
|
||||||
|
|
||||||
|
var sendErr = function (req, res, err) {
|
||||||
|
res.statusCode = 500;
|
||||||
|
res.end('error: ' + err.message);
|
||||||
|
};
|
||||||
|
|
||||||
|
var server = require('http').createServer(function(req, res) {
|
||||||
|
var route = _.find(routes, function (route) {
|
||||||
|
return route.re.test(req.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!route) return send404(req, res);
|
||||||
|
|
||||||
|
var origEnd = res.end;
|
||||||
|
var respEnded = false;
|
||||||
|
res.end = function () {
|
||||||
|
respEnded = true;
|
||||||
|
origEnd.apply(res, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
Promise.cast(route.middleware && route.middleware(req, res))
|
||||||
|
.then(function (ret) {
|
||||||
|
if (!respEnded) pass.web(req, res, { target: route.target });
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
return sendErr(res, res, err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.on = function (prefix, opts) {
|
||||||
|
var route = {};
|
||||||
|
|
||||||
|
if (_.isRegExp(prefix)) {
|
||||||
|
route.re = prefix;
|
||||||
|
}
|
||||||
|
else if (prefix === '*') {
|
||||||
|
route.re = /.*/;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
route.re = new RegExp('^' + prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isString(opts)) {
|
||||||
|
route.target = opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isPlainObject(opts)) {
|
||||||
|
_.assign(route, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
routes.push(route);
|
||||||
|
return route;
|
||||||
|
};
|
||||||
|
|
||||||
|
proxy.listen = function () {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var port;
|
||||||
|
|
||||||
|
var nextPort = function () {
|
||||||
|
port = portOptions.shift();
|
||||||
|
if (!port) done(new Error('No more port options available.'));
|
||||||
|
server.listen(port);
|
||||||
|
};
|
||||||
|
|
||||||
|
var onError = function (err) {
|
||||||
|
if (err && err.code === 'EADDRINUSE') nextPort();
|
||||||
|
else done(err);
|
||||||
|
};
|
||||||
|
|
||||||
|
var onListening = function () {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
var done = function (err) {
|
||||||
|
server.removeListener('error', onError);
|
||||||
|
server.removeListener('listening', onListening);
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve(port);
|
||||||
|
};
|
||||||
|
|
||||||
|
server.on('error', onError, true);
|
||||||
|
server.on('listening', onListening, true);
|
||||||
|
nextPort();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
71
test/utils/automated_browser/index.js
Normal file
71
test/utils/automated_browser/index.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* jshint node:true */
|
||||||
|
var wd = require('wd');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var readFileSync = require('fs').readFileSync;
|
||||||
|
var rel = require('path').join.bind(null, __dirname);
|
||||||
|
|
||||||
|
var Connector = require('./_connector');
|
||||||
|
var DevServer = require('./_dev_server');
|
||||||
|
|
||||||
|
var portOptions = [
|
||||||
|
4000, 4001, 4040, 4321, 4502, 4503, 4567, 5000, 5001, 5050, 5555, 5432, 6000, 6001, 6060,
|
||||||
|
6666, 6543, 7000, 7070, 7774, 7777, 8000, 8001, 8003, 8031, 8080, 8081, 8443, 8765, 8777,
|
||||||
|
8888, 9000, 9001, 9031, 9080, 9090, 9876, 9877, 9999, 49221, 55001
|
||||||
|
];
|
||||||
|
|
||||||
|
var configfile = readFileSync(rel('../../src/config.js'), 'utf8').replace(
|
||||||
|
/elasticsearch:[^\n]+/,
|
||||||
|
'elasticsearch: \'http://\' + window.location.host + \'/es-proxy\','
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.init = function (opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
var server = new DevServer();
|
||||||
|
|
||||||
|
if (opts.useSauceLabs) {
|
||||||
|
var connector = new Connector();
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.listen()
|
||||||
|
.then(function (port) {
|
||||||
|
return wd.promiseChainRemote()
|
||||||
|
.init({
|
||||||
|
browserName: browserName || 'chrome',
|
||||||
|
baseUrl: 'http://localhost:' + port
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function (wd) {
|
||||||
|
return {
|
||||||
|
server: server,
|
||||||
|
wd: wd,
|
||||||
|
close: function () {
|
||||||
|
return Promise.all([
|
||||||
|
wd.close
|
||||||
|
server.close()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.usingSauceLabs = function () {
|
||||||
|
var server = new DevServer();
|
||||||
|
|
||||||
|
|
||||||
|
var close = function () {
|
||||||
|
return Promise.all([
|
||||||
|
proxy.close(),
|
||||||
|
connector.close(),
|
||||||
|
server.close()
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return server.listen()
|
||||||
|
.then(function (devServerPort) {
|
||||||
|
return connector.listen()
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
106
test/utils/dev_server/index.js
Normal file
106
test/utils/dev_server/index.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/* jshint node:true */
|
||||||
|
|
||||||
|
var connect = require('connect');
|
||||||
|
var http = require('http');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
var instrumentationMiddleware = require('./_instrumentation');
|
||||||
|
var amdRapperMiddleware = require('./_amd_rapper');
|
||||||
|
var rel = require('path').join.bind(null, __dirname);
|
||||||
|
|
||||||
|
var proxy = require('http-proxy').createProxyServer({});
|
||||||
|
var ROOT = rel('../../../');
|
||||||
|
var SRC = rel('../../../src');
|
||||||
|
|
||||||
|
module.exports = function DevServer(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var server = this;
|
||||||
|
var app = connect();
|
||||||
|
var httpServer = http.createServer(app);
|
||||||
|
|
||||||
|
app.use(instrumentationMiddleware({
|
||||||
|
root: ROOT,
|
||||||
|
displayRoot: SRC,
|
||||||
|
filter: function (filename) {
|
||||||
|
return filename.match(/.*\/src\/.*\.js$/)
|
||||||
|
&& !filename.match(/.*\/src\/bower_components\/.*\.js$/)
|
||||||
|
&& !filename.match(/.*\/src\/kibana\/utils\/(event_emitter|next_tick)\.js$/);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use(amdRapperMiddleware({
|
||||||
|
root: ROOT
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use('/es-proxy', function (req, res) {
|
||||||
|
req.url = req.url.replace(/^\/es-proxy/, '');
|
||||||
|
proxy.web(req, res, { target: 'http://localhost:' + (process.env.ES_PORT || 9200) });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(connect.static(ROOT));
|
||||||
|
|
||||||
|
// respond to the "maybe_start_server" pings
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (req.method !== 'HEAD' || req.url !== '/') return next();
|
||||||
|
res.statusCode === 200;
|
||||||
|
res.setHeader('Pong', 'Kibana 4 Dev Server');
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (req.url !== '/') return next();
|
||||||
|
res.statusCode = 303;
|
||||||
|
res.setHeader('Location', '/src/');
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// prevent chrome's stupid "this page is in spanish" on the directories page
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
res.setHeader('Content-Language', 'en');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
// allow browsing directories
|
||||||
|
app.use(connect.directory(ROOT));
|
||||||
|
|
||||||
|
server.listenOnFirstOpenPort = function (ports) {
|
||||||
|
var options = ports.slice(0);
|
||||||
|
|
||||||
|
// wrap this logic in an IIFE so that we can call it again later
|
||||||
|
return (function attempt() {
|
||||||
|
var port = options.shift();
|
||||||
|
if (!port) return Promise.reject(new Error('None of the supplied options succeeded'));
|
||||||
|
|
||||||
|
return server.listen(port)
|
||||||
|
// filter out EADDRINUSE errors and call attempt again
|
||||||
|
.catch(function (err) {
|
||||||
|
if (err.code === 'EADDRINUSE') return attempt();
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|
||||||
|
server.listen = function (port) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var done = function (err) {
|
||||||
|
httpServer.removeListener('error', done);
|
||||||
|
httpServer.removeListener('listening', done);
|
||||||
|
|
||||||
|
// pass the error along
|
||||||
|
if (err) return reject(err);
|
||||||
|
|
||||||
|
resolve(server.port = httpServer.address().port);
|
||||||
|
};
|
||||||
|
|
||||||
|
// call done with an error
|
||||||
|
httpServer.on('error', done, true);
|
||||||
|
// call done without any args
|
||||||
|
httpServer.on('listening', done, true);
|
||||||
|
|
||||||
|
httpServer.listen(port);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
server.close = httpServer.close.bind(httpServer);
|
||||||
|
};
|
Loading…
Reference in a new issue