dataProduct : get inherited fields from corresponding Domain (#19343)

* dataProduct : get inherited fields from corresponding Domain

* add tests

---------

Co-authored-by: karanh37 <karanh37@gmail.com>
This commit is contained in:
sonika-shah 2025-01-14 22:16:23 +05:30 committed by GitHub
parent 94cbadb772
commit 788dfc331f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 167 additions and 2 deletions

View File

@ -14,7 +14,9 @@
package org.openmetadata.service.jdbi3;
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
import static org.openmetadata.schema.type.Include.ALL;
import static org.openmetadata.service.Entity.DATA_PRODUCT;
import static org.openmetadata.service.Entity.DOMAIN;
import static org.openmetadata.service.Entity.FIELD_ASSETS;
import static org.openmetadata.service.util.EntityUtil.entityReferenceMatch;
@ -26,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jdbi.v3.sqlobject.transaction.Transaction;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.entity.domains.DataProduct;
import org.openmetadata.schema.entity.domains.Domain;
import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.Relationship;
@ -93,6 +96,22 @@ public class DataProductRepository extends EntityRepository<DataProduct> {
}
}
public final EntityReference getDomain(Domain domain) {
return getFromEntityRef(domain.getId(), Relationship.CONTAINS, DOMAIN, false);
}
@Override
public void setInheritedFields(DataProduct dataProduct, Fields fields) {
// If dataProduct does not have owners and experts, inherit them from its domain
EntityReference parentRef =
dataProduct.getDomain() != null ? dataProduct.getDomain() : getDomain(dataProduct);
if (parentRef != null) {
Domain parent = Entity.getEntity(DOMAIN, parentRef.getId(), "owners,experts", ALL);
inheritOwners(dataProduct, fields, parent);
inheritExperts(dataProduct, fields, parent);
}
}
@Override
public EntityUpdater getUpdater(DataProduct original, DataProduct updated, Operation operation) {
return new DataProductUpdater(original, updated, operation);

View File

@ -23,8 +23,10 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.api.domains.CreateDataProduct;
import org.openmetadata.schema.api.domains.CreateDomain;
import org.openmetadata.schema.entity.data.Topic;
import org.openmetadata.schema.entity.domains.DataProduct;
import org.openmetadata.schema.entity.domains.Domain;
import org.openmetadata.schema.entity.type.Style;
import org.openmetadata.schema.type.ChangeDescription;
import org.openmetadata.schema.type.EntityReference;
@ -177,6 +179,74 @@ public class DataProductResourceTest extends EntityResourceTest<DataProduct, Cre
.hasMessage(String.format("dataProduct instance for %s not found", rdnUUID));
}
@Test
void test_inheritOwnerExpertsFromDomain(TestInfo test) throws IOException {
DomainResourceTest domainResourceTest = new DomainResourceTest();
// Create parent domain
CreateDomain parentDomainReq =
domainResourceTest
.createRequest(test, 1)
.withOwners(List.of(USER1_REF))
.withExperts(List.of(USER2.getFullyQualifiedName()));
Domain parentDomain = domainResourceTest.createEntity(parentDomainReq, ADMIN_AUTH_HEADERS);
parentDomain = domainResourceTest.getEntity(parentDomain.getId(), "*", ADMIN_AUTH_HEADERS);
// Create data product corresponding to parent domain
CreateDataProduct create =
createRequestWithoutExpertsOwners(getEntityName(test, 1))
.withDomain(parentDomain.getFullyQualifiedName());
DataProduct dataProduct = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
assertOwners(dataProduct.getOwners(), parentDomain.getOwners());
assertEntityReferences(dataProduct.getExperts(), parentDomain.getExperts());
// Create subdomain with no owners and experts
CreateDomain subDomainReq =
domainResourceTest
.createRequestWithoutOwnersExperts(getEntityName(test, 2))
.withDomain(parentDomain.getFullyQualifiedName());
Domain subDomain = domainResourceTest.createEntity(subDomainReq, ADMIN_AUTH_HEADERS);
subDomain = domainResourceTest.getEntity(subDomain.getId(), "*", ADMIN_AUTH_HEADERS);
// Create data product corresponding to subdomain
CreateDataProduct subDomainDataProductCreate =
createRequestWithoutExpertsOwners(getEntityName(test, 2))
.withDomain(subDomain.getFullyQualifiedName());
DataProduct subDomainDataProduct =
createAndCheckEntity(subDomainDataProductCreate, ADMIN_AUTH_HEADERS);
// Subdomain and its data product should inherit owners and experts from parent domain
assertOwners(subDomain.getOwners(), parentDomain.getOwners());
assertEntityReferences(subDomain.getExperts(), parentDomain.getExperts());
assertOwners(subDomainDataProduct.getOwners(), parentDomain.getOwners());
assertEntityReferences(subDomainDataProduct.getExperts(), parentDomain.getExperts());
// Add owner and expert to subdomain
Domain updateSubDomainOwner =
JsonUtils.readValue(JsonUtils.pojoToJson(subDomain), Domain.class);
updateSubDomainOwner.setOwners(List.of(TEAM11_REF));
domainResourceTest.patchEntity(
subDomain.getId(),
JsonUtils.pojoToJson(subDomain),
updateSubDomainOwner,
ADMIN_AUTH_HEADERS);
subDomain = domainResourceTest.getEntity(subDomain.getId(), "*", ADMIN_AUTH_HEADERS);
Domain updateSubDomainExpert =
JsonUtils.readValue(JsonUtils.pojoToJson(subDomain), Domain.class);
updateSubDomainExpert.setExperts(List.of(USER1_REF));
domainResourceTest.patchEntity(
subDomain.getId(),
JsonUtils.pojoToJson(subDomain),
updateSubDomainExpert,
ADMIN_AUTH_HEADERS);
subDomain = domainResourceTest.getEntity(subDomain.getId(), "*", ADMIN_AUTH_HEADERS);
// Data product of subdomain should also have the same changes as its corresponding domain
assertOwners(subDomainDataProduct.getOwners(), subDomain.getOwners());
assertEntityReferences(subDomainDataProduct.getExperts(), subDomain.getExperts());
}
private void entityInDataProduct(
EntityInterface entity, EntityInterface product, boolean inDataProduct)
throws HttpResponseException {
@ -200,6 +270,15 @@ public class DataProductResourceTest extends EntityResourceTest<DataProduct, Cre
.withAssets(TEST_TABLE1 != null ? listOf(TEST_TABLE1.getEntityReference()) : null);
}
public CreateDataProduct createRequestWithoutExpertsOwners(String name) {
return new CreateDataProduct()
.withName(name)
.withDescription(name)
.withDomain(DOMAIN.getFullyQualifiedName())
.withStyle(new Style().withColor("#40E0D0").withIconURL("https://dataProductIcon"))
.withAssets(TEST_TABLE1 != null ? listOf(TEST_TABLE1.getEntityReference()) : null);
}
@Override
public void validateCreatedEntity(
DataProduct createdEntity, CreateDataProduct request, Map<String, String> authHeaders) {

View File

@ -153,6 +153,14 @@ public class DomainResourceTest extends EntityResourceTest<Domain, CreateDomain>
.withExperts(listOf(USER1.getFullyQualifiedName()));
}
public CreateDomain createRequestWithoutOwnersExperts(String name) {
return new CreateDomain()
.withName(name)
.withDomainType(DomainType.AGGREGATE)
.withDescription("name")
.withStyle(new Style().withColor("#FFA07A").withIconURL("https://domainIcon"));
}
@Override
public void validateCreatedEntity(
Domain createdEntity, CreateDomain request, Map<String, String> authHeaders) {

View File

@ -334,6 +334,61 @@ test.describe('Domains', () => {
await afterAction();
}
});
test('Should inherit owners and experts from parent domain', async ({
page,
}) => {
const { afterAction, apiContext } = await getApiContext(page);
const user1 = new UserClass();
const user2 = new UserClass();
let domain;
let dataProduct;
try {
await user1.create(apiContext);
await user2.create(apiContext);
domain = new Domain({
name: 'PW_Domain_Inherit_Testing',
displayName: 'PW_Domain_Inherit_Testing',
description: 'playwright domain description',
domainType: 'Aggregate',
fullyQualifiedName: 'PW_Domain_Inherit_Testing',
owners: [
{
name: user1.responseData.name,
type: 'user',
fullyQualifiedName: user1.responseData.fullyQualifiedName ?? '',
id: user1.responseData.id,
},
],
experts: [user2.responseData.name],
});
dataProduct = new DataProduct(domain);
await domain.create(apiContext);
await dataProduct.create(apiContext);
await page.reload();
await redirectToHomePage(page);
await sidebarClick(page, SidebarItem.DOMAIN);
await selectDomain(page, domain.data);
await selectDataProduct(page, domain.data, dataProduct.data);
await expect(
page.getByTestId('domain-owner-name').getByTestId('owner-label')
).toContainText(user1.responseData.displayName);
await expect(
page.getByTestId('domain-expert-name').getByTestId('owner-label')
).toContainText(user2.responseData.displayName);
} finally {
await dataProduct?.delete(apiContext);
await domain?.delete(apiContext);
await user1.delete(apiContext);
await user2.delete(apiContext);
await afterAction();
}
});
});
test.describe('Domains Rbac', () => {

View File

@ -16,6 +16,8 @@ import { uuid } from '../../utils/common';
type UserTeamRef = {
name: string;
type: string;
fullyQualifiedName?: string;
id?: string;
};
type ResponseDataType = {
@ -26,7 +28,7 @@ type ResponseDataType = {
id?: string;
fullyQualifiedName?: string;
owners?: UserTeamRef[];
experts?: UserTeamRef[];
experts?: string[];
};
export class Domain {

View File

@ -17,6 +17,8 @@ import { Domain } from './Domain';
type UserTeamRef = {
name: string;
type: string;
fullyQualifiedName?: string;
id?: string;
};
type ResponseDataType = {
@ -27,7 +29,7 @@ type ResponseDataType = {
id?: string;
fullyQualifiedName?: string;
owners?: UserTeamRef[];
experts?: UserTeamRef[];
experts?: string[];
parent?: string;
};