diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/settings.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/settings.ts index 801551040db..3d2b4cc6157 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/constant/settings.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/settings.ts @@ -66,6 +66,7 @@ export enum GlobalSettingOptions { APPLICATIONS = 'apps', OM_HEALTH = 'om-health', APPEARANCE = 'appearance', + DATA_OBSERVABILITY = 'dataObservability', } export const SETTINGS_OPTIONS_PATH = { @@ -103,6 +104,10 @@ export const SETTINGS_OPTIONS_PATH = { GlobalSettingsMenuCategory.SERVICES, `${GlobalSettingsMenuCategory.SERVICES}.${GlobalSettingOptions.METADATA}`, ], + [GlobalSettingOptions.DATA_OBSERVABILITY]: [ + GlobalSettingsMenuCategory.SERVICES, + `${GlobalSettingsMenuCategory.SERVICES}.${GlobalSettingOptions.DATA_OBSERVABILITY}`, + ], // Applications diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuitePipelineRedeploy.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuitePipelineRedeploy.spec.ts new file mode 100644 index 00000000000..660b2f7b5ae --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuitePipelineRedeploy.spec.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import test, { expect } from '@playwright/test'; +import { GlobalSettingOptions } from '../../constant/settings'; +import { TableClass } from '../../support/entity/TableClass'; +import { createNewPage, redirectToHomePage } from '../../utils/common'; +import { settingClick } from '../../utils/sidebar'; + +// use the admin user to login +test.use({ storageState: 'playwright/.auth/admin.json' }); + +const table1 = new TableClass(); +const table2 = new TableClass(); + +test.describe('Bulk Re-Deploy pipelines ', () => { + test.beforeAll('Setup pre-requests', async ({ browser }) => { + const { afterAction, apiContext } = await createNewPage(browser); + + await table1.create(apiContext); + await table2.create(apiContext); + + await table1.createTestSuiteAndPipelines(apiContext); + await table2.createTestSuiteAndPipelines(apiContext); + + await afterAction(); + }); + + test.afterAll('Clean up', async ({ browser }) => { + const { afterAction, apiContext } = await createNewPage(browser); + + await table1.delete(apiContext); + await table2.delete(apiContext); + + await afterAction(); + }); + + test.beforeEach('Visit home page', async ({ page }) => { + await redirectToHomePage(page); + }); + + test('Re-deploy all test-suite ingestion pipelines', async ({ page }) => { + await settingClick(page, GlobalSettingOptions.DATA_OBSERVABILITY); + + await expect( + page.getByRole('button', { name: 'Re Deploy' }) + ).not.toBeEnabled(); + await expect(page.locator('.ant-table-container')).toBeVisible(); + + await page.getByRole('checkbox').first().click(); + + await expect(page.getByRole('button', { name: 'Re Deploy' })).toBeEnabled(); + + await page.getByRole('button', { name: 'Re Deploy' }).click(); + + await expect( + page.getByText('Pipelines Re Deploy Successfully') + ).toBeVisible(); + }); + + // TODO: Add test to verify the re-deployed pipelines for Database, Dashboard and other entities +}); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts index 5425a8d5b3c..38f7167f0b5 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts @@ -158,6 +158,42 @@ export class TableClass extends EntityClass { }); } + async createTestSuiteAndPipelines(apiContext: APIRequestContext) { + if (!this.entityResponseData) { + return Promise.reject('Entity not created'); + } + + const testSuiteData = await apiContext + .post('/api/v1/dataQuality/testSuites/executable', { + data: { + name: `pw-test-suite-${uuid()}`, + executableEntityReference: + this.entityResponseData['fullyQualifiedName'], + description: 'Playwright test suite for table', + }, + }) + .then((res) => res.json()); + + await apiContext.post(`/api/v1/services/ingestionPipelines`, { + data: { + airflowConfig: {}, + name: `${this.entityResponseData['fullyQualifiedName']}_test_suite`, + pipelineType: 'TestSuite', + service: { + id: testSuiteData.id, + type: 'testSuite', + }, + sourceConfig: { + config: { + type: 'TestSuite', + entityFullyQualifiedName: + this.entityResponseData['fullyQualifiedName'], + }, + }, + }, + }); + } + async delete(apiContext: APIRequestContext) { const serviceResponse = await apiContext.delete( `/api/v1/services/databaseServices/name/${encodeURIComponent( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestionPipelineList.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestionPipelineList.component.tsx index f73456cbe6d..7c17e89e2ba 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestionPipelineList.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestionPipelineList.component.tsx @@ -18,6 +18,7 @@ import cronstrue from 'cronstrue'; import { isNil, map, startCase } from 'lodash'; import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { EntityType } from '../../../../../enums/entity.enum'; import { ServiceCategory } from '../../../../../enums/service.enum'; import { IngestionPipeline, @@ -48,8 +49,10 @@ import { IngestionRecentRuns } from '../IngestionRecentRun/IngestionRecentRuns.c export const IngestionPipelineList = ({ serviceName, + className, }: { - serviceName: ServiceCategory; + serviceName: ServiceCategory | 'testSuites'; + className?: string; }) => { const { theme } = useApplicationStore(); const [pipelines, setPipelines] = useState>(); @@ -192,7 +195,10 @@ export const IngestionPipelineList = ({ try { const { data, paging: pagingRes } = await getIngestionPipelines({ arrQueryFields: ['owner'], - serviceType: getEntityTypeFromServiceCategory(serviceName), + serviceType: + serviceName === 'testSuites' + ? EntityType.TEST_SUITE + : getEntityTypeFromServiceCategory(serviceName), paging, pipelineType, limit, @@ -250,7 +256,7 @@ export const IngestionPipelineList = ({ } return ( - +