mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
moved devServer into a module so that it can be used programmatically
This commit is contained in:
parent
c4c8af0675
commit
7ace826b63
26 changed files with 500 additions and 109 deletions
0
.creds.json
Normal file
0
.creds.json
Normal file
10
package.json
10
package.json
|
@ -6,22 +6,22 @@
|
|||
"main": "Gulpfile.js",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"bluebird": "~2.0.7",
|
||||
"connect": "~2.19.5",
|
||||
"event-stream": "~3.1.5",
|
||||
"expect.js": "~0.2.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-cli": "~0.1.13",
|
||||
"grunt-contrib-connect": "~0.6.0",
|
||||
"grunt-contrib-jade": "~0.10.0",
|
||||
"grunt-contrib-jshint": "~0.8.0",
|
||||
"grunt-contrib-less": "~0.10.0",
|
||||
"grunt-contrib-requirejs": "~0.4.4",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-mocha": "~0.4.10",
|
||||
"http-proxy": "~1.1.4",
|
||||
"istanbul": "~0.2.4",
|
||||
"load-grunt-config": "~0.7.0",
|
||||
"lodash": "~2.4.1",
|
||||
"bluebird": "~1.2.4",
|
||||
"mocha": "~1.17.1",
|
||||
"event-stream": "~3.1.5"
|
||||
"mocha": "~1.17.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
.thumbnail > img,
|
||||
.thumbnail a > img,
|
||||
.carousel-inner > .item > img,
|
||||
|
|
|
@ -323,8 +323,6 @@ define(function (require) {
|
|||
};
|
||||
}, {});
|
||||
|
||||
if (!indexPattern) return;
|
||||
|
||||
var columnObjects = arrayToKeys($state.columns);
|
||||
|
||||
$scope.fields = [];
|
||||
|
@ -332,6 +330,8 @@ define(function (require) {
|
|||
$scope.formatsByName = {};
|
||||
$state.columns = $state.columns || [];
|
||||
|
||||
if (!indexPattern) return;
|
||||
|
||||
// Inject source into list;
|
||||
//$scope.fields.push({name: '_source', type: 'source', display: false});
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ define(function (require) {
|
|||
template: headerHtml,
|
||||
controller: function ($scope) {
|
||||
$scope.headerClass = function (column) {
|
||||
if (!$scope.mapping) return;
|
||||
if ($scope.mapping[column] && !$scope.mapping[column].indexed) return;
|
||||
|
||||
var sorting = $scope.sorting;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
.thumbnail > img,
|
||||
.thumbnail a > img,
|
||||
.carousel-inner > .item > img,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
.thumbnail > img,
|
||||
.thumbnail a > img,
|
||||
.carousel-inner > .item > img,
|
||||
|
|
|
@ -66,10 +66,12 @@ define(function (require) {
|
|||
var row = rowStack.slice(0);
|
||||
var metric = bucket.value == null ? bucket.doc_count : bucket.value;
|
||||
|
||||
if (revColStack.length) [].push.apply(row, new Array(revColStack.length));
|
||||
|
||||
// we have a full row, minus the final metric
|
||||
row.push(metric);
|
||||
if (!revColStack.length) {
|
||||
// we have a full row, minus the final metric
|
||||
row.push(metric);
|
||||
} else {
|
||||
[].push.apply(row, new Array(revColStack.length + 1));
|
||||
}
|
||||
|
||||
chartData.rows.push(row);
|
||||
};
|
||||
|
@ -184,8 +186,6 @@ define(function (require) {
|
|||
rows: []
|
||||
};
|
||||
|
||||
// debugger;
|
||||
|
||||
(function cleanup(obj) {
|
||||
if (obj.rows && obj.columns) {
|
||||
// this obj is a chart
|
||||
|
@ -196,10 +196,11 @@ define(function (require) {
|
|||
|
||||
var rows = obj.rows;
|
||||
var cols = obj.columns;
|
||||
|
||||
delete obj.rows;
|
||||
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) {
|
||||
raw.rows.push([].concat(raw.splitValStack, row));
|
||||
});
|
||||
|
@ -210,6 +211,7 @@ define(function (require) {
|
|||
delete obj.splits;
|
||||
|
||||
labelStack.push(obj.label);
|
||||
|
||||
_.forOwn(splits, function (split) {
|
||||
raw.splitColumns.push(split.column);
|
||||
raw.splitValStack.push(split.value);
|
||||
|
|
|
@ -100,15 +100,6 @@ define(function (require) {
|
|||
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 = {
|
||||
hide: true,
|
||||
default: {},
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
.thumbnail > img,
|
||||
.thumbnail a > img,
|
||||
.carousel-inner > .item > img,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
.thumbnail > img,
|
||||
.thumbnail a > img,
|
||||
.carousel-inner > .item > img,
|
||||
|
|
|
@ -56,8 +56,6 @@ define(function (require) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (newPage === oldPage) return;
|
||||
|
||||
// setup the list of the other pages to link to
|
||||
$scope.otherPages = [];
|
||||
var width = +getOtherWidth($scope) || 5;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
@import "icon_font.css";
|
||||
/*!
|
||||
* Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Bootswatch
|
||||
// -----------------------------------------------------
|
||||
|
||||
@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
// @import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");
|
||||
|
||||
// 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() {
|
||||
grunt.task.run(['connect:dev']);
|
||||
grunt.task.run(['server']);
|
||||
done();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
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…
Add table
Add a link
Reference in a new issue