/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import React from "react"; import "@testing-library/jest-dom/extend-expect"; import { render, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { browserServicesMock, coreServicesMock } from "../../../../../test/mocks"; import DataStreamsActions, { DataStreamsActionsProps } from "./index"; import { ServicesContext } from "../../../../services"; import { CoreServicesContext } from "../../../../components/core_services"; import { Route, HashRouter as Router, Switch, Redirect } from "react-router-dom"; import { ROUTES } from "../../../../utils/constants"; import { buildMockApiCallerForFlush, selectedDataStreams } from "../../../../containers/FlushIndexModal/FlushIndexModalTestHelper"; const historyPushMock = jest.fn(); function renderWithRouter(props: Omit) { return { ...render( ( { routeProps.history.push(...args); historyPushMock(...args); }, }} /> )} /> ), }; } describe(" spec", () => { it("renders the component and all the actions should be disabled when no items selected", async () => { const { container, getByTestId } = renderWithRouter({ selectedItems: [], onDelete: () => null, }); await waitFor(() => { expect(container.firstChild).toMatchSnapshot(); }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); await waitFor(() => { expect(getByTestId("deleteAction")).toBeDisabled(); }); }); it("delete data streams by calling commonService", async () => { const onDelete = jest.fn(); browserServicesMock.commonService.apiCaller = jest.fn( async (): Promise => { return { ok: true, response: {} }; } ); const { container, getByTestId, getByPlaceholderText } = renderWithRouter({ selectedItems: [{ name: "test_data_stream" }], onDelete, }); await waitFor(() => { expect(container.firstChild).toMatchSnapshot(); }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("deleteAction")); userEvent.type(getByPlaceholderText("delete"), "delete"); userEvent.click(getByTestId("deleteConfirmButton")); await waitFor(() => { expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledTimes(1); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "transport.request", data: { path: `/_data_stream/test_data_stream`, method: "DELETE", }, }); expect(onDelete).toHaveBeenCalledTimes(1); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledTimes(1); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith("Delete [test_data_stream] successfully"); }); }, 30000); it("clear cache for data streams by calling commonService", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { switch (payload.endpoint) { case "cluster.state": return { ok: true, response: { blocks: {}, }, }; default: return { ok: true, response: {}, }; } } ); const { container, getByTestId, getByText } = renderWithRouter({ selectedItems: [ { name: "test_data_stream", indices: [ { index_name: ".ds-test_data_stream-000001", }, { index_name: ".ds-test_data_stream-000002", }, ], }, ], onDelete: () => {}, }); await waitFor(() => { expect(container.firstChild).toMatchSnapshot(); }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("ClearCacheAction")); await waitFor(() => { getByText("Cache will be cleared for the following data streams."); }); userEvent.click(getByTestId("ClearCacheConfirmButton")); await waitFor(() => { expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledTimes(2); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "cluster.state", data: { metric: "blocks", }, }); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "indices.clearCache", data: { index: "test_data_stream", }, }); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledTimes(1); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Cache for test_data_stream has been successfully cleared." ); }); }); it("cannot clear cache for data streams if they are closed or blocked", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (): Promise => { return { ok: true, response: { blocks: { indices: { ".ds-test_data_stream_1-000001": { "4": { description: "index closed", retryable: false, levels: ["read", "write"], }, }, ".ds-test_data_stream_2-000001": { "5": { description: "index read-only (api)", retryable: false, levels: ["write", "metadata_write"], }, }, }, }, }, }; } ); const { container, getByTestId } = renderWithRouter({ selectedItems: [ { name: "test_data_stream_1", indices: [ { index_name: ".ds-test_data_stream_1-000001", index_uuid: "x", }, { index_name: ".ds-test_data_stream_1-000002", index_uuid: "y", }, ], }, { name: "test_data_stream_2", indices: [ { index_name: ".ds-test_data_stream_2-000001", index_uuid: "z", }, { index_name: ".ds-test_data_stream_2-000002", index_uuid: "c", }, ], }, ], onDelete: () => {}, }); await waitFor(() => { expect(container.firstChild).toMatchSnapshot(); }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("ClearCacheAction")); await waitFor(() => { expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledTimes(1); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "cluster.state", data: { metric: "blocks", }, }); expect(coreServicesMock.notifications.toasts.addDanger).toHaveBeenCalledTimes(1); expect(coreServicesMock.notifications.toasts.addDanger).toHaveBeenCalledWith({ title: "Unable to clear cache", text: "Cache cannot be cleared for the selected data streams because they are closed or blocked.", }); }); }); it("filter data streams failed when clearing caches for multiple data streams", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { switch (payload.endpoint) { case "cluster.state": return { ok: true, error: "test failure", }; default: return { ok: true, response: {}, }; } } ); const { container, getByTestId, getByText } = renderWithRouter({ selectedItems: [ { name: "test_data_stream1", indices: [ { index_name: ".ds-test_data_stream1-000001", }, { index_name: ".ds-test_data_stream1-000002", }, ], }, { name: "test_data_stream2", indices: [ { index_name: ".ds-test_data_stream2-000001", }, { index_name: ".ds-test_data_stream2-000002", }, ], }, ], onDelete: () => {}, }); await waitFor(() => { expect(container.firstChild).toMatchSnapshot(); }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("ClearCacheAction")); await waitFor(() => { getByText("Cache will be cleared for the following data streams."); }); userEvent.click(getByTestId("ClearCacheConfirmButton")); await waitFor(() => { expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledTimes(2); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "cluster.state", data: { metric: "blocks", }, }); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "indices.clearCache", data: { index: "test_data_stream1,test_data_stream2", }, }); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledTimes(1); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Cache for 2 data streams [test_data_stream1, test_data_stream2] have been successfully cleared." ); }); }); it("renders flush component", async () => { browserServicesMock.commonService.apiCaller = buildMockApiCallerForFlush(); const { getByTestId, getByText, queryByTestId } = render( ( { routeProps.history.push(...args); historyPushMock(...args); }, }} /> )} /> ); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("Flush Action")); await waitFor(() => { expect(queryByTestId("Flush Action")).toBeNull(); expect(getByText("The following data streams will be flushed:")).toBeInTheDocument(); expect(document.body.children).toMatchSnapshot(); }); }); it("flush all data streams disabled", async () => { browserServicesMock.commonService.apiCaller = buildMockApiCallerForFlush(); const { getByTestId } = render( ( { routeProps.history.push(...args); historyPushMock(...args); }, }} /> )} /> ); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); expect(getByTestId("Flush Action")).toBeDisabled(); }); it("refresh data streams by calling commonService", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { if (payload.endpoint === "cluster.state") { return { ok: true, response: { blocks: { indices: { ".ds-blocked-000001": { "4": {}, }, }, }, }, }; } else if (payload.endpoint === "indices.refresh") { return { ok: true, response: {}, }; } else if (payload.endpoint === "cat.indices") { return { ok: true, response: "red_index close\n", }; } } ); const { getByTestId, getByText, queryByTestId } = renderWithRouter({ selectedItems: [ { name: "unblocked_data_stream", indices: [ { index_name: ".ds-unblocked-000001", }, { index_name: ".ds-blocked-000002", }, ], }, { name: "blocked_data_stream", indices: [ { index_name: ".ds-blocked-000001", }, { index_name: ".ds-blocked-000002", }, ], }, ], }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("refreshAction")); await waitFor(() => { expect(queryByTestId("refreshAction")).toBeNull(); getByText("The following data stream will be refreshed."); expect(getByTestId("UnblockedItem-unblocked_data_stream")).not.toBeNull(); getByText( "The following data stream cannot be refreshed because each data stream has one or more indexes that are either closed or in red status." ); expect(getByTestId("BlockedItem-blocked_data_stream")).not.toBeNull(); expect(document.body).toMatchSnapshot(); }); userEvent.click(getByTestId("refreshConfirmButton")); await waitFor(() => { expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "cluster.state", data: { metric: "blocks", }, }); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "indices.refresh", data: { index: "unblocked_data_stream", }, }); expect(browserServicesMock.commonService.apiCaller).toHaveBeenCalledWith({ endpoint: "cat.indices", data: { h: "i,s", health: "red", }, }); expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "The data stream [unblocked_data_stream] has been successfully refreshed." ); }); }, 30000); it("refresh multiple data streams by calling commonService", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { if (payload.endpoint === "cluster.state") { return { ok: true, response: { blocks: { indices: { ".ds-blocked-000001": { "4": {}, }, ".ds-blocked1-000001": { "4": {}, }, }, }, }, }; } else if (payload.endpoint === "indices.refresh") { return { ok: true, response: {}, }; } else if (payload.endpoint === "cat.indices") { return { ok: true, response: ".ds-red-000001 close\n", }; } } ); const { getByTestId, getByText } = renderWithRouter({ selectedItems: [ { name: "unblocked_data_stream", indices: [ { index_name: ".ds-unblocked-000001", }, { index_name: ".ds-unblocked-000002", }, ], }, { name: "unblocked_data_stream1", indices: [ { index_name: ".ds-unblocked1-000001", }, { index_name: ".ds-unblocked1-000002", }, ], }, { name: "blocked_data_stream", indices: [ { index_name: ".ds-blocked-000001", }, { index_name: ".ds-blocked-000002", }, ], }, { name: "blocked_data_stream1", indices: [ { index_name: ".ds-blocked1-000001", }, { index_name: ".ds-blocked1-000002", }, ], }, { name: "red_data_stream", indices: [ { index_name: ".ds-red-000001", }, ], }, ], }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("refreshAction")); await waitFor(() => { getByText("The following data streams will be refreshed."); expect(getByTestId("UnblockedItem-unblocked_data_stream")).not.toBeNull(); expect(getByTestId("UnblockedItem-unblocked_data_stream1")).not.toBeNull(); expect(getByTestId("UnblockedItem-red_data_stream")).not.toBeNull(); getByText( "The following data streams cannot be refreshed because each data stream has one or more indexes that are either closed or in red status." ); expect(getByTestId("BlockedItem-blocked_data_stream")).not.toBeNull(); expect(getByTestId("BlockedItem-blocked_data_stream1")).not.toBeNull(); }); userEvent.click(getByTestId("refreshConfirmButton")); await waitFor(() => { expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "3 data streams [unblocked_data_stream, unblocked_data_stream1, red_data_stream] have been successfully refreshed." ); }); }, 30000); it("refresh data streams disabled because all indexes are closed calling commonService", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { if (payload.endpoint === "cluster.state") { return { ok: true, response: { blocks: { indices: { ".ds-blocked-000001": { "4": {}, }, }, }, }, }; } else if (payload.endpoint === "indices.refresh") { return { ok: true, response: {}, }; } else if (payload.endpoint === "cat.indices") { return { ok: true, response: ".ds-red-000001 open\n", }; } } ); const { getByTestId } = renderWithRouter({ selectedItems: [ { name: "blocked_data_stream", indices: [ { index_name: ".ds-blocked-000001", }, ], }, { name: "red_data_stream", indices: [ { index_name: ".ds-red-000001", }, ], }, ], }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("refreshAction")); await waitFor(() => { expect(coreServicesMock.notifications.toasts.addDanger).toHaveBeenCalledWith({ text: "All selected data streams cannot be refreshed because each data stream has one or more indexes that are either closed or in red status.", title: "Unable to refresh data streams.", }); }); }, 30000); it("refresh data streams even failed to get index status", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { if (payload.endpoint === "cluster.state") { throw "failed to call cluster.state"; } else if (payload.endpoint === "indices.refresh") { return { ok: true, response: {}, }; } else if (payload.endpoint === "cat.indices") { return { ok: true, response: "red_index close\n", }; } } ); const { getByTestId, getByText } = renderWithRouter({ selectedItems: [ { name: "blocked_data_stream", indices: [ { index_name: ".ds-blocked-000001", }, ], }, ], }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("refreshAction")); await waitFor(() => { getByText("The following data stream will be refreshed."); expect(getByTestId("UnblockedItem-blocked_data_stream")).not.toBeNull(); }); userEvent.click(getByTestId("refreshConfirmButton")); await waitFor(() => { expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "The data stream [blocked_data_stream] has been successfully refreshed." ); }); }, 30000); it("refresh multi data streams even failed to get index status", async () => { browserServicesMock.commonService.apiCaller = jest.fn( async (payload): Promise => { if (payload.endpoint === "cluster.state") { throw "failed to call cluster.state"; } else if (payload.endpoint === "indices.refresh") { return { ok: true, response: {}, }; } else if (payload.endpoint === "cat.indices") { return { ok: true, response: "red_index close\n", }; } } ); const { getByTestId, getByText } = renderWithRouter({ selectedItems: [ { name: "blocked_data_stream", indices: [ { index_name: ".ds-blocked-000001", }, ], }, { name: "blocked_data_stream1", indices: [ { index_name: ".ds-blocked1-000001", }, ], }, ], }); userEvent.click(document.querySelector('[data-test-subj="moreAction"] button') as Element); userEvent.click(getByTestId("refreshAction")); await waitFor(() => { getByText("The following data streams will be refreshed."); expect(getByTestId("UnblockedItem-blocked_data_stream")).not.toBeNull(); expect(getByTestId("UnblockedItem-blocked_data_stream1")).not.toBeNull(); }); userEvent.click(getByTestId("refreshConfirmButton")); await waitFor(() => { expect(coreServicesMock.notifications.toasts.addSuccess).toHaveBeenCalledWith( "2 data streams [blocked_data_stream, blocked_data_stream1] have been successfully refreshed." ); }); }, 30000); });