diff --git a/.gitignore b/.gitignore index d0963d86caed..4f697649a07d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ target /test/screenshots/diff /test/screenshots/failure /test/screenshots/session +/test/screenshots/visual_regression_gallery.html /esvm .htpasswd .eslintcache diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1305577cff46..1dfc15573980 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ Once that is complete just run: ``` sh -npm run test && npm run build +npm run test && npm run build -- --skip-os-packages ``` #### 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. -`npm run test:quick` +`npm run test:quick` Runs both server and browser tests, but skips linting -`npm run test:server` +`npm run test:server` 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. -`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. +`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. ![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 for development and fixing individual tests. #### 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. -`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. #### 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 -`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. -`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. -`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. ##### 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 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 -npm run build:ospackages +npm run build -- --skip-archives ``` To specify a package to build you can add `rpm` or `deb` as an argument. ```sh -npm run build:ospackages -- --rpm +npm run build -- --rpm ``` Distributable packages can be found in `target/` after the build completes. diff --git a/Gruntfile.js b/Gruntfile.js index 3fef79398e4f..d6fa1c8a1381 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,7 +9,7 @@ module.exports = function (grunt) { pkg: grunt.file.readJSON('package.json'), root: __dirname, src: __dirname + '/src', - build: __dirname + '/build', // temporary build directory + buildDir: __dirname + '/build', // temporary build directory plugins: __dirname + '/src/plugins', server: __dirname + '/src/server', target: __dirname + '/target', // location of the compressed build targets @@ -69,6 +69,9 @@ module.exports = function (grunt) { 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'; // ensure that these run first, other configs need them config.services = require('./tasks/config/services')(grunt); diff --git a/README.md b/README.md index 113d563f5859..aba972f854b3 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 4ef7fe630146..bd9c82d73452 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -8,6 +8,7 @@ :k4pull: https://github.com/elastic/kibana/pull/ :version: master :esversion: master +:packageversion: master include::introduction.asciidoc[] diff --git a/docs/kibana-repositories.asciidoc b/docs/kibana-repositories.asciidoc index a2492d8b680c..8f2ee31bda0f 100644 --- a/docs/kibana-repositories.asciidoc +++ b/docs/kibana-repositories.asciidoc @@ -26,7 +26,7 @@ wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add + ["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] @@ -82,11 +82,11 @@ rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch + ["source","sh",subs="attributes"] -------------------------------------------------- -[kibana-{version}] -name=Kibana repository for {version}.x packages -baseurl=http://packages.elastic.co/kibana/{version}/centos +[kibana-{packageversion}] +name=Kibana repository for {packageversion} packages +baseurl=https://packages.elastic.co/kibana/{packageversion}/centos gpgcheck=1 -gpgkey=http://packages.elastic.co/GPG-KEY-elasticsearch +gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch enabled=1 -------------------------------------------------- + diff --git a/package.json b/package.json index 6df3f6c0a697..af14d6755397 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dashboarding" ], "private": false, - "version": "5.0.0-snapshot", + "version": "5.0.0", "build": { "number": 8467, "sha": "6cb7fec4e154faa0a4a3fee4b33dfef91b9870d9" @@ -39,7 +39,7 @@ "Tim Sullivan " ], "scripts": { - "test": "grunt test", + "test": "grunt test; grunt test:visualRegression", "test:dev": "grunt test:dev", "test:quick": "grunt test:quick", "test:browser": "grunt test:browser", @@ -49,7 +49,6 @@ "test:server": "grunt test:server", "test:coverage": "grunt test:coverage", "build": "grunt build", - "build:ospackages": "grunt build --os-packages", "start": "sh ./bin/kibana --dev", "precommit": "grunt precommit", "karma": "karma start", @@ -60,8 +59,7 @@ "makelogs": "makelogs", "mocha": "mocha", "mocha:debug": "mocha --debug-brk", - "sterilize": "grunt sterilize", - "compareScreenshots": "node utilities/compareScreenshots" + "sterilize": "grunt sterilize" }, "repository": { "type": "git", @@ -128,8 +126,8 @@ "marked": "0.3.3", "minimatch": "2.0.10", "mkdirp": "0.5.1", - "moment": "2.10.6", - "moment-timezone": "0.4.1", + "moment": "2.13.0", + "moment-timezone": "0.5.4", "node-uuid": "1.4.7", "raw-loader": "0.5.1", "request": "2.61.0", @@ -155,6 +153,7 @@ "babel-eslint": "4.1.8", "chokidar": "1.4.3", "chromedriver": "2.21.2", + "dot": "1.0.3", "elasticdump": "2.1.1", "eslint": "1.10.3", "eslint-plugin-mocha": "1.1.0", @@ -193,7 +192,7 @@ "nock": "2.10.0", "npm": "2.11.0", "portscanner": "1.0.0", - "simple-git": "1.8.0", + "simple-git": "1.37.0", "sinon": "1.17.2", "source-map": "0.4.4", "source-map-support": "0.4.0", diff --git a/src/cli/serve/__tests__/reload_logging_config.js b/src/cli/serve/__tests__/reload_logging_config.js index e53e646974f1..98bc195a4efa 100644 --- a/src/cli/serve/__tests__/reload_logging_config.js +++ b/src/cli/serve/__tests__/reload_logging_config.js @@ -23,6 +23,8 @@ function setLoggingJson(enabled) { describe(`Server logging configuration`, function () { it(`should be reloadable via SIGHUP process signaling`, function (done) { + this.timeout(60000); + let asserted = false; let json = Infinity; const conf = setLoggingJson(true); diff --git a/src/cli_plugin/install/index.js b/src/cli_plugin/install/index.js index 177666bca514..cb5bdaf69bc6 100644 --- a/src/cli_plugin/install/index.js +++ b/src/cli_plugin/install/index.js @@ -1,8 +1,10 @@ import { fromRoot } from '../../utils'; +import fs from 'fs'; import install from './install'; import Logger from '../lib/logger'; import pkg from '../../utils/package_json'; import { parse, parseMilliseconds } from './settings'; +import { find } from 'lodash'; function processCommand(command, options) { let settings; @@ -18,6 +20,24 @@ function processCommand(command, options) { 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) { program .command('install ') @@ -26,7 +46,7 @@ export default function pluginInstall(program) { .option( '-c, --config ', 'path to the config file', - fromRoot('config/kibana.yml') + getDefaultConfigPath() ) .option( '-t, --timeout ', diff --git a/src/plugins/status_page/public/status_page.html b/src/plugins/status_page/public/status_page.html index 09ef885ac32c..c0ae2fa404f0 100644 --- a/src/plugins/status_page/public/status_page.html +++ b/src/plugins/status_page/public/status_page.html @@ -1,8 +1,8 @@ -
+

- Status: {{ ui.serverStateMessage }} - + Status: {{ ui.serverStateMessage }} + {{ ui.name }} @@ -15,27 +15,29 @@

-
-

Installed Plugins

-
+
+

Status Breakdown

+ +
-

- No plugin status information available +

+ No status information available

