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

[Snapshot restore] Add support for feature_states #131310

Merged
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
837cb19
Update copy to not include system indices
sabarasaba Apr 28, 2022
5de8d29
Dont include system indices in ds/indices dropdown
sabarasaba Apr 28, 2022
236f978
Start working on supporting feature states
sabarasaba Apr 28, 2022
a3bda45
Store feature states array of options in local state
sabarasaba May 2, 2022
8a6473c
Fix up server side integration and show deets in flyout
sabarasaba May 2, 2022
181d500
Fix linter issues
sabarasaba May 2, 2022
cb899ef
commit using @elastic.co
sabarasaba May 2, 2022
8e16971
Connect the dots in restore snapshot wizard
sabarasaba May 2, 2022
0080dcd
Fix linter issues
sabarasaba May 2, 2022
469a53c
Finish up wiring up last features
sabarasaba May 2, 2022
5e5ada2
Fix copy
sabarasaba May 2, 2022
b8a7dd9
CR
sabarasaba May 2, 2022
3d4c2ca
Refactor tooltip implementation
sabarasaba May 2, 2022
13c83ef
Fix tests
sabarasaba May 2, 2022
1595fa7
Fix i18n
sabarasaba May 2, 2022
7711a1c
Add tests
sabarasaba May 3, 2022
d6f0a7d
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine May 3, 2022
e0b2f84
Add missing tests
sabarasaba May 4, 2022
e845207
Merge branch 'main' into snapshot_restore/system_indices_fix
kibanamachine May 4, 2022
ec9d815
Add option for selecting none of the feature states
sabarasaba May 5, 2022
d750fee
Finish off refactoring label placement and fixing up tests
sabarasaba May 5, 2022
79f5736
Add tests
sabarasaba May 6, 2022
433b30b
Remove nextTick and refactor tests
sabarasaba May 9, 2022
dbebbfc
Refactor feature states into its own setting
sabarasaba May 9, 2022
5cea032
Fix docs link
sabarasaba May 9, 2022
38fe3d1
Copy review
sabarasaba May 9, 2022
fa8c67b
Fix tests
sabarasaba May 10, 2022
3aad8f3
Fix small bug and add more tests
sabarasaba May 10, 2022
d8f782f
Merge branch 'main' into snapshot_restore/system_indices_fix
kibanamachine May 10, 2022
8f16d3b
Fix linter issue
sabarasaba May 10, 2022
1c514ee
Address CR
sabarasaba May 10, 2022
63c69e6
Change duped locale id
sabarasaba May 10, 2022
5b3dc19
Address CR changes
sabarasaba May 10, 2022
1413dd6
Copy updates
sabarasaba May 12, 2022
fef1131
Merge branch 'main' into snapshot_restore/system_indices_fix
kibanamachine May 12, 2022
eca5016
CR changes
sabarasaba May 16, 2022
9124877
Merge branch 'main' into snapshot_restore/system_indices_fix
kibanamachine May 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ export const POLICY_NAME = 'my-test-policy';

export const SNAPSHOT_NAME = 'my-test-snapshot';

export const POLICY_EDIT = getPolicy({ name: POLICY_NAME, retention: { minCount: 1 } });
export const POLICY_EDIT = getPolicy({
name: POLICY_NAME,
retention: { minCount: 1 },
config: { includeGlobalState: true, featureStates: ['kibana'] },
});
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ const registerHttpRequestMockHelpers = (
error?: ResponseError
) => mockResponse('GET', `${API_BASE_PATH}policies/indices`, response, error);

const setLoadPoliciesResponse = (
response: HttpResponse = { indices: [] },
error?: ResponseError
) => mockResponse('GET', `${API_BASE_PATH}policies`, response, error);

const setAddPolicyResponse = (response?: HttpResponse, error?: ResponseError) =>
mockResponse('POST', `${API_BASE_PATH}policies`, response, error);

Expand Down Expand Up @@ -119,6 +124,9 @@ const registerHttpRequestMockHelpers = (
error
);

const setLoadFeaturesResponse = (response: HttpResponse = [], error?: ResponseError) =>
mockResponse('GET', `${API_BASE_PATH}policies/features`, response, error);

