diff --git a/.gitignore b/.gitignore index 78ce49b03b17..e7ab50b2a859 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ disabledPlugins webpackstats.json config/kibana.dev.yml coverage +selenium diff --git a/Gruntfile.js b/Gruntfile.js index 554fd6681d51..c2ebb469ab25 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -78,7 +78,7 @@ module.exports = function (grunt) { init: true, config: config, loadGruntTasks: { - pattern: ['grunt-*', '@*/grunt-*', 'gruntify-*', '@*/gruntify-*'] + pattern: ['grunt-*', '@*/grunt-*', 'gruntify-*', '@*/gruntify-*', 'intern'] } }); diff --git a/package.json b/package.json index 8499c678a40f..24bf246c08fe 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,9 @@ "test:dev": "grunt test:dev", "test:quick": "grunt test:quick", "test:browser": "grunt test:browser", + "test:ui": "grunt test:ui", + "test:ui:server": "grunt test:ui:server", + "test:ui:runner": "grunt test:ui:runner", "test:server": "grunt test:server", "test:coverage": "grunt test:coverage", "build": "grunt build", @@ -140,12 +143,13 @@ "grunt-contrib-copy": "0.8.1", "grunt-esvm": "1.1.8", "grunt-karma": "0.12.0", - "grunt-run": "0.4.0", + "grunt-run": "0.5.0", "grunt-s3": "0.2.0-alpha.3", "grunt-simple-mocha": "0.4.0", "gruntify-eslint": "1.0.1", "html-entities": "1.1.3", "husky": "0.8.1", + "intern": "3.0.1", "istanbul-instrumenter-loader": "0.1.3", "karma": "0.13.9", "karma-chrome-launcher": "0.2.0", diff --git a/tasks/config/downloadSelenium.js b/tasks/config/downloadSelenium.js new file mode 100644 index 000000000000..c70610b1e553 --- /dev/null +++ b/tasks/config/downloadSelenium.js @@ -0,0 +1,15 @@ +var path = require('path'); + + +module.exports = function (grunt) { + return { + options: { + selenium: { + filename: 'selenium-server-standalone-2.47.1.jar', + server: 'https://selenium-release.storage.googleapis.com/2.47/', + md5: 'e6cb10b8f0f353c6ca4a8f62fb5cb472', + directory: path.join(grunt.config.get('root'), 'selenium') + } + } + }; +}; diff --git a/tasks/config/esvm.js b/tasks/config/esvm.js index 597270ee2bb1..f9811b860d3c 100644 --- a/tasks/config/esvm.js +++ b/tasks/config/esvm.js @@ -36,6 +36,17 @@ module.exports = function (grunt) { directory: resolve(directory, 'test'), purge: true } + }, + ui: { + options: { + directory: resolve(directory, 'test'), + purge: true, + config: { + http: { + port: 9220 + } + } + } } }; }; diff --git a/tasks/config/intern.js b/tasks/config/intern.js new file mode 100644 index 000000000000..d1a698b6b959 --- /dev/null +++ b/tasks/config/intern.js @@ -0,0 +1,13 @@ +var path = require('path'); + + +module.exports = function (grunt) { + return { + options: { + runType: 'runner', + config: 'test/intern', + reporters: ['Console'] + }, + dev: {} + }; +}; diff --git a/tasks/config/loadFixtures.js b/tasks/config/loadFixtures.js new file mode 100644 index 000000000000..15eebbdfc43b --- /dev/null +++ b/tasks/config/loadFixtures.js @@ -0,0 +1,11 @@ +var path = require('path'); + + +module.exports = function (grunt) { + return { + options: { + server: 'http://localhost:9220', + dataDir: path.join(grunt.config.get('root'), 'test/fixtures') + } + }; +}; diff --git a/tasks/config/run.js b/tasks/config/run.js index 954fdbc5f37e..af3cdfa736aa 100644 --- a/tasks/config/run.js +++ b/tasks/config/run.js @@ -22,6 +22,21 @@ module.exports = function (grunt) { ] }, + testUIServer: { + options: { + wait: false, + ready: /Server running/, + quiet: false, + failOnError: false + }, + cmd: /^win/.test(platform) ? '.\\bin\\kibana.bat' : './bin/kibana', + args: [ + '--server.port=5620', + '--elasticsearch.url=http://localhost:9220', + '--logging.json=false' + ] + }, + testCoverageServer: { options: { wait: false, @@ -60,6 +75,34 @@ module.exports = function (grunt) { ] }, + seleniumServer: { + options: { + wait: false, + ready: /Selenium Server is up and running/, + quiet: true, + failOnError: false + }, + cmd: 'java', + args: [ + '-jar', + 'selenium/selenium-server-standalone-2.47.1.jar' + ] + }, + + devSeleniumServer: { + options: { + wait: false, + ready: /Selenium Server is up and running/, + quiet: false, + failOnError: false + }, + cmd: 'java', + args: [ + '-jar', + 'selenium/selenium-server-standalone-2.47.1.jar' + ] + }, + optimizeBuild: { options: { wait: false, diff --git a/tasks/downloadSelenium.js b/tasks/downloadSelenium.js new file mode 100644 index 000000000000..62840493ee2a --- /dev/null +++ b/tasks/downloadSelenium.js @@ -0,0 +1,60 @@ +var _ = require('lodash'); +var request = require('request'); +var fs = require('fs'); +var path = require('path'); +var colors = require('ansicolors'); +var crypto = require('crypto'); +var {spawn} = require('child_process'); + +module.exports = function (grunt) { + grunt.registerTask('downloadSelenium', 'Download selenium standalone', function (keepalive) { + const done = this.async(); + const config = this.options(); + + const SELENIUM_FILE_PATH = path.join(config.selenium.directory, config.selenium.filename); + const SELENIUM_DOWNLOAD_URL = config.selenium.server + config.selenium.filename; + + function validateDownload(path, expectedHash, success) { + grunt.log.write('Validating hash...'); + fs.readFile(path, function checkHash(err, data) { + if (err) grunt.fail.warn(err); + + const calculatedHash = crypto.createHash('md5').update(data).digest('hex'); + if (calculatedHash !== expectedHash) return grunt.fail.warn('Selenium download has an invalid hash'); + + grunt.log.writeln('done'); + success(); + }); + } + + function downloadSelenium(success) { + grunt.log.write(`Downloading ${SELENIUM_DOWNLOAD_URL}...`); + request.get(SELENIUM_DOWNLOAD_URL) + .pipe(fs.createWriteStream(SELENIUM_FILE_PATH)) + .on('error', function downloadError(err) { + grunt.fail.warn(err); + }) + .on('finish', function downloadFinish() { + grunt.log.writeln('done'); + validateDownload(SELENIUM_FILE_PATH, config.selenium.md5, success); + }); + } + + function start() { + try { + fs.mkdirSync(config.selenium.directory); + } catch (err) { + if (err && err.code !== 'EEXIST') grunt.fail.warn(err); + } + + if (fs.existsSync(SELENIUM_FILE_PATH)) { + validateDownload(SELENIUM_FILE_PATH, config.selenium.md5, done); + } else { + downloadSelenium(done); + } + } + + start(); + + }); +}; diff --git a/tasks/loadFixtures.js b/tasks/loadFixtures.js new file mode 100644 index 000000000000..b92ba4cf82f0 --- /dev/null +++ b/tasks/loadFixtures.js @@ -0,0 +1,31 @@ +var _ = require('lodash'); +var wreck = require('wreck'); +var fs = require('fs'); +var path = require('path'); +var colors = require('ansicolors'); + +module.exports = function (grunt) { + grunt.registerTask('loadFixtures', 'Loads fixtures into elasticsearch', function () { + const config = this.options(); + const done = this.async(); + const files = fs.readdirSync(config.dataDir); + let doneProcessing = 0; + + files.forEach(function (file) { + wreck.post(`${config.server}/_bulk`, { + payload: fs.createReadStream(path.join(config.dataDir, file)), + json: true + }, function bulkResponse(err, res, payload) { + var status; + if (err || res.statusCode !== 200) { + grunt.fail.warn(err || payload); + status = colors.red('error'); + } else { + status = colors.green('success'); + } + grunt.log.writeln(`[${status}] ${file}`); + if (++doneProcessing === files.length) done(); + }); + }); + }); +}; diff --git a/tasks/test.js b/tasks/test.js index c0672ba64826..18b466834781 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -6,6 +6,7 @@ module.exports = function (grunt) { grunt.registerTask('test:quick', [ 'test:server', + 'test:ui', 'test:browser' ]); @@ -14,6 +15,30 @@ module.exports = function (grunt) { 'karma:dev' ]); + grunt.registerTask('test:ui', [ + 'esvm:ui', + 'loadFixtures', + 'run:testUIServer', + 'downloadSelenium', + 'run:seleniumServer', + 'intern:dev', + 'esvm_shutdown:ui', + 'stop:seleniumServer', + 'stop:testUIServer' + ]); + + grunt.registerTask('test:ui:server', [ + 'esvm:ui', + 'loadFixtures', + 'run:testUIServer', + 'downloadSelenium', + 'run:devSeleniumServer:keepalive' + ]); + + grunt.registerTask('test:ui:runner', [ + 'intern:dev' + ]); + grunt.registerTask('test', function (subTask) { if (subTask) grunt.fail.fatal(`invalid task "test:${subTask}"`); diff --git a/test/fixtures/test.json b/test/fixtures/test.json new file mode 100644 index 000000000000..134d798a687a --- /dev/null +++ b/test/fixtures/test.json @@ -0,0 +1,6 @@ +{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } } +{ "field1" : "value1" } +{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "2" } } +{ "field1" : "value2" } +{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "3" } } +{ "field1" : "value3" } diff --git a/test/functional/status.js b/test/functional/status.js new file mode 100644 index 000000000000..514de74c0676 --- /dev/null +++ b/test/functional/status.js @@ -0,0 +1,21 @@ +define(function (require) { + var registerSuite = require('intern!object'); + var expect = require('intern/dojo/node!expect.js'); + + registerSuite(function () { + var url = 'http://localhost:5620/status'; + return { + 'status': function () { + return this.remote + .get(url) + .refresh() + .setFindTimeout(60000) + .findByCssSelector('.plugin_status_breakdown') + .getVisibleText() + .then(function (text) { + expect(text.indexOf('plugin:kibana Ready')).to.be.above(-1); + }); + } + }; + }); +}); diff --git a/test/intern.js b/test/intern.js new file mode 100644 index 000000000000..371c758cd152 --- /dev/null +++ b/test/intern.js @@ -0,0 +1,17 @@ +define({ + capabilities: { + 'selenium-version': '2.47.1', + 'idle-timeout': 30 + }, + environments: [ + { + browserName: 'firefox' + } + ], + webdriver: { + host: 'localhost', + port: 4444 + }, + functionalSuites: ['test/functional/status.js'], + excludeInstrumentation: /^(?:tests|node_modules)\// +});