- +
- - + - - - + + + diff --git a/src/plugins/status_page/public/status_page.js b/src/plugins/status_page/public/status_page.js index 2fc65f299b80..05c0ad1b1b22 100644 --- a/src/plugins/status_page/public/status_page.js +++ b/src/plugins/status_page/public/status_page.js @@ -28,9 +28,10 @@ const chrome = require('ui/chrome') const data = resp.data; ui.metrics = data.metrics; - ui.statuses = data.status.statuses; ui.name = data.name; + ui.statuses = data.status.statuses; + const overall = data.status.overall; if (!ui.serverState || (ui.serverState !== overall.state)) { ui.serverState = overall.state; diff --git a/src/plugins/status_page/public/status_page.less b/src/plugins/status_page/public/status_page.less index c18e5a3ad8c3..d82736de7278 100644 --- a/src/plugins/status_page/public/status_page.less +++ b/src/plugins/status_page/public/status_page.less @@ -5,9 +5,9 @@ @status-metric-border: #aaa; @status-metric-title-color: #666; -@status-plugins-bg: #fff; -@status-plugins-border: #bbb; -@status-plugins-headings-color: #666; +@status-statuses-bg: #fff; +@status-statuses-border: #bbb; +@status-statuses-headings-color: #666; @status-default: #7c7c7c; @status-green: #94c63d; @@ -58,13 +58,13 @@ } } -// plugin status table section -.plugin_status_wrapper { +// status status table section +.statuses_wrapper { margin-top: 25px; margin-left: -5px; margin-right: -5px; border-top:2px solid; - background-color: @status-plugins-bg; + background-color: @status-statuses-bg; padding: 10px; h3 { @@ -72,33 +72,34 @@ margin-bottom: 3px; } - .missing_statuses, - .loading_statuses { + .statuses_loading, + .statuses_missing { padding: 20px; text-align: center; } - .plugin_status_breakdown { + .statuses { margin-left: 0; margin-right: 0; + margin-bottom: 30px; - .status_row { + .status { height:30px; line-height:30px; border-bottom:1px solid; - border-bottom-color: @status-plugins-border; + border-bottom-color: @status-statuses-border; } th { - color:@status-plugins-headings-color; + color:@status-statuses-headings-color; font-weight: normal; height:25px; line-height:25px; border-bottom:1px solid; - border-bottom-color: @status-plugins-border; + border-bottom-color: @status-statuses-border; } - .status_name { + .status_id { padding:0px 5px; border-left: 2px solid; } @@ -111,17 +112,17 @@ } } -//plugin state -.plugin_state(@color, @icon) { - .plugin_state_color { +//status state +.status_state(@color, @icon) { + .status_state_color { color: @color; } - .plugin_state_icon:before { + .status_state_icon:before { content: @icon; } - .status_name { + .status_id { border-left-color: @color !important; } @@ -130,49 +131,49 @@ } } -.plugin_state_default { - .plugin_state(@status-default, @icon-default); +.status_state_default { + .status_state(@status-default, @icon-default); } -.plugin_state_green { - .plugin_state(@status-green, @icon-green); +.status_state_green { + .status_state(@status-green, @icon-green); } -.plugin_state_yellow { - .plugin_state(@status-yellow, @icon-yellow); +.status_state_yellow { + .status_state(@status-yellow, @icon-yellow); } -.plugin_state_red { - .plugin_state(@status-red, @icon-red); +.status_state_red { + .status_state(@status-red, @icon-red); } //server state .state(@color, @icon) { - .state_color { + .overall_state_color { color: @color; } - .state_icon:before { + .overall_state_icon:before { content: @icon; } - .plugin_status_wrapper { + .statuses_wrapper { border-top-color: @color; } } -.state_default { +.overall_state_default { .state(@status-default, @icon-default); } -.state_green { +.overall_state_green { .state(@status-green, @icon-green); } -.state_yellow { +.overall_state_yellow { .state(@status-yellow, @icon-yellow); } -.state_red { +.overall_state_red { .state(@status-red, @icon-red); } diff --git a/src/server/plugins/plugin.js b/src/server/plugins/plugin.js index 9b805f0c411b..877ff2d887bb 100644 --- a/src/server/plugins/plugin.js +++ b/src/server/plugins/plugin.js @@ -127,7 +127,7 @@ module.exports = class Plugin { server.exposeStaticDir(`/plugins/${id}/{path*}`, this.publicDir); } - this.status = kbnServer.status.create(this); + this.status = kbnServer.status.createForPlugin(this); server.expose('status', this.status); return await attempt(this.externalInit, [server, options], this); diff --git a/src/server/status/__tests__/server_status.js b/src/server/status/__tests__/server_status.js index 6c3b627c6981..3d08250fbf81 100644 --- a/src/server/status/__tests__/server_status.js +++ b/src/server/status/__tests__/server_status.js @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { find } from 'lodash'; import expect from 'expect.js'; import sinon from 'sinon'; @@ -17,31 +17,63 @@ describe('ServerStatus class', function () { serverStatus = new ServerStatus(server); }); - describe('#create(plugin)', function () { - it('should create a new status by plugin', function () { - let status = serverStatus.create(plugin); + describe('#create(id)', () => { + it('should create a new plugin with an id', () => { + const status = serverStatus.create('someid'); expect(status).to.be.a(Status); }); }); - describe('#get(name)', function () { - it('exposes plugins by its id/name', function () { - let status = serverStatus.create(plugin); - expect(serverStatus.get('name')).to.be(status); + describe('#createForPlugin(plugin)', function () { + it('should create a new status by plugin', function () { + let status = serverStatus.createForPlugin(plugin); + expect(status).to.be.a(Status); }); }); - describe('#getState(name)', function () { - it('should expose the state of the plugin by name', function () { - let status = serverStatus.create(plugin); + describe('#get(id)', () => { + it('exposes statuses by their id', () => { + 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(); - 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 () { 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'); @@ -69,25 +101,24 @@ describe('ServerStatus class', function () { it('serializes to overall status and individuals', function () { const pluginOne = {id: 'one', version: '1.0.0'}; const pluginTwo = {id: 'two', version: '2.0.0'}; - const pluginThree = {id: 'three', version: '3.0.0'}; - let one = serverStatus.create(pluginOne); - let two = serverStatus.create(pluginTwo); - let three = serverStatus.create(pluginThree); + let service = serverStatus.create('some service'); + let p1 = serverStatus.createForPlugin(pluginOne); + let p2 = serverStatus.createForPlugin(pluginTwo); - one.green(); - two.yellow(); - three.red(); + service.green(); + p1.yellow(); + p2.red(); - let obj = JSON.parse(JSON.stringify(serverStatus)); - expect(obj).to.have.property('overall'); - expect(obj.overall.state).to.eql(serverStatus.overall().state); - expect(obj.statuses).to.have.length(3); + let json = JSON.parse(JSON.stringify(serverStatus)); + expect(json).to.have.property('overall'); + expect(json.overall.state).to.eql(serverStatus.overall().state); + expect(json.statuses).to.have.length(3); - let outs = _.indexBy(obj.statuses, 'name'); - expect(outs.one).to.have.property('state', 'green'); - expect(outs.two).to.have.property('state', 'yellow'); - expect(outs.three).to.have.property('state', 'red'); + const out = status => find(json.statuses, { id: status.id }); + expect(out(service)).to.have.property('state', 'green'); + expect(out(p1)).to.have.property('state', 'yellow'); + expect(out(p2)).to.have.property('state', 'red'); }); }); diff --git a/src/server/status/__tests__/status.js b/src/server/status/__tests__/status.js index eafeb9f2f7fc..ae8e41908962 100644 --- a/src/server/status/__tests__/status.js +++ b/src/server/status/__tests__/status.js @@ -15,11 +15,11 @@ describe('Status class', 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) { - let status = serverStatus.create(plugin); + let status = serverStatus.createForPlugin(plugin); status.once('change', function (prev, prevMsg) { 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 () { - let status = serverStatus.create(plugin); + let status = serverStatus.createForPlugin(plugin); let stub = sinon.stub(); status.on('change', stub); status.green('Ready'); @@ -52,18 +52,17 @@ describe('Status class', function () { }); it('should create a JSON representation of the status', function () { - let status = serverStatus.create(plugin); + let status = serverStatus.createForPlugin(plugin); status.green('Ready'); let json = status.toJSON(); - expect(json.name).to.eql(plugin.id); - expect(json.version).to.eql(plugin.version); + expect(json.id).to.eql(status.id); expect(json.state).to.eql('green'); expect(json.message).to.eql('Ready'); }); 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'; status.green(msg); @@ -77,7 +76,7 @@ describe('Status class', function () { }); 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'; status.green(msg); @@ -92,7 +91,7 @@ describe('Status class', function () { function testState(color) { 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; status[color](message); 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) { - let status = serverStatus.create(plugin); + let status = serverStatus.createForPlugin(plugin); let message = 'testing ' + color; status.on('change', function (prev, prevMsg) { 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) { - let status = serverStatus.create(plugin); + let status = serverStatus.createForPlugin(plugin); let message = 'testing ' + color; status.on(color, function (prev, prevMsg) { expect(status.state).to.be(color); diff --git a/src/server/status/server_status.js b/src/server/status/server_status.js index 99cc6e69fb7a..e292a41da0c4 100644 --- a/src/server/status/server_status.js +++ b/src/server/status/server_status.js @@ -9,8 +9,16 @@ module.exports = class ServerStatus { this._created = {}; } - create(plugin) { - return (this._created[plugin.id] = new Status(plugin, this.server)); + create(id) { + 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) { @@ -22,12 +30,26 @@ module.exports = class ServerStatus { }); } - get(name) { - return this._created[name]; + get(id) { + return this._created[id]; } - getState(name) { - return _.get(this._created, [name, 'state'], 'uninitialized'); + getForPluginId(pluginId) { + 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() { diff --git a/src/server/status/status.js b/src/server/status/status.js index e19278e6e788..2aefc1fff1d8 100644 --- a/src/server/status/status.js +++ b/src/server/status/status.js @@ -3,18 +3,26 @@ import states from './states'; import { EventEmitter } from 'events'; class Status extends EventEmitter { - constructor(plugin, server) { + constructor(id, server) { 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.state = 'uninitialized'; this.message = 'uninitialized'; this.on('change', function (previous, previousMsg) { 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, { tmpl: 'Status changed from <%= prevState %> to <%= state %><%= message ? " - " + message : "" %>', @@ -28,8 +36,7 @@ class Status extends EventEmitter { toJSON() { return { - name: this.plugin.id, - version: this.plugin.version, + id: this.id, state: this.state, icon: states.get(this.state).icon, message: this.message, diff --git a/tasks/build/babel_cache.js b/tasks/build/babel_cache.js new file mode 100644 index 000000000000..d7ea3d87569c --- /dev/null +++ b/tasks/build/babel_cache.js @@ -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'); + }); +}; diff --git a/tasks/build/get_props.js b/tasks/build/get_props.js deleted file mode 100644 index 458139b7df9d..000000000000 --- a/tasks/build/get_props.js +++ /dev/null @@ -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())); - }); -}; diff --git a/tasks/build/index.js b/tasks/build/index.js index 6a5ea09914a9..d66f627293b6 100644 --- a/tasks/build/index.js +++ b/tasks/build/index.js @@ -3,7 +3,6 @@ module.exports = function (grunt) { grunt.registerTask('build', 'Build packages', function () { grunt.task.run(flatten([ - '_build:getProps', 'clean:build', 'clean:target', '_build:downloadNodeBuilds:start', @@ -13,6 +12,7 @@ module.exports = function (grunt) { '_build:installedPlugins', '_build:packageJson', '_build:readme', + '_build:babelCache', '_build:installNpmDeps', '_build:removePkgJsonDeps', 'clean:testsFromModules', @@ -23,11 +23,11 @@ module.exports = function (grunt) { '_build:downloadNodeBuilds:finish', '_build:versionedLinks', '_build:osShellScripts', - '_build:archives', - grunt.option('os-packages') ? [ + grunt.option('skip-archives') ? [] : ['_build:archives'], + grunt.option('skip-os-packages') ? [] : [ '_build:pleaseRun', '_build:osPackages', - ] : [], + ], '_build:shasums' ])); }); diff --git a/tasks/build/os_packages.js b/tasks/build/os_packages.js index 87c5b83a5813..c739bf122e1c 100644 --- a/tasks/build/os_packages.js +++ b/tasks/build/os_packages.js @@ -3,14 +3,16 @@ import { indexBy } from 'lodash'; import exec from '../utils/exec'; 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 servicesByName = indexBy(grunt.config.get('services'), 'name'); - const config = grunt.config.get('packages'); + const servicesByName = indexBy(config.get('services'), 'name'); + const packages = config.get('packages'); const fpm = args => exec('fpm', args); grunt.registerTask('_build:osPackages', function () { - grunt.config.get('platforms') + config.get('platforms') .filter(({ name }) => /linux-x(86|64)$/.test(name)) .map(({ name, buildDir }) => { const architecture = /x64$/.test(name) ? 'x86_64' : 'i386'; @@ -25,25 +27,26 @@ export default (grunt) => { '--package', targetDir, '-s', 'dir', // input type '--architecture', architecture, - '--name', config.name, - '--description', config.description, - '--version', config.version, - '--url', config.site, - '--vendor', config.vendor, - '--maintainer', config.maintainer, - '--license', config.license, + '--name', packages.name, + '--description', packages.description, + '--version', packages.version, + '--url', packages.site, + '--vendor', packages.vendor, + '--maintainer', packages.maintainer, + '--license', packages.license, '--after-install', resolve(packageScriptsDir, 'post_install.sh'), '--before-install', resolve(packageScriptsDir, 'pre_install.sh'), '--before-remove', resolve(packageScriptsDir, 'pre_remove.sh'), '--after-remove', resolve(packageScriptsDir, 'post_remove.sh'), - '--config-files', config.path.kibanaConfig, - '--template-value', `user=${config.user}`, - '--template-value', `group=${config.group}`, - '--template-value', `optimizeDir=${config.path.home}/optimize`, - + '--config-files', packages.path.kibanaConfig, + '--template-value', `user=${packages.user}`, + '--template-value', `group=${packages.group}`, + '--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 //uses relative path to --prefix, strip the leading / - '--exclude', `${config.path.home.slice(1)}/config` + '--exclude', `${packages.path.home.slice(1)}/config` ]; const debOptions = [ '-t', 'deb', @@ -54,8 +57,8 @@ export default (grunt) => { '--rpm-os', 'linux' ]; const args = [ - `${buildDir}/=${config.path.home}/`, - `${buildDir}/config/=${config.path.conf}/`, + `${buildDir}/=${packages.path.home}/`, + `${buildDir}/config/=${packages.path.conf}/`, `${servicesByName.sysv.outputDir}/etc/=/etc/`, `${servicesByName.systemd.outputDir}/lib/=/lib/` ]; diff --git a/tasks/build/package_json.js b/tasks/build/package_json.js index 3f61e724033d..a9038a2dd6d5 100644 --- a/tasks/build/package_json.js +++ b/tasks/build/package_json.js @@ -5,6 +5,7 @@ module.exports = function (grunt) { let deepModules = grunt.config.get('deepModules'); grunt.registerTask('_build:packageJson', function () { + const { sha, number, version } = grunt.config.get('build'); grunt.file.write( 'build/kibana/package.json', @@ -12,10 +13,10 @@ module.exports = function (grunt) { name: pkg.name, description: pkg.description, keywords: pkg.keywords, - version: pkg.version, + version, build: { - number: grunt.config.get('buildNum'), - sha: grunt.config.get('buildSha') + number, + sha }, repository: pkg.repository, engines: { diff --git a/tasks/build/package_scripts/post_remove.sh b/tasks/build/package_scripts/post_remove.sh index 43e8e5e6d4ac..d0ac977cdd3b 100644 --- a/tasks/build/package_scripts/post_remove.sh +++ b/tasks/build/package_scripts/post_remove.sh @@ -10,20 +10,26 @@ user_remove() { } REMOVE_USER=false +REMOVE_DIRS=false case $1 in # Includes cases for all valid arguments, exit 1 otherwise # Debian purge) 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 0) REMOVE_USER=true + REMOVE_DIRS=true ;; 1) @@ -40,3 +46,17 @@ if [ "$REMOVE_USER" = "true" ]; then user_remove "<%= user %>" 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 diff --git a/tasks/build/pleaserun.js b/tasks/build/pleaserun.js index b7a7e8f4eb65..adb9af186821 100644 --- a/tasks/build/pleaserun.js +++ b/tasks/build/pleaserun.js @@ -1,10 +1,11 @@ import { resolve } from 'path'; import { appendFileSync } from 'fs'; import exec from '../utils/exec'; +import { capitalize } from 'lodash'; export default (grunt) => { 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.config.get('services').forEach((service) => { @@ -15,7 +16,7 @@ export default (grunt) => { '--install-prefix', service.outputDir, '--overwrite', '--name', name, - '--description', description, + '--description', capitalize(name), '--user', user, '--group', group, '--sysv-log-path', path.logs, diff --git a/tasks/build/shasums.js b/tasks/build/shasums.js index 5d1df98b7f27..cb0b405c2ad2 100644 --- a/tasks/build/shasums.js +++ b/tasks/build/shasums.js @@ -8,6 +8,9 @@ module.exports = function (grunt) { grunt.registerTask('_build:shasums', function () { var targetDir = grunt.config.get('target'); + // for when shasums is run but archives and ospackages was not + grunt.file.mkdir(targetDir); + readdir(targetDir) .map(function (archive) { // only sha the archives and packages diff --git a/tasks/build/versioned_links.js b/tasks/build/versioned_links.js index 449321bd009a..876c977fe213 100644 --- a/tasks/build/versioned_links.js +++ b/tasks/build/versioned_links.js @@ -12,10 +12,7 @@ module.exports = function (grunt) { return resolve(rootPath, file); }); - //We don't want to build os packages with symlinks - let transferFiles = (source, link) => grunt.option('os-packages') - ? exec('cp', ['-r', source, link]) - : exec('ln', ['-s', source, link]); + let transferFiles = (source, link) => exec('cp', ['-r', source, link]); grunt.config.get('platforms').forEach(function (platform) { grunt.file.mkdir(platform.buildDir); diff --git a/tasks/config/build.js b/tasks/config/build.js new file mode 100644 index 000000000000..c1778cd4dbf8 --- /dev/null +++ b/tasks/config/build.js @@ -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`; +} diff --git a/tasks/config/clean.js b/tasks/config/clean.js index f83a81608556..4128505fd189 100644 --- a/tasks/config/clean.js +++ b/tasks/config/clean.js @@ -3,6 +3,7 @@ module.exports = function (grunt) { return { build: 'build', target: 'target', + screenshots: 'test/screenshots/session', testsFromModules: 'build/kibana/node_modules/**/{test,tests}/**', deepModuleBins: 'build/kibana/node_modules/*/node_modules/**/.bin/{' + modules.join(',') + '}', deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/', diff --git a/tasks/config/packages.js b/tasks/config/packages.js index 1c847168b33c..3162c4bffff3 100644 --- a/tasks/config/packages.js +++ b/tasks/config/packages.js @@ -1,8 +1,8 @@ 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_PRODUCTION = `kibana/${VERSION.match(/\d\.\d/)[0]}`; + const FOLDER_PRODUCTION = `kibana/${VERSION.match(/\d\./)[0]}x`; const FOLDERNAME_DEB = 'debian'; const FOLDERNAME_RPM = 'centos'; @@ -13,8 +13,8 @@ export default (grunt) => { const PREFIX_PRODUCTION_RPM = `${FOLDER_PRODUCTION}/${FOLDERNAME_RPM}`; const FOLDER_CONFIG = '/etc/kibana'; - const FOLDER_LOGS = '/var/log/kibana'; const FOLDER_HOME = '/usr/share/kibana'; + const FOLDER_PLUGINS = `${FOLDER_HOME}/installedPlugins`; const FILE_KIBANA_CONF = `${FOLDER_CONFIG}/kibana.yml`; const FILE_KIBANA_BINARY = `${FOLDER_HOME}/bin/kibana`; @@ -43,7 +43,7 @@ export default (grunt) => { version: VERSION, path: { conf: FOLDER_CONFIG, - logs: FOLDER_LOGS, + plugins: FOLDER_PLUGINS, home: FOLDER_HOME, kibanaBin: FILE_KIBANA_BINARY, kibanaConfig: FILE_KIBANA_CONF diff --git a/tasks/config/platforms.js b/tasks/config/platforms.js index 4a39f1b7dcc3..2874f0d89495 100644 --- a/tasks/config/platforms.js +++ b/tasks/config/platforms.js @@ -1,7 +1,7 @@ module.exports = function (grunt) { let { resolve } = require('path'); - let version = grunt.config.get('pkg.version'); + let { version } = grunt.config.get('build'); let nodeVersion = grunt.config.get('nodeVersion'); let rootPath = grunt.config.get('root'); let baseUri = `https://nodejs.org/dist/v${nodeVersion}`; diff --git a/tasks/jenkins.js b/tasks/jenkins.js index 141f8084a9ec..3b198b8c2acc 100644 --- a/tasks/jenkins.js +++ b/tasks/jenkins.js @@ -12,9 +12,6 @@ module.exports = function (grunt) { path.unshift(`${HOME}/bin`); process.env.PATH = path.join(delimiter); - // always build os packages on jenkins - grunt.option('os-packages', true); - grunt.task.run(compact([ 'rejectRejFiles', 'test', diff --git a/tasks/rebuild/confirm.js b/tasks/rebuild/confirm.js index 9a4c6b310f4a..5ece1bce93b8 100644 --- a/tasks/rebuild/confirm.js +++ b/tasks/rebuild/confirm.js @@ -6,8 +6,8 @@ import { createInterface } from 'readline'; export default (grunt) => { grunt.registerTask('_rebuild:confirm', function () { const newVersion = grunt.option('buildversion') || grunt.config.get('pkg').version; - const newBuildNum = grunt.option('buildnum') || grunt.config.get('buildNum'); - const newSha = grunt.option('buildsha') || grunt.config.get('buildSha'); + const newBuildNum = grunt.option('buildnum') || grunt.config.get('build.number'); + const newSha = grunt.option('buildsha') || grunt.config.get('build.sha'); grunt.config('rebuild', { newVersion, newBuildNum, newSha }); diff --git a/tasks/rebuild/create_archives.js b/tasks/rebuild/create_archives.js index 1593f66facaa..852e3b52e666 100644 --- a/tasks/rebuild/create_archives.js +++ b/tasks/rebuild/create_archives.js @@ -3,7 +3,7 @@ import { join } from 'path'; export default (grunt) => { grunt.registerTask('_rebuild:createArchives', function () { - const buildDir = grunt.config.get('build'); + const buildDir = grunt.config.get('buildDir'); const targetDir = grunt.config.get('target'); grunt.file.mkdir('target'); diff --git a/tasks/rebuild/extract_zips.js b/tasks/rebuild/extract_zips.js index 497c1ec148c4..fdd02601ad6e 100644 --- a/tasks/rebuild/extract_zips.js +++ b/tasks/rebuild/extract_zips.js @@ -2,7 +2,7 @@ import { execFileSync } from 'child_process'; export default (grunt) => { grunt.registerTask('_rebuild:extractZips', function () { - const buildDir = grunt.config.get('build'); + const buildDir = grunt.config.get('buildDir'); const targetDir = grunt.config.get('target'); const zips = grunt.file.expand({ cwd: targetDir }, '*.zip'); diff --git a/tasks/rebuild/index.js b/tasks/rebuild/index.js index d6d73b01bbb6..4e382c06a5cc 100644 --- a/tasks/rebuild/index.js +++ b/tasks/rebuild/index.js @@ -20,7 +20,6 @@ import { trim } from 'lodash'; export default (grunt) => { grunt.registerTask('rebuild', 'Rebuilds targets as a new version', function () { grunt.task.run([ - '_build:getProps', '_rebuild:confirm', '_rebuild:continue' ]); diff --git a/tasks/rebuild/update_builds.js b/tasks/rebuild/update_builds.js index d9a3a64caef2..afe4177804f5 100644 --- a/tasks/rebuild/update_builds.js +++ b/tasks/rebuild/update_builds.js @@ -4,7 +4,7 @@ import { join } from 'path'; export default (grunt) => { 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'); diff --git a/tasks/test.js b/tasks/test.js index 13ef2208a4a5..a4fcc6d0ae5d 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -1,5 +1,16 @@ -var _ = require('lodash'); +const _ = require('lodash'); +const visualRegression = require('../utilities/visual_regression'); + 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:browser', [ 'run:testServer', 'karma:unit' ]); grunt.registerTask('test:coverage', [ 'run:testCoverageServer', 'karma:coverage' ]); @@ -20,6 +31,7 @@ module.exports = function (grunt) { 'esvm:ui', 'run:testUIServer', 'run:chromeDriver', + 'clean:screenshots', 'intern:dev', 'esvm_shutdown:ui', 'stop:chromeDriver', @@ -33,6 +45,7 @@ module.exports = function (grunt) { ]); grunt.registerTask('test:ui:runner', [ + 'clean:screenshots', 'intern:dev' ]); @@ -53,7 +66,7 @@ module.exports = function (grunt) { 'intern:api' ]); - grunt.registerTask('test', function (subTask) { + grunt.registerTask('test', subTask => { if (subTask) grunt.fail.fatal(`invalid task "test:${subTask}"`); grunt.task.run(_.compact([ diff --git a/test/functional/apps/console/_console.js b/test/functional/apps/console/_console.js index 2f96481dca0d..92b505e4390c 100644 --- a/test/functional/apps/console/_console.js +++ b/test/functional/apps/console/_console.js @@ -13,7 +13,6 @@ bdd.describe('console app', function describeIndexTests() { return common.navigateToApp('console', false); }); - bdd.it('should show the default request', function () { var expectedRequest = [ '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 return consolePage.collapseHelp() .then(function () { + common.saveScreenshot('Console-help-collapsed'); return common.try(function () { return consolePage.getRequest() .then(function (actualRequest) { @@ -40,6 +41,7 @@ bdd.describe('console app', function describeIndexTests() { var expectedResponseContains = '"_index": ".kibana",'; return consolePage.clickPlay() .then(function () { + common.saveScreenshot('Console-default-request'); return common.try(function () { return consolePage.getResponse() .then(function (actualResponse) { diff --git a/test/functional/apps/dashboard/_dashboard.js b/test/functional/apps/dashboard/_dashboard.js index d81682b6b2eb..d068880e6351 100644 --- a/test/functional/apps/dashboard/_dashboard.js +++ b/test/functional/apps/dashboard/_dashboard.js @@ -42,6 +42,8 @@ bdd.describe('dashboard tab', function describeIndexTests() { ]; bdd.it('should be able to add visualizations to dashboard', function addVisualizations() { + common.saveScreenshot('Dashboard-no-visualizations'); + function addVisualizations(arr) { return arr.reduce(function (promise, vizName) { return promise @@ -54,13 +56,13 @@ bdd.describe('dashboard tab', function describeIndexTests() { return addVisualizations(visualizations) .then(function () { 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() { var fromTime = '2015-09-19 06:31:44.000'; var toTime = '2015-09-23 18:31:44.000'; - var testSubName = 'Dashboard Test 1'; // .then(function () { common.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"'); @@ -69,21 +71,23 @@ bdd.describe('dashboard tab', function describeIndexTests() { return headerPage.getSpinnerDone(); }) .then(function takeScreenshot() { - common.debug('Take screenshot'); - common.saveScreenshot('./screenshot-' + testSubName + '.png'); + common.saveScreenshot('Dashboard-set-timepicker'); }); }); 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 - return dashboardPage.saveDashboard(testSubName) + return dashboardPage.saveDashboard(dashboardName) // click New Dashboard just to clear the one we just created .then(function () { return dashboardPage.clickNewDashboard(); }) .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); 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() .then(function (panelTitles) { common.log('visualization titles = ' + panelTitles); + common.saveScreenshot('Dashboard-visualization-sizes'); expect(panelTitles).to.eql(visObjects); }); }); diff --git a/test/functional/apps/discover/_collapse_expand.js b/test/functional/apps/discover/_collapse_expand.js index 354638990d28..52b2e40f269c 100644 --- a/test/functional/apps/discover/_collapse_expand.js +++ b/test/functional/apps/discover/_collapse_expand.js @@ -38,6 +38,7 @@ bdd.describe('discover tab', function describeIndexTests() { bdd.describe('field data', function () { bdd.it('should initially be expanded', function () { + common.saveScreenshot('Discover-sidebar-expanded'); return discoverPage.getSidebarWidth() .then(function (width) { common.debug('expanded sidebar width = ' + width); @@ -48,6 +49,7 @@ bdd.describe('discover tab', function describeIndexTests() { bdd.it('should collapse when clicked', function () { return discoverPage.toggleSidebarCollapse() .then(function () { + common.saveScreenshot('Discover-sidebar-collapsed'); common.debug('discoverPage.getSidebarWidth()'); return discoverPage.getSidebarWidth(); }) diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index abb8f8e5bd9c..d2a51b3a6641 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -58,6 +58,7 @@ bdd.describe('discover app', function describeIndexTests() { return headerPage.getToastMessage(); }) .then(function (toastMessage) { + common.saveScreenshot('Discover-save-query-toast'); expect(toastMessage).to.be(expectedSavedQueryMessage); }) .then(function () { @@ -80,6 +81,7 @@ bdd.describe('discover app', function describeIndexTests() { return discoverPage.getCurrentQueryName(); }) .then(function (actualQueryNameString) { + common.saveScreenshot('Discover-load-query'); expect(actualQueryNameString).to.be(queryName1); }); }); @@ -289,6 +291,7 @@ bdd.describe('discover app', function describeIndexTests() { bdd.it('should show "no results"', () => { return discoverPage.hasNoResults().then(visible => { + common.saveScreenshot('Discover-no-results'); expect(visible).to.be(true); }); }); diff --git a/test/functional/apps/discover/_field_data.js b/test/functional/apps/discover/_field_data.js index eac33162b91b..7d94ef978e8a 100644 --- a/test/functional/apps/discover/_field_data.js +++ b/test/functional/apps/discover/_field_data.js @@ -49,6 +49,7 @@ bdd.describe('discover app', function describeIndexTests() { return common.try(function tryingForTime() { return discoverPage.getHitCount() .then(function compareData(hitCount) { + common.saveScreenshot('Discover-field-data'); 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 () { var expectedHitCount = '11,156'; return discoverPage.query('_type:apache') @@ -222,6 +222,7 @@ bdd.describe('discover app', function describeIndexTests() { return common.try(function tryingForTime() { return discoverPage.getDocTableIndex(1) .then(function (rowData) { + common.saveScreenshot('Discover-sort-down'); expect(rowData).to.be(ExpectedDoc); }); }); @@ -237,6 +238,7 @@ bdd.describe('discover app', function describeIndexTests() { return headerPage.getToastMessage(); }) .then(function (toastMessage) { + common.saveScreenshot('Discover-syntax-error-toast'); expect(toastMessage).to.be(expectedError); }) .then(function () { diff --git a/test/functional/apps/discover/_shared_links.js b/test/functional/apps/discover/_shared_links.js index dbbe940b115f..2b4e205c484f 100644 --- a/test/functional/apps/discover/_shared_links.js +++ b/test/functional/apps/discover/_shared_links.js @@ -56,6 +56,7 @@ bdd.describe('shared links', function describeIndexTests() { var expectedCaption = 'Share a link'; return discoverPage.clickShare() .then(function () { + common.saveScreenshot('Discover-share-link'); return discoverPage.getShareCaption(); }) .then(function (actualCaption) { @@ -85,6 +86,7 @@ bdd.describe('shared links', function describeIndexTests() { return headerPage.getToastMessage(); }) .then(function (toastMessage) { + common.saveScreenshot('Discover-copy-to-clipboard-toast'); expect(toastMessage).to.match(expectedToastMessage); }) .then(function () { @@ -98,6 +100,7 @@ bdd.describe('shared links', function describeIndexTests() { return discoverPage.clickShortenUrl() .then(function () { return common.try(function tryingForTime() { + common.saveScreenshot('Discover-shorten-url-button'); return discoverPage.getShortenedUrl() .then(function (actualUrl) { expect(actualUrl).to.match(re); diff --git a/test/functional/apps/settings/_advanced_settings.js b/test/functional/apps/settings/_advanced_settings.js index b85b4b4ee049..498842801fbd 100644 --- a/test/functional/apps/settings/_advanced_settings.js +++ b/test/functional/apps/settings/_advanced_settings.js @@ -25,10 +25,12 @@ bdd.describe('creating and deleting default index', function describeIndexTests( bdd.it('should allow setting advanced settings', function () { return settingsPage.clickAdvancedTab() .then(function TestCallSetAdvancedSettingsForTimezone() { + common.saveScreenshot('Settings-advanced-tab'); common.debug('calling setAdvancedSetting'); return settingsPage.setAdvancedSettings('dateFormat:tz', 'America/Phoenix'); }) .then(function GetAdvancedSetting() { + common.saveScreenshot('Settings-set-timezone'); return settingsPage.getAdvancedSettings('dateFormat:tz'); }) .then(function (advancedSetting) { diff --git a/test/functional/apps/settings/_creation_form_changes.js b/test/functional/apps/settings/_creation_form_changes.js index f80d771a127b..fb3b8bf497fe 100644 --- a/test/functional/apps/settings/_creation_form_changes.js +++ b/test/functional/apps/settings/_creation_form_changes.js @@ -30,6 +30,7 @@ bdd.describe('user input reactions', function () { return settingsPage.getTimeBasedIndexPatternCheckbox(waitTime); }) .then(function () { + common.saveScreenshot('Settings-indices-hide-time-based-index-pattern'); // we expect the promise above to fail var handler = common.handleError(self); var msg = 'Found time based index pattern checkbox'; @@ -47,6 +48,7 @@ bdd.describe('user input reactions', function () { .then(function () { return settingsPage.getCreateButton().isEnabled() .then(function (enabled) { + common.saveScreenshot('Settings-indices-enable-creation'); expect(enabled).to.be.ok(); }); }); diff --git a/test/functional/apps/settings/_index_pattern_create_delete.js b/test/functional/apps/settings/_index_pattern_create_delete.js index 0578662e76ea..1ad16594f7b3 100644 --- a/test/functional/apps/settings/_index_pattern_create_delete.js +++ b/test/functional/apps/settings/_index_pattern_create_delete.js @@ -26,6 +26,7 @@ bdd.describe('creating and deleting default index', function describeIndexTests( bdd.it('should have index pattern in page header', function pageHeader() { return settingsPage.getIndexPageHeading().getVisibleText() .then(function (patternName) { + common.saveScreenshot('Settings-indices-new-index-pattern'); 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?'; return settingsPage.removeIndexPattern() .then(function (alertText) { + common.saveScreenshot('Settings-indices-confirm-remove-index-pattern'); expect(alertText).to.be(expectedAlertText); }); }); diff --git a/test/functional/apps/settings/_index_pattern_popularity.js b/test/functional/apps/settings/_index_pattern_popularity.js index f7bb041db67f..97f9d84a6b48 100644 --- a/test/functional/apps/settings/_index_pattern_popularity.js +++ b/test/functional/apps/settings/_index_pattern_popularity.js @@ -63,6 +63,7 @@ bdd.describe('index result popularity', function describeIndexTests() { .then(function (popularity) { common.debug('popularity = ' + popularity); 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) { common.debug('popularity = ' + popularity); expect(popularity).to.be('1'); + common.saveScreenshot('Settings-indices-result-popularity-saved'); }); }); }); // end 'change popularity' diff --git a/test/functional/apps/settings/_index_pattern_results_sort.js b/test/functional/apps/settings/_index_pattern_results_sort.js index 5f2fc88a52ac..50e1ade1ac2e 100644 --- a/test/functional/apps/settings/_index_pattern_results_sort.js +++ b/test/functional/apps/settings/_index_pattern_results_sort.js @@ -51,6 +51,7 @@ bdd.describe('index result field sort', function describeIndexTests() { return col.selector(); }) .then(function (rowText) { + common.saveScreenshot(`Settings-indices-column-${col.heading}-sort-ascending`); expect(rowText).to.be(col.first); }); }); @@ -64,6 +65,7 @@ bdd.describe('index result field sort', function describeIndexTests() { return col.selector(); }) .then(function (rowText) { + common.saveScreenshot(`Settings-indices-column-${col.heading}-sort-descending`); expect(rowText).to.be(col.last); }); }); @@ -115,6 +117,7 @@ bdd.describe('index result field sort', function describeIndexTests() { return settingsPage.getPageFieldCount(); }) .then(function (pageCount) { + common.saveScreenshot('Settings-indices-paged'); var expectedSize = (val < 4) ? expectedDefaultPageSize : expectedLastPageCount; expect(pageCount.length).to.be(expectedSize); }); diff --git a/test/functional/apps/settings/_initial_state.js b/test/functional/apps/settings/_initial_state.js index 8d844572dd55..c5cdc243cba3 100644 --- a/test/functional/apps/settings/_initial_state.js +++ b/test/functional/apps/settings/_initial_state.js @@ -20,6 +20,7 @@ bdd.describe('initial state', function () { bdd.it('should load with time pattern checked', function () { return settingsPage.getTimeBasedEventsCheckbox().isSelected() .then(function (selected) { + common.saveScreenshot('Settings-initial-state'); expect(selected).to.be.ok(); }); }); diff --git a/test/functional/apps/visualize/_area_chart.js b/test/functional/apps/visualize/_area_chart.js index b95c5275b85b..de0eab0c140b 100644 --- a/test/functional/apps/visualize/_area_chart.js +++ b/test/functional/apps/visualize/_area_chart.js @@ -61,13 +61,13 @@ bdd.describe('visualize app', function describeIndexTests() { }); bdd.describe('area charts', function indexPatternCreation() { - var testSubName = 'AreaChart'; - var vizName1 = 'Visualization ' + testSubName; + var vizName1 = 'Visualization AreaChart'; bdd.it('should save and load', function pageHeader() { return visualizePage.saveVisualization(vizName1) .then(function (message) { common.debug('Saved viz message = ' + message); + common.saveScreenshot('Visualize-area-chart-save-toast'); expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"'); }) .then(function testVisualizeWaitForToastMessageGone() { @@ -87,7 +87,6 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.it('should show correct chart, take screenshot', function pageHeader() { var chartHeight = 0; 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) { common.debug('expectedAreaChartData = ' + expectedAreaChartData); common.debug('actual chart data = ' + paths); + common.saveScreenshot('Visualize-area-chart'); 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() { var expectedTableData = [ 'September 20th 2015, 00:00:00.000 37', '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); }); }); - - - }); }); diff --git a/test/functional/apps/visualize/_chart_types.js b/test/functional/apps/visualize/_chart_types.js index 1e375de7f868..6d9cc2e9b3cb 100644 --- a/test/functional/apps/visualize/_chart_types.js +++ b/test/functional/apps/visualize/_chart_types.js @@ -16,9 +16,7 @@ bdd.describe('visualize app', function describeIndexTests() { }); bdd.describe('chart types', function indexPatternCreation() { - bdd.it('should show the correct chart types', function pageHeader() { - var expectedChartTypes = [ 'Area chart', 'Data table', 'Line chart', 'Markdown widget', 'Metric', 'Pie chart', 'Tile map', 'Vertical bar chart' @@ -28,6 +26,7 @@ bdd.describe('visualize app', function describeIndexTests() { .then(function testChartTypes(chartTypes) { common.debug('returned chart types = ' + chartTypes); common.debug('expected chart types = ' + expectedChartTypes); + common.saveScreenshot('Visualize-chart-types'); expect(chartTypes).to.eql(expectedChartTypes); }); }); diff --git a/test/functional/apps/visualize/_data_table.js b/test/functional/apps/visualize/_data_table.js index 8734f51a54ac..302825c8cf51 100644 --- a/test/functional/apps/visualize/_data_table.js +++ b/test/functional/apps/visualize/_data_table.js @@ -52,10 +52,8 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.describe('data table', function indexPatternCreation() { - var testSubName = 'DataTable'; - var vizName1 = 'Visualization ' + testSubName; + var vizName1 = 'Visualization DataTable'; bdd.it('should be able to save and load', function pageHeader() { return visualizePage.saveVisualization(vizName1) @@ -74,7 +72,6 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.it('should show correct data, take screenshot', function pageHeader() { var chartHeight = 0; 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() .then(function showData(data) { common.debug(data.split('\n')); + common.saveScreenshot('Visualize-data-table'); expect(data.split('\n')).to.eql(expectedChartData); - }) - .then(function takeScreenshot() { - common.debug('Take screenshot'); - common.saveScreenshot('./screenshot-' + testSubName + '.png'); }); }); - }); }); diff --git a/test/functional/apps/visualize/_line_chart.js b/test/functional/apps/visualize/_line_chart.js index 469187597dbc..2b186a1f21ba 100644 --- a/test/functional/apps/visualize/_line_chart.js +++ b/test/functional/apps/visualize/_line_chart.js @@ -52,12 +52,9 @@ bdd.describe('visualize app', function describeIndexTests() { }); bdd.describe('line charts', function indexPatternCreation() { - var testSubName = 'LineChart'; - var vizName1 = 'Visualization ' + testSubName; + var vizName1 = 'Visualization LineChart'; bdd.it('should be able to save and load', function pageHeader() { - - common.debug('Start of test' + testSubName + 'Visualization'); var remote = this.remote; return visualizePage.saveVisualization(vizName1) @@ -88,24 +85,18 @@ bdd.describe('visualize app', function describeIndexTests() { // sleep a bit before trying to get the chart data return common.sleep(3000) .then(function () { - return common.try(function () { - return visualizePage.getLineChartData('fill="#57c17b"') - .then(function showData(data) { - var tolerance = 10; // the y-axis scale is 10000 so 10 is 0.1% - for (var x = 0; x < data.length; x++) { - common.debug('x=' + x + ' expectedChartData[x].split(\' \')[1] = ' + - (expectedChartData[x].split(' ')[1]).replace(',', '') + ' data[x]=' + 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(); - } - common.debug('Done'); - }); + return visualizePage.getLineChartData('fill="#57c17b"') + .then(function showData(data) { + common.saveScreenshot('Visualize-line-chart'); + var tolerance = 10; // the y-axis scale is 10000 so 10 is 0.1% + for (var x = 0; x < data.length; x++) { + common.debug('x=' + x + ' expectedChartData[x].split(\' \')[1] = ' + + (expectedChartData[x].split(' ')[1]).replace(',', '') + ' data[x]=' + 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(); + } + common.debug('Done'); }); - }) - .then(function takeScreenshot() { - // take a snapshot just as an example. - common.debug('Take screenshot'); - common.saveScreenshot('./screenshot-' + testSubName + '.png'); }); }); diff --git a/test/functional/apps/visualize/_metric_chart.js b/test/functional/apps/visualize/_metric_chart.js index 811061858af2..29a4cd96e993 100644 --- a/test/functional/apps/visualize/_metric_chart.js +++ b/test/functional/apps/visualize/_metric_chart.js @@ -14,11 +14,6 @@ bdd.describe('visualize app', function describeIndexTests() { var toTime = '2015-09-23 18:31:44.000'; bdd.before(function () { - - var testSubName = 'MetricChart'; - common.debug('Start of test' + testSubName + 'Visualization'); - var vizName1 = 'Visualization ' + testSubName; - common.debug('navigateToApp visualize'); return common.navigateToApp('visualize') .then(function () { @@ -34,7 +29,6 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.describe('metric chart', function indexPatternCreation() { bdd.it('should show Count', function pageHeader() { @@ -44,6 +38,7 @@ bdd.describe('visualize app', function describeIndexTests() { return common.try(function tryingForTime() { return visualizePage.getMetric() .then(function (metricValue) { + common.saveScreenshot('Visualize-metric-chart'); expect(expectedCount).to.eql(metricValue.split('\n')); }); }); diff --git a/test/functional/apps/visualize/_pie_chart.js b/test/functional/apps/visualize/_pie_chart.js index 424f855698a3..e94467860204 100644 --- a/test/functional/apps/visualize/_pie_chart.js +++ b/test/functional/apps/visualize/_pie_chart.js @@ -60,12 +60,9 @@ bdd.describe('visualize app', function describeIndexTests() { bdd.describe('pie chart', function indexPatternCreation() { - var testSubName = 'PieChart'; - var vizName1 = 'Visualization ' + testSubName; - + var vizName1 = 'Visualization PieChart'; bdd.it('should save and load', function pageHeader() { - common.debug('Start of test' + testSubName + 'Visualization'); var remote = this.remote; return visualizePage.saveVisualization(vizName1) @@ -96,11 +93,8 @@ bdd.describe('visualize app', function describeIndexTests() { .then(function (pieData) { var barHeightTolerance = 1; common.debug('pieData.length = ' + pieData.length); + common.saveScreenshot('Visualize-pie-chart'); 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); }); }); - - }); }); diff --git a/test/functional/apps/visualize/_tile_map.js b/test/functional/apps/visualize/_tile_map.js index 3693fbc88836..a8dd2d914073 100644 --- a/test/functional/apps/visualize/_tile_map.js +++ b/test/functional/apps/visualize/_tile_map.js @@ -50,14 +50,10 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.describe('tile map chart', function indexPatternCreation() { bdd.it('should save and load, take screenshot', function pageHeader() { - var testSubName = 'TileMap'; - common.debug('Start of test' + testSubName + 'Visualization'); - var vizName1 = 'Visualization ' + testSubName; - // var remote = this.remote; + var vizName1 = 'Visualization TileMap'; return visualizePage.saveVisualization(vizName1) .then(function (message) { @@ -79,14 +75,11 @@ bdd.describe('visualize app', function describeIndexTests() { }) .then(function takeScreenshot() { common.debug('Take screenshot'); - common.saveScreenshot('./screenshot-' + testSubName + '.png'); + common.saveScreenshot('Visualize-site-map'); }); }); 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', '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', @@ -107,7 +100,5 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); }); - - }); }); diff --git a/test/functional/apps/visualize/_vertical_bar_chart.js b/test/functional/apps/visualize/_vertical_bar_chart.js index ec399a32879b..e3cbc9f2366e 100644 --- a/test/functional/apps/visualize/_vertical_bar_chart.js +++ b/test/functional/apps/visualize/_vertical_bar_chart.js @@ -52,8 +52,7 @@ bdd.describe('visualize app', function describeIndexTests() { }); bdd.describe('vertical bar chart', function indexPatternCreation() { - var testSubName = 'VerticalBarChart'; - var vizName1 = 'Visualization ' + testSubName; + var vizName1 = 'Visualization VerticalBarChart'; bdd.it('should save and load', function pageHeader() { return visualizePage.saveVisualization(vizName1) @@ -75,7 +74,6 @@ bdd.describe('visualize app', function describeIndexTests() { }); }); - bdd.it('should show correct chart, take screenshot', function pageHeader() { 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 @@ -91,17 +89,13 @@ bdd.describe('visualize app', function describeIndexTests() { .then(function showData(data) { common.debug('data=' + data); common.debug('data.length=' + data.length); + common.saveScreenshot('Visualize-vertical-bar-chart'); 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() { - var testSubName = 'VerticalBarChart'; // this is only the first page of the tabular data. var expectedChartData = [ 'September 20th 2015, 00:00:00.000 37', 'September 20th 2015, 03:00:00.000 202', diff --git a/test/functional/status_page/index.js b/test/functional/status_page/index.js index 492e1742a56b..8d601df8a745 100644 --- a/test/functional/status_page/index.js +++ b/test/functional/status_page/index.js @@ -1,4 +1,7 @@ -import { bdd, common } from '../../support'; +import { + bdd, + common +} from '../../support'; var expect = require('expect.js'); @@ -11,11 +14,11 @@ bdd.describe('status page', function () { var self = this; return common.tryForTime(6000, function () { - return self.remote - .findByCssSelector('.plugin_status_breakdown') + return common.findTestSubject('statusBreakdown') .getVisibleText() .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)); diff --git a/test/screenshots/baseline/Console-default-request.png b/test/screenshots/baseline/Console-default-request.png new file mode 100644 index 000000000000..cdaf7f8202fb Binary files /dev/null and b/test/screenshots/baseline/Console-default-request.png differ diff --git a/test/screenshots/baseline/Console-help-collapsed.png b/test/screenshots/baseline/Console-help-collapsed.png new file mode 100644 index 000000000000..b7b7649b39be Binary files /dev/null and b/test/screenshots/baseline/Console-help-collapsed.png differ diff --git a/test/screenshots/baseline/Console-help-expanded.png b/test/screenshots/baseline/Console-help-expanded.png new file mode 100644 index 000000000000..4de6cc1c5838 Binary files /dev/null and b/test/screenshots/baseline/Console-help-expanded.png differ diff --git a/test/screenshots/baseline/Dashboard-add-visualizations.png b/test/screenshots/baseline/Dashboard-add-visualizations.png new file mode 100644 index 000000000000..7255b54da2a9 Binary files /dev/null and b/test/screenshots/baseline/Dashboard-add-visualizations.png differ diff --git a/test/screenshots/baseline/Dashboard-has-visualizations.png b/test/screenshots/baseline/Dashboard-has-visualizations.png new file mode 100644 index 000000000000..3f0e18b52a2c Binary files /dev/null and b/test/screenshots/baseline/Dashboard-has-visualizations.png differ diff --git a/test/screenshots/baseline/Dashboard-load-saved.png b/test/screenshots/baseline/Dashboard-load-saved.png new file mode 100644 index 000000000000..9aff82b17a52 Binary files /dev/null and b/test/screenshots/baseline/Dashboard-load-saved.png differ diff --git a/test/screenshots/baseline/Dashboard-no-visualizations.png b/test/screenshots/baseline/Dashboard-no-visualizations.png new file mode 100644 index 000000000000..3daa6682a0b8 Binary files /dev/null and b/test/screenshots/baseline/Dashboard-no-visualizations.png differ diff --git a/test/screenshots/baseline/Dashboard-set-timepicker.png b/test/screenshots/baseline/Dashboard-set-timepicker.png new file mode 100644 index 000000000000..60f4434a7f9f Binary files /dev/null and b/test/screenshots/baseline/Dashboard-set-timepicker.png differ diff --git a/test/screenshots/baseline/Dashboard-visualization-sizes.png b/test/screenshots/baseline/Dashboard-visualization-sizes.png new file mode 100644 index 000000000000..77af5a1f2c14 Binary files /dev/null and b/test/screenshots/baseline/Dashboard-visualization-sizes.png differ diff --git a/test/screenshots/baseline/Discover-copy-to-clipboard-toast.png b/test/screenshots/baseline/Discover-copy-to-clipboard-toast.png new file mode 100644 index 000000000000..1b4ce74c0c88 Binary files /dev/null and b/test/screenshots/baseline/Discover-copy-to-clipboard-toast.png differ diff --git a/test/screenshots/baseline/Discover-field-data.png b/test/screenshots/baseline/Discover-field-data.png new file mode 100644 index 000000000000..a67dd1f948f9 Binary files /dev/null and b/test/screenshots/baseline/Discover-field-data.png differ diff --git a/test/screenshots/baseline/Discover-load-query.png b/test/screenshots/baseline/Discover-load-query.png new file mode 100644 index 000000000000..0a81623880ff Binary files /dev/null and b/test/screenshots/baseline/Discover-load-query.png differ diff --git a/test/screenshots/baseline/Discover-no-results.png b/test/screenshots/baseline/Discover-no-results.png new file mode 100644 index 000000000000..087fc38e26f3 Binary files /dev/null and b/test/screenshots/baseline/Discover-no-results.png differ diff --git a/test/screenshots/baseline/Discover-save-query-toast.png b/test/screenshots/baseline/Discover-save-query-toast.png new file mode 100644 index 000000000000..af51accf12bb Binary files /dev/null and b/test/screenshots/baseline/Discover-save-query-toast.png differ diff --git a/test/screenshots/baseline/Discover-share-link.png b/test/screenshots/baseline/Discover-share-link.png new file mode 100644 index 000000000000..4d4517db52ca Binary files /dev/null and b/test/screenshots/baseline/Discover-share-link.png differ diff --git a/test/screenshots/baseline/Discover-shorten-url-button.png b/test/screenshots/baseline/Discover-shorten-url-button.png new file mode 100644 index 000000000000..d2e630e9646d Binary files /dev/null and b/test/screenshots/baseline/Discover-shorten-url-button.png differ diff --git a/test/screenshots/baseline/Discover-sidebar-collapsed.png b/test/screenshots/baseline/Discover-sidebar-collapsed.png new file mode 100644 index 000000000000..5e49a212f37d Binary files /dev/null and b/test/screenshots/baseline/Discover-sidebar-collapsed.png differ diff --git a/test/screenshots/baseline/Discover-sidebar-expanded.png b/test/screenshots/baseline/Discover-sidebar-expanded.png new file mode 100644 index 000000000000..f755d632aa50 Binary files /dev/null and b/test/screenshots/baseline/Discover-sidebar-expanded.png differ diff --git a/test/screenshots/baseline/Discover-sort-down.png b/test/screenshots/baseline/Discover-sort-down.png new file mode 100644 index 000000000000..835389854b91 Binary files /dev/null and b/test/screenshots/baseline/Discover-sort-down.png differ diff --git a/test/screenshots/baseline/Discover-syntax-error-toast.png b/test/screenshots/baseline/Discover-syntax-error-toast.png new file mode 100644 index 000000000000..0456e7a7ce07 Binary files /dev/null and b/test/screenshots/baseline/Discover-syntax-error-toast.png differ diff --git a/test/screenshots/baseline/Settings-advanced-tab.png b/test/screenshots/baseline/Settings-advanced-tab.png new file mode 100644 index 000000000000..9d3cf76c72c1 Binary files /dev/null and b/test/screenshots/baseline/Settings-advanced-tab.png differ diff --git a/test/screenshots/baseline/Settings-indices-column-name-sort-ascending.png b/test/screenshots/baseline/Settings-indices-column-name-sort-ascending.png new file mode 100644 index 000000000000..4dd2e3b42049 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-column-name-sort-ascending.png differ diff --git a/test/screenshots/baseline/Settings-indices-column-name-sort-descending.png b/test/screenshots/baseline/Settings-indices-column-name-sort-descending.png new file mode 100644 index 000000000000..2f992bbecccf Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-column-name-sort-descending.png differ diff --git a/test/screenshots/baseline/Settings-indices-column-type-sort-ascending.png b/test/screenshots/baseline/Settings-indices-column-type-sort-ascending.png new file mode 100644 index 000000000000..dbddbfed3568 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-column-type-sort-ascending.png differ diff --git a/test/screenshots/baseline/Settings-indices-column-type-sort-descending.png b/test/screenshots/baseline/Settings-indices-column-type-sort-descending.png new file mode 100644 index 000000000000..266f0fc92df3 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-column-type-sort-descending.png differ diff --git a/test/screenshots/baseline/Settings-indices-confirm-remove-index-pattern.png b/test/screenshots/baseline/Settings-indices-confirm-remove-index-pattern.png new file mode 100644 index 000000000000..f27eb7ed00b1 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-confirm-remove-index-pattern.png differ diff --git a/test/screenshots/baseline/Settings-indices-enable-creation.png b/test/screenshots/baseline/Settings-indices-enable-creation.png new file mode 100644 index 000000000000..b6f1bd8ba2e9 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-enable-creation.png differ diff --git a/test/screenshots/baseline/Settings-indices-new-index-pattern.png b/test/screenshots/baseline/Settings-indices-new-index-pattern.png new file mode 100644 index 000000000000..76c41c91676d Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-new-index-pattern.png differ diff --git a/test/screenshots/baseline/Settings-indices-paged.png b/test/screenshots/baseline/Settings-indices-paged.png new file mode 100644 index 000000000000..7e72d34e4366 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-paged.png differ diff --git a/test/screenshots/baseline/Settings-indices-result-popularity-saved.png b/test/screenshots/baseline/Settings-indices-result-popularity-saved.png new file mode 100644 index 000000000000..7fda78f64e8e Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-result-popularity-saved.png differ diff --git a/test/screenshots/baseline/Settings-indices-result-popularity-updated.png b/test/screenshots/baseline/Settings-indices-result-popularity-updated.png new file mode 100644 index 000000000000..7d29ab297073 Binary files /dev/null and b/test/screenshots/baseline/Settings-indices-result-popularity-updated.png differ diff --git a/test/screenshots/baseline/Settings-initial-state.png b/test/screenshots/baseline/Settings-initial-state.png new file mode 100644 index 000000000000..f27eb7ed00b1 Binary files /dev/null and b/test/screenshots/baseline/Settings-initial-state.png differ diff --git a/test/screenshots/baseline/Settings-set-timezone.png b/test/screenshots/baseline/Settings-set-timezone.png new file mode 100644 index 000000000000..cde95b470e09 Binary files /dev/null and b/test/screenshots/baseline/Settings-set-timezone.png differ diff --git a/test/screenshots/baseline/Status.png b/test/screenshots/baseline/Status.png new file mode 100644 index 000000000000..8c3ad8d3a915 Binary files /dev/null and b/test/screenshots/baseline/Status.png differ diff --git a/test/screenshots/baseline/Visualize-area-chart-save-toast.png b/test/screenshots/baseline/Visualize-area-chart-save-toast.png new file mode 100644 index 000000000000..9cacf128de06 Binary files /dev/null and b/test/screenshots/baseline/Visualize-area-chart-save-toast.png differ diff --git a/test/screenshots/baseline/Visualize-area-chart.png b/test/screenshots/baseline/Visualize-area-chart.png new file mode 100644 index 000000000000..8be0c7b0a570 Binary files /dev/null and b/test/screenshots/baseline/Visualize-area-chart.png differ diff --git a/test/screenshots/baseline/Visualize-chart-types.png b/test/screenshots/baseline/Visualize-chart-types.png new file mode 100644 index 000000000000..705598645c33 Binary files /dev/null and b/test/screenshots/baseline/Visualize-chart-types.png differ diff --git a/test/screenshots/baseline/Visualize-data-table.png b/test/screenshots/baseline/Visualize-data-table.png new file mode 100644 index 000000000000..c696723d35d6 Binary files /dev/null and b/test/screenshots/baseline/Visualize-data-table.png differ diff --git a/test/screenshots/baseline/Visualize-line-chart.png b/test/screenshots/baseline/Visualize-line-chart.png new file mode 100644 index 000000000000..88ee84a52db8 Binary files /dev/null and b/test/screenshots/baseline/Visualize-line-chart.png differ diff --git a/test/screenshots/baseline/Visualize-metric-chart.png b/test/screenshots/baseline/Visualize-metric-chart.png new file mode 100644 index 000000000000..1c92e816a3bc Binary files /dev/null and b/test/screenshots/baseline/Visualize-metric-chart.png differ diff --git a/test/screenshots/baseline/Visualize-pie-chart.png b/test/screenshots/baseline/Visualize-pie-chart.png new file mode 100644 index 000000000000..857e4fb19bd2 Binary files /dev/null and b/test/screenshots/baseline/Visualize-pie-chart.png differ diff --git a/test/screenshots/baseline/Visualize-site-map.png b/test/screenshots/baseline/Visualize-site-map.png new file mode 100644 index 000000000000..d4b6838b25a4 Binary files /dev/null and b/test/screenshots/baseline/Visualize-site-map.png differ diff --git a/test/screenshots/baseline/Visualize-vertical-bar-chart.png b/test/screenshots/baseline/Visualize-vertical-bar-chart.png new file mode 100644 index 000000000000..3c9e9610cbcb Binary files /dev/null and b/test/screenshots/baseline/Visualize-vertical-bar-chart.png differ diff --git a/test/screenshots/baseline/screenshot-AreaChart.png b/test/screenshots/baseline/screenshot-AreaChart.png deleted file mode 100644 index d5bbbd9b3080..000000000000 Binary files a/test/screenshots/baseline/screenshot-AreaChart.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-Dashboard Test 1.png b/test/screenshots/baseline/screenshot-Dashboard Test 1.png deleted file mode 100644 index 0d09c01f83ce..000000000000 Binary files a/test/screenshots/baseline/screenshot-Dashboard Test 1.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-DataTable.png b/test/screenshots/baseline/screenshot-DataTable.png deleted file mode 100644 index d1328c28229c..000000000000 Binary files a/test/screenshots/baseline/screenshot-DataTable.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-LineChart.png b/test/screenshots/baseline/screenshot-LineChart.png deleted file mode 100644 index 5b0a8b9b1d49..000000000000 Binary files a/test/screenshots/baseline/screenshot-LineChart.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-PieChart.png b/test/screenshots/baseline/screenshot-PieChart.png deleted file mode 100644 index b51e7ad69f52..000000000000 Binary files a/test/screenshots/baseline/screenshot-PieChart.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-TileMap.png b/test/screenshots/baseline/screenshot-TileMap.png deleted file mode 100644 index cdd55dbe7362..000000000000 Binary files a/test/screenshots/baseline/screenshot-TileMap.png and /dev/null differ diff --git a/test/screenshots/baseline/screenshot-VerticalBarChart.png b/test/screenshots/baseline/screenshot-VerticalBarChart.png deleted file mode 100644 index 819eaf925f2e..000000000000 Binary files a/test/screenshots/baseline/screenshot-VerticalBarChart.png and /dev/null differ diff --git a/test/support/pages/common.js b/test/support/pages/common.js index abb167fa0dee..d50e991ce061 100644 --- a/test/support/pages/common.js +++ b/test/support/pages/common.js @@ -256,7 +256,7 @@ export default (function () { const testName = (testObj.parent) ? [testObj.parent.name, testObj.name].join('_') : testObj.name; return reason => { const now = Date.now(); - const fileName = `failure_${now}_${testName}.png`; + const fileName = `failure_${now}_${testName}`; return this.saveScreenshot(fileName, true) .then(function () { @@ -269,7 +269,7 @@ export default (function () { try { const directoryName = isFailure ? 'failure' : 'session'; const directoryPath = path.resolve(`test/screenshots/${directoryName}`); - const filePath = path.resolve(directoryPath, fileName); + const filePath = path.resolve(directoryPath, `${fileName}.png`); this.debug(`Taking screenshot "${filePath}"`); const screenshot = await this.remote.takeScreenshot(); diff --git a/utilities/compareScreenshots.js b/utilities/compareScreenshots.js deleted file mode 100644 index af7722b9eb1f..000000000000 --- a/utilities/compareScreenshots.js +++ /dev/null @@ -1,43 +0,0 @@ - -const fs = require('fs'); -const path = require('path'); -const imageDiff = require('image-diff'); -const mkdirp = require('mkdirp'); - -function compareScreenshots() { - const SCREENSHOTS_DIR = 'test/screenshots'; - const BASELINE_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'baseline'); - const DIFF_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'diff'); - const SESSION_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'session'); - - // We don't need to create the baseline dir because it's committed. - mkdirp.sync(DIFF_SCREENSHOTS_DIR); - mkdirp.sync(SESSION_SCREENSHOTS_DIR); - - fs.readdir(SESSION_SCREENSHOTS_DIR, (readDirError, files) => { - const screenshots = files.filter(file => file.indexOf('.png') !== -1); - - screenshots.forEach(screenshot => { - const sessionImagePath = path.resolve(SESSION_SCREENSHOTS_DIR, screenshot); - const baselineImagePath = path.resolve(BASELINE_SCREENSHOTS_DIR, screenshot); - const diffImagePath = path.resolve(DIFF_SCREENSHOTS_DIR, screenshot); - - imageDiff.getFullResult({ - actualImage: sessionImagePath, - expectedImage: baselineImagePath, - diffImage: diffImagePath, - shadow: true, - }, (comparisonError, result) => { - if (comparisonError) { - throw comparisonError; - } - - const change = result.percentage; - const changePercentage = (change * 100).toFixed(2); - console.log(`${screenshot} has changed by ${changePercentage}%`); - }); - }); - }); -} - -compareScreenshots(); diff --git a/utilities/templates/visual_regression_gallery.dot b/utilities/templates/visual_regression_gallery.dot new file mode 100644 index 000000000000..176590aa6066 --- /dev/null +++ b/utilities/templates/visual_regression_gallery.dot @@ -0,0 +1,296 @@ + + + + Kibana Visual Regression Gallery + + + + + + + + +
+ Kibana Visual Regression Gallery +
+ +
+ {{=it.branch}} - {{=it.date}} +
+ + {{~it.comparisons :comparison:index}} +
+
+ ({{=comparison.percentage}}%) {{=comparison.name}} +
+ +
+
Diff
+ +
+ Baseline +
+
+ +
+ +
+ +
+ + + + + +
+ +
+
+
+ {{~}} + + + + + diff --git a/utilities/visual_regression.js b/utilities/visual_regression.js new file mode 100644 index 000000000000..f1385d8c31a8 --- /dev/null +++ b/utilities/visual_regression.js @@ -0,0 +1,130 @@ + +import bluebird, { + fromNode, + promisify, +} from 'bluebird'; +import dot from 'dot'; +import fs from 'fs'; +import path from 'path'; +import imageDiff from 'image-diff'; +import mkdirp from 'mkdirp'; +import moment from 'moment'; +import SimpleGit from 'simple-git'; + +const readDirAsync = promisify(fs.readdir); +const readFileAsync = promisify(fs.readFile); +const writeFileAsync = promisify(fs.writeFile); + +// Preserve whitespace in our HTML output. +dot.templateSettings.strip = false; + +const templates = dot.process({ + path: path.resolve('./utilities/templates') +}); + +function buildGallery(comparisons) { + const simpleGit = new SimpleGit(); + const asyncBranch = promisify(simpleGit.branch, simpleGit); + + return asyncBranch().then(data => { + const branch = data.current; + + const html = templates.visual_regression_gallery({ + date: moment().format('MMMM Do YYYY, h:mm:ss a'), + branch, + hiddenThreshold: 0, + warningThreshold: 0.03, + comparisons, + }); + + return writeFileAsync( + path.resolve('./test/screenshots/visual_regression_gallery.html'), + html + ); + }); +} + +async function compareScreenshots() { + const SCREENSHOTS_DIR = 'test/screenshots'; + const BASELINE_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'baseline'); + const DIFF_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'diff'); + const SESSION_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'session'); + + // We don't need to create the baseline dir because it's committed. + mkdirp.sync(DIFF_SCREENSHOTS_DIR); + mkdirp.sync(SESSION_SCREENSHOTS_DIR); + const files = await readDirAsync(SESSION_SCREENSHOTS_DIR); + const screenshots = files.filter(file => file.indexOf('.png') !== -1); + + // We'll use this data to build a screenshot gallery in HTML. + return await bluebird.map(screenshots, async screenshot => { + // We're going to load image data and cache it in this object. + const comparison = { + name: screenshot, + change: undefined, + percentage: undefined, + imageData: { + session: undefined, + baseline: undefined, + diff: undefined, + } + }; + + const sessionImagePath = path.resolve( + SESSION_SCREENSHOTS_DIR, + screenshot + ); + + const baselineImagePath = path.resolve( + BASELINE_SCREENSHOTS_DIR, + screenshot + ); + + const diffImagePath = path.resolve( + DIFF_SCREENSHOTS_DIR, + screenshot + ); + + // Diff the images asynchronously. + const diffResult = await fromNode((cb) => { + imageDiff.getFullResult({ + actualImage: sessionImagePath, + expectedImage: baselineImagePath, + diffImage: diffImagePath, + shadow: true, + }, cb); + }); + + const change = diffResult.percentage; + const changePercentage = (change * 100).toFixed(2); + console.log(`(${changePercentage}%) ${screenshot}`); + comparison.percentage = changePercentage; + comparison.change = change; + + // Once the images have been diffed, we can load and store the image data. + comparison.imageData.session = + await readFileAsync(sessionImagePath, 'base64'); + + comparison.imageData.baseline = + await readFileAsync(baselineImagePath, 'base64'); + + comparison.imageData.diff = + await readFileAsync(diffImagePath, 'base64'); + + return comparison; + }); +} + +module.exports = { + run: done => { + compareScreenshots().then(screenshotComparisons => { + // Once all of the data has been loaded, we can build the gallery. + buildGallery(screenshotComparisons).then(() => { + done(); + }); + }, error => { + console.error(error); + done(false); + }); + } +};
NameVersionID Status
{{status.name}}{{status.version}}
{{status.id}} - + {{status.message}}