From 1e83ca331177598aa7a15b3cb2fb436e3b017dbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yulia=20=C4=8Cech?=
<6585477+yuliacech@users.noreply.github.com>
Date: Tue, 2 Mar 2021 15:28:12 +0100
Subject: [PATCH] [ILM] Refactor edit_policy client integration tests into
separate feature files (#92826)
* Refactor edit_policy client integration tests into separate feature files
* Fixed merge conflicts with master
* Updated rollover tests to match master branch code
* Split reactive_form into smaller files
* Renamed flyout tests file
---
.../edit_policy/constants.ts | 21 +-
.../edit_policy/edit_policy.helpers.tsx | 9 -
.../edit_policy/edit_policy.test.ts | 1136 -----------------
.../edit_policy/features/cold_phase.test.ts | 52 +
.../edit_policy/features/delete_phase.test.ts | 169 +++
.../node_allocation.test.ts | 138 +-
.../features/request_flyout.test.ts | 66 +
.../edit_policy/features/rollover.test.ts | 108 ++
.../features/searchable_snapshots.test.ts | 163 +++
.../edit_policy/features/timeline.test.ts | 64 +
.../edit_policy/features/warm_phase.test.ts | 52 +
.../form_validation/error_indicators.test.ts | 159 +++
.../reactive_form/reactive_form.test.ts | 143 ---
.../policy_serialization.test.ts | 426 +++++++
14 files changed, 1373 insertions(+), 1333 deletions(-)
delete mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts
rename x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/{reactive_form => features}/node_allocation.test.ts (78%)
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts
delete mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
index 2c8fbfc749a82..e47036b82e594 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
@@ -13,26 +13,6 @@ export const POLICY_NAME = 'my_policy';
export const SNAPSHOT_POLICY_NAME = 'my_snapshot_policy';
export const NEW_SNAPSHOT_POLICY_NAME = 'my_new_snapshot_policy';
-export const DEFAULT_POLICY: PolicyFromES = {
- version: 1,
- modified_date: Date.now().toString(),
- policy: {
- name: 'my_policy',
- phases: {
- hot: {
- min_age: '0ms',
- actions: {
- rollover: {
- max_age: '30d',
- max_size: '50gb',
- },
- },
- },
- },
- },
- name: 'my_policy',
-};
-
export const POLICY_WITH_MIGRATE_OFF: PolicyFromES = {
version: 1,
modified_date: Date.now().toString(),
@@ -191,6 +171,7 @@ export const POLICY_WITH_NODE_ROLE_ALLOCATION: PolicyFromES = {
},
},
warm: {
+ min_age: '0ms',
actions: {},
},
},
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
index c61b431eed46d..b692d7fe69cd4 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
@@ -183,13 +183,6 @@ export const setup = async (arg?: {
const enable = (phase: Phases) => createFormToggleAction(`enablePhaseSwitch-${phase}`);
- const showDataAllocationOptions = (phase: Phases) => () => {
- act(() => {
- find(`${phase}-dataTierAllocationControls.dataTierSelect`).simulate('click');
- });
- component.update();
- };
-
const createMinAgeActions = (phase: Phases) => {
return {
hasMinAgeInput: () => exists(`${phase}-selectedMinimumAge`),
@@ -384,7 +377,6 @@ export const setup = async (arg?: {
},
warm: {
enable: enable('warm'),
- showDataAllocationOptions: showDataAllocationOptions('warm'),
...createMinAgeActions('warm'),
setReplicas: setReplicas('warm'),
hasErrorIndicator: () => exists('phaseErrorIndicator-warm'),
@@ -396,7 +388,6 @@ export const setup = async (arg?: {
},
cold: {
enable: enable('cold'),
- showDataAllocationOptions: showDataAllocationOptions('cold'),
...createMinAgeActions('cold'),
setReplicas: setReplicas('cold'),
setFreeze,
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
deleted file mode 100644
index 740aeebb852f1..0000000000000
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
+++ /dev/null
@@ -1,1136 +0,0 @@
-/*
- * 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 { licensingMock } from '../../../../licensing/public/mocks';
-import { API_BASE_PATH } from '../../../common/constants';
-import { setupEnvironment } from '../helpers/setup_environment';
-import { EditPolicyTestBed, setup } from './edit_policy.helpers';
-
-import {
- DELETE_PHASE_POLICY,
- NEW_SNAPSHOT_POLICY_NAME,
- SNAPSHOT_POLICY_NAME,
- DEFAULT_POLICY,
- POLICY_WITH_MIGRATE_OFF,
- POLICY_WITH_INCLUDE_EXCLUDE,
- POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION,
- POLICY_WITH_NODE_ROLE_ALLOCATION,
- POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS,
- getDefaultHotPhasePolicy,
-} from './constants';
-
-describe('', () => {
- let testBed: EditPolicyTestBed;
- const { server, httpRequestsMockHelpers } = setupEnvironment();
-
- afterAll(() => {
- server.restore();
- });
-
- describe('serialization', () => {
- /**
- * We assume that policies that populate this form are loaded directly from ES and so
- * are valid according to ES. There may be settings in the policy created through the ILM
- * API that the UI does not cater for, like the unfollow action. We do not want to overwrite
- * the configuration for these actions in the UI.
- */
- it('preserves policy settings it did not configure', async () => {
- httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS]);
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component, actions } = testBed;
- component.update();
-
- // Set max docs to test whether we keep the unknown fields in that object after serializing
- await actions.hot.setMaxDocs('1000');
- // Remove the delete phase to ensure that we also correctly remove data
- await actions.delete.disablePhase();
- await actions.savePolicy();
-
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
-
- expect(entirePolicy).toEqual({
- foo: 'bar', // Made up value
- name: 'my_policy',
- phases: {
- hot: {
- actions: {
- rollover: {
- max_docs: 1000,
- max_size: '50gb',
- unknown_setting: 123, // Made up setting that should stay preserved
- },
- },
- min_age: '0ms',
- },
- warm: {
- actions: {
- my_unfollow_action: {}, // Made up action
- set_priority: {
- priority: 22,
- unknown_setting: true,
- },
- },
- min_age: '0d',
- },
- },
- });
- });
- });
-
- describe('hot phase', () => {
- describe('serialization', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('setting all values', async () => {
- const { actions } = testBed;
-
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.setMaxSize('123', 'mb');
- await actions.hot.setMaxDocs('123');
- await actions.hot.setMaxAge('123', 'h');
- await actions.hot.toggleForceMerge(true);
- await actions.hot.setForcemergeSegmentsCount('123');
- await actions.hot.setBestCompression(true);
- await actions.hot.toggleShrink(true);
- await actions.hot.setShrink('2');
- await actions.hot.toggleReadonly(true);
- await actions.hot.toggleIndexPriority(true);
- await actions.hot.setIndexPriority('123');
-
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- expect(entirePolicy).toMatchInlineSnapshot(`
- Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "forcemerge": Object {
- "index_codec": "best_compression",
- "max_num_segments": 123,
- },
- "readonly": Object {},
- "rollover": Object {
- "max_age": "123h",
- "max_docs": 123,
- "max_size": "123mb",
- },
- "set_priority": Object {
- "priority": 123,
- },
- "shrink": Object {
- "number_of_shards": 2,
- },
- },
- "min_age": "0ms",
- },
- },
- }
- `);
- });
-
- test('setting searchable snapshot', async () => {
- const { actions } = testBed;
-
- await actions.hot.setSearchableSnapshot('my-repo');
-
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- expect(entirePolicy.phases.hot.actions.searchable_snapshot.snapshot_repository).toBe(
- 'my-repo'
- );
- });
-
- test('disabling rollover', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- const hotActions = policy.phases.hot.actions;
- const rolloverAction = hotActions.rollover;
- expect(rolloverAction).toBe(undefined);
- expect(hotActions).toMatchInlineSnapshot(`Object {}`);
- });
-
- test('enabling searchable snapshot should hide force merge, freeze and shrink in subsequent phases', async () => {
- const { actions } = testBed;
-
- await actions.warm.enable(true);
- await actions.cold.enable(true);
-
- expect(actions.warm.forceMergeFieldExists()).toBeTruthy();
- expect(actions.warm.shrinkExists()).toBeTruthy();
- expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
- expect(actions.cold.freezeExists()).toBeTruthy();
-
- await actions.hot.setSearchableSnapshot('my-repo');
-
- expect(actions.warm.forceMergeFieldExists()).toBeFalsy();
- expect(actions.warm.shrinkExists()).toBeFalsy();
- // searchable snapshot in cold is still visible
- expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
- expect(actions.cold.freezeExists()).toBeFalsy();
- });
-
- test('disabling rollover toggle, but enabling default rollover', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
- await actions.hot.toggleDefaultRollover(true);
-
- expect(actions.hot.forceMergeFieldExists()).toBeTruthy();
- expect(actions.hot.shrinkExists()).toBeTruthy();
- expect(actions.hot.searchableSnapshotsExists()).toBeTruthy();
- });
- });
- });
-
- describe('warm phase', () => {
- describe('serialization', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('default values', async () => {
- const { actions } = testBed;
- await actions.warm.enable(true);
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
- expect(warmPhase).toMatchInlineSnapshot(`
- Object {
- "actions": Object {
- "set_priority": Object {
- "priority": 50,
- },
- },
- "min_age": "0d",
- }
- `);
- });
-
- test('setting all values', async () => {
- const { actions } = testBed;
- await actions.warm.enable(true);
- await actions.warm.setDataAllocation('node_attrs');
- await actions.warm.setSelectedNodeAttribute('test:123');
- await actions.warm.setReplicas('123');
- await actions.warm.toggleShrink(true);
- await actions.warm.setShrink('123');
- await actions.warm.toggleForceMerge(true);
- await actions.warm.setForcemergeSegmentsCount('123');
- await actions.warm.setBestCompression(true);
- await actions.warm.toggleReadonly(true);
- await actions.warm.setIndexPriority('123');
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- // Check shape of entire policy
- expect(entirePolicy).toMatchInlineSnapshot(`
- Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- },
- "min_age": "0ms",
- },
- "warm": Object {
- "actions": Object {
- "allocate": Object {
- "number_of_replicas": 123,
- "require": Object {
- "test": "123",
- },
- },
- "forcemerge": Object {
- "index_codec": "best_compression",
- "max_num_segments": 123,
- },
- "readonly": Object {},
- "set_priority": Object {
- "priority": 123,
- },
- "shrink": Object {
- "number_of_shards": 123,
- },
- },
- "min_age": "0d",
- },
- },
- }
- `);
- });
- });
-
- describe('policy with include and exclude', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_INCLUDE_EXCLUDE]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('preserves include, exclude allocation settings', async () => {
- const { actions } = testBed;
- await actions.warm.setDataAllocation('node_attrs');
- await actions.warm.setSelectedNodeAttribute('test:123');
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const warmPhaseAllocate = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
- .actions.allocate;
- expect(warmPhaseAllocate).toMatchInlineSnapshot(`
- Object {
- "exclude": Object {
- "def": "456",
- },
- "include": Object {
- "abc": "123",
- },
- "require": Object {
- "test": "123",
- },
- }
- `);
- });
- });
- });
-
- describe('cold phase', () => {
- describe('serialization', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('default values', async () => {
- const { actions } = testBed;
-
- await actions.cold.enable(true);
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- expect(entirePolicy.phases.cold).toMatchInlineSnapshot(`
- Object {
- "actions": Object {
- "set_priority": Object {
- "priority": 0,
- },
- },
- "min_age": "0d",
- }
- `);
- });
-
- test('setting all values, excluding searchable snapshot', async () => {
- const { actions } = testBed;
-
- await actions.cold.enable(true);
- await actions.cold.setMinAgeValue('123');
- await actions.cold.setMinAgeUnits('s');
- await actions.cold.setDataAllocation('node_attrs');
- await actions.cold.setSelectedNodeAttribute('test:123');
- await actions.cold.setSearchableSnapshot('my-repo');
- await actions.cold.setReplicas('123');
- await actions.cold.setFreeze(true);
- await actions.cold.setIndexPriority('123');
-
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
-
- expect(entirePolicy).toMatchInlineSnapshot(`
- Object {
- "name": "my_policy",
- "phases": Object {
- "cold": Object {
- "actions": Object {
- "allocate": Object {
- "number_of_replicas": 123,
- "require": Object {
- "test": "123",
- },
- },
- "freeze": Object {},
- "searchable_snapshot": Object {
- "snapshot_repository": "my-repo",
- },
- "set_priority": Object {
- "priority": 123,
- },
- },
- "min_age": "123s",
- },
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- },
- "min_age": "0ms",
- },
- },
- }
- `);
- });
- });
- });
-
- describe('delete phase', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]);
- httpRequestsMockHelpers.setLoadSnapshotPolicies([
- SNAPSHOT_POLICY_NAME,
- NEW_SNAPSHOT_POLICY_NAME,
- ]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('serialization', async () => {
- httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]);
- await act(async () => {
- testBed = await setup();
- });
- const { component, actions } = testBed;
- component.update();
- await actions.delete.enablePhase();
- await actions.setWaitForSnapshotPolicy('test');
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- expect(entirePolicy.phases.delete).toEqual({
- min_age: '365d',
- actions: {
- delete: {},
- wait_for_snapshot: {
- policy: 'test',
- },
- },
- });
- });
-
- test('wait for snapshot policy field should correctly display snapshot policy name', () => {
- expect(testBed.find('snapshotPolicyCombobox').prop('data-currentvalue')).toEqual([
- {
- label: DELETE_PHASE_POLICY.policy.phases.delete?.actions.wait_for_snapshot?.policy,
- },
- ]);
- });
-
- test('wait for snapshot field should correctly update snapshot policy name', async () => {
- const { actions } = testBed;
-
- await actions.setWaitForSnapshotPolicy(NEW_SNAPSHOT_POLICY_NAME);
- await actions.savePolicy();
-
- const expected = {
- name: DELETE_PHASE_POLICY.name,
- phases: {
- ...DELETE_PHASE_POLICY.policy.phases,
- delete: {
- ...DELETE_PHASE_POLICY.policy.phases.delete,
- actions: {
- ...DELETE_PHASE_POLICY.policy.phases.delete?.actions,
- wait_for_snapshot: {
- policy: NEW_SNAPSHOT_POLICY_NAME,
- },
- },
- },
- },
- };
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/policies`);
- expect(latestRequest.method).toBe('POST');
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
- });
-
- test('wait for snapshot field should display a callout when the input is not an existing policy', async () => {
- const { actions } = testBed;
-
- await actions.setWaitForSnapshotPolicy('my_custom_policy');
- expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy();
- expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy();
- expect(testBed.find('customPolicyCallout').exists()).toBeTruthy();
- });
-
- test('wait for snapshot field should delete action if field is empty', async () => {
- const { actions } = testBed;
-
- await actions.setWaitForSnapshotPolicy('');
- await actions.savePolicy();
-
- const expected = {
- name: DELETE_PHASE_POLICY.name,
- phases: {
- ...DELETE_PHASE_POLICY.policy.phases,
- delete: {
- ...DELETE_PHASE_POLICY.policy.phases.delete,
- actions: {
- ...DELETE_PHASE_POLICY.policy.phases.delete?.actions,
- },
- },
- },
- };
-
- delete expected.phases.delete.actions.wait_for_snapshot;
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
- });
-
- test('wait for snapshot field should display a callout when there are no snapshot policies', async () => {
- // need to call setup on testBed again for it to use a newly defined snapshot policies response
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
- await act(async () => {
- testBed = await setup();
- });
-
- testBed.component.update();
- expect(testBed.find('customPolicyCallout').exists()).toBeFalsy();
- expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy();
- expect(testBed.find('noPoliciesCallout').exists()).toBeTruthy();
- });
-
- test('wait for snapshot field should display a callout when there is an error loading snapshot policies', async () => {
- // need to call setup on testBed again for it to use a newly defined snapshot policies response
- httpRequestsMockHelpers.setLoadSnapshotPolicies([], { status: 500, body: 'error' });
- await act(async () => {
- testBed = await setup();
- });
-
- testBed.component.update();
- expect(testBed.find('customPolicyCallout').exists()).toBeFalsy();
- expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy();
- expect(testBed.find('policiesErrorCallout').exists()).toBeTruthy();
- });
- });
-
- describe('data allocation', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_MIGRATE_OFF]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('setting node_attr based allocation, but not selecting node attribute', async () => {
- const { actions } = testBed;
- await actions.warm.setDataAllocation('node_attrs');
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
-
- expect(warmPhase.actions.migrate).toEqual({ enabled: false });
- });
-
- describe('node roles', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ROLE_ALLOCATION]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- });
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('detecting use of the recommended allocation type', () => {
- const { find } = testBed;
- const selectedDataAllocation = find(
- 'warm-dataTierAllocationControls.dataTierSelect'
- ).text();
- expect(selectedDataAllocation).toBe('Use warm nodes (recommended)');
- });
-
- test('setting replicas serialization', async () => {
- const { actions } = testBed;
- await actions.warm.setReplicas('123');
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const warmPhaseActions = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
- .actions;
- expect(warmPhaseActions).toMatchInlineSnapshot(`
- Object {
- "allocate": Object {
- "number_of_replicas": 123,
- },
- }
- `);
- });
- });
-
- describe('node attr and none', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- });
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('detecting use of the custom allocation type', () => {
- const { find } = testBed;
- expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toBe('Custom');
- });
- test('detecting use of the "off" allocation type', () => {
- const { find } = testBed;
- expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off');
- });
- });
- describe('on cloud', () => {
- describe('using legacy data role config', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByAttributes: { test: ['123'] },
- // On cloud, even if there are data_* roles set, the default, recommended allocation option should not
- // be available.
- nodesByRoles: { data_hot: ['123'] },
- isUsingDeprecatedDataRoleConfig: true,
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
-
- await act(async () => {
- testBed = await setup({
- appServicesContext: {
- cloud: {
- isCloudEnabled: true,
- },
- license: licensingMock.createLicense({ license: { type: 'basic' } }),
- },
- });
- });
-
- const { component } = testBed;
- component.update();
- });
- test('removes default, recommended option', async () => {
- const { actions, find } = testBed;
- await actions.warm.enable(true);
- actions.warm.showDataAllocationOptions();
-
- expect(find('defaultDataAllocationOption').exists()).toBeFalsy();
- expect(find('customDataAllocationOption').exists()).toBeTruthy();
- expect(find('noneDataAllocationOption').exists()).toBeTruthy();
- // Show the call-to-action for users to migrate their cluster to use node roles
- expect(find('cloudDataTierCallout').exists()).toBeTruthy();
- });
- });
- describe('using node roles', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data_hot: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
-
- await act(async () => {
- testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('should show recommended, custom and "off" options on cloud with data roles', async () => {
- const { actions, find } = testBed;
-
- await actions.warm.enable(true);
- actions.warm.showDataAllocationOptions();
- expect(find('defaultDataAllocationOption').exists()).toBeTruthy();
- expect(find('customDataAllocationOption').exists()).toBeTruthy();
- expect(find('noneDataAllocationOption').exists()).toBeTruthy();
- // We should not be showing the call-to-action for users to activate the cold tier on cloud
- expect(find('cloudMissingColdTierCallout').exists()).toBeFalsy();
- // Do not show the call-to-action for users to migrate their cluster to use node roles
- expect(find('cloudDataTierCallout').exists()).toBeFalsy();
- });
-
- test('should show cloud notice when cold tier nodes do not exist', async () => {
- const { actions, find } = testBed;
- await actions.cold.enable(true);
- expect(find('cloudMissingColdTierCallout').exists()).toBeTruthy();
- // Assert that other notices are not showing
- expect(find('defaultAllocationNotice').exists()).toBeFalsy();
- expect(find('noNodeAttributesWarning').exists()).toBeFalsy();
- });
- });
- });
- });
-
- describe('searchable snapshot', () => {
- describe('on non-enterprise license', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
-
- await act(async () => {
- testBed = await setup({
- appServicesContext: {
- license: licensingMock.createLicense({ license: { type: 'basic' } }),
- },
- });
- });
-
- const { component } = testBed;
- component.update();
- });
- test('disable setting searchable snapshots', async () => {
- const { actions } = testBed;
-
- expect(actions.cold.searchableSnapshotsExists()).toBeFalsy();
- expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
-
- await actions.cold.enable(true);
-
- // Still hidden in hot
- expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
-
- expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
- expect(actions.cold.searchableSnapshotDisabledDueToLicense()).toBeTruthy();
- });
- });
-
- describe('on cloud', () => {
- describe('new policy', () => {
- beforeEach(async () => {
- // simulate creating a new policy
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
-
- await act(async () => {
- testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
- });
-
- const { component } = testBed;
- component.update();
- });
- test('defaults searchable snapshot to true on cloud', async () => {
- const { find, actions } = testBed;
- await actions.cold.enable(true);
- expect(
- find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked']
- ).toBe(true);
- });
- });
- describe('existing policy', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data_hot: ['123'] },
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
-
- await act(async () => {
- testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
- });
-
- const { component } = testBed;
- component.update();
- });
- test('correctly sets snapshot repository default to "found-snapshots"', async () => {
- const { actions } = testBed;
- await actions.cold.enable(true);
- await actions.cold.toggleSearchableSnapshot(true);
- await actions.savePolicy();
- const latestRequest = server.requests[server.requests.length - 1];
- const request = JSON.parse(JSON.parse(latestRequest.requestBody).body);
- expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual(
- 'found-snapshots'
- );
- });
- });
- });
- });
- describe('with rollover', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['abc'] });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('shows rollover tip on minimum age', async () => {
- const { actions } = testBed;
-
- await actions.warm.enable(true);
- await actions.cold.enable(true);
- await actions.delete.enablePhase();
-
- expect(actions.warm.hasRolloverTipOnMinAge()).toBeTruthy();
- expect(actions.cold.hasRolloverTipOnMinAge()).toBeTruthy();
- expect(actions.delete.hasRolloverTipOnMinAge()).toBeTruthy();
- });
- });
-
- describe('without rollover', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- isUsingDeprecatedDataRoleConfig: false,
- nodesByAttributes: { test: ['123'] },
- nodesByRoles: { data: ['123'] },
- });
- httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup({
- appServicesContext: {
- license: licensingMock.createLicense({ license: { type: 'enterprise' } }),
- },
- });
- });
-
- const { component } = testBed;
- component.update();
- });
- test('hides fields in hot phase', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
-
- expect(actions.hot.forceMergeFieldExists()).toBeFalsy();
- expect(actions.hot.shrinkExists()).toBeFalsy();
- expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
- expect(actions.hot.readonlyExists()).toBeFalsy();
- });
-
- test('hiding rollover tip on minimum age', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
-
- await actions.warm.enable(true);
- await actions.cold.enable(true);
- await actions.delete.enablePhase();
-
- expect(actions.warm.hasRolloverTipOnMinAge()).toBeFalsy();
- expect(actions.cold.hasRolloverTipOnMinAge()).toBeFalsy();
- expect(actions.delete.hasRolloverTipOnMinAge()).toBeFalsy();
- });
- });
-
- describe('policy timeline', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- test('showing all phases on the timeline', async () => {
- const { actions } = testBed;
- // This is how the default policy should look
- expect(actions.timeline.hasHotPhase()).toBe(true);
- expect(actions.timeline.hasWarmPhase()).toBe(false);
- expect(actions.timeline.hasColdPhase()).toBe(false);
- expect(actions.timeline.hasDeletePhase()).toBe(false);
-
- await actions.warm.enable(true);
- expect(actions.timeline.hasHotPhase()).toBe(true);
- expect(actions.timeline.hasWarmPhase()).toBe(true);
- expect(actions.timeline.hasColdPhase()).toBe(false);
- expect(actions.timeline.hasDeletePhase()).toBe(false);
-
- await actions.cold.enable(true);
- expect(actions.timeline.hasHotPhase()).toBe(true);
- expect(actions.timeline.hasWarmPhase()).toBe(true);
- expect(actions.timeline.hasColdPhase()).toBe(true);
- expect(actions.timeline.hasDeletePhase()).toBe(false);
-
- await actions.delete.enablePhase();
- expect(actions.timeline.hasHotPhase()).toBe(true);
- expect(actions.timeline.hasWarmPhase()).toBe(true);
- expect(actions.timeline.hasColdPhase()).toBe(true);
- expect(actions.timeline.hasDeletePhase()).toBe(true);
- });
- });
-
- describe('policy error notifications', () => {
- let runTimers: () => void;
- beforeAll(() => {
- jest.useFakeTimers();
- });
-
- afterAll(() => {
- jest.useRealTimers();
- });
-
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: {},
- nodesByAttributes: { test: ['123'] },
- isUsingDeprecatedDataRoleConfig: false,
- });
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
-
- ({ runTimers } = testBed);
- });
-
- test('shows phase error indicators correctly', async () => {
- // This test simulates a user configuring a policy phase by phase. The flow is the following:
- // 0. Start with policy with no validation issues present
- // 1. Configure hot, introducing a validation error
- // 2. Configure warm, introducing a validation error
- // 3. Configure cold, introducing a validation error
- // 4. Fix validation error in hot
- // 5. Fix validation error in warm
- // 6. Fix validation error in cold
- // We assert against each of these progressive states.
-
- const { actions } = testBed;
-
- // 0. No validation issues
- expect(actions.hasGlobalErrorCallout()).toBe(false);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
-
- // 1. Hot phase validation issue
- await actions.hot.toggleForceMerge(true);
- await actions.hot.setForcemergeSegmentsCount('-22');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(true);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
-
- // 2. Warm phase validation issue
- await actions.warm.enable(true);
- await actions.warm.toggleForceMerge(true);
- await actions.warm.setForcemergeSegmentsCount('-22');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(true);
- expect(actions.warm.hasErrorIndicator()).toBe(true);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
-
- // 3. Cold phase validation issue
- await actions.cold.enable(true);
- await actions.cold.setReplicas('-33');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(true);
- expect(actions.warm.hasErrorIndicator()).toBe(true);
- expect(actions.cold.hasErrorIndicator()).toBe(true);
-
- // 4. Fix validation issue in hot
- await actions.hot.setForcemergeSegmentsCount('1');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(true);
- expect(actions.cold.hasErrorIndicator()).toBe(true);
-
- // 5. Fix validation issue in warm
- await actions.warm.setForcemergeSegmentsCount('1');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(true);
-
- // 6. Fix validation issue in cold
- await actions.cold.setReplicas('1');
- runTimers();
- expect(actions.hasGlobalErrorCallout()).toBe(false);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
- });
-
- test('global error callout should show if there are any form errors', async () => {
- const { actions } = testBed;
-
- expect(actions.hasGlobalErrorCallout()).toBe(false);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
-
- await actions.saveAsNewPolicy(true);
- await actions.setPolicyName('');
- runTimers();
-
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
- });
-
- test('clears all error indicators if last erroring field is unmounted', async () => {
- const { actions } = testBed;
-
- await actions.cold.enable(true);
- // introduce validation error
- await actions.cold.setSearchableSnapshot('');
- runTimers();
-
- await actions.savePolicy();
- runTimers();
-
- expect(actions.hasGlobalErrorCallout()).toBe(true);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(true);
-
- // unmount the field
- await actions.cold.toggleSearchableSnapshot(false);
-
- expect(actions.hasGlobalErrorCallout()).toBe(false);
- expect(actions.hot.hasErrorIndicator()).toBe(false);
- expect(actions.warm.hasErrorIndicator()).toBe(false);
- expect(actions.cold.hasErrorIndicator()).toBe(false);
- });
- });
-});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts
new file mode 100644
index 0000000000000..dfb7411eb941f
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts
@@ -0,0 +1,52 @@
+/*
+ * 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 { setupEnvironment } from '../../helpers/setup_environment';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import { getDefaultHotPhasePolicy } from '../constants';
+
+describe(' cold phase', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ beforeAll(() => {
+ jest.useFakeTimers();
+ });
+
+ afterAll(() => {
+ jest.useRealTimers();
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: { data: ['node1'] },
+ nodesByAttributes: { 'attribute:true': ['node1'] },
+ isUsingDeprecatedDataRoleConfig: true,
+ });
+ httpRequestsMockHelpers.setNodesDetails('attribute:true', [
+ { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } },
+ ]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('shows timing only when enabled', async () => {
+ const { actions } = testBed;
+ expect(actions.cold.hasMinAgeInput()).toBeFalsy();
+ await actions.cold.enable(true);
+ expect(actions.cold.hasMinAgeInput()).toBeTruthy();
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts
new file mode 100644
index 0000000000000..0fb4951e4a4a6
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts
@@ -0,0 +1,169 @@
+/*
+ * 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 {
+ DELETE_PHASE_POLICY,
+ getDefaultHotPhasePolicy,
+ NEW_SNAPSHOT_POLICY_NAME,
+ SNAPSHOT_POLICY_NAME,
+} from '../constants';
+import { act } from 'react-dom/test-utils';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import { API_BASE_PATH } from '../../../../common/constants';
+import { setupEnvironment } from '../../helpers/setup_environment';
+
+describe(' delete phase', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([
+ SNAPSHOT_POLICY_NAME,
+ NEW_SNAPSHOT_POLICY_NAME,
+ ]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('is hidden when disabled', async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component, actions } = testBed;
+ component.update();
+
+ expect(actions.delete.isShown()).toBeFalsy();
+ await actions.delete.enablePhase();
+ expect(actions.delete.isShown()).toBeTruthy();
+ });
+
+ test('shows timing after it was enabled', async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component, actions } = testBed;
+ component.update();
+
+ expect(actions.delete.hasMinAgeInput()).toBeFalsy();
+ await actions.delete.enablePhase();
+ expect(actions.delete.hasMinAgeInput()).toBeTruthy();
+ });
+
+ describe('wait for snapshot', () => {
+ test('shows snapshot policy name', () => {
+ expect(testBed.find('snapshotPolicyCombobox').prop('data-currentvalue')).toEqual([
+ {
+ label: DELETE_PHASE_POLICY.policy.phases.delete?.actions.wait_for_snapshot?.policy,
+ },
+ ]);
+ });
+
+ test('updates snapshot policy name', async () => {
+ const { actions } = testBed;
+
+ await actions.setWaitForSnapshotPolicy(NEW_SNAPSHOT_POLICY_NAME);
+ await actions.savePolicy();
+
+ const expected = {
+ name: DELETE_PHASE_POLICY.name,
+ phases: {
+ ...DELETE_PHASE_POLICY.policy.phases,
+ delete: {
+ ...DELETE_PHASE_POLICY.policy.phases.delete,
+ actions: {
+ ...DELETE_PHASE_POLICY.policy.phases.delete?.actions,
+ wait_for_snapshot: {
+ policy: NEW_SNAPSHOT_POLICY_NAME,
+ },
+ },
+ },
+ },
+ };
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/policies`);
+ expect(latestRequest.method).toBe('POST');
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
+ });
+
+ test('shows a callout when the input is not an existing policy', async () => {
+ const { actions } = testBed;
+
+ await actions.setWaitForSnapshotPolicy('my_custom_policy');
+ expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy();
+ expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy();
+ expect(testBed.find('customPolicyCallout').exists()).toBeTruthy();
+ });
+
+ test('removes the action if field is empty', async () => {
+ const { actions } = testBed;
+
+ await actions.setWaitForSnapshotPolicy('');
+ await actions.savePolicy();
+
+ const expected = {
+ name: DELETE_PHASE_POLICY.name,
+ phases: {
+ ...DELETE_PHASE_POLICY.policy.phases,
+ delete: {
+ ...DELETE_PHASE_POLICY.policy.phases.delete,
+ actions: {
+ ...DELETE_PHASE_POLICY.policy.phases.delete?.actions,
+ },
+ },
+ },
+ };
+
+ delete expected.phases.delete.actions.wait_for_snapshot;
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
+ });
+
+ test('shows a callout when there are no snapshot policies', async () => {
+ // need to call setup on testBed again for it to use a newly defined snapshot policies response
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ testBed.component.update();
+ expect(testBed.find('customPolicyCallout').exists()).toBeFalsy();
+ expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy();
+ expect(testBed.find('noPoliciesCallout').exists()).toBeTruthy();
+ });
+
+ test('shows a callout when there is an error loading snapshot policies', async () => {
+ // need to call setup on testBed again for it to use a newly defined snapshot policies response
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([], { status: 500, body: 'error' });
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ testBed.component.update();
+ expect(testBed.find('customPolicyCallout').exists()).toBeFalsy();
+ expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy();
+ expect(testBed.find('policiesErrorCallout').exists()).toBeTruthy();
+ });
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts
similarity index 78%
rename from x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts
rename to x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts
index b02d190d10899..13e55a1f39e2c 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts
@@ -8,6 +8,11 @@
import { act } from 'react-dom/test-utils';
import { setupEnvironment } from '../../helpers/setup_environment';
import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import {
+ POLICY_WITH_MIGRATE_OFF,
+ POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION,
+ POLICY_WITH_NODE_ROLE_ALLOCATION,
+} from '../constants';
describe(' node allocation', () => {
let testBed: EditPolicyTestBed;
@@ -308,7 +313,7 @@ describe(' node allocation', () => {
});
describe('on cloud', () => {
- describe('with deprecated data role config', () => {
+ describe('using legacy data role config', () => {
test('should hide data tier option on cloud', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
@@ -319,7 +324,7 @@ describe(' node allocation', () => {
await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
});
- const { actions, component, exists } = testBed;
+ const { actions, component, exists, find } = testBed;
component.update();
await actions.warm.enable(true);
@@ -330,30 +335,13 @@ describe(' node allocation', () => {
expect(exists('defaultDataAllocationOption')).toBeFalsy();
expect(exists('customDataAllocationOption')).toBeTruthy();
expect(exists('noneDataAllocationOption')).toBeTruthy();
- });
-
- test('should ask users to migrate to node roles when on cloud using legacy data role', async () => {
- httpRequestsMockHelpers.setListNodes({
- nodesByAttributes: { test: ['123'] },
- // On cloud, if using legacy config there will not be any "data_*" roles set.
- nodesByRoles: { data: ['test'] },
- isUsingDeprecatedDataRoleConfig: true,
- });
- await act(async () => {
- testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
- });
- const { actions, component, exists } = testBed;
-
- component.update();
- await actions.warm.enable(true);
- expect(component.find('.euiLoadingSpinner').exists()).toBeFalsy();
-
- expect(exists('cloudDataTierCallout')).toBeTruthy();
+ // Show the call-to-action for users to migrate their cluster to use node roles
+ expect(find('cloudDataTierCallout').exists()).toBeTruthy();
});
});
- describe('with node role config', () => {
- test('shows data role, custom and "off" options on cloud with data roles', async () => {
+ describe('using node role config', () => {
+ test('shows recommended, custom and "off" options on cloud with data roles', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] },
@@ -362,7 +350,7 @@ describe(' node allocation', () => {
await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
});
- const { actions, component, exists } = testBed;
+ const { actions, component, exists, find } = testBed;
component.update();
await actions.warm.enable(true);
@@ -372,8 +360,10 @@ describe(' node allocation', () => {
expect(exists('defaultDataAllocationOption')).toBeTruthy();
expect(exists('customDataAllocationOption')).toBeTruthy();
expect(exists('noneDataAllocationOption')).toBeTruthy();
- // We should not be showing the call-to-action for users to activate data tiers in cloud
+ // We should not be showing the call-to-action for users to activate data tier in cloud
expect(exists('cloudDataTierCallout')).toBeFalsy();
+ // Do not show the call-to-action for users to migrate their cluster to use node roles
+ expect(find('cloudDataTierCallout').exists()).toBeFalsy();
});
test('shows cloud notice when cold tier nodes do not exist', async () => {
@@ -398,4 +388,102 @@ describe(' node allocation', () => {
});
});
});
+
+ describe('data allocation', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_MIGRATE_OFF]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('setting node_attr based allocation, but not selecting node attribute', async () => {
+ const { actions } = testBed;
+ await actions.warm.setDataAllocation('node_attrs');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
+
+ expect(warmPhase.actions.migrate).toEqual({ enabled: false });
+ });
+
+ describe('node roles', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ROLE_ALLOCATION]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('detecting use of the recommended allocation type', () => {
+ const { find } = testBed;
+ const selectedDataAllocation = find(
+ 'warm-dataTierAllocationControls.dataTierSelect'
+ ).text();
+ expect(selectedDataAllocation).toBe('Use warm nodes (recommended)');
+ });
+
+ test('setting replicas serialization', async () => {
+ const { actions } = testBed;
+ await actions.warm.setReplicas('123');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const warmPhaseActions = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
+ .actions;
+ expect(warmPhaseActions).toMatchInlineSnapshot(`
+ Object {
+ "allocate": Object {
+ "number_of_replicas": 123,
+ },
+ }
+ `);
+ });
+ });
+
+ describe('node attr and none', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('detecting use of the custom allocation type', () => {
+ const { find } = testBed;
+ expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toBe('Custom');
+ });
+ test('detecting use of the "off" allocation type', () => {
+ const { find } = testBed;
+ expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off');
+ });
+ });
+ });
});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts
new file mode 100644
index 0000000000000..6584c19c85be3
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts
@@ -0,0 +1,66 @@
+/*
+ * 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 { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import { setupEnvironment } from '../../helpers/setup_environment';
+import { getDefaultHotPhasePolicy } from '../constants';
+
+describe(' request flyout', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ beforeAll(() => {
+ jest.useFakeTimers();
+ });
+
+ afterAll(() => {
+ jest.useRealTimers();
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('renders a json in flyout for a default policy', async () => {
+ const { find, component } = testBed;
+ await act(async () => {
+ find('requestButton').simulate('click');
+ });
+ component.update();
+
+ const json = component.find(`code`).text();
+ const expected = `PUT _ilm/policy/my_policy\n${JSON.stringify(
+ {
+ policy: {
+ phases: {
+ hot: {
+ min_age: '0ms',
+ actions: {
+ rollover: {
+ max_age: '30d',
+ max_size: '50gb',
+ },
+ },
+ },
+ },
+ },
+ },
+ null,
+ 2
+ )}`;
+ expect(json).toBe(expected);
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts
new file mode 100644
index 0000000000000..e2b67efbf588d
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts
@@ -0,0 +1,108 @@
+/*
+ * 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 { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import { setupEnvironment } from '../../helpers/setup_environment';
+import { getDefaultHotPhasePolicy } from '../constants';
+import { act } from 'react-dom/test-utils';
+import { licensingMock } from '../../../../../licensing/public/mocks';
+
+describe(' timeline', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+ httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['abc'] });
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+
+ await act(async () => {
+ testBed = await setup({
+ appServicesContext: {
+ license: licensingMock.createLicense({ license: { type: 'enterprise' } }),
+ },
+ });
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('shows forcemerge when rollover enabled', async () => {
+ const { actions } = testBed;
+ expect(actions.hot.forceMergeFieldExists()).toBeTruthy();
+ });
+ test('hides forcemerge when rollover is disabled', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ expect(actions.hot.forceMergeFieldExists()).toBeFalsy();
+ });
+
+ test('shows shrink input when rollover enabled', async () => {
+ const { actions } = testBed;
+ expect(actions.hot.shrinkExists()).toBeTruthy();
+ });
+ test('hides shrink input when rollover is disabled', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ expect(actions.hot.shrinkExists()).toBeFalsy();
+ });
+ test('shows readonly input when rollover enabled', async () => {
+ const { actions } = testBed;
+ expect(actions.hot.readonlyExists()).toBeTruthy();
+ });
+ test('hides readonly input when rollover is disabled', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ expect(actions.hot.readonlyExists()).toBeFalsy();
+ });
+ test('hides and disables searchable snapshot field', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ await actions.cold.enable(true);
+
+ expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
+ });
+
+ test('shows rollover tip on minimum age', async () => {
+ const { actions } = testBed;
+
+ await actions.warm.enable(true);
+ await actions.cold.enable(true);
+ await actions.delete.enablePhase();
+
+ expect(actions.warm.hasRolloverTipOnMinAge()).toBeTruthy();
+ expect(actions.cold.hasRolloverTipOnMinAge()).toBeTruthy();
+ expect(actions.delete.hasRolloverTipOnMinAge()).toBeTruthy();
+ });
+ test('hiding rollover tip on minimum age', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+
+ await actions.warm.enable(true);
+ await actions.cold.enable(true);
+ await actions.delete.enablePhase();
+
+ expect(actions.warm.hasRolloverTipOnMinAge()).toBeFalsy();
+ expect(actions.cold.hasRolloverTipOnMinAge()).toBeFalsy();
+ expect(actions.delete.hasRolloverTipOnMinAge()).toBeFalsy();
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts
new file mode 100644
index 0000000000000..ed678a6b217ae
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts
@@ -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
+ * 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 { licensingMock } from '../../../../../licensing/public/mocks';
+import { setupEnvironment } from '../../helpers/setup_environment';
+import { getDefaultHotPhasePolicy } from '../constants';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+
+describe(' searchable snapshots', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('enabling searchable snapshot should hide force merge, freeze and shrink in subsequent phases', async () => {
+ const { actions } = testBed;
+
+ await actions.warm.enable(true);
+ await actions.cold.enable(true);
+
+ expect(actions.warm.forceMergeFieldExists()).toBeTruthy();
+ expect(actions.warm.shrinkExists()).toBeTruthy();
+ expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
+ expect(actions.cold.freezeExists()).toBeTruthy();
+
+ await actions.hot.setSearchableSnapshot('my-repo');
+
+ expect(actions.warm.forceMergeFieldExists()).toBeFalsy();
+ expect(actions.warm.shrinkExists()).toBeFalsy();
+ // searchable snapshot in cold is still visible
+ expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
+ expect(actions.cold.freezeExists()).toBeFalsy();
+ });
+
+ test('disabling rollover toggle, but enabling default rollover', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ await actions.hot.toggleDefaultRollover(true);
+
+ expect(actions.hot.forceMergeFieldExists()).toBeTruthy();
+ expect(actions.hot.shrinkExists()).toBeTruthy();
+ expect(actions.hot.searchableSnapshotsExists()).toBeTruthy();
+ });
+
+ describe('on cloud', () => {
+ describe('new policy', () => {
+ beforeEach(async () => {
+ // simulate creating a new policy
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+ httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
+
+ await act(async () => {
+ testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+ test('defaults searchable snapshot to true on cloud', async () => {
+ const { find, actions } = testBed;
+ await actions.cold.enable(true);
+ expect(
+ find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked']
+ ).toBe(true);
+ });
+ });
+ describe('existing policy', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+ httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });
+
+ await act(async () => {
+ testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+ test('correctly sets snapshot repository default to "found-snapshots"', async () => {
+ const { actions } = testBed;
+ await actions.cold.enable(true);
+ await actions.cold.toggleSearchableSnapshot(true);
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const request = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual(
+ 'found-snapshots'
+ );
+ });
+ });
+ });
+ describe('on non-enterprise license', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+ httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['my-repo'] });
+
+ await act(async () => {
+ testBed = await setup({
+ appServicesContext: {
+ license: licensingMock.createLicense({ license: { type: 'basic' } }),
+ },
+ });
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+ test('disable setting searchable snapshots', async () => {
+ const { actions } = testBed;
+
+ expect(actions.cold.searchableSnapshotsExists()).toBeFalsy();
+ expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
+
+ await actions.cold.enable(true);
+
+ // Still hidden in hot
+ expect(actions.hot.searchableSnapshotsExists()).toBeFalsy();
+
+ expect(actions.cold.searchableSnapshotsExists()).toBeTruthy();
+ expect(actions.cold.searchableSnapshotDisabledDueToLicense()).toBeTruthy();
+ });
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts
new file mode 100644
index 0000000000000..3618bad45e4f1
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts
@@ -0,0 +1,64 @@
+/*
+ * 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 { setupEnvironment } from '../../helpers/setup_environment';
+import { getDefaultHotPhasePolicy } from '../constants';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+
+describe(' timeline', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('showing all phases on the timeline', async () => {
+ const { actions } = testBed;
+ // This is how the default policy should look
+ expect(actions.timeline.hasHotPhase()).toBe(true);
+ expect(actions.timeline.hasWarmPhase()).toBe(false);
+ expect(actions.timeline.hasColdPhase()).toBe(false);
+ expect(actions.timeline.hasDeletePhase()).toBe(false);
+
+ await actions.warm.enable(true);
+ expect(actions.timeline.hasHotPhase()).toBe(true);
+ expect(actions.timeline.hasWarmPhase()).toBe(true);
+ expect(actions.timeline.hasColdPhase()).toBe(false);
+ expect(actions.timeline.hasDeletePhase()).toBe(false);
+
+ await actions.cold.enable(true);
+ expect(actions.timeline.hasHotPhase()).toBe(true);
+ expect(actions.timeline.hasWarmPhase()).toBe(true);
+ expect(actions.timeline.hasColdPhase()).toBe(true);
+ expect(actions.timeline.hasDeletePhase()).toBe(false);
+
+ await actions.delete.enablePhase();
+ expect(actions.timeline.hasHotPhase()).toBe(true);
+ expect(actions.timeline.hasWarmPhase()).toBe(true);
+ expect(actions.timeline.hasColdPhase()).toBe(true);
+ expect(actions.timeline.hasDeletePhase()).toBe(true);
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts
new file mode 100644
index 0000000000000..2252f8d1f5fa8
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts
@@ -0,0 +1,52 @@
+/*
+ * 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 { setupEnvironment } from '../../helpers/setup_environment';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+import { getDefaultHotPhasePolicy } from '../constants';
+
+describe(' warm phase', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ beforeAll(() => {
+ jest.useFakeTimers();
+ });
+
+ afterAll(() => {
+ jest.useRealTimers();
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: { data: ['node1'] },
+ nodesByAttributes: { 'attribute:true': ['node1'] },
+ isUsingDeprecatedDataRoleConfig: true,
+ });
+ httpRequestsMockHelpers.setNodesDetails('attribute:true', [
+ { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } },
+ ]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('shows timing only when enabled', async () => {
+ const { actions } = testBed;
+ expect(actions.warm.hasMinAgeInput()).toBeFalsy();
+ await actions.warm.enable(true);
+ expect(actions.warm.hasMinAgeInput()).toBeTruthy();
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts
new file mode 100644
index 0000000000000..e2d937cf9c8db
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts
@@ -0,0 +1,159 @@
+/*
+ * 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 { setupEnvironment } from '../../helpers/setup_environment';
+import { getDefaultHotPhasePolicy } from '../constants';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+
+describe(' error indicators', () => {
+ let testBed: EditPolicyTestBed;
+ let runTimers: () => void;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ beforeAll(() => {
+ jest.useFakeTimers();
+ });
+
+ afterAll(() => {
+ jest.useRealTimers();
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+
+ ({ runTimers } = testBed);
+ });
+ test('shows phase error indicators correctly', async () => {
+ // This test simulates a user configuring a policy phase by phase. The flow is the following:
+ // 0. Start with policy with no validation issues present
+ // 1. Configure hot, introducing a validation error
+ // 2. Configure warm, introducing a validation error
+ // 3. Configure cold, introducing a validation error
+ // 4. Fix validation error in hot
+ // 5. Fix validation error in warm
+ // 6. Fix validation error in cold
+ // We assert against each of these progressive states.
+
+ const { actions } = testBed;
+
+ // 0. No validation issues
+ expect(actions.hasGlobalErrorCallout()).toBe(false);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+
+ // 1. Hot phase validation issue
+ await actions.hot.toggleForceMerge(true);
+ await actions.hot.setForcemergeSegmentsCount('-22');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(true);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+
+ // 2. Warm phase validation issue
+ await actions.warm.enable(true);
+ await actions.warm.toggleForceMerge(true);
+ await actions.warm.setForcemergeSegmentsCount('-22');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(true);
+ expect(actions.warm.hasErrorIndicator()).toBe(true);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+
+ // 3. Cold phase validation issue
+ await actions.cold.enable(true);
+ await actions.cold.setReplicas('-33');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(true);
+ expect(actions.warm.hasErrorIndicator()).toBe(true);
+ expect(actions.cold.hasErrorIndicator()).toBe(true);
+
+ // 4. Fix validation issue in hot
+ await actions.hot.setForcemergeSegmentsCount('1');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(true);
+ expect(actions.cold.hasErrorIndicator()).toBe(true);
+
+ // 5. Fix validation issue in warm
+ await actions.warm.setForcemergeSegmentsCount('1');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(true);
+
+ // 6. Fix validation issue in cold
+ await actions.cold.setReplicas('1');
+ runTimers();
+ expect(actions.hasGlobalErrorCallout()).toBe(false);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+ });
+
+ test('global error callout should show if there are any form errors', async () => {
+ const { actions } = testBed;
+
+ expect(actions.hasGlobalErrorCallout()).toBe(false);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+
+ await actions.saveAsNewPolicy(true);
+ await actions.setPolicyName('');
+ runTimers();
+
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+ });
+
+ test('clears all error indicators if last erroring field is unmounted', async () => {
+ const { actions } = testBed;
+
+ await actions.cold.enable(true);
+ // introduce validation error
+ await actions.cold.setSearchableSnapshot('');
+ runTimers();
+
+ await actions.savePolicy();
+ runTimers();
+
+ expect(actions.hasGlobalErrorCallout()).toBe(true);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(true);
+
+ // unmount the field
+ await actions.cold.toggleSearchableSnapshot(false);
+
+ expect(actions.hasGlobalErrorCallout()).toBe(false);
+ expect(actions.hot.hasErrorIndicator()).toBe(false);
+ expect(actions.warm.hasErrorIndicator()).toBe(false);
+ expect(actions.cold.hasErrorIndicator()).toBe(false);
+ });
+});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts
deleted file mode 100644
index 9c23780f1d021..0000000000000
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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 { setupEnvironment } from '../../helpers/setup_environment';
-import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
-import { DEFAULT_POLICY } from '../constants';
-
-describe(' reactive form', () => {
- let testBed: EditPolicyTestBed;
- const { server, httpRequestsMockHelpers } = setupEnvironment();
-
- beforeAll(() => {
- jest.useFakeTimers();
- });
-
- afterAll(() => {
- jest.useRealTimers();
- server.restore();
- });
-
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]);
- httpRequestsMockHelpers.setListNodes({
- nodesByRoles: { data: ['node1'] },
- nodesByAttributes: { 'attribute:true': ['node1'] },
- isUsingDeprecatedDataRoleConfig: true,
- });
- httpRequestsMockHelpers.setNodesDetails('attribute:true', [
- { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } },
- ]);
- httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
-
- await act(async () => {
- testBed = await setup();
- });
-
- const { component } = testBed;
- component.update();
- });
-
- describe('rollover', () => {
- test('shows forcemerge when rollover enabled', async () => {
- const { actions } = testBed;
- expect(actions.hot.forceMergeFieldExists()).toBeTruthy();
- });
- test('hides forcemerge when rollover is disabled', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
- expect(actions.hot.forceMergeFieldExists()).toBeFalsy();
- });
-
- test('shows shrink input when rollover enabled', async () => {
- const { actions } = testBed;
- expect(actions.hot.shrinkExists()).toBeTruthy();
- });
- test('hides shrink input when rollover is disabled', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
- expect(actions.hot.shrinkExists()).toBeFalsy();
- });
- test('shows readonly input when rollover enabled', async () => {
- const { actions } = testBed;
- expect(actions.hot.readonlyExists()).toBeTruthy();
- });
- test('hides readonly input when rollover is disabled', async () => {
- const { actions } = testBed;
- await actions.hot.toggleDefaultRollover(false);
- await actions.hot.toggleRollover(false);
- expect(actions.hot.readonlyExists()).toBeFalsy();
- });
- });
-
- describe('timing', () => {
- test('warm phase shows timing only when enabled', async () => {
- const { actions } = testBed;
- expect(actions.warm.hasMinAgeInput()).toBeFalsy();
- await actions.warm.enable(true);
- expect(actions.warm.hasMinAgeInput()).toBeTruthy();
- });
-
- test('cold phase shows timing only when enabled', async () => {
- const { actions } = testBed;
- expect(actions.cold.hasMinAgeInput()).toBeFalsy();
- await actions.cold.enable(true);
- expect(actions.cold.hasMinAgeInput()).toBeTruthy();
- });
-
- test('delete phase shows timing after it was enabled', async () => {
- const { actions } = testBed;
- expect(actions.delete.hasMinAgeInput()).toBeFalsy();
- await actions.delete.enablePhase();
- expect(actions.delete.hasMinAgeInput()).toBeTruthy();
- });
- });
-
- describe('delete phase', () => {
- test('is hidden when disabled', async () => {
- const { actions } = testBed;
- expect(actions.delete.isShown()).toBeFalsy();
- await actions.delete.enablePhase();
- expect(actions.delete.isShown()).toBeTruthy();
- });
- });
-
- describe('json in flyout', () => {
- test('renders a json in flyout for a default policy', async () => {
- const { find, component } = testBed;
- await act(async () => {
- find('requestButton').simulate('click');
- });
- component.update();
-
- const json = component.find(`code`).text();
- const expected = `PUT _ilm/policy/my_policy\n${JSON.stringify(
- {
- policy: {
- phases: {
- hot: {
- min_age: '0ms',
- actions: {
- rollover: {
- max_age: '30d',
- max_size: '50gb',
- },
- },
- },
- },
- },
- },
- null,
- 2
- )}`;
- expect(json).toBe(expected);
- });
- });
-});
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts
new file mode 100644
index 0000000000000..61ceab1990c72
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts
@@ -0,0 +1,426 @@
+/*
+ * 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 { setupEnvironment } from '../../helpers/setup_environment';
+import {
+ getDefaultHotPhasePolicy,
+ POLICY_WITH_INCLUDE_EXCLUDE,
+ POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS,
+} from '../constants';
+import { EditPolicyTestBed, setup } from '../edit_policy.helpers';
+
+describe(' serialization', () => {
+ let testBed: EditPolicyTestBed;
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ describe('top level form', () => {
+ /**
+ * We assume that policies that populate this form are loaded directly from ES and so
+ * are valid according to ES. There may be settings in the policy created through the ILM
+ * API that the UI does not cater for, like the unfollow action. We do not want to overwrite
+ * the configuration for these actions in the UI.
+ */
+ it('preserves policy settings it did not configure', async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS]);
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component, actions } = testBed;
+ component.update();
+
+ // Set max docs to test whether we keep the unknown fields in that object after serializing
+ await actions.hot.setMaxDocs('1000');
+ // Remove the delete phase to ensure that we also correctly remove data
+ await actions.delete.disablePhase();
+ await actions.savePolicy();
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+
+ expect(entirePolicy).toEqual({
+ foo: 'bar', // Made up value
+ name: 'my_policy',
+ phases: {
+ hot: {
+ actions: {
+ rollover: {
+ max_docs: 1000,
+ max_size: '50gb',
+ unknown_setting: 123, // Made up setting that should stay preserved
+ },
+ },
+ min_age: '0ms',
+ },
+ warm: {
+ actions: {
+ my_unfollow_action: {}, // Made up action
+ set_priority: {
+ priority: 22,
+ unknown_setting: true,
+ },
+ },
+ min_age: '0d',
+ },
+ },
+ });
+ });
+ });
+
+ describe('hot phase', () => {
+ test('setting all values', async () => {
+ const { actions } = testBed;
+
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.setMaxSize('123', 'mb');
+ await actions.hot.setMaxDocs('123');
+ await actions.hot.setMaxAge('123', 'h');
+ await actions.hot.toggleForceMerge(true);
+ await actions.hot.setForcemergeSegmentsCount('123');
+ await actions.hot.setBestCompression(true);
+ await actions.hot.toggleShrink(true);
+ await actions.hot.setShrink('2');
+ await actions.hot.toggleReadonly(true);
+ await actions.hot.toggleIndexPriority(true);
+ await actions.hot.setIndexPriority('123');
+
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(entirePolicy).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "forcemerge": Object {
+ "index_codec": "best_compression",
+ "max_num_segments": 123,
+ },
+ "readonly": Object {},
+ "rollover": Object {
+ "max_age": "123h",
+ "max_docs": 123,
+ "max_size": "123mb",
+ },
+ "set_priority": Object {
+ "priority": 123,
+ },
+ "shrink": Object {
+ "number_of_shards": 2,
+ },
+ },
+ "min_age": "0ms",
+ },
+ },
+ }
+ `);
+ });
+
+ test('setting searchable snapshot', async () => {
+ const { actions } = testBed;
+
+ await actions.hot.setSearchableSnapshot('my-repo');
+
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(entirePolicy.phases.hot.actions.searchable_snapshot.snapshot_repository).toBe(
+ 'my-repo'
+ );
+ });
+
+ test('disabling rollover', async () => {
+ const { actions } = testBed;
+ await actions.hot.toggleDefaultRollover(false);
+ await actions.hot.toggleRollover(false);
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ const hotActions = policy.phases.hot.actions;
+ const rolloverAction = hotActions.rollover;
+ expect(rolloverAction).toBe(undefined);
+ expect(hotActions).toMatchInlineSnapshot(`Object {}`);
+ });
+ });
+
+ describe('warm phase', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('default values', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable(true);
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
+ expect(warmPhase).toMatchInlineSnapshot(`
+ Object {
+ "actions": Object {
+ "set_priority": Object {
+ "priority": 50,
+ },
+ },
+ "min_age": "0d",
+ }
+ `);
+ });
+
+ test('setting all values', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable(true);
+ await actions.warm.setDataAllocation('node_attrs');
+ await actions.warm.setSelectedNodeAttribute('test:123');
+ await actions.warm.setReplicas('123');
+ await actions.warm.toggleShrink(true);
+ await actions.warm.setShrink('123');
+ await actions.warm.toggleForceMerge(true);
+ await actions.warm.setForcemergeSegmentsCount('123');
+ await actions.warm.setBestCompression(true);
+ await actions.warm.toggleReadonly(true);
+ await actions.warm.setIndexPriority('123');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ // Check shape of entire policy
+ expect(entirePolicy).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ },
+ "min_age": "0ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "allocate": Object {
+ "number_of_replicas": 123,
+ "require": Object {
+ "test": "123",
+ },
+ },
+ "forcemerge": Object {
+ "index_codec": "best_compression",
+ "max_num_segments": 123,
+ },
+ "readonly": Object {},
+ "set_priority": Object {
+ "priority": 123,
+ },
+ "shrink": Object {
+ "number_of_shards": 123,
+ },
+ },
+ "min_age": "0d",
+ },
+ },
+ }
+ `);
+ });
+
+ describe('policy with include and exclude', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_INCLUDE_EXCLUDE]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('preserves include, exclude allocation settings', async () => {
+ const { actions } = testBed;
+ await actions.warm.setDataAllocation('node_attrs');
+ await actions.warm.setSelectedNodeAttribute('test:123');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const warmPhaseAllocate = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
+ .actions.allocate;
+ expect(warmPhaseAllocate).toMatchInlineSnapshot(`
+ Object {
+ "exclude": Object {
+ "def": "456",
+ },
+ "include": Object {
+ "abc": "123",
+ },
+ "require": Object {
+ "test": "123",
+ },
+ }
+ `);
+ });
+ });
+ });
+
+ describe('cold phase', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('default values', async () => {
+ const { actions } = testBed;
+
+ await actions.cold.enable(true);
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(entirePolicy.phases.cold).toMatchInlineSnapshot(`
+ Object {
+ "actions": Object {
+ "set_priority": Object {
+ "priority": 0,
+ },
+ },
+ "min_age": "0d",
+ }
+ `);
+ });
+
+ test('setting all values, excluding searchable snapshot', async () => {
+ const { actions } = testBed;
+
+ await actions.cold.enable(true);
+ await actions.cold.setMinAgeValue('123');
+ await actions.cold.setMinAgeUnits('s');
+ await actions.cold.setDataAllocation('node_attrs');
+ await actions.cold.setSelectedNodeAttribute('test:123');
+ await actions.cold.setReplicas('123');
+ await actions.cold.setFreeze(true);
+ await actions.cold.setIndexPriority('123');
+
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+
+ expect(entirePolicy).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "cold": Object {
+ "actions": Object {
+ "allocate": Object {
+ "number_of_replicas": 123,
+ "require": Object {
+ "test": "123",
+ },
+ },
+ "freeze": Object {},
+ "set_priority": Object {
+ "priority": 123,
+ },
+ },
+ "min_age": "123s",
+ },
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ },
+ "min_age": "0ms",
+ },
+ },
+ }
+ `);
+ });
+
+ // Setting searchable snapshot field disables setting replicas so we test this separately
+ test('setting searchable snapshot', async () => {
+ const { actions } = testBed;
+ await actions.cold.enable(true);
+ await actions.cold.setSearchableSnapshot('my-repo');
+ await actions.savePolicy();
+ const latestRequest2 = server.requests[server.requests.length - 1];
+ const entirePolicy2 = JSON.parse(JSON.parse(latestRequest2.requestBody).body);
+ expect(entirePolicy2.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual(
+ 'my-repo'
+ );
+ });
+ });
+
+ test('delete phase', async () => {
+ const { actions } = testBed;
+ await actions.delete.enablePhase();
+ await actions.setWaitForSnapshotPolicy('test');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(entirePolicy.phases.delete).toEqual({
+ min_age: '365d',
+ actions: {
+ delete: {},
+ wait_for_snapshot: {
+ policy: 'test',
+ },
+ },
+ });
+ });
+});