Merge master

This commit is contained in:
LeeDr 2016-06-15 11:29:23 -05:00
commit bfcb875c77
112 changed files with 827 additions and 322 deletions

1
.gitignore vendored
View file

@ -15,6 +15,7 @@ target
/test/screenshots/diff /test/screenshots/diff
/test/screenshots/failure /test/screenshots/failure
/test/screenshots/session /test/screenshots/session
/test/screenshots/visual_regression_gallery.html
/esvm /esvm
.htpasswd .htpasswd
.eslintcache .eslintcache

View file

@ -113,7 +113,7 @@ Once that is complete just run:
``` ```
sh sh
npm run test && npm run build npm run test && npm run build -- --skip-os-packages
``` ```
#### Debugging unit tests #### Debugging unit tests
@ -121,27 +121,27 @@ npm run test && npm run build
The standard `npm run test` task runs several sub tasks and can take several minutes to complete, making debugging failures pretty painful. In order to ease the pain specialized tasks provide alternate methods for running the tests. The standard `npm run test` task runs several sub tasks and can take several minutes to complete, making debugging failures pretty painful. In order to ease the pain specialized tasks provide alternate methods for running the tests.
`npm run test:quick` `npm run test:quick`
Runs both server and browser tests, but skips linting Runs both server and browser tests, but skips linting
`npm run test:server` `npm run test:server`
Run only the server tests Run only the server tests
`npm run test:browser` `npm run test:browser`
Run only the browser tests. Coverage reports are available for browser tests by running `npm run test:coverage`. You can find the results under the `coverage/` directory that will be created upon completion. Run only the browser tests. Coverage reports are available for browser tests by running `npm run test:coverage`. You can find the results under the `coverage/` directory that will be created upon completion.
`npm run test:dev` `npm run test:dev`
Initializes an environment for debugging the browser tests. Includes an dedicated instance of the kibana server for building the test bundle, and a karma server. When running this task the build is optimized for the first time and then a karma-owned instance of the browser is opened. Click the "debug" button to open a new tab that executes the unit tests. Initializes an environment for debugging the browser tests. Includes an dedicated instance of the kibana server for building the test bundle, and a karma server. When running this task the build is optimized for the first time and then a karma-owned instance of the browser is opened. Click the "debug" button to open a new tab that executes the unit tests.
![Browser test debugging](http://i.imgur.com/DwHxgfq.png) ![Browser test debugging](http://i.imgur.com/DwHxgfq.png)
`npm run mocha [test file or dir]` or `npm run mocha:debug [test file or dir]` `npm run mocha [test file or dir]` or `npm run mocha:debug [test file or dir]`
Run a one off test with the local project version of mocha, babel compilation, and optional debugging. Great Run a one off test with the local project version of mocha, babel compilation, and optional debugging. Great
for development and fixing individual tests. for development and fixing individual tests.
#### Unit testing plugins #### Unit testing plugins
This should work super if you're using the [Kibana plugin generator](https://github.com/elastic/generator-kibana-plugin). If you're not using the generator, well, you're on your own. We suggest you look at how the generator works. This should work super if you're using the [Kibana plugin generator](https://github.com/elastic/generator-kibana-plugin). If you're not using the generator, well, you're on your own. We suggest you look at how the generator works.
`npm run test:dev -- --kbnServer.testsBundle.pluginId=some_special_plugin --kbnServer.plugin-path=../some_special_plugin` `npm run test:dev -- --kbnServer.testsBundle.pluginId=some_special_plugin --kbnServer.plugin-path=../some_special_plugin`
Run the tests for just your particular plugin. Assuming you plugin lives outside of the `installedPlugins directory`, which it should. Run the tests for just your particular plugin. Assuming you plugin lives outside of the `installedPlugins directory`, which it should.
#### Running browser automation tests: #### Running browser automation tests:
@ -151,13 +151,13 @@ Run the tests for just your particular plugin. Assuming you plugin lives outside
The following will start Kibana, Elasticsearch and Selenium for you. To run the functional UI tests use the following commands The following will start Kibana, Elasticsearch and Selenium for you. To run the functional UI tests use the following commands
`npm run test:ui` `npm run test:ui`
Run the functional UI tests one time and exit. This is used by the CI systems and is great for quickly checking that things pass. It is essentially a combination of the next two tasks. Run the functional UI tests one time and exit. This is used by the CI systems and is great for quickly checking that things pass. It is essentially a combination of the next two tasks.
`npm run test:ui:server` `npm run test:ui:server`
Start the server required for the `test:ui:runner` tasks. Once the server is started `test:ui:runner` can be run multiple times without waiting for the server to start. Start the server required for the `test:ui:runner` tasks. Once the server is started `test:ui:runner` can be run multiple times without waiting for the server to start.
`npm run test:ui:runner` `npm run test:ui:runner`
Execute the front-end selenium tests. This requires the server started by the `test:ui:server` task. Execute the front-end selenium tests. This requires the server started by the `test:ui:server` task.
##### If you already have ElasticSearch, Kibana, and Selenium Server running: ##### If you already have ElasticSearch, Kibana, and Selenium Server running:
@ -187,12 +187,12 @@ Packages are built using fpm, pleaserun, dpkg, and rpm. fpm and pleaserun can b
apt-get install ruby-dev rpm apt-get install ruby-dev rpm
gem install fpm -v 1.5.0 # required by pleaserun 0.0.16 gem install fpm -v 1.5.0 # required by pleaserun 0.0.16
gem install pleaserun -v 0.0.16 # higher versions fail at the moment gem install pleaserun -v 0.0.16 # higher versions fail at the moment
npm run build:ospackages npm run build -- --skip-archives
``` ```
To specify a package to build you can add `rpm` or `deb` as an argument. To specify a package to build you can add `rpm` or `deb` as an argument.
```sh ```sh
npm run build:ospackages -- --rpm npm run build -- --rpm
``` ```
Distributable packages can be found in `target/` after the build completes. Distributable packages can be found in `target/` after the build completes.

View file

@ -9,7 +9,7 @@ module.exports = function (grunt) {
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
root: __dirname, root: __dirname,
src: __dirname + '/src', src: __dirname + '/src',
build: __dirname + '/build', // temporary build directory buildDir: __dirname + '/build', // temporary build directory
plugins: __dirname + '/src/plugins', plugins: __dirname + '/src/plugins',
server: __dirname + '/src/server', server: __dirname + '/src/server',
target: __dirname + '/target', // location of the compressed build targets target: __dirname + '/target', // location of the compressed build targets
@ -69,6 +69,9 @@ module.exports = function (grunt) {
grunt.config.merge(config); grunt.config.merge(config);
// must run before even services/platforms
grunt.config.set('build', require('./tasks/config/build')(grunt));
config.packageScriptsDir = __dirname + '/tasks/build/package_scripts'; config.packageScriptsDir = __dirname + '/tasks/build/package_scripts';
// ensure that these run first, other configs need them // ensure that these run first, other configs need them
config.services = require('./tasks/config/services')(grunt); config.services = require('./tasks/config/services')(grunt);

View file

@ -1,4 +1,4 @@
# Kibana 5.0.0-snapshot # Kibana 5.0.0
Kibana is an open source ([Apache Licensed](https://github.com/elastic/kibana/blob/master/LICENSE.md)), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elasticsearch. Kibana is an open source ([Apache Licensed](https://github.com/elastic/kibana/blob/master/LICENSE.md)), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elasticsearch.

View file

@ -8,6 +8,7 @@
:k4pull: https://github.com/elastic/kibana/pull/ :k4pull: https://github.com/elastic/kibana/pull/
:version: master :version: master
:esversion: master :esversion: master
:packageversion: master
include::introduction.asciidoc[] include::introduction.asciidoc[]

View file

@ -26,7 +26,7 @@ wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add
+ +
["source","sh",subs="attributes"] ["source","sh",subs="attributes"]
-------------------------------------------------- --------------------------------------------------
echo "deb http://packages.elastic.co/kibana/{version}/debian stable main" | sudo tee -a /etc/apt/sources.list.d/kibana.list echo "deb https://packages.elastic.co/kibana/{packageversion}/debian stable main" | sudo tee -a /etc/apt/sources.list.d/kibana.list
-------------------------------------------------- --------------------------------------------------
+ +
[WARNING] [WARNING]
@ -82,11 +82,11 @@ rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
+ +
["source","sh",subs="attributes"] ["source","sh",subs="attributes"]
-------------------------------------------------- --------------------------------------------------
[kibana-{version}] [kibana-{packageversion}]
name=Kibana repository for {version}.x packages name=Kibana repository for {packageversion} packages
baseurl=http://packages.elastic.co/kibana/{version}/centos baseurl=https://packages.elastic.co/kibana/{packageversion}/centos
gpgcheck=1 gpgcheck=1
gpgkey=http://packages.elastic.co/GPG-KEY-elasticsearch gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1 enabled=1
-------------------------------------------------- --------------------------------------------------
+ +

View file

@ -11,7 +11,7 @@
"dashboarding" "dashboarding"
], ],
"private": false, "private": false,
"version": "5.0.0-snapshot", "version": "5.0.0",
"build": { "build": {
"number": 8467, "number": 8467,
"sha": "6cb7fec4e154faa0a4a3fee4b33dfef91b9870d9" "sha": "6cb7fec4e154faa0a4a3fee4b33dfef91b9870d9"
@ -39,7 +39,7 @@
"Tim Sullivan <tim@elastic.co>" "Tim Sullivan <tim@elastic.co>"
], ],
"scripts": { "scripts": {
"test": "grunt test", "test": "grunt test; grunt test:visualRegression",
"test:dev": "grunt test:dev", "test:dev": "grunt test:dev",
"test:quick": "grunt test:quick", "test:quick": "grunt test:quick",
"test:browser": "grunt test:browser", "test:browser": "grunt test:browser",
@ -49,7 +49,6 @@
"test:server": "grunt test:server", "test:server": "grunt test:server",
"test:coverage": "grunt test:coverage", "test:coverage": "grunt test:coverage",
"build": "grunt build", "build": "grunt build",
"build:ospackages": "grunt build --os-packages",
"start": "sh ./bin/kibana --dev", "start": "sh ./bin/kibana --dev",
"precommit": "grunt precommit", "precommit": "grunt precommit",
"karma": "karma start", "karma": "karma start",
@ -60,8 +59,7 @@
"makelogs": "makelogs", "makelogs": "makelogs",
"mocha": "mocha", "mocha": "mocha",
"mocha:debug": "mocha --debug-brk", "mocha:debug": "mocha --debug-brk",
"sterilize": "grunt sterilize", "sterilize": "grunt sterilize"
"compareScreenshots": "node utilities/compareScreenshots"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -128,8 +126,8 @@
"marked": "0.3.3", "marked": "0.3.3",
"minimatch": "2.0.10", "minimatch": "2.0.10",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"moment": "2.10.6", "moment": "2.13.0",
"moment-timezone": "0.4.1", "moment-timezone": "0.5.4",
"node-uuid": "1.4.7", "node-uuid": "1.4.7",
"raw-loader": "0.5.1", "raw-loader": "0.5.1",
"request": "2.61.0", "request": "2.61.0",
@ -155,6 +153,7 @@
"babel-eslint": "4.1.8", "babel-eslint": "4.1.8",
"chokidar": "1.4.3", "chokidar": "1.4.3",
"chromedriver": "2.21.2", "chromedriver": "2.21.2",
"dot": "1.0.3",
"elasticdump": "2.1.1", "elasticdump": "2.1.1",
"eslint": "1.10.3", "eslint": "1.10.3",
"eslint-plugin-mocha": "1.1.0", "eslint-plugin-mocha": "1.1.0",
@ -193,7 +192,7 @@
"nock": "2.10.0", "nock": "2.10.0",
"npm": "2.11.0", "npm": "2.11.0",
"portscanner": "1.0.0", "portscanner": "1.0.0",
"simple-git": "1.8.0", "simple-git": "1.37.0",
"sinon": "1.17.2", "sinon": "1.17.2",
"source-map": "0.4.4", "source-map": "0.4.4",
"source-map-support": "0.4.0", "source-map-support": "0.4.0",

View file

@ -23,6 +23,8 @@ function setLoggingJson(enabled) {
describe(`Server logging configuration`, function () { describe(`Server logging configuration`, function () {
it(`should be reloadable via SIGHUP process signaling`, function (done) { it(`should be reloadable via SIGHUP process signaling`, function (done) {
this.timeout(60000);
let asserted = false; let asserted = false;
let json = Infinity; let json = Infinity;
const conf = setLoggingJson(true); const conf = setLoggingJson(true);

View file

@ -1,8 +1,10 @@
import { fromRoot } from '../../utils'; import { fromRoot } from '../../utils';
import fs from 'fs';
import install from './install'; import install from './install';
import Logger from '../lib/logger'; import Logger from '../lib/logger';
import pkg from '../../utils/package_json'; import pkg from '../../utils/package_json';
import { parse, parseMilliseconds } from './settings'; import { parse, parseMilliseconds } from './settings';
import { find } from 'lodash';
function processCommand(command, options) { function processCommand(command, options) {
let settings; let settings;
@ -18,6 +20,24 @@ function processCommand(command, options) {
install(settings, logger); install(settings, logger);
} }
function getDefaultConfigPath() {
const paths = [
fromRoot('config/kibana.yml'),
'/etc/kibana/kibana.yml'
];
const availablePath = find(paths, configPath => {
try {
fs.accessSync(configPath, fs.R_OK);
return true;
} catch (e) {
//Check the next path
}
});
return availablePath || paths[0];
}
export default function pluginInstall(program) { export default function pluginInstall(program) {
program program
.command('install <plugin/url>') .command('install <plugin/url>')
@ -26,7 +46,7 @@ export default function pluginInstall(program) {
.option( .option(
'-c, --config <path>', '-c, --config <path>',
'path to the config file', 'path to the config file',
fromRoot('config/kibana.yml') getDefaultConfigPath()
) )
.option( .option(
'-t, --timeout <duration>', '-t, --timeout <duration>',

View file

@ -1,8 +1,8 @@
<div class="container state_default state_{{ui.serverState}}"> <div class="container overall_state_default overall_state_{{ui.serverState}}">
<header> <header>
<h1> <h1>
Status: <span class="state_color">{{ ui.serverStateMessage }}</span> Status: <span class="overall_state_color">{{ ui.serverStateMessage }}</span>
<i class="fa state_color state_icon" /> <i class="fa overall_state_color state_icon" />
<span class="pull-right"> <span class="pull-right">
{{ ui.name }} {{ ui.name }}
</span> </span>
@ -15,27 +15,29 @@
</div> </div>
</div> </div>
<div class="row plugin_status_wrapper"> <div class="row statuses_wrapper">
<h3>Installed Plugins</h3> <h3>Status Breakdown</h3>
<div ng-if="!ui.statuses && ui.loading" class="loading_statuses">
<div ng-if="!ui.statuses && ui.loading" class="statuses_loading">
<span class="spinner"></span> <span class="spinner"></span>
</div> </div>
<h4 ng-if="!ui.statuses && !ui.loading" class="missing_statuses"> <h4 ng-if="!ui.statuses && !ui.loading" class="statuses_missing">
No plugin status information available No status information available
</h4> </h4>
<table class="plugin_status_breakdown" ng-if="ui.statuses"> <table class="statuses" data-test-subj="statusBreakdown" ng-if="ui.statuses">
<tr class="row"> <tr class="row">
<th class="col-xs-2">Name</th> <th class="col-xs-4">ID</th>
<th class="col-xs-2">Version</th>
<th class="col-xs-8">Status</th> <th class="col-xs-8">Status</th>
</tr> </tr>
<tr ng-repeat="status in ui.statuses" class="status_row plugin_state_default plugin_state_{{status.state}} row"> <tr
<td class="col-xs-2 status_name">{{status.name}}</td> ng-repeat="status in ui.statuses"
<td class="col-xs-2 status_version">{{status.version}}</td> class="status status_state_default status_state_{{status.state}} row">
<td class="col-xs-4 status_id">{{status.id}}</td>
<td class="col-xs-8 status_message"> <td class="col-xs-8 status_message">
<i class="fa plugin_state_color plugin_state_icon" /> <i class="fa status_state_color status_state_icon" />
{{status.message}} {{status.message}}
</td> </td>
</tr> </tr>

View file

@ -28,9 +28,10 @@ const chrome = require('ui/chrome')
const data = resp.data; const data = resp.data;
ui.metrics = data.metrics; ui.metrics = data.metrics;
ui.statuses = data.status.statuses;
ui.name = data.name; ui.name = data.name;
ui.statuses = data.status.statuses;
const overall = data.status.overall; const overall = data.status.overall;
if (!ui.serverState || (ui.serverState !== overall.state)) { if (!ui.serverState || (ui.serverState !== overall.state)) {
ui.serverState = overall.state; ui.serverState = overall.state;

View file

@ -5,9 +5,9 @@
@status-metric-border: #aaa; @status-metric-border: #aaa;
@status-metric-title-color: #666; @status-metric-title-color: #666;
@status-plugins-bg: #fff; @status-statuses-bg: #fff;
@status-plugins-border: #bbb; @status-statuses-border: #bbb;
@status-plugins-headings-color: #666; @status-statuses-headings-color: #666;
@status-default: #7c7c7c; @status-default: #7c7c7c;
@status-green: #94c63d; @status-green: #94c63d;
@ -58,13 +58,13 @@
} }
} }
// plugin status table section // status status table section
.plugin_status_wrapper { .statuses_wrapper {
margin-top: 25px; margin-top: 25px;
margin-left: -5px; margin-left: -5px;
margin-right: -5px; margin-right: -5px;
border-top:2px solid; border-top:2px solid;
background-color: @status-plugins-bg; background-color: @status-statuses-bg;
padding: 10px; padding: 10px;
h3 { h3 {
@ -72,33 +72,34 @@
margin-bottom: 3px; margin-bottom: 3px;
} }
.missing_statuses, .statuses_loading,
.loading_statuses { .statuses_missing {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
} }
.plugin_status_breakdown { .statuses {
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
margin-bottom: 30px;
.status_row { .status {
height:30px; height:30px;
line-height:30px; line-height:30px;
border-bottom:1px solid; border-bottom:1px solid;
border-bottom-color: @status-plugins-border; border-bottom-color: @status-statuses-border;
} }
th { th {
color:@status-plugins-headings-color; color:@status-statuses-headings-color;
font-weight: normal; font-weight: normal;
height:25px; height:25px;
line-height:25px; line-height:25px;
border-bottom:1px solid; border-bottom:1px solid;
border-bottom-color: @status-plugins-border; border-bottom-color: @status-statuses-border;
} }
.status_name { .status_id {
padding:0px 5px; padding:0px 5px;
border-left: 2px solid; border-left: 2px solid;
} }
@ -111,17 +112,17 @@
} }
} }
//plugin state //status state
.plugin_state(@color, @icon) { .status_state(@color, @icon) {
.plugin_state_color { .status_state_color {
color: @color; color: @color;
} }
.plugin_state_icon:before { .status_state_icon:before {
content: @icon; content: @icon;
} }
.status_name { .status_id {
border-left-color: @color !important; border-left-color: @color !important;
} }
@ -130,49 +131,49 @@
} }
} }
.plugin_state_default { .status_state_default {
.plugin_state(@status-default, @icon-default); .status_state(@status-default, @icon-default);
} }
.plugin_state_green { .status_state_green {
.plugin_state(@status-green, @icon-green); .status_state(@status-green, @icon-green);
} }
.plugin_state_yellow { .status_state_yellow {
.plugin_state(@status-yellow, @icon-yellow); .status_state(@status-yellow, @icon-yellow);
} }
.plugin_state_red { .status_state_red {
.plugin_state(@status-red, @icon-red); .status_state(@status-red, @icon-red);
} }
//server state //server state
.state(@color, @icon) { .state(@color, @icon) {
.state_color { .overall_state_color {
color: @color; color: @color;
} }
.state_icon:before { .overall_state_icon:before {
content: @icon; content: @icon;
} }
.plugin_status_wrapper { .statuses_wrapper {
border-top-color: @color; border-top-color: @color;
} }
} }
.state_default { .overall_state_default {
.state(@status-default, @icon-default); .state(@status-default, @icon-default);
} }
.state_green { .overall_state_green {
.state(@status-green, @icon-green); .state(@status-green, @icon-green);
} }
.state_yellow { .overall_state_yellow {
.state(@status-yellow, @icon-yellow); .state(@status-yellow, @icon-yellow);
} }
.state_red { .overall_state_red {
.state(@status-red, @icon-red); .state(@status-red, @icon-red);
} }

View file

@ -127,7 +127,7 @@ module.exports = class Plugin {
server.exposeStaticDir(`/plugins/${id}/{path*}`, this.publicDir); server.exposeStaticDir(`/plugins/${id}/{path*}`, this.publicDir);
} }
this.status = kbnServer.status.create(this); this.status = kbnServer.status.createForPlugin(this);
server.expose('status', this.status); server.expose('status', this.status);
return await attempt(this.externalInit, [server, options], this); return await attempt(this.externalInit, [server, options], this);

View file

@ -1,4 +1,4 @@
import _ from 'lodash'; import { find } from 'lodash';
import expect from 'expect.js'; import expect from 'expect.js';
import sinon from 'sinon'; import sinon from 'sinon';
@ -17,31 +17,63 @@ describe('ServerStatus class', function () {
serverStatus = new ServerStatus(server); serverStatus = new ServerStatus(server);
}); });
describe('#create(plugin)', function () { describe('#create(id)', () => {
it('should create a new status by plugin', function () { it('should create a new plugin with an id', () => {
let status = serverStatus.create(plugin); const status = serverStatus.create('someid');
expect(status).to.be.a(Status); expect(status).to.be.a(Status);
}); });
}); });
describe('#get(name)', function () { describe('#createForPlugin(plugin)', function () {
it('exposes plugins by its id/name', function () { it('should create a new status by plugin', function () {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
expect(serverStatus.get('name')).to.be(status); expect(status).to.be.a(Status);
}); });
}); });
describe('#getState(name)', function () { describe('#get(id)', () => {
it('should expose the state of the plugin by name', function () { it('exposes statuses by their id', () => {
let status = serverStatus.create(plugin); const status = serverStatus.create('statusid');
expect(serverStatus.get('statusid')).to.be(status);
});
it('does not get the status for a plugin', () => {
serverStatus.createForPlugin(plugin);
expect(serverStatus.get(plugin)).to.be(undefined);
});
});
describe('#getForPluginId(plugin)', function () {
it('exposes plugin status for the plugin', function () {
let status = serverStatus.createForPlugin(plugin);
expect(serverStatus.getForPluginId(plugin.id)).to.be(status);
});
it('does not get plain statuses by their id', function () {
serverStatus.create('someid');
expect(serverStatus.getForPluginId('someid')).to.be(undefined);
});
});
describe('#getState(id)', function () {
it('should expose the state of a status by id', function () {
let status = serverStatus.create('someid');
status.green(); status.green();
expect(serverStatus.getState('name')).to.be('green'); expect(serverStatus.getState('someid')).to.be('green');
});
});
describe('#getStateForPluginId(plugin)', function () {
it('should expose the state of a plugin by id', function () {
let status = serverStatus.createForPlugin(plugin);
status.green();
expect(serverStatus.getStateForPluginId(plugin.id)).to.be('green');
}); });
}); });
describe('#overall()', function () { describe('#overall()', function () {
it('considers each status to produce a summary', function () { it('considers each status to produce a summary', function () {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
expect(serverStatus.overall().state).to.be('uninitialized'); expect(serverStatus.overall().state).to.be('uninitialized');
@ -69,25 +101,24 @@ describe('ServerStatus class', function () {
it('serializes to overall status and individuals', function () { it('serializes to overall status and individuals', function () {
const pluginOne = {id: 'one', version: '1.0.0'}; const pluginOne = {id: 'one', version: '1.0.0'};
const pluginTwo = {id: 'two', version: '2.0.0'}; const pluginTwo = {id: 'two', version: '2.0.0'};
const pluginThree = {id: 'three', version: '3.0.0'};
let one = serverStatus.create(pluginOne); let service = serverStatus.create('some service');
let two = serverStatus.create(pluginTwo); let p1 = serverStatus.createForPlugin(pluginOne);
let three = serverStatus.create(pluginThree); let p2 = serverStatus.createForPlugin(pluginTwo);
one.green(); service.green();
two.yellow(); p1.yellow();
three.red(); p2.red();
let obj = JSON.parse(JSON.stringify(serverStatus)); let json = JSON.parse(JSON.stringify(serverStatus));
expect(obj).to.have.property('overall'); expect(json).to.have.property('overall');
expect(obj.overall.state).to.eql(serverStatus.overall().state); expect(json.overall.state).to.eql(serverStatus.overall().state);
expect(obj.statuses).to.have.length(3); expect(json.statuses).to.have.length(3);
let outs = _.indexBy(obj.statuses, 'name'); const out = status => find(json.statuses, { id: status.id });
expect(outs.one).to.have.property('state', 'green'); expect(out(service)).to.have.property('state', 'green');
expect(outs.two).to.have.property('state', 'yellow'); expect(out(p1)).to.have.property('state', 'yellow');
expect(outs.three).to.have.property('state', 'red'); expect(out(p2)).to.have.property('state', 'red');
}); });
}); });

View file

@ -15,11 +15,11 @@ describe('Status class', function () {
}); });
it('should have an "uninitialized" state initially', function () { it('should have an "uninitialized" state initially', function () {
expect(serverStatus.create(plugin)).to.have.property('state', 'uninitialized'); expect(serverStatus.createForPlugin(plugin)).to.have.property('state', 'uninitialized');
}); });
it('emits change when the status is set', function (done) { it('emits change when the status is set', function (done) {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
status.once('change', function (prev, prevMsg) { status.once('change', function (prev, prevMsg) {
expect(status.state).to.be('green'); expect(status.state).to.be('green');
@ -42,7 +42,7 @@ describe('Status class', function () {
}); });
it('should only trigger the change listener when something changes', function () { it('should only trigger the change listener when something changes', function () {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let stub = sinon.stub(); let stub = sinon.stub();
status.on('change', stub); status.on('change', stub);
status.green('Ready'); status.green('Ready');
@ -52,18 +52,17 @@ describe('Status class', function () {
}); });
it('should create a JSON representation of the status', function () { it('should create a JSON representation of the status', function () {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
status.green('Ready'); status.green('Ready');
let json = status.toJSON(); let json = status.toJSON();
expect(json.name).to.eql(plugin.id); expect(json.id).to.eql(status.id);
expect(json.version).to.eql(plugin.version);
expect(json.state).to.eql('green'); expect(json.state).to.eql('green');
expect(json.message).to.eql('Ready'); expect(json.message).to.eql('Ready');
}); });
it('should call on handler if status is already matched', function (done) { it('should call on handler if status is already matched', function (done) {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let msg = 'Test Ready'; let msg = 'Test Ready';
status.green(msg); status.green(msg);
@ -77,7 +76,7 @@ describe('Status class', function () {
}); });
it('should call once handler if status is already matched', function (done) { it('should call once handler if status is already matched', function (done) {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let msg = 'Test Ready'; let msg = 'Test Ready';
status.green(msg); status.green(msg);
@ -92,7 +91,7 @@ describe('Status class', function () {
function testState(color) { function testState(color) {
it(`should change the state to ${color} when #${color}() is called`, function () { it(`should change the state to ${color} when #${color}() is called`, function () {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let message = 'testing ' + color; let message = 'testing ' + color;
status[color](message); status[color](message);
expect(status).to.have.property('state', color); expect(status).to.have.property('state', color);
@ -100,7 +99,7 @@ describe('Status class', function () {
}); });
it(`should trigger the "change" listner when #${color}() is called`, function (done) { it(`should trigger the "change" listner when #${color}() is called`, function (done) {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let message = 'testing ' + color; let message = 'testing ' + color;
status.on('change', function (prev, prevMsg) { status.on('change', function (prev, prevMsg) {
expect(status.state).to.be(color); expect(status.state).to.be(color);
@ -114,7 +113,7 @@ describe('Status class', function () {
}); });
it(`should trigger the "${color}" listner when #${color}() is called`, function (done) { it(`should trigger the "${color}" listner when #${color}() is called`, function (done) {
let status = serverStatus.create(plugin); let status = serverStatus.createForPlugin(plugin);
let message = 'testing ' + color; let message = 'testing ' + color;
status.on(color, function (prev, prevMsg) { status.on(color, function (prev, prevMsg) {
expect(status.state).to.be(color); expect(status.state).to.be(color);

View file

@ -9,8 +9,16 @@ module.exports = class ServerStatus {
this._created = {}; this._created = {};
} }
create(plugin) { create(id) {
return (this._created[plugin.id] = new Status(plugin, this.server)); const status = new Status(id, this.server);
this._created[status.id] = status;
return status;
}
createForPlugin(plugin) {
const status = this.create(`plugin:${plugin.id}@${plugin.version}`);
status.plugin = plugin;
return status;
} }
each(fn) { each(fn) {
@ -22,12 +30,26 @@ module.exports = class ServerStatus {
}); });
} }
get(name) { get(id) {
return this._created[name]; return this._created[id];
} }
getState(name) { getForPluginId(pluginId) {
return _.get(this._created, [name, 'state'], 'uninitialized'); return _.find(this._created, s =>
s.plugin && s.plugin.id === pluginId
);
}
getState(id) {
const status = this.get(id);
if (!status) return undefined;
return status.state || 'uninitialized';
}
getStateForPluginId(pluginId) {
const status = this.getForPluginId(pluginId);
if (!status) return undefined;
return status.state || 'uninitialized';
} }
overall() { overall() {

View file

@ -3,18 +3,26 @@ import states from './states';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
class Status extends EventEmitter { class Status extends EventEmitter {
constructor(plugin, server) { constructor(id, server) {
super(); super();
this.plugin = plugin; if (!id || typeof id !== 'string') {
throw new TypeError('Status constructor requires an `id` string');
}
this.id = id;
this.since = new Date(); this.since = new Date();
this.state = 'uninitialized'; this.state = 'uninitialized';
this.message = 'uninitialized'; this.message = 'uninitialized';
this.on('change', function (previous, previousMsg) { this.on('change', function (previous, previousMsg) {
this.since = new Date(); this.since = new Date();
let tags = ['status', `plugin:${this.plugin.toString()}`];
tags.push(this.state === 'red' ? 'error' : 'info'); const tags = [
'status',
this.id,
this.state === 'red' ? 'error' : 'info'
];
server.log(tags, { server.log(tags, {
tmpl: 'Status changed from <%= prevState %> to <%= state %><%= message ? " - " + message : "" %>', tmpl: 'Status changed from <%= prevState %> to <%= state %><%= message ? " - " + message : "" %>',
@ -28,8 +36,7 @@ class Status extends EventEmitter {
toJSON() { toJSON() {
return { return {
name: this.plugin.id, id: this.id,
version: this.plugin.version,
state: this.state, state: this.state,
icon: states.get(this.state).icon, icon: states.get(this.state).icon,
message: this.message, message: this.message,

View file

@ -0,0 +1,8 @@
export default function (grunt) {
grunt.registerTask('_build:babelCache', function () {
//When running from built packages, if a plugin is installed before babelcache
//exists it can become owned by root. This causes server startup to fail because
//the optimization process can't write to .babelcache.json.
grunt.file.write('build/kibana/optimize/.babelcache.json', '{}\n');
});
};

View file

@ -1,7 +0,0 @@
module.exports = function (grunt) {
var exec = require('child_process').execSync;
grunt.registerTask('_build:getProps', function () {
grunt.config.set('buildSha', String(exec('git rev-parse HEAD')).trim());
grunt.config.set('buildNum', parseFloat(String(exec('git log --format="%h" | wc -l')).trim()));
});
};

View file

@ -3,7 +3,6 @@ module.exports = function (grunt) {
grunt.registerTask('build', 'Build packages', function () { grunt.registerTask('build', 'Build packages', function () {
grunt.task.run(flatten([ grunt.task.run(flatten([
'_build:getProps',
'clean:build', 'clean:build',
'clean:target', 'clean:target',
'_build:downloadNodeBuilds:start', '_build:downloadNodeBuilds:start',
@ -13,6 +12,7 @@ module.exports = function (grunt) {
'_build:installedPlugins', '_build:installedPlugins',
'_build:packageJson', '_build:packageJson',
'_build:readme', '_build:readme',
'_build:babelCache',
'_build:installNpmDeps', '_build:installNpmDeps',
'_build:removePkgJsonDeps', '_build:removePkgJsonDeps',
'clean:testsFromModules', 'clean:testsFromModules',
@ -23,11 +23,11 @@ module.exports = function (grunt) {
'_build:downloadNodeBuilds:finish', '_build:downloadNodeBuilds:finish',
'_build:versionedLinks', '_build:versionedLinks',
'_build:osShellScripts', '_build:osShellScripts',
'_build:archives', grunt.option('skip-archives') ? [] : ['_build:archives'],
grunt.option('os-packages') ? [ grunt.option('skip-os-packages') ? [] : [
'_build:pleaseRun', '_build:pleaseRun',
'_build:osPackages', '_build:osPackages',
] : [], ],
'_build:shasums' '_build:shasums'
])); ]));
}); });

View file

@ -3,14 +3,16 @@ import { indexBy } from 'lodash';
import exec from '../utils/exec'; import exec from '../utils/exec';
export default (grunt) => { export default (grunt) => {
const targetDir = grunt.config.get('target'); const { config } = grunt;
const exec = require('../utils/exec');
const targetDir = config.get('target');
const packageScriptsDir = grunt.config.get('packageScriptsDir'); const packageScriptsDir = grunt.config.get('packageScriptsDir');
const servicesByName = indexBy(grunt.config.get('services'), 'name'); const servicesByName = indexBy(config.get('services'), 'name');
const config = grunt.config.get('packages'); const packages = config.get('packages');
const fpm = args => exec('fpm', args); const fpm = args => exec('fpm', args);
grunt.registerTask('_build:osPackages', function () { grunt.registerTask('_build:osPackages', function () {
grunt.config.get('platforms') config.get('platforms')
.filter(({ name }) => /linux-x(86|64)$/.test(name)) .filter(({ name }) => /linux-x(86|64)$/.test(name))
.map(({ name, buildDir }) => { .map(({ name, buildDir }) => {
const architecture = /x64$/.test(name) ? 'x86_64' : 'i386'; const architecture = /x64$/.test(name) ? 'x86_64' : 'i386';
@ -25,25 +27,26 @@ export default (grunt) => {
'--package', targetDir, '--package', targetDir,
'-s', 'dir', // input type '-s', 'dir', // input type
'--architecture', architecture, '--architecture', architecture,
'--name', config.name, '--name', packages.name,
'--description', config.description, '--description', packages.description,
'--version', config.version, '--version', packages.version,
'--url', config.site, '--url', packages.site,
'--vendor', config.vendor, '--vendor', packages.vendor,
'--maintainer', config.maintainer, '--maintainer', packages.maintainer,
'--license', config.license, '--license', packages.license,
'--after-install', resolve(packageScriptsDir, 'post_install.sh'), '--after-install', resolve(packageScriptsDir, 'post_install.sh'),
'--before-install', resolve(packageScriptsDir, 'pre_install.sh'), '--before-install', resolve(packageScriptsDir, 'pre_install.sh'),
'--before-remove', resolve(packageScriptsDir, 'pre_remove.sh'), '--before-remove', resolve(packageScriptsDir, 'pre_remove.sh'),
'--after-remove', resolve(packageScriptsDir, 'post_remove.sh'), '--after-remove', resolve(packageScriptsDir, 'post_remove.sh'),
'--config-files', config.path.kibanaConfig, '--config-files', packages.path.kibanaConfig,
'--template-value', `user=${config.user}`, '--template-value', `user=${packages.user}`,
'--template-value', `group=${config.group}`, '--template-value', `group=${packages.group}`,
'--template-value', `optimizeDir=${config.path.home}/optimize`, '--template-value', `optimizeDir=${packages.path.home}/optimize`,
'--template-value', `configDir=${packages.path.conf}`,
'--template-value', `pluginsDir=${packages.path.plugins}`,
//config folder is moved to path.conf, exclude {path.home}/config //config folder is moved to path.conf, exclude {path.home}/config
//uses relative path to --prefix, strip the leading / //uses relative path to --prefix, strip the leading /
'--exclude', `${config.path.home.slice(1)}/config` '--exclude', `${packages.path.home.slice(1)}/config`
]; ];
const debOptions = [ const debOptions = [
'-t', 'deb', '-t', 'deb',
@ -54,8 +57,8 @@ export default (grunt) => {
'--rpm-os', 'linux' '--rpm-os', 'linux'
]; ];
const args = [ const args = [
`${buildDir}/=${config.path.home}/`, `${buildDir}/=${packages.path.home}/`,
`${buildDir}/config/=${config.path.conf}/`, `${buildDir}/config/=${packages.path.conf}/`,
`${servicesByName.sysv.outputDir}/etc/=/etc/`, `${servicesByName.sysv.outputDir}/etc/=/etc/`,
`${servicesByName.systemd.outputDir}/lib/=/lib/` `${servicesByName.systemd.outputDir}/lib/=/lib/`
]; ];

View file

@ -5,6 +5,7 @@ module.exports = function (grunt) {
let deepModules = grunt.config.get('deepModules'); let deepModules = grunt.config.get('deepModules');
grunt.registerTask('_build:packageJson', function () { grunt.registerTask('_build:packageJson', function () {
const { sha, number, version } = grunt.config.get('build');
grunt.file.write( grunt.file.write(
'build/kibana/package.json', 'build/kibana/package.json',
@ -12,10 +13,10 @@ module.exports = function (grunt) {
name: pkg.name, name: pkg.name,
description: pkg.description, description: pkg.description,
keywords: pkg.keywords, keywords: pkg.keywords,
version: pkg.version, version,
build: { build: {
number: grunt.config.get('buildNum'), number,
sha: grunt.config.get('buildSha') sha
}, },
repository: pkg.repository, repository: pkg.repository,
engines: { engines: {

View file

@ -10,20 +10,26 @@ user_remove() {
} }
REMOVE_USER=false REMOVE_USER=false
REMOVE_DIRS=false
case $1 in case $1 in
# Includes cases for all valid arguments, exit 1 otherwise # Includes cases for all valid arguments, exit 1 otherwise
# Debian # Debian
purge) purge)
REMOVE_USER=true REMOVE_USER=true
REMOVE_DIRS=true
;;
remove)
REMOVE_DIRS=true
;; ;;
remove|failed-upgrade|abort-install|abort-upgrade|disappear|upgrade|disappear) failed-upgrade|abort-install|abort-upgrade|disappear|upgrade|disappear)
;; ;;
# Red Hat # Red Hat
0) 0)
REMOVE_USER=true REMOVE_USER=true
REMOVE_DIRS=true
;; ;;
1) 1)
@ -40,3 +46,17 @@ if [ "$REMOVE_USER" = "true" ]; then
user_remove "<%= user %>" user_remove "<%= user %>"
fi fi
fi fi
if [ "$REMOVE_DIRS" = "true" ]; then
if [ -d "<%= optimizeDir %>" ]; then
rm -rf "<%= optimizeDir %>"
fi
if [ -d "<%= pluginsDir %>" ]; then
rm -rf "<%= pluginsDir %>"
fi
if [ -d "<%= configDir %>" ]; then
rmdir --ignore-fail-on-non-empty "<%= configDir %>"
fi
fi

View file

@ -1,10 +1,11 @@
import { resolve } from 'path'; import { resolve } from 'path';
import { appendFileSync } from 'fs'; import { appendFileSync } from 'fs';
import exec from '../utils/exec'; import exec from '../utils/exec';
import { capitalize } from 'lodash';
export default (grunt) => { export default (grunt) => {
const userScriptsDir = grunt.config.get('userScriptsDir'); const userScriptsDir = grunt.config.get('userScriptsDir');
const { path, user, group, name, description } = grunt.config.get('packages'); const { path, user, group, name } = grunt.config.get('packages');
grunt.registerTask('_build:pleaseRun', function () { grunt.registerTask('_build:pleaseRun', function () {
grunt.config.get('services').forEach((service) => { grunt.config.get('services').forEach((service) => {
@ -15,7 +16,7 @@ export default (grunt) => {
'--install-prefix', service.outputDir, '--install-prefix', service.outputDir,
'--overwrite', '--overwrite',
'--name', name, '--name', name,
'--description', description, '--description', capitalize(name),
'--user', user, '--user', user,
'--group', group, '--group', group,
'--sysv-log-path', path.logs, '--sysv-log-path', path.logs,

View file

@ -8,6 +8,9 @@ module.exports = function (grunt) {
grunt.registerTask('_build:shasums', function () { grunt.registerTask('_build:shasums', function () {
var targetDir = grunt.config.get('target'); var targetDir = grunt.config.get('target');
// for when shasums is run but archives and ospackages was not
grunt.file.mkdir(targetDir);
readdir(targetDir) readdir(targetDir)
.map(function (archive) { .map(function (archive) {
// only sha the archives and packages // only sha the archives and packages

View file

@ -12,10 +12,7 @@ module.exports = function (grunt) {
return resolve(rootPath, file); return resolve(rootPath, file);
}); });
//We don't want to build os packages with symlinks let transferFiles = (source, link) => exec('cp', ['-r', source, link]);
let transferFiles = (source, link) => grunt.option('os-packages')
? exec('cp', ['-r', source, link])
: exec('ln', ['-s', source, link]);
grunt.config.get('platforms').forEach(function (platform) { grunt.config.get('platforms').forEach(function (platform) {
grunt.file.mkdir(platform.buildDir); grunt.file.mkdir(platform.buildDir);

15
tasks/config/build.js Normal file
View file

@ -0,0 +1,15 @@
import { execSync as exec } from 'child_process';
export default (grunt) => {
const pkgVersion = grunt.config.get('pkg.version');
const sha = String(exec('git rev-parse HEAD')).trim();
const number = parseFloat(String(exec('git log --format="%h" | wc -l')).trim());
const version = buildVersion(grunt.option('release'), pkgVersion);
return { sha, number, version };
};
function buildVersion(isRelease, version) {
return isRelease ? version : `${version}-snapshot`;
}

View file

@ -3,6 +3,7 @@ module.exports = function (grunt) {
return { return {
build: 'build', build: 'build',
target: 'target', target: 'target',
screenshots: 'test/screenshots/session',
testsFromModules: 'build/kibana/node_modules/**/{test,tests}/**', testsFromModules: 'build/kibana/node_modules/**/{test,tests}/**',
deepModuleBins: 'build/kibana/node_modules/*/node_modules/**/.bin/{' + modules.join(',') + '}', deepModuleBins: 'build/kibana/node_modules/*/node_modules/**/.bin/{' + modules.join(',') + '}',
deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/', deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/',

View file

@ -1,8 +1,8 @@
export default (grunt) => { export default (grunt) => {
const VERSION = grunt.config.get('pkg.version'); const VERSION = grunt.config.get('build.version');
const FOLDER_STAGING = `kibana/staging/${VERSION.match(/\d\.\d\.\d/)[0]}-XXXXXXX/repos/${VERSION.match(/\d\./)[0]}x`; const FOLDER_STAGING = `kibana/staging/${VERSION.match(/\d\.\d\.\d/)[0]}-XXXXXXX/repos/${VERSION.match(/\d\./)[0]}x`;
const FOLDER_PRODUCTION = `kibana/${VERSION.match(/\d\.\d/)[0]}`; const FOLDER_PRODUCTION = `kibana/${VERSION.match(/\d\./)[0]}x`;
const FOLDERNAME_DEB = 'debian'; const FOLDERNAME_DEB = 'debian';
const FOLDERNAME_RPM = 'centos'; const FOLDERNAME_RPM = 'centos';
@ -13,8 +13,8 @@ export default (grunt) => {
const PREFIX_PRODUCTION_RPM = `${FOLDER_PRODUCTION}/${FOLDERNAME_RPM}`; const PREFIX_PRODUCTION_RPM = `${FOLDER_PRODUCTION}/${FOLDERNAME_RPM}`;
const FOLDER_CONFIG = '/etc/kibana'; const FOLDER_CONFIG = '/etc/kibana';
const FOLDER_LOGS = '/var/log/kibana';
const FOLDER_HOME = '/usr/share/kibana'; const FOLDER_HOME = '/usr/share/kibana';
const FOLDER_PLUGINS = `${FOLDER_HOME}/installedPlugins`;
const FILE_KIBANA_CONF = `${FOLDER_CONFIG}/kibana.yml`; const FILE_KIBANA_CONF = `${FOLDER_CONFIG}/kibana.yml`;
const FILE_KIBANA_BINARY = `${FOLDER_HOME}/bin/kibana`; const FILE_KIBANA_BINARY = `${FOLDER_HOME}/bin/kibana`;
@ -43,7 +43,7 @@ export default (grunt) => {
version: VERSION, version: VERSION,
path: { path: {
conf: FOLDER_CONFIG, conf: FOLDER_CONFIG,
logs: FOLDER_LOGS, plugins: FOLDER_PLUGINS,
home: FOLDER_HOME, home: FOLDER_HOME,
kibanaBin: FILE_KIBANA_BINARY, kibanaBin: FILE_KIBANA_BINARY,
kibanaConfig: FILE_KIBANA_CONF kibanaConfig: FILE_KIBANA_CONF

View file

@ -1,7 +1,7 @@
module.exports = function (grunt) { module.exports = function (grunt) {
let { resolve } = require('path'); let { resolve } = require('path');
let version = grunt.config.get('pkg.version'); let { version } = grunt.config.get('build');
let nodeVersion = grunt.config.get('nodeVersion'); let nodeVersion = grunt.config.get('nodeVersion');
let rootPath = grunt.config.get('root'); let rootPath = grunt.config.get('root');
let baseUri = `https://nodejs.org/dist/v${nodeVersion}`; let baseUri = `https://nodejs.org/dist/v${nodeVersion}`;

View file

@ -12,9 +12,6 @@ module.exports = function (grunt) {
path.unshift(`${HOME}/bin`); path.unshift(`${HOME}/bin`);
process.env.PATH = path.join(delimiter); process.env.PATH = path.join(delimiter);
// always build os packages on jenkins
grunt.option('os-packages', true);
grunt.task.run(compact([ grunt.task.run(compact([
'rejectRejFiles', 'rejectRejFiles',
'test', 'test',

View file

@ -6,8 +6,8 @@ import { createInterface } from 'readline';
export default (grunt) => { export default (grunt) => {
grunt.registerTask('_rebuild:confirm', function () { grunt.registerTask('_rebuild:confirm', function () {
const newVersion = grunt.option('buildversion') || grunt.config.get('pkg').version; const newVersion = grunt.option('buildversion') || grunt.config.get('pkg').version;
const newBuildNum = grunt.option('buildnum') || grunt.config.get('buildNum'); const newBuildNum = grunt.option('buildnum') || grunt.config.get('build.number');
const newSha = grunt.option('buildsha') || grunt.config.get('buildSha'); const newSha = grunt.option('buildsha') || grunt.config.get('build.sha');
grunt.config('rebuild', { newVersion, newBuildNum, newSha }); grunt.config('rebuild', { newVersion, newBuildNum, newSha });

View file

@ -3,7 +3,7 @@ import { join } from 'path';
export default (grunt) => { export default (grunt) => {
grunt.registerTask('_rebuild:createArchives', function () { grunt.registerTask('_rebuild:createArchives', function () {
const buildDir = grunt.config.get('build'); const buildDir = grunt.config.get('buildDir');
const targetDir = grunt.config.get('target'); const targetDir = grunt.config.get('target');
grunt.file.mkdir('target'); grunt.file.mkdir('target');

View file

@ -2,7 +2,7 @@ import { execFileSync } from 'child_process';
export default (grunt) => { export default (grunt) => {
grunt.registerTask('_rebuild:extractZips', function () { grunt.registerTask('_rebuild:extractZips', function () {
const buildDir = grunt.config.get('build'); const buildDir = grunt.config.get('buildDir');
const targetDir = grunt.config.get('target'); const targetDir = grunt.config.get('target');
const zips = grunt.file.expand({ cwd: targetDir }, '*.zip'); const zips = grunt.file.expand({ cwd: targetDir }, '*.zip');

View file

@ -20,7 +20,6 @@ import { trim } from 'lodash';
export default (grunt) => { export default (grunt) => {
grunt.registerTask('rebuild', 'Rebuilds targets as a new version', function () { grunt.registerTask('rebuild', 'Rebuilds targets as a new version', function () {
grunt.task.run([ grunt.task.run([
'_build:getProps',
'_rebuild:confirm', '_rebuild:confirm',
'_rebuild:continue' '_rebuild:continue'
]); ]);

View file

@ -4,7 +4,7 @@ import { join } from 'path';
export default (grunt) => { export default (grunt) => {
grunt.registerTask('_rebuild:updateBuilds', function () { grunt.registerTask('_rebuild:updateBuilds', function () {
const buildDir = grunt.config.get('build'); const buildDir = grunt.config.get('buildDir');
const { newVersion, newBuildNum, newSha } = grunt.config.get('rebuild'); const { newVersion, newBuildNum, newSha } = grunt.config.get('rebuild');

View file

@ -1,5 +1,16 @@
var _ = require('lodash'); const _ = require('lodash');
const visualRegression = require('../utilities/visual_regression');
module.exports = function (grunt) { module.exports = function (grunt) {
grunt.registerTask(
'test:visualRegression',
'Compare screenshots and generate diff images.',
function () {
const done = this.async();
visualRegression.run(done);
}
);
grunt.registerTask('test:server', [ 'esvm:test', 'simplemocha:all', 'esvm_shutdown:test' ]); grunt.registerTask('test:server', [ 'esvm:test', 'simplemocha:all', 'esvm_shutdown:test' ]);
grunt.registerTask('test:browser', [ 'run:testServer', 'karma:unit' ]); grunt.registerTask('test:browser', [ 'run:testServer', 'karma:unit' ]);
grunt.registerTask('test:coverage', [ 'run:testCoverageServer', 'karma:coverage' ]); grunt.registerTask('test:coverage', [ 'run:testCoverageServer', 'karma:coverage' ]);
@ -20,6 +31,7 @@ module.exports = function (grunt) {
'esvm:ui', 'esvm:ui',
'run:testUIServer', 'run:testUIServer',
'run:chromeDriver', 'run:chromeDriver',
'clean:screenshots',
'intern:dev', 'intern:dev',
'esvm_shutdown:ui', 'esvm_shutdown:ui',
'stop:chromeDriver', 'stop:chromeDriver',
@ -33,6 +45,7 @@ module.exports = function (grunt) {
]); ]);
grunt.registerTask('test:ui:runner', [ grunt.registerTask('test:ui:runner', [
'clean:screenshots',
'intern:dev' 'intern:dev'
]); ]);
@ -53,7 +66,7 @@ module.exports = function (grunt) {
'intern:api' 'intern:api'
]); ]);
grunt.registerTask('test', function (subTask) { grunt.registerTask('test', subTask => {
if (subTask) grunt.fail.fatal(`invalid task "test:${subTask}"`); if (subTask) grunt.fail.fatal(`invalid task "test:${subTask}"`);
grunt.task.run(_.compact([ grunt.task.run(_.compact([

View file

@ -13,7 +13,6 @@ bdd.describe('console app', function describeIndexTests() {
return common.navigateToApp('console', false); return common.navigateToApp('console', false);
}); });
bdd.it('should show the default request', function () { bdd.it('should show the default request', function () {
var expectedRequest = [ var expectedRequest = [
'GET _search', 'GET _search',
@ -24,9 +23,11 @@ bdd.describe('console app', function describeIndexTests() {
'}', '}',
'' ''
]; ];
common.saveScreenshot('Console-help-expanded');
// collapse the help pane because we only get the VISIBLE TEXT, not the part that is scrolled // collapse the help pane because we only get the VISIBLE TEXT, not the part that is scrolled
return consolePage.collapseHelp() return consolePage.collapseHelp()
.then(function () { .then(function () {
common.saveScreenshot('Console-help-collapsed');
return common.try(function () { return common.try(function () {
return consolePage.getRequest() return consolePage.getRequest()
.then(function (actualRequest) { .then(function (actualRequest) {
@ -40,6 +41,7 @@ bdd.describe('console app', function describeIndexTests() {
var expectedResponseContains = '"_index": ".kibana",'; var expectedResponseContains = '"_index": ".kibana",';
return consolePage.clickPlay() return consolePage.clickPlay()
.then(function () { .then(function () {
common.saveScreenshot('Console-default-request');
return common.try(function () { return common.try(function () {
return consolePage.getResponse() return consolePage.getResponse()
.then(function (actualResponse) { .then(function (actualResponse) {

View file

@ -42,6 +42,8 @@ bdd.describe('dashboard tab', function describeIndexTests() {
]; ];
bdd.it('should be able to add visualizations to dashboard', function addVisualizations() { bdd.it('should be able to add visualizations to dashboard', function addVisualizations() {
common.saveScreenshot('Dashboard-no-visualizations');
function addVisualizations(arr) { function addVisualizations(arr) {
return arr.reduce(function (promise, vizName) { return arr.reduce(function (promise, vizName) {
return promise return promise
@ -54,13 +56,13 @@ bdd.describe('dashboard tab', function describeIndexTests() {
return addVisualizations(visualizations) return addVisualizations(visualizations)
.then(function () { .then(function () {
common.debug('done adding visualizations'); common.debug('done adding visualizations');
common.saveScreenshot('Dashboard-add-visualizations');
}); });
}); });
bdd.it('set the timepicker time to that which contains our test data', function setTimepicker() { bdd.it('set the timepicker time to that which contains our test data', function setTimepicker() {
var fromTime = '2015-09-19 06:31:44.000'; var fromTime = '2015-09-19 06:31:44.000';
var toTime = '2015-09-23 18:31:44.000'; var toTime = '2015-09-23 18:31:44.000';
var testSubName = 'Dashboard Test 1';
// .then(function () { // .then(function () {
common.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"'); common.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"');
@ -69,21 +71,23 @@ bdd.describe('dashboard tab', function describeIndexTests() {
return headerPage.getSpinnerDone(); return headerPage.getSpinnerDone();
}) })
.then(function takeScreenshot() { .then(function takeScreenshot() {
common.debug('Take screenshot'); common.saveScreenshot('Dashboard-set-timepicker');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });
bdd.it('should save and load dashboard', function saveAndLoadDashboard() { bdd.it('should save and load dashboard', function saveAndLoadDashboard() {
var testSubName = 'Dashboard Test 1'; const dashboardName = 'Dashboard Test 1';
// TODO: save time on the dashboard and test it // TODO: save time on the dashboard and test it
return dashboardPage.saveDashboard(testSubName) return dashboardPage.saveDashboard(dashboardName)
// click New Dashboard just to clear the one we just created // click New Dashboard just to clear the one we just created
.then(function () { .then(function () {
return dashboardPage.clickNewDashboard(); return dashboardPage.clickNewDashboard();
}) })
.then(function () { .then(function () {
return dashboardPage.loadSavedDashboard(testSubName); return dashboardPage.loadSavedDashboard(dashboardName);
})
.then(function () {
common.saveScreenshot('Dashboard-load-saved');
}); });
}); });
@ -94,6 +98,9 @@ bdd.describe('dashboard tab', function describeIndexTests() {
common.log('visualization titles = ' + panelTitles); common.log('visualization titles = ' + panelTitles);
expect(panelTitles).to.eql(visualizations); expect(panelTitles).to.eql(visualizations);
}); });
})
.then(function () {
common.saveScreenshot('Dashboard-has-visualizations');
}); });
}); });
@ -110,6 +117,7 @@ bdd.describe('dashboard tab', function describeIndexTests() {
return dashboardPage.getPanelData() return dashboardPage.getPanelData()
.then(function (panelTitles) { .then(function (panelTitles) {
common.log('visualization titles = ' + panelTitles); common.log('visualization titles = ' + panelTitles);
common.saveScreenshot('Dashboard-visualization-sizes');
expect(panelTitles).to.eql(visObjects); expect(panelTitles).to.eql(visObjects);
}); });
}); });

View file

@ -38,6 +38,7 @@ bdd.describe('discover tab', function describeIndexTests() {
bdd.describe('field data', function () { bdd.describe('field data', function () {
bdd.it('should initially be expanded', function () { bdd.it('should initially be expanded', function () {
common.saveScreenshot('Discover-sidebar-expanded');
return discoverPage.getSidebarWidth() return discoverPage.getSidebarWidth()
.then(function (width) { .then(function (width) {
common.debug('expanded sidebar width = ' + width); common.debug('expanded sidebar width = ' + width);
@ -48,6 +49,7 @@ bdd.describe('discover tab', function describeIndexTests() {
bdd.it('should collapse when clicked', function () { bdd.it('should collapse when clicked', function () {
return discoverPage.toggleSidebarCollapse() return discoverPage.toggleSidebarCollapse()
.then(function () { .then(function () {
common.saveScreenshot('Discover-sidebar-collapsed');
common.debug('discoverPage.getSidebarWidth()'); common.debug('discoverPage.getSidebarWidth()');
return discoverPage.getSidebarWidth(); return discoverPage.getSidebarWidth();
}) })

View file

@ -58,6 +58,7 @@ bdd.describe('discover app', function describeIndexTests() {
return headerPage.getToastMessage(); return headerPage.getToastMessage();
}) })
.then(function (toastMessage) { .then(function (toastMessage) {
common.saveScreenshot('Discover-save-query-toast');
expect(toastMessage).to.be(expectedSavedQueryMessage); expect(toastMessage).to.be(expectedSavedQueryMessage);
}) })
.then(function () { .then(function () {
@ -80,6 +81,7 @@ bdd.describe('discover app', function describeIndexTests() {
return discoverPage.getCurrentQueryName(); return discoverPage.getCurrentQueryName();
}) })
.then(function (actualQueryNameString) { .then(function (actualQueryNameString) {
common.saveScreenshot('Discover-load-query');
expect(actualQueryNameString).to.be(queryName1); expect(actualQueryNameString).to.be(queryName1);
}); });
}); });
@ -289,6 +291,7 @@ bdd.describe('discover app', function describeIndexTests() {
bdd.it('should show "no results"', () => { bdd.it('should show "no results"', () => {
return discoverPage.hasNoResults().then(visible => { return discoverPage.hasNoResults().then(visible => {
common.saveScreenshot('Discover-no-results');
expect(visible).to.be(true); expect(visible).to.be(true);
}); });
}); });

View file

@ -49,6 +49,7 @@ bdd.describe('discover app', function describeIndexTests() {
return common.try(function tryingForTime() { return common.try(function tryingForTime() {
return discoverPage.getHitCount() return discoverPage.getHitCount()
.then(function compareData(hitCount) { .then(function compareData(hitCount) {
common.saveScreenshot('Discover-field-data');
expect(hitCount).to.be(expectedHitCount); expect(hitCount).to.be(expectedHitCount);
}); });
}); });
@ -64,7 +65,6 @@ bdd.describe('discover app', function describeIndexTests() {
}); });
}); });
bdd.it('search _type:apache should show the correct hit count', function () { bdd.it('search _type:apache should show the correct hit count', function () {
var expectedHitCount = '11,156'; var expectedHitCount = '11,156';
return discoverPage.query('_type:apache') return discoverPage.query('_type:apache')
@ -222,6 +222,7 @@ bdd.describe('discover app', function describeIndexTests() {
return common.try(function tryingForTime() { return common.try(function tryingForTime() {
return discoverPage.getDocTableIndex(1) return discoverPage.getDocTableIndex(1)
.then(function (rowData) { .then(function (rowData) {
common.saveScreenshot('Discover-sort-down');
expect(rowData).to.be(ExpectedDoc); expect(rowData).to.be(ExpectedDoc);
}); });
}); });
@ -237,6 +238,7 @@ bdd.describe('discover app', function describeIndexTests() {
return headerPage.getToastMessage(); return headerPage.getToastMessage();
}) })
.then(function (toastMessage) { .then(function (toastMessage) {
common.saveScreenshot('Discover-syntax-error-toast');
expect(toastMessage).to.be(expectedError); expect(toastMessage).to.be(expectedError);
}) })
.then(function () { .then(function () {

View file

@ -56,6 +56,7 @@ bdd.describe('shared links', function describeIndexTests() {
var expectedCaption = 'Share a link'; var expectedCaption = 'Share a link';
return discoverPage.clickShare() return discoverPage.clickShare()
.then(function () { .then(function () {
common.saveScreenshot('Discover-share-link');
return discoverPage.getShareCaption(); return discoverPage.getShareCaption();
}) })
.then(function (actualCaption) { .then(function (actualCaption) {
@ -85,6 +86,7 @@ bdd.describe('shared links', function describeIndexTests() {
return headerPage.getToastMessage(); return headerPage.getToastMessage();
}) })
.then(function (toastMessage) { .then(function (toastMessage) {
common.saveScreenshot('Discover-copy-to-clipboard-toast');
expect(toastMessage).to.match(expectedToastMessage); expect(toastMessage).to.match(expectedToastMessage);
}) })
.then(function () { .then(function () {
@ -98,6 +100,7 @@ bdd.describe('shared links', function describeIndexTests() {
return discoverPage.clickShortenUrl() return discoverPage.clickShortenUrl()
.then(function () { .then(function () {
return common.try(function tryingForTime() { return common.try(function tryingForTime() {
common.saveScreenshot('Discover-shorten-url-button');
return discoverPage.getShortenedUrl() return discoverPage.getShortenedUrl()
.then(function (actualUrl) { .then(function (actualUrl) {
expect(actualUrl).to.match(re); expect(actualUrl).to.match(re);

View file

@ -25,10 +25,12 @@ bdd.describe('creating and deleting default index', function describeIndexTests(
bdd.it('should allow setting advanced settings', function () { bdd.it('should allow setting advanced settings', function () {
return settingsPage.clickAdvancedTab() return settingsPage.clickAdvancedTab()
.then(function TestCallSetAdvancedSettingsForTimezone() { .then(function TestCallSetAdvancedSettingsForTimezone() {
common.saveScreenshot('Settings-advanced-tab');
common.debug('calling setAdvancedSetting'); common.debug('calling setAdvancedSetting');
return settingsPage.setAdvancedSettings('dateFormat:tz', 'America/Phoenix'); return settingsPage.setAdvancedSettings('dateFormat:tz', 'America/Phoenix');
}) })
.then(function GetAdvancedSetting() { .then(function GetAdvancedSetting() {
common.saveScreenshot('Settings-set-timezone');
return settingsPage.getAdvancedSettings('dateFormat:tz'); return settingsPage.getAdvancedSettings('dateFormat:tz');
}) })
.then(function (advancedSetting) { .then(function (advancedSetting) {

View file

@ -30,6 +30,7 @@ bdd.describe('user input reactions', function () {
return settingsPage.getTimeBasedIndexPatternCheckbox(waitTime); return settingsPage.getTimeBasedIndexPatternCheckbox(waitTime);
}) })
.then(function () { .then(function () {
common.saveScreenshot('Settings-indices-hide-time-based-index-pattern');
// we expect the promise above to fail // we expect the promise above to fail
var handler = common.handleError(self); var handler = common.handleError(self);
var msg = 'Found time based index pattern checkbox'; var msg = 'Found time based index pattern checkbox';
@ -47,6 +48,7 @@ bdd.describe('user input reactions', function () {
.then(function () { .then(function () {
return settingsPage.getCreateButton().isEnabled() return settingsPage.getCreateButton().isEnabled()
.then(function (enabled) { .then(function (enabled) {
common.saveScreenshot('Settings-indices-enable-creation');
expect(enabled).to.be.ok(); expect(enabled).to.be.ok();
}); });
}); });

View file

@ -26,6 +26,7 @@ bdd.describe('creating and deleting default index', function describeIndexTests(
bdd.it('should have index pattern in page header', function pageHeader() { bdd.it('should have index pattern in page header', function pageHeader() {
return settingsPage.getIndexPageHeading().getVisibleText() return settingsPage.getIndexPageHeading().getVisibleText()
.then(function (patternName) { .then(function (patternName) {
common.saveScreenshot('Settings-indices-new-index-pattern');
expect(patternName).to.be('logstash-*'); expect(patternName).to.be('logstash-*');
}); });
}); });
@ -72,6 +73,7 @@ bdd.describe('creating and deleting default index', function describeIndexTests(
var expectedAlertText = 'Are you sure you want to remove this index pattern?'; var expectedAlertText = 'Are you sure you want to remove this index pattern?';
return settingsPage.removeIndexPattern() return settingsPage.removeIndexPattern()
.then(function (alertText) { .then(function (alertText) {
common.saveScreenshot('Settings-indices-confirm-remove-index-pattern');
expect(alertText).to.be(expectedAlertText); expect(alertText).to.be(expectedAlertText);
}); });
}); });

View file

@ -63,6 +63,7 @@ bdd.describe('index result popularity', function describeIndexTests() {
.then(function (popularity) { .then(function (popularity) {
common.debug('popularity = ' + popularity); common.debug('popularity = ' + popularity);
expect(popularity).to.be('1'); expect(popularity).to.be('1');
common.saveScreenshot('Settings-indices-result-popularity-updated');
}); });
}); });
@ -101,6 +102,7 @@ bdd.describe('index result popularity', function describeIndexTests() {
.then(function (popularity) { .then(function (popularity) {
common.debug('popularity = ' + popularity); common.debug('popularity = ' + popularity);
expect(popularity).to.be('1'); expect(popularity).to.be('1');
common.saveScreenshot('Settings-indices-result-popularity-saved');
}); });
}); });
}); // end 'change popularity' }); // end 'change popularity'

View file

@ -51,6 +51,7 @@ bdd.describe('index result field sort', function describeIndexTests() {
return col.selector(); return col.selector();
}) })
.then(function (rowText) { .then(function (rowText) {
common.saveScreenshot(`Settings-indices-column-${col.heading}-sort-ascending`);
expect(rowText).to.be(col.first); expect(rowText).to.be(col.first);
}); });
}); });
@ -64,6 +65,7 @@ bdd.describe('index result field sort', function describeIndexTests() {
return col.selector(); return col.selector();
}) })
.then(function (rowText) { .then(function (rowText) {
common.saveScreenshot(`Settings-indices-column-${col.heading}-sort-descending`);
expect(rowText).to.be(col.last); expect(rowText).to.be(col.last);
}); });
}); });
@ -115,6 +117,7 @@ bdd.describe('index result field sort', function describeIndexTests() {
return settingsPage.getPageFieldCount(); return settingsPage.getPageFieldCount();
}) })
.then(function (pageCount) { .then(function (pageCount) {
common.saveScreenshot('Settings-indices-paged');
var expectedSize = (val < 4) ? expectedDefaultPageSize : expectedLastPageCount; var expectedSize = (val < 4) ? expectedDefaultPageSize : expectedLastPageCount;
expect(pageCount.length).to.be(expectedSize); expect(pageCount.length).to.be(expectedSize);
}); });

View file

@ -20,6 +20,7 @@ bdd.describe('initial state', function () {
bdd.it('should load with time pattern checked', function () { bdd.it('should load with time pattern checked', function () {
return settingsPage.getTimeBasedEventsCheckbox().isSelected() return settingsPage.getTimeBasedEventsCheckbox().isSelected()
.then(function (selected) { .then(function (selected) {
common.saveScreenshot('Settings-initial-state');
expect(selected).to.be.ok(); expect(selected).to.be.ok();
}); });
}); });

View file

@ -61,13 +61,13 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
bdd.describe('area charts', function indexPatternCreation() { bdd.describe('area charts', function indexPatternCreation() {
var testSubName = 'AreaChart'; var vizName1 = 'Visualization AreaChart';
var vizName1 = 'Visualization ' + testSubName;
bdd.it('should save and load', function pageHeader() { bdd.it('should save and load', function pageHeader() {
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
.then(function (message) { .then(function (message) {
common.debug('Saved viz message = ' + message); common.debug('Saved viz message = ' + message);
common.saveScreenshot('Visualize-area-chart-save-toast');
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"'); expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
}) })
.then(function testVisualizeWaitForToastMessageGone() { .then(function testVisualizeWaitForToastMessageGone() {
@ -87,7 +87,6 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.it('should show correct chart, take screenshot', function pageHeader() { bdd.it('should show correct chart, take screenshot', function pageHeader() {
var chartHeight = 0; var chartHeight = 0;
var xAxisLabels = [ '2015-09-20 00:00', '2015-09-21 00:00', var xAxisLabels = [ '2015-09-20 00:00', '2015-09-21 00:00',
@ -118,15 +117,11 @@ bdd.describe('visualize app', function describeIndexTests() {
.then(function (paths) { .then(function (paths) {
common.debug('expectedAreaChartData = ' + expectedAreaChartData); common.debug('expectedAreaChartData = ' + expectedAreaChartData);
common.debug('actual chart data = ' + paths); common.debug('actual chart data = ' + paths);
common.saveScreenshot('Visualize-area-chart');
expect(paths).to.eql(expectedAreaChartData); expect(paths).to.eql(expectedAreaChartData);
})
.then(function takeScreenshot() {
common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });
bdd.it('should show correct data', function pageHeader() { bdd.it('should show correct data', function pageHeader() {
var expectedTableData = [ 'September 20th 2015, 00:00:00.000 37', var expectedTableData = [ 'September 20th 2015, 00:00:00.000 37',
'September 20th 2015, 03:00:00.000 202', 'September 20th 2015, 03:00:00.000 202',
@ -166,8 +161,5 @@ bdd.describe('visualize app', function describeIndexTests() {
expect(data.trim().split('\n')).to.eql(expectedTableData); expect(data.trim().split('\n')).to.eql(expectedTableData);
}); });
}); });
}); });
}); });

View file

@ -16,9 +16,7 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
bdd.describe('chart types', function indexPatternCreation() { bdd.describe('chart types', function indexPatternCreation() {
bdd.it('should show the correct chart types', function pageHeader() { bdd.it('should show the correct chart types', function pageHeader() {
var expectedChartTypes = [ var expectedChartTypes = [
'Area chart', 'Data table', 'Line chart', 'Markdown widget', 'Area chart', 'Data table', 'Line chart', 'Markdown widget',
'Metric', 'Pie chart', 'Tile map', 'Vertical bar chart' 'Metric', 'Pie chart', 'Tile map', 'Vertical bar chart'
@ -28,6 +26,7 @@ bdd.describe('visualize app', function describeIndexTests() {
.then(function testChartTypes(chartTypes) { .then(function testChartTypes(chartTypes) {
common.debug('returned chart types = ' + chartTypes); common.debug('returned chart types = ' + chartTypes);
common.debug('expected chart types = ' + expectedChartTypes); common.debug('expected chart types = ' + expectedChartTypes);
common.saveScreenshot('Visualize-chart-types');
expect(chartTypes).to.eql(expectedChartTypes); expect(chartTypes).to.eql(expectedChartTypes);
}); });
}); });

View file

@ -52,10 +52,8 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.describe('data table', function indexPatternCreation() { bdd.describe('data table', function indexPatternCreation() {
var testSubName = 'DataTable'; var vizName1 = 'Visualization DataTable';
var vizName1 = 'Visualization ' + testSubName;
bdd.it('should be able to save and load', function pageHeader() { bdd.it('should be able to save and load', function pageHeader() {
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
@ -74,7 +72,6 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.it('should show correct data, take screenshot', function pageHeader() { bdd.it('should show correct data, take screenshot', function pageHeader() {
var chartHeight = 0; var chartHeight = 0;
var expectedChartData = [ '0 2,088', '2,000 2,748', '4,000 2,707', '6,000 2,876', var expectedChartData = [ '0 2,088', '2,000 2,748', '4,000 2,707', '6,000 2,876',
@ -84,14 +81,10 @@ bdd.describe('visualize app', function describeIndexTests() {
return visualizePage.getDataTableData() return visualizePage.getDataTableData()
.then(function showData(data) { .then(function showData(data) {
common.debug(data.split('\n')); common.debug(data.split('\n'));
common.saveScreenshot('Visualize-data-table');
expect(data.split('\n')).to.eql(expectedChartData); expect(data.split('\n')).to.eql(expectedChartData);
})
.then(function takeScreenshot() {
common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });
}); });
}); });

View file

@ -52,12 +52,9 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
bdd.describe('line charts', function indexPatternCreation() { bdd.describe('line charts', function indexPatternCreation() {
var testSubName = 'LineChart'; var vizName1 = 'Visualization LineChart';
var vizName1 = 'Visualization ' + testSubName;
bdd.it('should be able to save and load', function pageHeader() { bdd.it('should be able to save and load', function pageHeader() {
common.debug('Start of test' + testSubName + 'Visualization');
var remote = this.remote; var remote = this.remote;
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
@ -88,24 +85,18 @@ bdd.describe('visualize app', function describeIndexTests() {
// sleep a bit before trying to get the chart data // sleep a bit before trying to get the chart data
return common.sleep(3000) return common.sleep(3000)
.then(function () { .then(function () {
return common.try(function () { return visualizePage.getLineChartData('fill="#57c17b"')
return visualizePage.getLineChartData('fill="#57c17b"') .then(function showData(data) {
.then(function showData(data) { common.saveScreenshot('Visualize-line-chart');
var tolerance = 10; // the y-axis scale is 10000 so 10 is 0.1% var tolerance = 10; // the y-axis scale is 10000 so 10 is 0.1%
for (var x = 0; x < data.length; x++) { for (var x = 0; x < data.length; x++) {
common.debug('x=' + x + ' expectedChartData[x].split(\' \')[1] = ' + common.debug('x=' + x + ' expectedChartData[x].split(\' \')[1] = ' +
(expectedChartData[x].split(' ')[1]).replace(',', '') + ' data[x]=' + data[x] + (expectedChartData[x].split(' ')[1]).replace(',', '') + ' data[x]=' + data[x] +
' diff=' + Math.abs(expectedChartData[x].split(' ')[1].replace(',', '') - data[x])); ' diff=' + Math.abs(expectedChartData[x].split(' ')[1].replace(',', '') - data[x]));
expect(Math.abs(expectedChartData[x].split(' ')[1].replace(',', '') - data[x]) < tolerance).to.be.ok(); expect(Math.abs(expectedChartData[x].split(' ')[1].replace(',', '') - data[x]) < tolerance).to.be.ok();
} }
common.debug('Done'); common.debug('Done');
});
}); });
})
.then(function takeScreenshot() {
// take a snapshot just as an example.
common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });

View file

@ -14,11 +14,6 @@ bdd.describe('visualize app', function describeIndexTests() {
var toTime = '2015-09-23 18:31:44.000'; var toTime = '2015-09-23 18:31:44.000';
bdd.before(function () { bdd.before(function () {
var testSubName = 'MetricChart';
common.debug('Start of test' + testSubName + 'Visualization');
var vizName1 = 'Visualization ' + testSubName;
common.debug('navigateToApp visualize'); common.debug('navigateToApp visualize');
return common.navigateToApp('visualize') return common.navigateToApp('visualize')
.then(function () { .then(function () {
@ -34,7 +29,6 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.describe('metric chart', function indexPatternCreation() { bdd.describe('metric chart', function indexPatternCreation() {
bdd.it('should show Count', function pageHeader() { bdd.it('should show Count', function pageHeader() {
@ -44,6 +38,7 @@ bdd.describe('visualize app', function describeIndexTests() {
return common.try(function tryingForTime() { return common.try(function tryingForTime() {
return visualizePage.getMetric() return visualizePage.getMetric()
.then(function (metricValue) { .then(function (metricValue) {
common.saveScreenshot('Visualize-metric-chart');
expect(expectedCount).to.eql(metricValue.split('\n')); expect(expectedCount).to.eql(metricValue.split('\n'));
}); });
}); });

View file

@ -60,12 +60,9 @@ bdd.describe('visualize app', function describeIndexTests() {
bdd.describe('pie chart', function indexPatternCreation() { bdd.describe('pie chart', function indexPatternCreation() {
var testSubName = 'PieChart'; var vizName1 = 'Visualization PieChart';
var vizName1 = 'Visualization ' + testSubName;
bdd.it('should save and load', function pageHeader() { bdd.it('should save and load', function pageHeader() {
common.debug('Start of test' + testSubName + 'Visualization');
var remote = this.remote; var remote = this.remote;
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
@ -96,11 +93,8 @@ bdd.describe('visualize app', function describeIndexTests() {
.then(function (pieData) { .then(function (pieData) {
var barHeightTolerance = 1; var barHeightTolerance = 1;
common.debug('pieData.length = ' + pieData.length); common.debug('pieData.length = ' + pieData.length);
common.saveScreenshot('Visualize-pie-chart');
expect(pieData.length).to.be(expectedPieChartSliceCount); expect(pieData.length).to.be(expectedPieChartSliceCount);
})
.then(function takeScreenshot() {
common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });
@ -122,7 +116,5 @@ bdd.describe('visualize app', function describeIndexTests() {
expect(data.trim().split('\n')).to.eql(expectedTableData); expect(data.trim().split('\n')).to.eql(expectedTableData);
}); });
}); });
}); });
}); });

View file

@ -50,14 +50,10 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.describe('tile map chart', function indexPatternCreation() { bdd.describe('tile map chart', function indexPatternCreation() {
bdd.it('should save and load, take screenshot', function pageHeader() { bdd.it('should save and load, take screenshot', function pageHeader() {
var testSubName = 'TileMap'; var vizName1 = 'Visualization TileMap';
common.debug('Start of test' + testSubName + 'Visualization');
var vizName1 = 'Visualization ' + testSubName;
// var remote = this.remote;
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
.then(function (message) { .then(function (message) {
@ -79,14 +75,11 @@ bdd.describe('visualize app', function describeIndexTests() {
}) })
.then(function takeScreenshot() { .then(function takeScreenshot() {
common.debug('Take screenshot'); common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png'); common.saveScreenshot('Visualize-site-map');
}); });
}); });
bdd.it('should show correct tile map data', function pageHeader() { bdd.it('should show correct tile map data', function pageHeader() {
var testSubName = 'TileMap';
common.debug('Start of test' + testSubName + 'Visualization');
// var remote = this.remote;
var expectedTableData = [ 'dn 1,429', 'dp 1,418', '9y 1,215', '9z 1,099', 'dr 1,076', var expectedTableData = [ 'dn 1,429', 'dp 1,418', '9y 1,215', '9z 1,099', 'dr 1,076',
'dj 982', '9v 938', '9q 722', '9w 475', 'cb 457', 'c2 453', '9x 420', 'dq 399', 'dj 982', '9v 938', '9q 722', '9w 475', 'cb 457', 'c2 453', '9x 420', 'dq 399',
'9r 396', '9t 274', 'c8 271', 'dh 214', 'b6 207', 'bd 206', 'b7 167', 'f0 141', '9r 396', '9t 274', 'c8 271', 'dh 214', 'b6 207', 'bd 206', 'b7 167', 'f0 141',
@ -107,7 +100,5 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
}); });
}); });
}); });

View file

@ -52,8 +52,7 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
bdd.describe('vertical bar chart', function indexPatternCreation() { bdd.describe('vertical bar chart', function indexPatternCreation() {
var testSubName = 'VerticalBarChart'; var vizName1 = 'Visualization VerticalBarChart';
var vizName1 = 'Visualization ' + testSubName;
bdd.it('should save and load', function pageHeader() { bdd.it('should save and load', function pageHeader() {
return visualizePage.saveVisualization(vizName1) return visualizePage.saveVisualization(vizName1)
@ -75,7 +74,6 @@ bdd.describe('visualize app', function describeIndexTests() {
}); });
}); });
bdd.it('should show correct chart, take screenshot', function pageHeader() { bdd.it('should show correct chart, take screenshot', function pageHeader() {
var expectedChartValues = [37, 202, 740, 1437, 1371, 751, 188, 31, 42, 202, 683, var expectedChartValues = [37, 202, 740, 1437, 1371, 751, 188, 31, 42, 202, 683,
1361, 1415, 707, 177, 27, 32, 175, 707, 1408, 1355, 726, 201, 29 1361, 1415, 707, 177, 27, 32, 175, 707, 1408, 1355, 726, 201, 29
@ -91,17 +89,13 @@ bdd.describe('visualize app', function describeIndexTests() {
.then(function showData(data) { .then(function showData(data) {
common.debug('data=' + data); common.debug('data=' + data);
common.debug('data.length=' + data.length); common.debug('data.length=' + data.length);
common.saveScreenshot('Visualize-vertical-bar-chart');
expect(data).to.eql(expectedChartValues); expect(data).to.eql(expectedChartValues);
})
.then(function takeScreenshot() {
common.debug('Take screenshot');
common.saveScreenshot('./screenshot-' + testSubName + '.png');
}); });
}); });
bdd.it('should show correct data', function pageHeader() { bdd.it('should show correct data', function pageHeader() {
var testSubName = 'VerticalBarChart';
// this is only the first page of the tabular data. // this is only the first page of the tabular data.
var expectedChartData = [ 'September 20th 2015, 00:00:00.000 37', var expectedChartData = [ 'September 20th 2015, 00:00:00.000 37',
'September 20th 2015, 03:00:00.000 202', 'September 20th 2015, 03:00:00.000 202',

View file

@ -1,4 +1,7 @@
import { bdd, common } from '../../support'; import {
bdd,
common
} from '../../support';
var expect = require('expect.js'); var expect = require('expect.js');
@ -11,11 +14,11 @@ bdd.describe('status page', function () {
var self = this; var self = this;
return common.tryForTime(6000, function () { return common.tryForTime(6000, function () {
return self.remote return common.findTestSubject('statusBreakdown')
.findByCssSelector('.plugin_status_breakdown')
.getVisibleText() .getVisibleText()
.then(function (text) { .then(function (text) {
expect(text.indexOf('kibana 1.0.0 Ready')).to.be.above(-1); common.saveScreenshot('Status');
expect(text.indexOf('plugin:kibana')).to.be.above(-1);
}); });
}) })
.catch(common.handleError(self)); .catch(common.handleError(self));

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 KiB

Some files were not shown because too many files have changed in this diff Show more