Skip to content

Commit

Permalink
Refactor reindex page (#395)
Browse files Browse the repository at this point in the history
* Reindex operation

Signed-off-by: Hailong Cui <[email protected]>

* update integration test

Signed-off-by: Hailong Cui <[email protected]>

* feat: update unit test for shrink

Signed-off-by: suzhou <[email protected]>

* update integ test

Signed-off-by: Hailong Cui <[email protected]>

* update integ test

Signed-off-by: Hailong Cui <[email protected]>

* add more UT

Signed-off-by: Hailong Cui <[email protected]>

* refactor on reindex flyout

Signed-off-by: Hailong Cui <[email protected]>

* fix reindex integration case

Signed-off-by: Hailong Cui <[email protected]>

* fix UT

Signed-off-by: Hailong Cui <[email protected]>

* change reindex from flyout to page

Signed-off-by: Hailong Cui <[email protected]>

* add integration test for reindex page

Signed-off-by: Hailong Cui <[email protected]>

* add UT for reindex

Signed-off-by: Hailong Cui <[email protected]>

* create index flyout

Signed-off-by: Hailong Cui <[email protected]>

* Refractor: Implement fields & validation (#384)

* Refractor: Implement fields & validation

Signed-off-by: suzhou <[email protected]>

* feat: update unit test

Signed-off-by: suzhou <[email protected]>

* Feature: bump opensearch version to 2.5.0

Signed-off-by: suzhou <[email protected]>

* Feature: update other version

Signed-off-by: suzhou <[email protected]>

* feat: use 2.4 version to run e2e test

Signed-off-by: suzhou <[email protected]>

* feat: add wait

Signed-off-by: suzhou <[email protected]>

* feat: update E2E test

Signed-off-by: suzhou <[email protected]>

Signed-off-by: suzhou <[email protected]>

* feat: modify ref pointer

Signed-off-by: suzhou <[email protected]>

* feat: update reIndex

Signed-off-by: suzhou <[email protected]>

* create index flyout

Signed-off-by: Hailong Cui <[email protected]>

* add UT for reindex action

Signed-off-by: Hailong Cui <[email protected]>

* feat: enable import settings & mappings

Signed-off-by: suzhou <[email protected]>

* feat: update unit test

Signed-off-by: suzhou <[email protected]>

* feat: update reIndex

Signed-off-by: suzhou <[email protected]>

* feat: enable import settings & mappings

Signed-off-by: suzhou <[email protected]>

* feat: update unit test

Signed-off-by: suzhou <[email protected]>

* expand aliases and data streams for import mapping and settings

Signed-off-by: Hailong Cui <[email protected]>

* feat: update ref problem

Signed-off-by: suzhou <[email protected]>

* rename button name to Reindex

Signed-off-by: Hailong Cui <[email protected]>

* fix integration test

Signed-off-by: Hailong Cui <[email protected]>

* fix auto populate source index from search query

Signed-off-by: Hailong Cui <[email protected]>

* feat: add unit test & optimize interface

Signed-off-by: suzhou <[email protected]>

* feat: update

Signed-off-by: suzhou <[email protected]>

* feat: update e2e test

Signed-off-by: suzhou <[email protected]>

* remove duplicate class ReindexRequest/ReindexResponse

Signed-off-by: Hailong Cui <[email protected]>

Signed-off-by: Hailong Cui <[email protected]>
Signed-off-by: suzhou <[email protected]>
Co-authored-by: suzhou <[email protected]>
  • Loading branch information
Hailong-am and SuZhou-Joe authored Nov 24, 2022
1 parent 7560eb0 commit 8c61ffb
Show file tree
Hide file tree
Showing 50 changed files with 3,892 additions and 1,829 deletions.
97 changes: 19 additions & 78 deletions cypress/integration/indices_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import samplePolicy from "../fixtures/sample_policy";

const POLICY_ID = "test_policy_id";
const SAMPLE_INDEX = "sample_index";
const REINDEX_DEST = "index-reindex-01";

describe("Indices", () => {
beforeEach(() => {
Expand Down Expand Up @@ -243,18 +242,13 @@ describe("Indices", () => {
});

cy.request({
method: "DELETE",
url: `${Cypress.env("opensearch")}/${reindexedIndex}`,
failOnStatusCode: false,
});
cy.request({
method: "DELETE",
url: `${Cypress.env("opensearch")}/${splittedIndex}`,
method: "PUT",
url: `${Cypress.env("opensearch")}/${splittedIndex}/_settings`,
body: {
"index.blocks.read_only": false,
},
failOnStatusCode: false,
});
});

after(() => {
cy.request({
method: "DELETE",
url: `${Cypress.env("opensearch")}/${reindexedIndex}`,
Expand Down Expand Up @@ -321,6 +315,19 @@ describe("Indices", () => {

cy.get('[placeholder="Search"]').type("p");
});

after(() => {
cy.request({
method: "DELETE",
url: `${Cypress.env("opensearch")}/${reindexedIndex}`,
failOnStatusCode: false,
});
cy.request({
method: "DELETE",
url: `${Cypress.env("opensearch")}/${splittedIndex}`,
failOnStatusCode: false,
});
});
});

describe("can shrink an index", () => {
Expand All @@ -335,6 +342,7 @@ describe("Indices", () => {
// Type in SAMPLE_INDEX in search input
cy.get(`input[type="search"]`).focus().type(SAMPLE_INDEX);

cy.wait(1000).get(".euiTableRow").should("have.length", 1);
// Confirm we have our initial index
cy.contains(SAMPLE_INDEX);

Expand Down Expand Up @@ -437,71 +445,4 @@ describe("Indices", () => {
});
});
});

describe("can perform reindex", () => {
before(() => {
cy.deleteAllIndices();
// Load ecommerce data
cy.request({
method: "POST",
url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`,
headers: {
"osd-xsrf": true,
},
}).then((response) => {
expect(response.status).equal(200);
});
cy.createIndex(SAMPLE_INDEX);
});

it("successfully", () => {
// Confirm we have our initial index
cy.contains(SAMPLE_INDEX);

// Click actions button
cy.get('[data-test-subj="More Action"]').click();

// Delete btn should be disabled if no items selected
cy.get('[data-test-subj="Reindex Action"]').should("have.class", "euiContextMenuItem-isDisabled");

// click any where to hide actions
cy.get("#_selection_column_opensearch_dashboards_sample_data_ecommerce-checkbox").click();
cy.get('[data-test-subj="Reindex Action"]').should("not.exist");

// Click actions button
cy.get('[data-test-subj="More Action"]').click();
// Delete btn should be enabled
cy.get('[data-test-subj="Reindex Action"]').should("exist").should("not.have.class", "euiContextMenuItem-isDisabled").click();

// source index populated
cy.get('[data-test-subj="sourceIndicesComboInput"] .euiBadge__text').contains("opensearch_dashboards_sample_data_ecommerce");

cy.get(`div[data-test-subj="destIndicesComboInput"]`)
.find(`input[data-test-subj="comboBoxSearchInput"]`)
.type(`${REINDEX_DEST}{enter}`);

// dest index settings show up
cy.get('div[data-test-subj="destSettingJsonEditor"]').should("exist");

// input query to reindex subset
cy.get('[data-test-subj="queryJsonEditor"] textarea')
.focus()
.clear()
.type('{"query":{"match":{"category":"Men\'s Clothing"}}}', { parseSpecialCharSequences: false });

// click to perform reindex
cy.get('[data-test-subj="flyout-footer-action-button"]').click();
cy.wait(20);
cy.contains(/Reindex .* success .* taskId .*/);

// Type in REINDEX_DEST in search input
cy.get(`input[type="search"]`).focus().type(REINDEX_DEST);

// Confirm we only see REINDEX_DEST in table
cy.get("tbody > tr").should(($tr) => {
expect($tr, "1 row").to.have.length(1);
expect($tr, "item").to.contain(REINDEX_DEST);
});
});
});
});
147 changes: 147 additions & 0 deletions cypress/integration/reindex_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { PLUGIN_NAME } from "../support/constants";
const REINDEX_DEST = "test-ecomm-rdx";
const REINDEX_DEST_NO_SOURCE = "test-reindex-nosource";

describe("Reindex", () => {
beforeEach(() => {
// Set welcome screen tracking to false
localStorage.setItem("home:welcome:show", "false");

// Visit ISM OSD
cy.visit(`${Cypress.env("opensearch_dashboards")}/app/${PLUGIN_NAME}#/indices`);

// Common text to wait for to confirm page loaded, give up to 60 seconds for initial load
cy.contains("Rows per page", { timeout: 60000 });
});

describe("Reindex validation error", () => {
before(() => {
cy.deleteAllIndices();
// Load ecommerce data
cy.request({
method: "POST",
url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`,
headers: {
"osd-xsrf": true,
},
}).then((response) => {
expect(response.status).equal(200);
});

cy.createIndex(REINDEX_DEST_NO_SOURCE, null, {
mappings: {
_source: {
enabled: false,
},
properties: {
name: {
type: "keyword",
},
},
},
});
});

it("source validation failed", () => {
// Confirm we have our initial index
cy.contains(REINDEX_DEST_NO_SOURCE);

cy.get(`[data-test-subj="checkboxSelectRow-${REINDEX_DEST_NO_SOURCE}"]`).check({ force: true });

// Click actions button
cy.get('[data-test-subj="More Action"]').click();
// Reindex should show as activate
cy.get('[data-test-subj="Reindex Action"]').should("exist").should("not.have.class", "euiContextMenuItem-isDisabled").click();

cy.contains(/_sources is not enabled/);
});
});

describe("Reindex successfully", () => {
before(() => {
cy.deleteAllIndices();
// Load ecommerce data
cy.request({
method: "POST",
url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`,
headers: {
"osd-xsrf": true,
},
}).then((response) => {
expect(response.status).equal(200);
});

cy.createIndex(REINDEX_DEST, null, { settings: { "index.number_of_replicas": 0 } });

cy.createPipeline("bumpOrderId", {
description: "sample description",
processors: [
{
set: {
field: "order_id",
value: "200{{order_id}}",
},
},
],
});
});

it("successfully", () => {
// Confirm we have our initial index
cy.contains("opensearch_dashboards_sample_data_ecommerce");

// Click actions button
cy.get('[data-test-subj="More Action"]').click();
// Reindex should show as activate
cy.get('[data-test-subj="Reindex Action"]').should("exist").should("not.have.class", "euiContextMenuItem-isDisabled").click();

cy.get(`div[data-test-subj="sourceSelector"]`)
.find(`input[data-test-subj="comboBoxSearchInput"]`)
.type(`opensearch_dashboards_sample_data_ecommerce{downArrow}{enter}`);

cy.get(`div[data-test-subj="destinationSelector"]`)
.find(`input[data-test-subj="comboBoxSearchInput"]`)
.type(`${REINDEX_DEST}{downArrow}{enter}`);

// open advance option
cy.get('[data-test-subj="advanceOptionToggle"]').click();

// enable subset query
cy.get('[data-test-subj="subsetOption"] #subset').click({ force: true });

// input query to reindex subset
cy.get('[data-test-subj="queryJsonEditor"] textarea')
.focus()
.clear()
.type('{"query":{"match":{"category":"Men\'s Clothing"}}}', { parseSpecialCharSequences: false });

// set slices to auto
cy.get('[data-test-subj="slices"]').clear().type("auto");

// input pipeline
cy.get(`div[data-test-subj="pipelineCombobox"]`).find(`input[data-test-subj="comboBoxSearchInput"]`).type("bumpOrderId{enter}");

// click to perform reindex
cy.get('[data-test-subj="reindexConfirmButton"]').click();
cy.wait(10);
cy.contains(/Reindex .* success .* taskId .*/);

cy.wait(10000);
// Type in REINDEX_DEST in search input
cy.get(`input[type="search"]`).focus().type(REINDEX_DEST);

// Confirm we only see REINDEX_DEST in table
cy.get("tbody > tr").should(($tr) => {
expect($tr, "1 row").to.have.length(1);
expect($tr, "item").to.contain(REINDEX_DEST);
// subset data number
expect($tr, "item").to.contain(4213);
});
});
});
});
4 changes: 4 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Cypress.Commands.add("createTransform", (transformId, transformJSON) => {
cy.request("PUT", `${Cypress.env("opensearch")}${API.TRANSFORM_JOBS_BASE}/${transformId}`, transformJSON);
});

Cypress.Commands.add("createPipeline", (pipelineId, pipelineJSON) => {
cy.request("PUT", `${Cypress.env("opensearch")}/_ingest/pipeline/${pipelineId}`, pipelineJSON);
});

Cypress.Commands.add("disableJitter", () => {
// Sets the jitter to 0 in the ISM plugin cluster settings
const jitterJson = {
Expand Down
7 changes: 7 additions & 0 deletions cypress/support/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,12 @@ declare namespace Cypress {
* cy.deleteTemplate("some_template")
*/
deleteTemplate(name: string);

/**
* Create a ingest pipeline
* @example
* cy.createPipeline("pipelineId", {"description": "sample description", "processors": []})
*/
createPipeline(pipelineId: string, pipeline: object);
}
}
17 changes: 13 additions & 4 deletions public/components/AdvancedSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from "react";
import React, { useCallback, useMemo, useRef } from "react";
import { EuiAccordion, EuiAccordionProps, EuiFormRow, EuiSpacer, EuiFormRowProps } from "@elastic/eui";
import JSONEditor, { JSONEditorProps } from "../JSONEditor";
import "./index.scss";
Expand All @@ -7,18 +7,20 @@ export interface IAdvancedSettingsProps {
rowProps?: Omit<EuiFormRowProps, "children">;
accordionProps?: EuiAccordionProps;
value?: Record<string, any>;
onChange?: (totalValue: IAdvancedSettingsProps["value"], key?: string, value?: any) => void;
onChange?: (totalValue: IAdvancedSettingsProps["value"]) => void;
renderProps?: (options: Pick<Required<IAdvancedSettingsProps>, "value" | "onChange">) => React.ReactChild;
editorProps?: Partial<JSONEditorProps>;
}

export default function AdvancedSettings(props: IAdvancedSettingsProps) {
const { value, renderProps, editorProps } = props;
const propsRef = useRef<IAdvancedSettingsProps>(props);
propsRef.current = props;

const onChangeInRenderProps = useCallback(
(val: string) => {
const parsedValue = JSON.parse(val);
props.onChange && props.onChange(parsedValue, undefined, parsedValue);
propsRef.current.onChange && propsRef.current.onChange(parsedValue);
},
[props.onChange]
);
Expand All @@ -33,7 +35,14 @@ export default function AdvancedSettings(props: IAdvancedSettingsProps) {
<EuiAccordion {...props.accordionProps} className="accordion-in-advanced-settings" id={accordionId}>
<EuiFormRow {...(props.rowProps as EuiFormRowProps)}>
{renderProps ? (
(renderProps({ value: value || {}, onChange: props.onChange || (() => null) }) as any)
(renderProps({
value: propsRef.current.value || {},
onChange: (val) => {
if (propsRef.current?.onChange) {
propsRef.current?.onChange(val);
}
},
}) as any)
) : (
<JSONEditor {...editorProps} value={JSON.stringify(value, null, 2)} onChange={onChangeInRenderProps} />
)}
Expand Down
2 changes: 1 addition & 1 deletion public/components/FormGenerator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export default forwardRef(function FormGenerator(props: IFormGeneratorProps, ref
...field.getValues(),
...val,
};
props.onChange && props.onChange(totalValue, undefined, val);
propsRef.current.onChange && propsRef.current.onChange(totalValue, undefined, val);
}}
/>
) : null}
Expand Down
30 changes: 30 additions & 0 deletions public/components/Toast/Toast.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { waitFor } from "@testing-library/react";
import { act } from "react-dom/test-utils";
import { SimpleEuiToast } from "./index";

describe("SimpleEuiToast show", () => {
it("render the component", async () => {
await act(async () => {
SimpleEuiToast.addSuccess("Success information");
});
expect(document.body).toMatchSnapshot();
expect(document.querySelector('[data-test-subj="toast_Success information"]')).not.toBeNull();
await act(async () => {
SimpleEuiToast.addDanger("Error information");
});
expect(document.querySelector('[data-test-subj="toast_Error information"]')).not.toBeNull();
await act(async () => {
SimpleEuiToast.show({
toastLifeTimeMs: 10,
title: "Test quick destroy",
});
});
await waitFor(() => {
expect(document.querySelector('[data-test-subj="toast_Test quick destroy"]')).toBeNull();
});
});
});
Loading

0 comments on commit 8c61ffb

Please sign in to comment.