Skip to content

Commit

Permalink
Merge branch 'master' into ml-feature-importance-functional-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Nov 16, 2020
2 parents 6549088 + 50efaec commit 1f04c2d
Show file tree
Hide file tree
Showing 84 changed files with 3,108 additions and 470 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ server.route({
=== Example 3: Discover

Discover takes advantage of subfeature privileges to allow fine-grained access control. In this example,
a single "Create Short URLs" subfeature privilege is defined, which allows users to grant access to this feature without having to grant the `all` privilege to Discover. In other words, you can grant `read` access to Discover, and also grant the ability to create short URLs.
two subfeature privileges are defined: "Create Short URLs", and "Generate PDF Reports". These allow users to grant access to this feature without having to grant the `all` privilege to Discover. In other words, you can grant `read` access to Discover, and also grant the ability to create short URLs or generate PDF reports.

Notice the "Generate PDF Reports" subfeature privilege has an additional `minimumPrivilege` option. Kibana will only offer this subfeature privilege if the
license requirement is satisfied.

["source","javascript"]
-----------
Expand Down Expand Up @@ -259,6 +262,28 @@ public setup(core, { features }) {
},
],
},
{
groupType: 'independent',
privileges: [
{
id: 'pdf_generate',
name: i18n.translate(
'xpack.features.ossFeatures.discoverGeneratePDFReportsPrivilegeName',
{
defaultMessage: 'Generate PDF Reports',
}
),
minimumLicense: 'platinum',
includeIn: 'all',
savedObject: {
all: [],
read: [],
},
api: ['generatePDFReports'],
ui: ['generatePDFReports'],
},
],
},
],
},
],
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/quick-start-guide.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ For more information, refer to <<lens, *Lens*>>.

If you are you ready to add your own data, refer to <<connect-to-elasticsearch,Add data to {kib}>>.

If you want to ingest your data, refer to {ingest-guide}/ingest-management-getting-started.html[Quick start: Get logs and metrics into the Elastic Stack].
If you want to ingest your data, refer to {ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack].
2 changes: 1 addition & 1 deletion docs/setup/connect-to-elasticsearch.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ship with dashboards and visualizations,
so you can quickly get insights into your data.

To get started, refer to
{ingest-guide}/ingest-management-getting-started.html[Quick start: Get logs and metrics into the Elastic Stack].
{ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack].