return {
setLoadRepositoriesResponse,
setLoadRepositoryTypesResponse,
Expand All @@ -131,6 +139,8 @@ const registerHttpRequestMockHelpers = (
setGetPolicyResponse,
setCleanupRepositoryResponse,
setRestoreSnapshotResponse,
setLoadFeaturesResponse,
setLoadPoliciesResponse,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export const formSetup = async (
export type PolicyFormTestSubjects =
| 'advancedCronInput'
| 'allIndicesToggle'
| 'globalStateToggle'
| 'featureStatesDropdown'
| 'backButton'
| 'deselectIndicesLink'
| 'allDataStreamsToggle'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { act } from 'react-dom/test-utils';
import {
registerTestBed,
AsyncTestBedConfig,
TestBed,
findTestSubject,
} from '@kbn/test-jest-helpers';
import { HttpSetup } from '@kbn/core/public';
import { PolicyList } from '../../../public/application/sections/home/policy_list';
import { WithAppDependencies } from './setup_environment';

const testBedConfig: AsyncTestBedConfig = {
memoryRouter: {
initialEntries: ['/policies'],
componentRoutePath: '/policies/:policyName?',
},
doMountAsync: true,
};

const createActions = (testBed: TestBed) => {
const clickPolicyAt = async (index: number) => {
const { component, table, router } = testBed;
const { rows } = table.getMetaData('policyTable');
const repositoryLink = findTestSubject(rows[index].reactWrapper, 'policyLink');

await act(async () => {
const { href } = repositoryLink.props();
router.navigateTo(href!);
});

component.update();
};

return {
clickPolicyAt,
};
};

export type PoliciesListTestBed = TestBed & {
actions: ReturnType<typeof createActions>;
};

export const setupPoliciesListPage = async (httpSetup: HttpSetup) => {
const initTestBed = registerTestBed(WithAppDependencies(PolicyList, httpSetup), testBedConfig);

const testBed = await initTestBed();

return {
...testBed,
actions: createActions(testBed),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import React from 'react';
import { i18n } from '@kbn/i18n';
import { merge } from 'lodash';
import { LocationDescriptorObject } from 'history';

import { HttpSetup } from '@kbn/core/public';
Expand All @@ -16,16 +17,30 @@ import {
breadcrumbService,
docTitleService,
} from '../../../public/application/services/navigation';
import {
AuthorizationContext,
Authorization,
Privileges,
GlobalFlyout,
} from '../../../public/shared_imports';
import { AppContextProvider } from '../../../public/application/app_context';
import { textService } from '../../../public/application/services/text';
import { init as initHttpRequests } from './http_requests';
import { UiMetricService } from '../../../public/application/services';

const { GlobalFlyoutProvider } = GlobalFlyout;
const history = scopedHistoryMock.create();
history.createHref.mockImplementation((location: LocationDescriptorObject) => {
return `${location.pathname}?${location.search}`;
});

const createAuthorizationContextValue = (privileges: Privileges) => {
return {
isLoading: false,
privileges: privileges ?? { hasAllPrivileges: false, missingPrivileges: {} },
} as Authorization;
};

export const services = {
uiMetricService: new UiMetricService('snapshot_restore'),
httpService,
Expand Down Expand Up @@ -60,16 +75,24 @@ export const setupEnvironment = () => {
this.terminate = () => {};
};

export const WithAppDependencies = (Comp: any, httpSetup?: HttpSetup) => (props: any) => {
// We need to optionally setup the httpService since some cit helpers (such as snapshot_list.helpers)
// use jest mocks to stub the fetch hooks instead of mocking api responses.
if (httpSetup) {
httpService.setup(httpSetup);
}
export const WithAppDependencies =
(Comp: any, httpSetup?: HttpSetup, { privileges, ...overrides }: Record<string, unknown> = {}) =>
(props: any) => {
// We need to optionally setup the httpService since some cit helpers (such as snapshot_list.helpers)
// use jest mocks to stub the fetch hooks instead of mocking api responses.
if (httpSetup) {
httpService.setup(httpSetup);
}

return (
<AppContextProvider value={appDependencies as any}>
<Comp {...props} />
</AppContextProvider>
);
};
return (
<AuthorizationContext.Provider
value={createAuthorizationContextValue(privileges as Privileges)}
>
<AppContextProvider value={merge(appDependencies, overrides) as any}>
<GlobalFlyoutProvider>
<Comp {...props} />
</GlobalFlyoutProvider>
</AppContextProvider>
</AuthorizationContext.Provider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -497,10 +497,12 @@ describe('<SnapshotRestoreHome />', () => {
const snapshot1 = fixtures.getSnapshot({
repository: REPOSITORY_NAME,
snapshot: `a${getRandomString()}`,
featureStates: ['kibana'],
});
const snapshot2 = fixtures.getSnapshot({
repository: REPOSITORY_NAME,
snapshot: `b${getRandomString()}`,
includeGlobalState: 0,
});
const snapshots = [snapshot1, snapshot2];

Expand Down Expand Up @@ -709,6 +711,29 @@ describe('<SnapshotRestoreHome />', () => {
expect(exists('snapshotDetail')).toBe(false);
});

test('should show feature states if include global state is enabled', async () => {
const { find, exists } = testBed;

// Assert against first snapshot shown in the table, which should have includeGlobalState enabled
expect(exists('featureStates')).toBe(true);
expect(find('featureStates.value').text()).toBe('kibana');

// Close the flyout
find('snapshotDetail.closeButton').simulate('click');

// Replace the get snapshot details api call with the payload of the second snapshot which we're about to click
httpRequestsMockHelpers.setGetSnapshotResponse(
snapshot2.repository,
snapshot2.snapshot,
snapshot2
);

// Now we will assert against the second result of the table which shouldnt have includeGlobalState
await testBed.actions.clickSnapshotAt(1);

expect(exists('featureStates')).toBe(false);
});

describe('tabs', () => {
test('should have 2 tabs', () => {
const { find } = testBed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ describe('<PolicyAdd />', () => {
indices: ['my_index'],
dataStreams: ['my_data_stream', 'my_other_data_stream'],
});
httpRequestsMockHelpers.setLoadFeaturesResponse({
features: [{ name: 'kibana' }, { name: 'tasks' }],
});

testBed = await setup(httpSetup);
await nextTick();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for cleaning this up!

Expand Down Expand Up @@ -161,6 +164,25 @@ describe('<PolicyAdd />', () => {

expect(find('dataStreamBadge').length).toBe(2);
});

describe('feature states', () => {
test('feature states dropdown is only shown when include global state is enabled', async () => {
const { exists, component, form } = testBed;

// By default the toggle is enabled
expect(exists('featureStatesDropdown')).toBe(true);

await act(async () => {
// Toggle "All indices" switch
form.toggleEuiSwitch('globalStateToggle');
await nextTick();
});
component.update();

// But after we toggle off the include global state it should be hidden
expect(exists('featureStatesDropdown')).toBe(false);
});
});
});

describe('retention (step 3)', () => {
Expand Down Expand Up @@ -212,14 +234,20 @@ describe('<PolicyAdd />', () => {

describe('form payload & api errors', () => {
beforeEach(async () => {
const { actions, form } = testBed;
const { actions, form, component } = testBed;

// Complete step 1
form.setInputValue('nameInput', POLICY_NAME);
form.setInputValue('snapshotNameInput', SNAPSHOT_NAME);
actions.clickNextButton();

// Complete step 2
await act(async () => {
await nextTick();
sabarasaba marked this conversation as resolved.
Show resolved Hide resolved
});
component.update();

form.setComboBoxValue('featureStatesDropdown', 'kibana');
actions.clickNextButton();

// Complete step 3
Expand All @@ -245,7 +273,10 @@ describe('<PolicyAdd />', () => {
snapshotName: SNAPSHOT_NAME,
schedule: DEFAULT_POLICY_SCHEDULE,
repository: repository.name,
config: {},
config: {
includeGlobalState: true,
featureStates: ['kibana'],
},
retention: {
expireAfterValue: Number(EXPIRE_AFTER_VALUE),
expireAfterUnit: 'd', // default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ describe('<PolicyEdit />', () => {
httpRequestsMockHelpers.setLoadRepositoriesResponse({
repositories: [{ name: POLICY_EDIT.repository }],
});
httpRequestsMockHelpers.setLoadFeaturesResponse({
features: [{ name: 'kibana' }, { name: 'tasks' }],
});

testBed = await setup(httpSetup);

Expand Down Expand Up @@ -151,6 +154,8 @@ describe('<PolicyEdit />', () => {
schedule,
repository,
config: {
includeGlobalState: true,
featureStates: ['kibana'],
ignoreUnavailable: true,
},
retention: {
Expand Down Expand Up @@ -193,7 +198,10 @@ describe('<PolicyEdit />', () => {
snapshotName,
schedule,
repository,
config,
config: {
includeGlobalState: true,
...config,
},
retention: {
...retention,
expireAfterUnit: TIME_UNITS.DAY, // default value
Expand Down
Loading