Fixes #8783 Support moving glossary terms in a nested fashion (#8784)

This commit is contained in:
Suresh Srinivas 2022-11-15 19:39:25 -08:00 committed by GitHub
parent ea8cf999ad
commit 6a0b89c27e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 312 additions and 40 deletions

View File

@ -1090,7 +1090,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
/** Remove owner relationship for a given entity */
private void removeOwner(T entity, EntityReference owner) {
if (owner != null && owner.getId() != null) {
if (EntityUtil.getId(owner) != null) {
LOG.info("Removing owner {}:{} for entity {}", owner.getType(), owner.getId(), entity.getId());
deleteRelationship(owner.getId(), owner.getType(), entity.getId(), entityType, Relationship.OWNS);
}

View File

@ -18,7 +18,10 @@ 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.GLOSSARY;
import static org.openmetadata.service.Entity.GLOSSARY_TERM;
import static org.openmetadata.service.util.EntityUtil.entityReferenceMatch;
import static org.openmetadata.service.util.EntityUtil.getId;
import static org.openmetadata.service.util.EntityUtil.stringMatch;
import static org.openmetadata.service.util.EntityUtil.termReferenceMatch;
@ -26,6 +29,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.TermReference;
@ -40,7 +44,6 @@ import org.openmetadata.schema.type.TagLabel.TagSource;
import org.openmetadata.service.Entity;
import org.openmetadata.service.exception.CatalogExceptionMessage;
import org.openmetadata.service.jdbi3.CollectionDAO.EntityRelationshipRecord;
import org.openmetadata.service.jdbi3.EntityRepository.EntityUpdater;
import org.openmetadata.service.resources.glossary.GlossaryTermResource;
import org.openmetadata.service.util.EntityUtil;
import org.openmetadata.service.util.EntityUtil.Fields;
@ -99,14 +102,14 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
@Override
public void prepare(GlossaryTerm entity) throws IOException {
validateHierarchy(entity);
// Validate glossary
Fields glossaryFields = Entity.getFields(Entity.GLOSSARY, "reviewers");
Fields glossaryFields = Entity.getFields(GLOSSARY, "reviewers");
Glossary glossary = Entity.getEntity(entity.getGlossary(), glossaryFields, Include.NON_DELETED);
entity.setGlossary(glossary.getEntityReference());
// If reviewers is not set in the glossary term, then carry it from the glossary
System.out.println("XXX reviewers " + entity.getReviewers());
System.out.println("XXX glossary reviewers " + glossary.getReviewers());
entity.setReviewers(entity.getReviewers() == null ? glossary.getReviewers() : entity.getReviewers());
// Validate parent term
@ -152,11 +155,8 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
@Override
public void storeRelationships(GlossaryTerm entity) {
addRelationship(
entity.getGlossary().getId(), entity.getId(), Entity.GLOSSARY, GLOSSARY_TERM, Relationship.CONTAINS);
if (entity.getParent() != null) {
addRelationship(entity.getParent().getId(), entity.getId(), GLOSSARY_TERM, GLOSSARY_TERM, Relationship.CONTAINS);
}
addGlossaryRelationship(entity);
addParentRelationship(entity);
for (EntityReference relTerm : listOrEmpty(entity.getRelatedTerms())) {
// Make this bidirectional relationship
addRelationship(entity.getId(), relTerm.getId(), GLOSSARY_TERM, GLOSSARY_TERM, Relationship.RELATED_TO, true);
@ -170,8 +170,8 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
@Override
public void restorePatchAttributes(GlossaryTerm original, GlossaryTerm updated) {
// Patch can't update Children, Glossary, or Parent
updated.withChildren(original.getChildren()).withGlossary(original.getGlossary()).withParent(original.getParent());
// Patch can't update Children
updated.withChildren(original.getChildren());
}
@Override
@ -186,7 +186,7 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
}
protected EntityReference getGlossary(GlossaryTerm term) throws IOException {
return getFromEntityRef(term.getId(), Relationship.CONTAINS, Entity.GLOSSARY, true);
return getFromEntityRef(term.getId(), Relationship.CONTAINS, GLOSSARY, true);
}
public EntityReference getGlossary(String id) throws IOException {
@ -204,6 +204,49 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
daoCollection.tagUsageDAO().deleteTagLabels(TagSource.GLOSSARY.ordinal(), entity.getFullyQualifiedName());
}
private void addGlossaryRelationship(GlossaryTerm term) {
addRelationship(term.getGlossary().getId(), term.getId(), GLOSSARY, GLOSSARY_TERM, Relationship.CONTAINS);
}
private void deleteGlossaryRelationship(GlossaryTerm term) {
deleteRelationship(term.getGlossary().getId(), GLOSSARY, term.getId(), GLOSSARY_TERM, Relationship.CONTAINS);
}
private void updateGlossaryRelationship(GlossaryTerm orig, GlossaryTerm updated) {
deleteGlossaryRelationship(orig);
addGlossaryRelationship(updated);
}
private void addParentRelationship(GlossaryTerm term) {
if (term.getParent() != null) {
addRelationship(term.getParent().getId(), term.getId(), GLOSSARY_TERM, GLOSSARY_TERM, Relationship.CONTAINS);
}
}
private void deleteParentRelationship(GlossaryTerm term) {
if (term.getParent() != null) {
deleteRelationship(term.getParent().getId(), GLOSSARY_TERM, term.getId(), GLOSSARY_TERM, Relationship.CONTAINS);
}
}
private void updateParentRelationship(GlossaryTerm orig, GlossaryTerm updated) {
deleteParentRelationship(orig);
addParentRelationship(updated);
}
private void validateHierarchy(GlossaryTerm term) {
// The glossary and the parent term must belong to the same hierachy
if (term.getParent() == null) {
return; // Parent is the root of the glossary
}
if (!term.getParent().getFullyQualifiedName().startsWith(term.getGlossary().getFullyQualifiedName())) {
throw new IllegalArgumentException(
String.format(
"Invalid hierarchy - parent [%s] does not belong to glossary[%s]",
term.getParent().getFullyQualifiedName(), term.getGlossary().getFullyQualifiedName()));
}
}
/** Handles entity updated from PUT and POST operation. */
public class GlossaryTermUpdater extends EntityUpdater {
public GlossaryTermUpdater(GlossaryTerm original, GlossaryTerm updated, Operation operation) {
@ -218,6 +261,7 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
updateRelatedTerms(original, updated);
updateReviewers(original, updated);
updateName(original, updated);
updateParent(original, updated);
}
@Override
@ -293,5 +337,27 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
recordChange("name", original.getName(), updated.getName());
}
}
private void updateParent(GlossaryTerm original, GlossaryTerm updated) throws JsonProcessingException {
// Can't change parent and glossary both at the same time
UUID oldParentId = getId(original.getParent());
UUID newParentId = getId(updated.getParent());
boolean parentChanged = !Objects.equals(oldParentId, newParentId);
UUID oldGlossaryId = getId(original.getGlossary());
UUID newGlossaryId = getId(updated.getGlossary());
boolean glossaryChanged = !Objects.equals(oldGlossaryId, newGlossaryId);
daoCollection.glossaryTermDAO().updateFqn(original.getFullyQualifiedName(), updated.getFullyQualifiedName());
daoCollection.tagUsageDAO().rename(original.getFullyQualifiedName(), updated.getFullyQualifiedName());
if (glossaryChanged) {
updateGlossaryRelationship(original, updated);
recordChange("glossary", original.getGlossary(), updated.getGlossary(), true, entityReferenceMatch);
}
if (parentChanged) {
updateParentRelationship(original, updated);
recordChange("parent", original.getParent(), updated.getParent(), true, entityReferenceMatch);
}
}
}
}

View File

@ -20,6 +20,7 @@ import static org.openmetadata.service.Entity.FIELD_OWNER;
import static org.openmetadata.service.Entity.LOCATION;
import static org.openmetadata.service.Entity.POLICY;
import static org.openmetadata.service.util.EntityUtil.entityReferenceMatch;
import static org.openmetadata.service.util.EntityUtil.getId;
import static org.openmetadata.service.util.EntityUtil.getRuleField;
import static org.openmetadata.service.util.EntityUtil.ruleMatch;
@ -92,7 +93,7 @@ public class PolicyRepository extends EntityRepository<Policy> {
/** Generate EntityReference for a given Policy's Location. * */
@Transaction
private EntityReference getLocationReference(Policy policy) throws IOException {
if (policy == null || policy.getLocation() == null || policy.getLocation().getId() == null) {
if (policy == null || getId(policy.getLocation()) == null) {
return null;
}
@ -163,7 +164,7 @@ public class PolicyRepository extends EntityRepository<Policy> {
}
private void setLocation(Policy policy, EntityReference location) {
if (location == null || location.getId() == null) {
if (getId(location) == null) {
return;
}
addRelationship(policy.getId(), policy.getLocation().getId(), POLICY, Entity.LOCATION, Relationship.APPLIED_TO);
@ -184,12 +185,12 @@ public class PolicyRepository extends EntityRepository<Policy> {
private void updateLocation(Policy origPolicy, Policy updatedPolicy) throws IOException {
// remove original Policy --> Location relationship if exists.
if (origPolicy.getLocation() != null && origPolicy.getLocation().getId() != null) {
if (getId(origPolicy.getLocation()) != null) {
deleteRelationship(
origPolicy.getId(), POLICY, origPolicy.getLocation().getId(), Entity.LOCATION, Relationship.APPLIED_TO);
}
// insert updated Policy --> Location relationship.
if (updatedPolicy.getLocation() != null && updatedPolicy.getLocation().getId() != null) {
if (getId(updatedPolicy.getLocation()) != null) {
addRelationship(
updatedPolicy.getId(),
updatedPolicy.getLocation().getId(),

View File

@ -460,4 +460,20 @@ public final class EntityUtil {
public static MetadataOperation createOrUpdateOperation(ResourceContext resourceContext) throws IOException {
return resourceContext.getEntity() == null ? MetadataOperation.CREATE : MetadataOperation.EDIT_ALL;
}
public static UUID getId(EntityReference ref) {
return ref == null ? null : ref.getId();
}
public static String getFqn(EntityReference ref) {
return ref == null ? null : ref.getFullyQualifiedName();
}
public static String getFqn(EntityInterface entity) {
return entity == null ? null : entity.getFullyQualifiedName();
}
public static EntityReference getEntityReference(EntityInterface entity) {
return entity == null ? null : entity.getEntityReference();
}
}

View File

@ -23,6 +23,8 @@ import static org.openmetadata.schema.type.ProviderType.SYSTEM;
import static org.openmetadata.service.util.EntityUtil.fieldAdded;
import static org.openmetadata.service.util.EntityUtil.fieldDeleted;
import static org.openmetadata.service.util.EntityUtil.fieldUpdated;
import static org.openmetadata.service.util.EntityUtil.getEntityReference;
import static org.openmetadata.service.util.EntityUtil.getFqn;
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.service.util.TestUtils.UpdateType.MINOR_UPDATE;
import static org.openmetadata.service.util.TestUtils.assertListNull;
@ -36,6 +38,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.Response.Status;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpResponseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
@ -65,6 +68,7 @@ import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.TestUtils;
import org.openmetadata.service.util.TestUtils.UpdateType;
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlossary> {
public GlossaryResourceTest() {
@ -203,6 +207,102 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo
assertTagPrefixAbsent(table.getColumns().get(0).getTags(), "renameGlossary");
}
@Test
void patch_moveGlossaryTerm(TestInfo test) throws IOException {
//
// These test move a glossary term to different parts of the glossary hierarchy and to different glossaries
//
// Create glossary with the following hierarchy
// -> t1 -> t11 -> t111
// g -> t12 -> t121
// -> t2 -> t21 -> t211
//
// h -> h1 -> h11 -> h111
Glossary g = createEntity(createRequest("changeParent_g"), ADMIN_AUTH_HEADERS);
Glossary h = createEntity(createRequest("changeParent_h"), ADMIN_AUTH_HEADERS);
GlossaryTermResourceTest glossaryTermResourceTest = new GlossaryTermResourceTest();
GlossaryTerm t1 = createGlossaryTerm(glossaryTermResourceTest, g, null, "t1");
GlossaryTerm t11 = createGlossaryTerm(glossaryTermResourceTest, g, t1, "t11");
GlossaryTerm t111 = createGlossaryTerm(glossaryTermResourceTest, g, t11, "t111");
GlossaryTerm t12 = createGlossaryTerm(glossaryTermResourceTest, g, t1, "t12");
GlossaryTerm t121 = createGlossaryTerm(glossaryTermResourceTest, g, t12, "t121");
GlossaryTerm t13 = createGlossaryTerm(glossaryTermResourceTest, g, t1, "t13");
GlossaryTerm t131 = createGlossaryTerm(glossaryTermResourceTest, g, t13, "t131");
GlossaryTerm t2 = createGlossaryTerm(glossaryTermResourceTest, g, null, "t2");
GlossaryTerm t21 = createGlossaryTerm(glossaryTermResourceTest, g, t2, "t21");
GlossaryTerm t211 = createGlossaryTerm(glossaryTermResourceTest, g, t21, "t211");
GlossaryTerm h1 = createGlossaryTerm(glossaryTermResourceTest, h, null, "h1");
GlossaryTerm h11 = createGlossaryTerm(glossaryTermResourceTest, h, h1, "h11");
GlossaryTerm h111 = createGlossaryTerm(glossaryTermResourceTest, h, h11, "h111");
// Create a table with all the terms as tag labels
TableResourceTest tableResourceTest = new TableResourceTest();
List<TagLabel> tagLabels = toTagLabels(t1, t11, t111, t12, t121, t13, t131, t2, t21, t211, h1, h11, h111);
Column column = new Column().withName("c1").withDataType(ColumnDataType.INT).withTags(tagLabels);
CreateTable createTable =
tableResourceTest.createRequest(getEntityName(test)).withTags(tagLabels).withColumns(CommonUtil.listOf(column));
Table table = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
Object[][] scenarios = {
// { glossaryTerm being moved, parent/glossary to move to, [... parent/glossary to move to] }
// Leaf node t111 is moved in these tests
{t111, g, t1, t11},
{t111, t2, t21, t211}, // Diff hierarchy and glossary
{t111, h, h1, h11, h111}, // Diff hierarchy and diff glossary
// Middle node t11 is moved in these tests
{t11, g, t1}, // Same hierarchy and glossary
{t11, t2, t21, t211}, // Diff hierarchy and same glossary
{t11, h, h1, h11, h111}, // Diff hierarchy and diff glossary
// Top node t1 is moved in these tests
{t1, g}, // Same hierarchy and glossary
{t1, t2, t21, t211}, // Diff hierarchy and same glossary
{t1, h, h1, h11, h111} // Diff hierarchy and diff glossary
};
for (int i = 0; i < scenarios.length; i++) {
GlossaryTerm termToMove = (GlossaryTerm) scenarios[i][0];
// Moving to another glossary term as parent
for (int j = 1; j < scenarios[i].length; j++) {
GlossaryTerm updatedTerm;
EntityReference newGlossary;
EntityReference newParent;
if (scenarios[i][j] instanceof Glossary) { // Moving to root of another glossary
newGlossary = ((Glossary) scenarios[i][j]).getEntityReference();
newParent = null;
} else { // Moving to another glossary term as parent
GlossaryTerm newParentTerm = (GlossaryTerm) scenarios[i][j];
newGlossary = newParentTerm.getGlossary();
newParent = newParentTerm.getEntityReference();
}
LOG.info(
"Scenario iteration [{}, {}] move {} from glossary{} parent {} to glossary {} and parent {}",
i,
j,
getFqn(termToMove),
getFqn(termToMove.getGlossary()),
getFqn(termToMove.getParent()),
getFqn(newParent),
getFqn(newGlossary));
updatedTerm = moveGlossaryTermAndBack(newGlossary, newParent, termToMove, table);
copyGlossaryTerm(updatedTerm, termToMove);
}
}
}
private void copyGlossaryTerm(GlossaryTerm from, GlossaryTerm to) {
to.withGlossary(from.getGlossary())
.withParent(from.getParent())
.withFullyQualifiedName(from.getFullyQualifiedName())
.withChangeDescription(from.getChangeDescription())
.withVersion(from.getVersion());
}
@Override
public CreateGlossary createRequest(String name) {
return new CreateGlossary().withName(name).withDescription("d");
@ -270,7 +370,7 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo
.withName(name)
.withDescription("d")
.withGlossary(glossary.getEntityReference())
.withParent(parent == null ? null : parent.getEntityReference())
.withParent(getEntityReference(parent))
.withProvider(provider);
return resource.createEntity(create, ADMIN_AUTH_HEADERS);
}
@ -304,9 +404,44 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo
}
}
/** Change the parent of a glossary term to another glossary term then move it back to the previous hierarchy */
private GlossaryTerm moveGlossaryTermAndBack(
EntityReference newGlossary, EntityReference newParent, GlossaryTerm term, Table table) throws IOException {
EntityReference previousParent = term.getParent();
EntityReference previousGlossary = term.getGlossary();
// Change the parent to new parent
GlossaryTerm updatedTerm = moveGlossaryTerm(newGlossary, newParent, term, table);
// Change the parent back to old parent
return moveGlossaryTerm(previousGlossary, previousParent, updatedTerm, table);
}
private GlossaryTerm moveGlossaryTerm(
EntityReference newGlossary, EntityReference newParent, GlossaryTerm term, Table table) throws IOException {
GlossaryTermResourceTest glossaryTermResourceTest = new GlossaryTermResourceTest();
String previousTermFqn = term.getFullyQualifiedName();
// Update the parent
GlossaryTerm updatedTerm = glossaryTermResourceTest.moveGlossaryTerm(newGlossary, newParent, term);
assertTagLabelsChanged(table, previousTermFqn, updatedTerm.getFullyQualifiedName());
return updatedTerm;
}
private void assertTagPrefixAbsent(List<TagLabel> labels, String prefix) {
for (TagLabel tag : labels) {
assertFalse(tag.getTagFQN().startsWith(prefix), tag.getTagFQN());
}
}
private void assertTagLabelsChanged(Table table, String previousTermFqn, String newTermFqn)
throws HttpResponseException {
TableResourceTest tableResourceTest = new TableResourceTest();
table = tableResourceTest.getEntity(table.getId(), "columns,tags", ADMIN_AUTH_HEADERS);
// Ensure the previous term is no longer used as tags due tag label renaming
if (!previousTermFqn.equals(newTermFqn)) { // Old and new parent are different
assertTagPrefixAbsent(table.getTags(), previousTermFqn);
assertTagPrefixAbsent(table.getColumns().get(0).getTags(), previousTermFqn);
}
}
}

View File

@ -32,8 +32,11 @@ import static org.openmetadata.service.resources.databases.TableResourceTest.get
import static org.openmetadata.service.util.EntityUtil.fieldAdded;
import static org.openmetadata.service.util.EntityUtil.fieldDeleted;
import static org.openmetadata.service.util.EntityUtil.fieldUpdated;
import static org.openmetadata.service.util.EntityUtil.getEntityReference;
import static org.openmetadata.service.util.EntityUtil.getId;
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.service.util.TestUtils.UpdateType.MINOR_UPDATE;
import static org.openmetadata.service.util.TestUtils.UpdateType.NO_CHANGE;
import static org.openmetadata.service.util.TestUtils.assertListNotEmpty;
import static org.openmetadata.service.util.TestUtils.assertListNotNull;
import static org.openmetadata.service.util.TestUtils.assertListNull;
@ -47,6 +50,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.http.client.HttpResponseException;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@ -73,6 +77,7 @@ import org.openmetadata.service.util.FullyQualifiedName;
import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.ResultList;
import org.openmetadata.service.util.TestUtils;
import org.openmetadata.service.util.TestUtils.UpdateType;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, CreateGlossaryTerm> {
@ -333,7 +338,7 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
public GlossaryTerm createTerm(
Glossary glossary, GlossaryTerm parent, String termName, List<EntityReference> reviewers) throws IOException {
EntityReference glossaryRef = glossary.getEntityReference();
EntityReference parentRef = parent != null ? parent.getEntityReference() : null;
EntityReference parentRef = getEntityReference(parent);
CreateGlossaryTerm createGlossaryTerm =
createRequest(termName, "", "", null).withGlossary(glossaryRef).withParent(parentRef).withReviewers(reviewers);
return createAndCheckEntity(createGlossaryTerm, ADMIN_AUTH_HEADERS);
@ -434,29 +439,29 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
}
switch (fieldName) {
case "reviewers":
{
@SuppressWarnings("unchecked")
List<EntityReference> expectedRefs = (List<EntityReference>) expected;
List<EntityReference> actualRefs = JsonUtils.readObjects(actual.toString(), EntityReference.class);
assertEntityReferences(expectedRefs, actualRefs);
break;
}
@SuppressWarnings("unchecked")
List<EntityReference> expectedRefs = (List<EntityReference>) expected;
List<EntityReference> actualRefs = JsonUtils.readObjects(actual.toString(), EntityReference.class);
assertEntityReferences(expectedRefs, actualRefs);
break;
case "parent":
case "glossary":
EntityReference expectedRef = (EntityReference) expected;
EntityReference actualRef = JsonUtils.readValue(actual.toString(), EntityReference.class);
assertEquals(expectedRef.getId(), actualRef.getId());
break;
case "synonyms":
{
@SuppressWarnings("unchecked")
List<String> expectedRefs = (List<String>) expected;
List<String> actualRefs = JsonUtils.readObjects(actual.toString(), String.class);
assertStrings(expectedRefs, actualRefs);
break;
}
@SuppressWarnings("unchecked")
List<String> expectedStrings = (List<String>) expected;
List<String> actualStrings = JsonUtils.readObjects(actual.toString(), String.class);
assertStrings(expectedStrings, actualStrings);
break;
case "references":
{
@SuppressWarnings("unchecked")
List<TermReference> expectedRefs = (List<TermReference>) expected;
List<TermReference> actualRefs = JsonUtils.readObjects(actual.toString(), TermReference.class);
assertTermReferences(expectedRefs, actualRefs);
break;
}
@SuppressWarnings("unchecked")
List<TermReference> expectedTermRefs = (List<TermReference>) expected;
List<TermReference> actualTermRefs = JsonUtils.readObjects(actual.toString(), TermReference.class);
assertTermReferences(expectedTermRefs, actualTermRefs);
break;
case "status":
Status expectedStatus = (Status) expected;
Status actualStatus = Status.fromValue(actual.toString());
@ -491,4 +496,53 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
assertTrue(child.getFullyQualifiedName().startsWith(getTerm.getFullyQualifiedName()));
}
}
public GlossaryTerm moveGlossaryTerm(EntityReference newGlossary, EntityReference newParent, GlossaryTerm term)
throws IOException {
EntityReference oldGlossary = term.getGlossary();
EntityReference oldParent = term.getParent();
String json = JsonUtils.pojoToJson(term);
ChangeDescription change = getChangeDescription(term.getVersion());
// Changes description for glossary term parent change
UpdateType update = MINOR_UPDATE;
if (newParent == null && oldParent != null) {
fieldDeleted(change, "parent", oldParent);
} else if (oldParent == null && newParent != null) {
fieldAdded(change, "parent", newParent);
} else if (Objects.equals(getId(newParent), getId(oldParent))) {
update = NO_CHANGE;
} else {
fieldUpdated(change, "parent", oldParent, newParent);
}
// Changes description for glossary change for glossary term
if (!newGlossary.getId().equals(oldGlossary.getId())) {
update = MINOR_UPDATE;
fieldUpdated(change, "glossary", oldGlossary, newGlossary);
}
String parentFQN = newParent == null ? newGlossary.getFullyQualifiedName() : newParent.getFullyQualifiedName();
term.setFullyQualifiedName(FullyQualifiedName.add(parentFQN, term.getName()));
term.setParent(newParent);
term.setGlossary(newGlossary);
term = patchEntityAndCheck(term, json, ADMIN_AUTH_HEADERS, update, change);
assertChildrenFqnChanged(term);
return term;
}
public void assertChildrenFqnChanged(GlossaryTerm term) throws HttpResponseException {
// GET the glossary term and check all the children are renamed
GlossaryTerm newTerm = getEntity(term.getId(), ADMIN_AUTH_HEADERS);
for (EntityReference ref : newTerm.getChildren()) {
assertTrue(ref.getFullyQualifiedName().startsWith(newTerm.getFullyQualifiedName()));
}
// List children glossary terms with this term as the parent and ensure rename
Map<String, String> queryParams = new HashMap<>();
queryParams.put("parent", term.getId().toString());
List<GlossaryTerm> children = listEntities(queryParams, ADMIN_AUTH_HEADERS).getData();
for (GlossaryTerm child : listOrEmpty(children)) {
assertTrue(child.getFullyQualifiedName().startsWith(newTerm.getFullyQualifiedName()));
}
}
}