Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] [functionalTestRunner] replace intern (#10910) #11171

Merged
merged 4 commits into from
Apr 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 2 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,7 @@ npm run test:ui:runner

##### Browser Automation Notes

- Using Page Objects pattern (https://theintern.github.io/intern/#writing-functional-test)
- At least the initial tests for the Settings, Discover, and Visualize tabs all depend on a very specific set of logstash-type data (generated with makelogs). Since that is a static set of data, all the Discover and Visualize tests use a specific Absolute time range. This guarantees the same results each run.
- These tests have been developed and tested with Chrome and Firefox browser. In theory, they should work on all browsers (that's the benefit of Intern using Leadfoot).
- These tests should also work with an external testing service like https://saucelabs.com/ or https://www.browserstack.com/ but that has not been tested.
- https://theintern.github.io/
- https://theintern.github.io/leadfoot/module-leadfoot_Element.html
[Read about the `FunctionalTestRunner`](https://www.elastic.co/guide/en/kibana/current/development-functional-tests.html) to learn more about how you can run and develop functional tests for Kibana core and plugins.

### Building OS packages

Expand Down Expand Up @@ -374,4 +369,4 @@ Remember, someone is blocked by a pull awaiting review, make it count. Be thorou
1. **Hand it off** If you're the first reviewer and everything looks good but the changes are more than a few lines, hand the pull to someone else to take a second look. Again, try to find the right person to assign it to.
1. **Merge the code** When everything looks good, put in a `LGTM` (looks good to me) comment. Merge into the target branch. Check the labels on the pull to see if backporting is required, and perform the backport if so.

Thank you so much for reading our guidelines! :tada:
Thank you so much for reading our guidelines! :tada:
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module.exports = function (grunt) {
init: true,
config: config,
loadGruntTasks: {
pattern: ['grunt-*', '@*/grunt-*', 'gruntify-*', '@*/gruntify-*', 'intern']
pattern: ['grunt-*', '@*/grunt-*', 'gruntify-*', '@*/gruntify-*']
}
});

Expand Down
5 changes: 4 additions & 1 deletion docs/development/core-development.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
* <<development-dependencies>>
* <<development-modules>>
* <<development-elasticsearch>>
* <<development-functional-tests>>

include::core/development-basepath.asciidoc[]

include::core/development-dependencies.asciidoc[]

include::core/development-modules.asciidoc[]

include::plugin/development-elasticsearch.asciidoc[]
include::core/development-elasticsearch.asciidoc[]

include::core/development-functional-tests.asciidoc[]
383 changes: 383 additions & 0 deletions docs/development/core/development-functional-tests.asciidoc

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions docs/development/plugin-development.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ The Kibana plugin interfaces are in a state of constant development. We cannot

* <<development-plugin-resources>>
* <<development-uiexports>>
* <<development-plugin-functional-tests>>


include::plugin/development-plugin-resources.asciidoc[]

include::plugin/development-uiexports.asciidoc[]

include::plugin/development-plugin-functional-tests.asciidoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
[[development-plugin-functional-tests]]
=== Functional Tests for Plugins

Plugins use the `FunctionalTestRunner` by running it out of the Kibana repo. Ensure that your Kibana Development Environment is setup properly before continuing.

[float]
==== Writing your own configuration

Every project or plugin should have its own `FunctionalTestRunner` config file. Just like Kibana's, this config file will define all of the test files to load, providers for Services and PageObjects, as well as configuration options for certain services.

To get started copy and paste this example to `test/functional/config.js`:

["source","js"]
-----------
import { resolve } from 'path';
import { MyServiceProvider } from './services/my_service';
import { MyAppPageProvider } from './services/my_app_page;

// allow overriding the default kibana directory
// using the KIBANA_DIR environment variable
const KIBANA_CONFIG_PATH = resolve(process.env.KIBANA_DIR || '../kibana', 'test/functional/config.js');

// the default export of config files must be a config provider
// that returns an object with the projects config values
export default async function ({ readConfigFile }) {

// read the Kibana config file so that we can utilize some of
// its services and PageObjects
const kibanaConfig = await readConfigFile(KIBANA_CONFIG_PATH);

return {
// list paths to the files that contain your plugins tests
testFiles: [
resolve(__dirname, './my_test_file.js'),
],

// define the name and providers for services that should be
// available to your tests. If you don't specify anything here
// only the built-in services will be avaliable
services: {
...kibanaConfig.get('services'),
myService: MyServiceProvider,
},

// just like services, PageObjects are defined as a map of
// names to Providers. Merge in Kibana's or pick specific ones
pageObjects: {
management: kibanaConfig.get('pageObjects.management'),
myApp: MyAppPageProvider,
},

// the apps section defines the urls that
// `PageObjects.common.navigateTo(appKey)` will use.
// Merge urls for your plugin with the urls defined in
// Kibana's config in order to use this helper
apps: {
...kibanaConfig.get('apps'),
myApp: {
pathname: '/app/my_app',
}
},

// choose where esArchiver should load archives from
esArchiver: {
directory: resolve(__dirname, './es_archives'),
},

// choose where screenshots should be saved
screenshots: {
directory: resolve(__dirname, './tmp/screenshots'),
}

// more settings, like timeouts, mochaOpts, etc are
// defined in the config schema. See {blob}src/functional_test_runner/lib/config/schema.js[src/functional_test_runner/lib/config/schema.js]
};
}

-----------

From the root of your repo you should now be able to run the `FunctionalTestRunner` script from your plugin project.

["source","shell"]
-----------
node ../kibana/scripts/functional_test_runner
-----------

[float]
==== Using esArchiver

We're working on documentation for this, but for now the best place to look is the original {pull}10359[pull request].

1 change: 1 addition & 0 deletions docs/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ release-state can be: released | prerelease | unreleased
:issue: {repo}issues/
:pull: {repo}pull/
:commit: {repo}commit/
:blob: {repo}blob/{branch}/
:security: https://www.elastic.co/community/security/


Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@
"expose-loader": "0.7.0",
"extract-text-webpack-plugin": "0.8.2",
"file-loader": "0.8.4",
"font-awesome": "4.4.0",
"flot-charts": "0.8.3",
"font-awesome": "4.4.0",
"glob": "5.0.13",
"glob-all": "3.0.1",
"good-squeeze": "2.1.0",
Expand Down Expand Up @@ -206,12 +206,12 @@
"auto-release-sinon": "1.0.3",
"babel-eslint": "6.1.2",
"chai": "3.5.0",
"chance": "1.0.6",
"cheerio": "0.22.0",
"chokidar": "1.6.0",
"chromedriver": "2.24.1",
"chromedriver": "2.28.0",
"classnames": "2.2.5",
"del": "1.2.1",
"elasticdump": "2.1.1",
"digdug": "1.6.3",
"enzyme": "2.7.0",
"enzyme-to-json": "1.4.5",
"eslint": "3.11.1",
Expand Down Expand Up @@ -240,7 +240,6 @@
"html-loader": "0.4.3",
"husky": "0.8.1",
"image-diff": "1.6.0",
"intern": "3.2.3",
"istanbul-instrumenter-loader": "0.1.3",
"jest": "19.0.0",
"jest-cli": "19.0.0",
Expand All @@ -253,6 +252,7 @@
"karma-mocha": "0.2.0",
"karma-safari-launcher": "0.1.1",
"keymirror": "0.1.1",
"leadfoot": "1.7.1",
"license-checker": "5.1.2",
"load-grunt-config": "0.19.2",
"makelogs": "3.2.3",
Expand Down
16 changes: 16 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# kibana dev scripts

This directory contains scripts useful for interacting with Kibana tools in development. Use the node executable and `--help` flag to learn about how they work:

```sh
node scripts/{{script name}} --help
```

## for developers

This directory is excluded from the build and tools within it should help users discover their capabilities. Each script in this directory must:

- include the `../src/optimize/babel/register` module to bootstrap babel
- call out to source code that is in the `src` directory
- react to the `--help` flag
- run everywhere OR check and fail fast when a required OS or toolchain is not available
2 changes: 2 additions & 0 deletions scripts/es_archiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require('../src/optimize/babel/register');
require('../src/es_archiver/cli');
2 changes: 2 additions & 0 deletions scripts/functional_test_runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require('../src/optimize/babel/register');
require('../src/functional_test_runner/cli');
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
</div>
</kbn-top-nav>

<div class="kuiViewContent kuiViewContent--constrainedWidth">
<div
class="kuiViewContent kuiViewContent--constrainedWidth"
data-test-subj="dashboardLandingPage"
>
<!-- ControlledTable -->
<div class="kuiViewContentItem kuiControlledTable kuiVerticalRhythm">
<!-- ToolBar -->
Expand Down
2 changes: 1 addition & 1 deletion src/core_plugins/status_page/public/status_page.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="container overall_state_default overall_state_{{ui.serverState}}">
<div data-test-subj="statusPageContainer" class="container overall_state_default overall_state_{{ui.serverState}}">
<header>
<h1>
Status: <span class="overall_state_color">{{ ui.serverStateMessage }}</span>
Expand Down
4 changes: 4 additions & 0 deletions src/es_archiver/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { saveAction } from './save';
export { loadAction } from './load';
export { unloadAction } from './unload';
export { rebuildAllAction } from './rebuild_all';
39 changes: 39 additions & 0 deletions src/es_archiver/actions/load.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { resolve } from 'path';
import { createReadStream } from 'fs';

import {
createPromiseFromStreams
} from '../../utils';

import {
isGzip,
createStats,
prioritizeMappings,
readDirectory,
createParseArchiveStreams,
createCreateIndexStream,
createIndexDocRecordsStream,
} from '../lib';

export async function loadAction({ name, skipExisting, client, dataDir, log }) {
const inputDir = resolve(dataDir, name);
const stats = createStats(name, log);

const files = prioritizeMappings(await readDirectory(inputDir));
for (const filename of files) {
log.info('[%s] Loading %j', name, filename);

await createPromiseFromStreams([
createReadStream(resolve(inputDir, filename)),
...createParseArchiveStreams({ gzip: isGzip(filename) }),
createCreateIndexStream({ client, stats, skipExisting }),
createIndexDocRecordsStream(client, stats),
]);
}

stats.forEachIndex((index, { docs }) => {
log.info('[%s] Indexed %d docs into %j', name, docs.indexed, index);
});

return stats.toJSON();
}
46 changes: 46 additions & 0 deletions src/es_archiver/actions/rebuild_all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { resolve } from 'path';
import {
rename,
createReadStream,
createWriteStream
} from 'fs';

import { fromNode } from 'bluebird';

import {
createPromiseFromStreams
} from '../../utils';

import {
prioritizeMappings,
readDirectory,
isGzip,
createParseArchiveStreams,
createFormatArchiveStreams,
} from '../lib';

export async function rebuildAllAction({ dataDir, log }) {
const archiveNames = await readDirectory(dataDir);

for (const name of archiveNames) {
const inputDir = resolve(dataDir, name);
const files = prioritizeMappings(await readDirectory(inputDir));
for (const filename of files) {
log.info('[%s] Rebuilding %j', name, filename);

const path = resolve(inputDir, filename);
const gzip = isGzip(path);
const tempFile = path + (gzip ? '.rebuilding.gz' : '.rebuilding');

await createPromiseFromStreams([
createReadStream(path),
...createParseArchiveStreams({ gzip }),
...createFormatArchiveStreams({ gzip }),
createWriteStream(tempFile),
]);

await fromNode(cb => rename(tempFile, path, cb));
log.info('[%s] Rebuilt %j', name, filename);
}
}
}
55 changes: 55 additions & 0 deletions src/es_archiver/actions/save.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { resolve } from 'path';
import { createWriteStream } from 'fs';

import { fromNode } from 'bluebird';
import mkdirp from 'mkdirp';

import {
createListStream,
createPromiseFromStreams,
} from '../../utils';

import {
createStats,
createGenerateIndexRecordsStream,
createFormatArchiveStreams,
createGenerateDocRecordsStream,
} from '../lib';

export async function saveAction({ name, indices, client, dataDir, log }) {
const outputDir = resolve(dataDir, name);
const stats = createStats(name, log);

log.info('[%s] Creating archive of %j', name, indices);

await fromNode(cb => mkdirp(outputDir, cb));
const resolvedIndexes = Object.keys(await client.indices.get({
index: indices,
feature: ['_settings'],
filterPath: ['*.settings.index.uuid']
}));

await Promise.all([
// export and save the matching indices to mappings.json
createPromiseFromStreams([
createListStream(resolvedIndexes),
createGenerateIndexRecordsStream(client, stats),
...createFormatArchiveStreams(),
createWriteStream(resolve(outputDir, 'mappings.json')),
]),

// export all documents from matching indexes into data.json.gz
createPromiseFromStreams([
createListStream(resolvedIndexes),
createGenerateDocRecordsStream(client, stats),
...createFormatArchiveStreams({ gzip: true }),
createWriteStream(resolve(outputDir, 'data.json.gz'))
])
]);

stats.forEachIndex((index, { docs }) => {
log.info('[%s] Archived %d docs from %j', name, docs.archived, index);
});

return stats.toJSON();
}