2024-06-27 15:32:58 +05:30
|
|
|
/*
|
|
|
|
* 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 from '@playwright/test';
|
|
|
|
import { get } from 'lodash';
|
2024-08-10 14:31:14 +05:30
|
|
|
import { ApiEndpointClass } from '../../support/entity/ApiEndpointClass';
|
2024-06-27 15:32:58 +05:30
|
|
|
import { ContainerClass } from '../../support/entity/ContainerClass';
|
|
|
|
import { DashboardClass } from '../../support/entity/DashboardClass';
|
2024-09-15 23:06:31 -07:00
|
|
|
import { MetricClass } from '../../support/entity/MetricClass';
|
2024-06-27 15:32:58 +05:30
|
|
|
import { MlModelClass } from '../../support/entity/MlModelClass';
|
|
|
|
import { PipelineClass } from '../../support/entity/PipelineClass';
|
|
|
|
import { SearchIndexClass } from '../../support/entity/SearchIndexClass';
|
|
|
|
import { TableClass } from '../../support/entity/TableClass';
|
|
|
|
import { TopicClass } from '../../support/entity/TopicClass';
|
|
|
|
import {
|
|
|
|
createNewPage,
|
|
|
|
getApiContext,
|
|
|
|
redirectToHomePage,
|
|
|
|
} from '../../utils/common';
|
|
|
|
import {
|
|
|
|
activateColumnLayer,
|
|
|
|
addColumnLineage,
|
|
|
|
addPipelineBetweenNodes,
|
2024-07-09 15:33:28 +05:30
|
|
|
applyPipelineFromModal,
|
2024-06-27 15:32:58 +05:30
|
|
|
connectEdgeBetweenNodes,
|
|
|
|
deleteEdge,
|
|
|
|
deleteNode,
|
2024-09-30 10:54:39 +05:30
|
|
|
editLineage,
|
2024-06-27 15:32:58 +05:30
|
|
|
performZoomOut,
|
|
|
|
removeColumnLineage,
|
|
|
|
setupEntitiesForLineage,
|
|
|
|
verifyColumnLayerInactive,
|
|
|
|
verifyNodePresent,
|
2024-07-09 15:33:28 +05:30
|
|
|
visitLineageTab,
|
2024-06-27 15:32:58 +05:30
|
|
|
} from '../../utils/lineage';
|
|
|
|
|
|
|
|
// use the admin user to login
|
|
|
|
test.use({ storageState: 'playwright/.auth/admin.json' });
|
|
|
|
|
|
|
|
const entities = [
|
|
|
|
TableClass,
|
|
|
|
DashboardClass,
|
|
|
|
TopicClass,
|
|
|
|
MlModelClass,
|
|
|
|
ContainerClass,
|
|
|
|
SearchIndexClass,
|
2024-09-30 10:54:39 +05:30
|
|
|
ApiEndpointClass,
|
2024-09-15 23:06:31 -07:00
|
|
|
MetricClass,
|
2024-06-27 15:32:58 +05:30
|
|
|
] as const;
|
|
|
|
|
2024-07-09 15:33:28 +05:30
|
|
|
const pipeline = new PipelineClass();
|
|
|
|
|
|
|
|
test.beforeAll('Setup pre-requests', async ({ browser }) => {
|
|
|
|
const { apiContext, afterAction } = await createNewPage(browser);
|
|
|
|
await pipeline.create(apiContext);
|
|
|
|
await afterAction();
|
|
|
|
});
|
|
|
|
|
|
|
|
test.afterAll('Cleanup', async ({ browser }) => {
|
|
|
|
const { apiContext, afterAction } = await createNewPage(browser);
|
|
|
|
await pipeline.delete(apiContext);
|
|
|
|
await afterAction();
|
|
|
|
});
|
|
|
|
|
2024-06-27 15:32:58 +05:30
|
|
|
for (const EntityClass of entities) {
|
|
|
|
const defaultEntity = new EntityClass();
|
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
test(`Lineage creation from ${defaultEntity.getType()} entity`, async ({
|
|
|
|
browser,
|
|
|
|
}) => {
|
|
|
|
test.slow(true);
|
|
|
|
|
|
|
|
const { page } = await createNewPage(browser);
|
|
|
|
const { currentEntity, entities, cleanup } = await setupEntitiesForLineage(
|
|
|
|
page,
|
|
|
|
defaultEntity
|
|
|
|
);
|
|
|
|
|
|
|
|
await test.step('Should create lineage for the entity', async () => {
|
|
|
|
await redirectToHomePage(page);
|
|
|
|
await currentEntity.visitEntityPage(page);
|
|
|
|
await visitLineageTab(page);
|
|
|
|
await verifyColumnLayerInactive(page);
|
|
|
|
await editLineage(page);
|
|
|
|
await performZoomOut(page);
|
|
|
|
for (const entity of entities) {
|
|
|
|
await connectEdgeBetweenNodes(page, currentEntity, entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
await redirectToHomePage(page);
|
|
|
|
await currentEntity.visitEntityPage(page);
|
|
|
|
await visitLineageTab(page);
|
|
|
|
await page
|
|
|
|
.locator('.react-flow__controls-fitview')
|
|
|
|
.dispatchEvent('click');
|
|
|
|
|
|
|
|
for (const entity of entities) {
|
|
|
|
await verifyNodePresent(page, entity);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await test.step('Should create pipeline between entities', async () => {
|
|
|
|
await editLineage(page);
|
|
|
|
await performZoomOut(page);
|
|
|
|
|
|
|
|
for (const entity of entities) {
|
|
|
|
await applyPipelineFromModal(page, currentEntity, entity, pipeline);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await test.step('Remove lineage between nodes for the entity', async () => {
|
|
|
|
await redirectToHomePage(page);
|
|
|
|
await currentEntity.visitEntityPage(page);
|
|
|
|
await visitLineageTab(page);
|
|
|
|
await editLineage(page);
|
|
|
|
await performZoomOut(page);
|
|
|
|
|
|
|
|
for (const entity of entities) {
|
|
|
|
await deleteEdge(page, currentEntity, entity);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await cleanup();
|
|
|
|
});
|
2024-06-27 15:32:58 +05:30
|
|
|
}
|
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
test('Verify column lineage between tables', async ({ browser }) => {
|
2024-06-27 15:32:58 +05:30
|
|
|
const { page } = await createNewPage(browser);
|
|
|
|
const { apiContext, afterAction } = await getApiContext(page);
|
|
|
|
const table1 = new TableClass();
|
|
|
|
const table2 = new TableClass();
|
|
|
|
|
|
|
|
await table1.create(apiContext);
|
|
|
|
await table2.create(apiContext);
|
|
|
|
|
|
|
|
const sourceTableFqn = get(table1, 'entityResponseData.fullyQualifiedName');
|
|
|
|
const sourceCol = `${sourceTableFqn}.${get(
|
|
|
|
table1,
|
|
|
|
'entityResponseData.columns[0].name'
|
|
|
|
)}`;
|
|
|
|
|
|
|
|
const targetTableFqn = get(table2, 'entityResponseData.fullyQualifiedName');
|
|
|
|
const targetCol = `${targetTableFqn}.${get(
|
|
|
|
table2,
|
|
|
|
'entityResponseData.columns[0].name'
|
|
|
|
)}`;
|
|
|
|
|
|
|
|
await addPipelineBetweenNodes(page, table1, table2);
|
|
|
|
await activateColumnLayer(page);
|
|
|
|
|
|
|
|
// Add column lineage
|
|
|
|
await addColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
|
|
|
|
|
|
|
await removeColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
|
|
|
|
|
|
|
await deleteNode(page, table2);
|
|
|
|
await table1.delete(apiContext);
|
|
|
|
await table2.delete(apiContext);
|
|
|
|
|
|
|
|
await afterAction();
|
|
|
|
});
|
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
test('Verify column lineage between table and topic', async ({ browser }) => {
|
|
|
|
const { page } = await createNewPage(browser);
|
|
|
|
const { apiContext, afterAction } = await getApiContext(page);
|
|
|
|
const table = new TableClass();
|
|
|
|
const topic = new TopicClass();
|
|
|
|
await table.create(apiContext);
|
|
|
|
await topic.create(apiContext);
|
2024-06-27 15:32:58 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName');
|
|
|
|
const sourceCol = `${sourceTableFqn}.${get(
|
|
|
|
table,
|
|
|
|
'entityResponseData.columns[0].name'
|
|
|
|
)}`;
|
|
|
|
const targetCol = get(
|
|
|
|
topic,
|
|
|
|
'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName'
|
|
|
|
);
|
2024-06-27 15:32:58 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await addPipelineBetweenNodes(page, table, topic);
|
|
|
|
await activateColumnLayer(page);
|
2024-06-27 15:32:58 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
// Add column lineage
|
|
|
|
await addColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
2024-06-27 15:32:58 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await removeColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await deleteNode(page, topic);
|
|
|
|
await table.delete(apiContext);
|
|
|
|
await topic.delete(apiContext);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await afterAction();
|
|
|
|
});
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
test('Verify column lineage between topic and api endpoint', async ({
|
|
|
|
browser,
|
|
|
|
}) => {
|
|
|
|
const { page } = await createNewPage(browser);
|
|
|
|
const { apiContext, afterAction } = await getApiContext(page);
|
|
|
|
const topic = new TopicClass();
|
|
|
|
const apiEndpoint = new ApiEndpointClass();
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await topic.create(apiContext);
|
|
|
|
await apiEndpoint.create(apiContext);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
const sourceCol = get(
|
|
|
|
topic,
|
|
|
|
'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName'
|
|
|
|
);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
const targetCol = get(
|
|
|
|
apiEndpoint,
|
|
|
|
'entityResponseData.responseSchema.schemaFields[0].children[1].fullyQualifiedName'
|
|
|
|
);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await addPipelineBetweenNodes(page, topic, apiEndpoint);
|
|
|
|
await activateColumnLayer(page);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
// Add column lineage
|
|
|
|
await addColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await removeColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await deleteNode(page, apiEndpoint);
|
|
|
|
await topic.delete(apiContext);
|
|
|
|
await apiEndpoint.delete(apiContext);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await afterAction();
|
|
|
|
});
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
test('Verify column lineage between table and api endpoint', async ({
|
|
|
|
browser,
|
|
|
|
}) => {
|
|
|
|
const { page } = await createNewPage(browser);
|
|
|
|
const { apiContext, afterAction } = await getApiContext(page);
|
|
|
|
const table = new TableClass();
|
|
|
|
const apiEndpoint = new ApiEndpointClass();
|
|
|
|
await table.create(apiContext);
|
|
|
|
await apiEndpoint.create(apiContext);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName');
|
|
|
|
const sourceCol = `${sourceTableFqn}.${get(
|
|
|
|
table,
|
|
|
|
'entityResponseData.columns[0].name'
|
|
|
|
)}`;
|
|
|
|
const targetCol = get(
|
|
|
|
apiEndpoint,
|
|
|
|
'entityResponseData.responseSchema.schemaFields[0].children[0].fullyQualifiedName'
|
|
|
|
);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await addPipelineBetweenNodes(page, table, apiEndpoint);
|
|
|
|
await activateColumnLayer(page);
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
// Add column lineage
|
|
|
|
await addColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
2024-08-10 14:31:14 +05:30
|
|
|
|
2024-09-30 10:54:39 +05:30
|
|
|
await removeColumnLineage(page, sourceCol, targetCol);
|
|
|
|
await page.click('[data-testid="edit-lineage"]');
|
|
|
|
|
|
|
|
await deleteNode(page, apiEndpoint);
|
|
|
|
await table.delete(apiContext);
|
|
|
|
await apiEndpoint.delete(apiContext);
|
|
|
|
|
|
|
|
await afterAction();
|
|
|
|
});
|