[role="screenshot"]
image::images/add-data-fleet.png[Add data using Fleet]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set_chmod() {

set_chown() {
chown <%= user %>:<%= group %> <%= logDir %>
chown <%= user %>:<%= group %> <%= pidDir %>
chown -R <%= user %>:<%= group %> <%= dataDir %>
chown -R root:<%= group %> ${KBN_PATH_CONF}
}
Expand Down
4 changes: 4 additions & 0 deletions src/dev/build/tasks/os_packages/run_fpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export async function runFpm(
'--template-value',
`logDir=/var/log/kibana`,
'--template-value',
`pidDir=/run/kibana`,
'--template-value',
`envFile=/etc/default/kibana`,
// config and data directories are copied to /usr/share and /var/lib
// below, so exclude them from the main package source located in
Expand All @@ -120,6 +122,8 @@ export async function runFpm(
`usr/share/kibana/config`,
'--exclude',
`usr/share/kibana/data`,
'--exclude',
'run/kibana/.gitempty',

// flags specific to the package we are building, supplied by tasks below
...pkgSpecificFlags,
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/

import { of, merge, timer, throwError } from 'rxjs';
import { takeWhile, switchMap, expand, mergeMap, tap } from 'rxjs/operators';
import { map, takeWhile, switchMap, expand, mergeMap, tap } from 'rxjs/operators';
import { ApiResponse } from '@elastic/elasticsearch';

import {
doSearch,
Expand Down Expand Up @@ -35,6 +36,15 @@ export const doPartialSearch = <SearchResponse = any>(
takeWhile((response) => !isCompleteResponse(response), true)
);

export const normalizeEqlResponse = <SearchResponse extends ApiResponse = ApiResponse>() =>
map<SearchResponse, SearchResponse>((eqlResponse) => ({
...eqlResponse,
body: {
...eqlResponse.body,
...eqlResponse,
},
}));

export const throwOnEsError = () =>
mergeMap((r: IKibanaSearchResponse) =>
isErrorResponse(r) ? merge(of(r), throwError(new AbortError())) : of(r)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const getMockEqlResponse = () => ({
sequences: [],
},
},
meta: {},
statusCode: 200,
});

describe('EQL search strategy', () => {
Expand Down Expand Up @@ -193,5 +195,20 @@ describe('EQL search strategy', () => {
expect(requestOptions).toEqual(expect.objectContaining({ ignore: [400] }));
});
});

describe('response', () => {
it('contains a rawResponse field containing the full search response', async () => {
const eqlSearch = await eqlSearchStrategyProvider(mockLogger);
const response = await eqlSearch
.search({ id: 'my-search-id', options: { ignore: [400] } }, {}, mockDeps)
.toPromise();

expect(response).toEqual(
expect.objectContaining({
rawResponse: expect.objectContaining(getMockEqlResponse()),
})
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import type { Logger } from 'kibana/server';
import type { ApiResponse } from '@elastic/elasticsearch';

import { search } from '../../../../../src/plugins/data/server';
import { doPartialSearch } from '../../common/search/es_search/es_search_rxjs_utils';
import {
doPartialSearch,
normalizeEqlResponse,
} from '../../common/search/es_search/es_search_rxjs_utils';
import { getAsyncOptions, getDefaultSearchParams } from './get_default_search_params';

import type { ISearchStrategy, IEsRawSearchResponse } from '../../../../../src/plugins/data/server';
Expand Down Expand Up @@ -64,7 +67,7 @@ export const eqlSearchStrategyProvider = (
(response) => response.body.id,
request.id,
options
).pipe(utils.toKibanaSearchResponse());
).pipe(normalizeEqlResponse(), utils.toKibanaSearchResponse());
},
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { resetContext } from 'kea';

import { mockHttpValues } from '../../../__mocks__';
jest.mock('../../../shared/http', () => ({
HttpLogic: { values: mockHttpValues },
}));
const { http } = mockHttpValues;

jest.mock('../../../shared/flash_messages', () => ({
flashAPIErrors: jest.fn(),
}));
import { flashAPIErrors } from '../../../shared/flash_messages';

jest.mock('../engine', () => ({
EngineLogic: { values: { engineName: 'some-engine' } },
}));

import { EngineOverviewLogic } from './';

describe('EngineOverviewLogic', () => {
const mockEngineMetrics = {
apiLogsUnavailable: true,
documentCount: 10,
startDate: '1970-01-30',
endDate: '1970-01-31',
operationsPerDay: [0, 0, 0, 0, 0, 0, 0],
queriesPerDay: [0, 0, 0, 0, 0, 25, 50],
totalClicks: 50,
totalQueries: 75,
};

const DEFAULT_VALUES = {
dataLoading: true,
apiLogsUnavailable: false,
documentCount: 0,
startDate: '',
endDate: '',
operationsPerDay: [],
queriesPerDay: [],
totalClicks: 0,
totalQueries: 0,
timeoutId: null,
};

const mount = () => {
resetContext({});
EngineOverviewLogic.mount();
};

beforeEach(() => {
jest.clearAllMocks();
});

it('has expected default values', () => {
mount();
expect(EngineOverviewLogic.values).toEqual(DEFAULT_VALUES);
});

describe('actions', () => {
describe('setPolledData', () => {
it('should set all received data as top-level values and set dataLoading to false', () => {
mount();
EngineOverviewLogic.actions.setPolledData(mockEngineMetrics);

expect(EngineOverviewLogic.values).toEqual({
...DEFAULT_VALUES,
...mockEngineMetrics,
dataLoading: false,
});
});
});

describe('setTimeoutId', () => {
describe('timeoutId', () => {
it('should be set to the provided value', () => {
mount();
EngineOverviewLogic.actions.setTimeoutId(123);

expect(EngineOverviewLogic.values).toEqual({
...DEFAULT_VALUES,
timeoutId: 123,
});
});
});
});

describe('pollForOverviewMetrics', () => {
it('fetches data and calls onPollingSuccess', async () => {
mount();
jest.spyOn(EngineOverviewLogic.actions, 'onPollingSuccess');
const promise = Promise.resolve(mockEngineMetrics);
http.get.mockReturnValueOnce(promise);

EngineOverviewLogic.actions.pollForOverviewMetrics();
await promise;

expect(http.get).toHaveBeenCalledWith('/api/app_search/engines/some-engine/overview');
expect(EngineOverviewLogic.actions.onPollingSuccess).toHaveBeenCalledWith(
mockEngineMetrics
);
});

it('handles errors', async () => {
mount();
const promise = Promise.reject('An error occurred');
http.get.mockReturnValue(promise);

try {
EngineOverviewLogic.actions.pollForOverviewMetrics();
await promise;
} catch {
// Do nothing
}
expect(flashAPIErrors).toHaveBeenCalledWith('An error occurred');
});
});

describe('onPollingSuccess', () => {
it('starts a polling timeout and sets data', async () => {
mount();
jest.useFakeTimers();
jest.spyOn(EngineOverviewLogic.actions, 'setTimeoutId');
jest.spyOn(EngineOverviewLogic.actions, 'setPolledData');

EngineOverviewLogic.actions.onPollingSuccess(mockEngineMetrics);

expect(setTimeout).toHaveBeenCalledWith(
EngineOverviewLogic.actions.pollForOverviewMetrics,
5000
);
expect(EngineOverviewLogic.actions.setTimeoutId).toHaveBeenCalledWith(expect.any(Number));
expect(EngineOverviewLogic.actions.setPolledData).toHaveBeenCalledWith(mockEngineMetrics);
});
});
});

describe('unmount', () => {
let unmount: Function;

beforeEach(() => {
jest.useFakeTimers();
resetContext({});
unmount = EngineOverviewLogic.mount();
});

it('clears existing polling timeouts on unmount', () => {
EngineOverviewLogic.actions.setTimeoutId(123);
unmount();
expect(clearTimeout).toHaveBeenCalled();
});

it("does not clear timeout if one hasn't been set", () => {
unmount();
expect(clearTimeout).not.toHaveBeenCalled();
});
});
});
Loading

0 comments on commit 1f04c2d

Please sign in to comment.