11587 Task 1 - Simplify field inheritance from parent to child entities (#11588)

This commit is contained in:
Suresh Srinivas 2023-07-04 10:00:16 -07:00 committed by GitHub
parent 71fed53e33
commit a313dc19f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 112 additions and 85 deletions

View File

@ -64,6 +64,7 @@ public final class Entity {
public static final String FIELD_DISPLAY_NAME = "displayName";
public static final String FIELD_EXTENSION = "extension";
public static final String FIELD_USAGE_SUMMARY = "usageSummary";
public static final String FIELD_REVIEWERS = "reviewers";
public static final String FIELD_DOMAIN = "domain";
public static final String FIELD_DATA_PRODUCTS = "dataProducts";

View File

@ -104,19 +104,21 @@ public class DatabaseSchemaRepository extends EntityRepository<DatabaseSchema> {
schema.withDatabase(databaseRef).withService(database.getService());
}
@Override
public void setInheritedFields(DatabaseSchema schema) throws IOException {
Database database = Entity.getEntity(schema.getDatabase(), "owner", Include.ALL);
setInheritedProperties(schema, schema.getDatabase().getId());
}
public void setInheritedProperties(DatabaseSchema schema, UUID databaseId) throws IOException {
public DatabaseSchema setInheritedFields(DatabaseSchema schema, Fields fields) throws IOException {
Database database = null;
UUID databaseId = schema.getDatabase().getId();
// If schema does not have owner, then inherit parent database owner
if (fields.contains(FIELD_OWNER) && schema.getOwner() == null) {
database = Entity.getEntity(Entity.DATABASE, databaseId, "owner", ALL);
schema.withOwner(database.getOwner());
}
// If schema does not have its own retention period, then inherit parent database retention period
if (schema.getRetentionPeriod() == null) {
database = database == null ? Entity.getEntity(Entity.DATABASE, databaseId, "", ALL) : database;
schema.withRetentionPeriod(database.getRetentionPeriod());
}
return schema;
}
@Override
@ -136,16 +138,11 @@ public class DatabaseSchemaRepository extends EntityRepository<DatabaseSchema> {
}
private void populateDatabase(DatabaseSchema schema) throws IOException {
Database database = Entity.getEntity(schema.getDatabase(), "owner", ALL);
Database database = Entity.getEntity(schema.getDatabase(), "", ALL);
schema
.withDatabase(database.getEntityReference())
.withService(database.getService())
.withServiceType(database.getServiceType());
// Carry forward ownership from database, if necessary
if (database.getOwner() != null && schema.getOwner() == null) {
schema.withOwner(database.getOwner().withDescription("inherited"));
}
}
public class DatabaseSchemaUpdater extends EntityUpdater {

View File

@ -254,13 +254,13 @@ public abstract class EntityRepository<T extends EntityInterface> {
public abstract void storeRelationships(T entity) throws IOException;
/**
* This method is called to set inherited property that an entity inherits from its parent.
* This method is called to set inherited fields that an entity inherits from its parent.
*
* @see TableRepository#setInheritedFields(Table) for an example implementation
* @see TableRepository#setInheritedFields(Table, Fields) for an example implementation
*/
@SuppressWarnings("unused")
public void setInheritedFields(T entity) throws IOException {
// Override to set inherited properties
public T setInheritedFields(T entity, Fields fields) throws IOException {
return entity;
}
/**
@ -368,7 +368,10 @@ public abstract class EntityRepository<T extends EntityInterface> {
@Transaction
public final T get(UriInfo uriInfo, UUID id, Fields fields, Include include) throws IOException {
return withHref(uriInfo, setFieldsInternal(dao.findEntityById(id, include), fields));
T entity = dao.findEntityById(id, include);
setFieldsInternal(entity, fields);
setInheritedFields(entity, fields);
return withHref(uriInfo, entity);
}
@Transaction
@ -573,7 +576,6 @@ public abstract class EntityRepository<T extends EntityInterface> {
entity.setDomain(fields.contains(FIELD_DOMAIN) ? getDomain(entity) : null);
entity.setDataProducts(fields.contains(FIELD_DATA_PRODUCTS) ? getDataProducts(entity) : null);
setFields(entity, fields);
setInheritedFields(entity);
return entity;
}
@ -613,14 +615,6 @@ public abstract class EntityRepository<T extends EntityInterface> {
// Get all the fields in the original entity that can be updated during PUT operation
setFieldsInternal(original, putFields);
EntityReference updatedOwner = updated.getOwner();
if (updatedOwner != null
&& updatedOwner.getDescription() != null
&& updatedOwner.getDescription().equals("inherited")) {
// Don't let inherited ownership overwrite existing ownership
updated.setOwner(original.getOwner() != null ? original.getOwner() : updatedOwner);
}
// If the entity state is soft-deleted, recursively undelete the entity and it's children
if (Boolean.TRUE.equals(original.getDeleted())) {
restoreEntity(updated.getUpdatedBy(), entityType, original.getId());
@ -630,7 +624,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
EntityUpdater entityUpdater = getUpdater(original, updated, Operation.PUT);
entityUpdater.update();
String change = entityUpdater.fieldsChanged() ? RestUtil.ENTITY_UPDATED : RestUtil.ENTITY_NO_CHANGE;
setInheritedFields(updated);
setInheritedFields(updated, new Fields(allowedFields));
return new PutResponse<>(Status.OK, withHref(uriInfo, updated), change);
}
@ -638,6 +632,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
public final PatchResponse<T> patch(UriInfo uriInfo, UUID id, String user, JsonPatch patch) throws IOException {
// Get all the fields in the original entity that can be updated during PATCH operation
T original = setFieldsInternal(dao.findEntityById(id), patchFields);
setInheritedFields(original, patchFields);
// Apply JSON patch to the original entity to get the updated entity
T updated = JsonUtils.applyPatch(original, patch, entityClass);
@ -652,7 +647,6 @@ public abstract class EntityRepository<T extends EntityInterface> {
EntityUpdater entityUpdater = getUpdater(original, updated, Operation.PATCH);
entityUpdater.update();
String change = entityUpdater.fieldsChanged() ? RestUtil.ENTITY_UPDATED : RestUtil.ENTITY_NO_CHANGE;
setInheritedFields(updated);
return new PatchResponse<>(Status.OK, withHref(uriInfo, updated), change);
}
@ -903,7 +897,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
storeEntity(entity, false);
storeExtension(entity);
storeRelationshipsInternal(entity);
setInheritedFields(entity);
setInheritedFields(entity, new Fields(allowedFields));
return entity;
}
@ -1392,7 +1386,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
return !supportsOwner ? null : Entity.getEntityReferenceById(ref.getType(), ref.getId(), ALL);
}
public void populateOwner(EntityReference owner) throws IOException {
protected void populateOwner(EntityReference owner) throws IOException {
if (owner == null) {
return;
}
@ -1453,7 +1447,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
return new Fields(allowedFields, fields);
}
public final Fields getFields(List<String> fields) {
protected final Fields getFields(List<String> fields) {
return new Fields(allowedFields, fields);
}
@ -1650,6 +1644,8 @@ public abstract class EntityRepository<T extends EntityInterface> {
&& recordChange(FIELD_OWNER, origOwner, updatedOwner, true, entityReferenceMatch)) {
// Update owner for all PATCH operations. For PUT operations, ownership can't be removed
EntityRepository.this.updateOwner(original, origOwner, updatedOwner);
} else {
updated.setOwner(origOwner);
}
}

View File

@ -17,7 +17,10 @@
package org.openmetadata.service.jdbi3;
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.schema.type.Include.ALL;
import static org.openmetadata.service.Entity.FIELD_OWNER;
import static org.openmetadata.service.Entity.FIELD_REVIEWERS;
import static org.openmetadata.service.Entity.GLOSSARY;
import static org.openmetadata.service.Entity.GLOSSARY_TERM;
import static org.openmetadata.service.exception.CatalogExceptionMessage.invalidGlossaryTermMove;
@ -76,6 +79,36 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
return entity.withUsageCount(fields.contains("usageCount") ? getUsageCount(entity) : null);
}
@Override
public GlossaryTerm setInheritedFields(GlossaryTerm glossaryTerm, Fields fields) throws IOException {
Glossary glossary = null;
GlossaryTerm parentTerm = null;
if (fields.contains(FIELD_OWNER) && glossaryTerm.getOwner() == null) {
if (glossaryTerm.getParent() != null) {
parentTerm = get(null, glossaryTerm.getParent().getId(), getFields("owner,reviewers"));
glossaryTerm.setOwner(parentTerm.getOwner());
} else {
glossary = Entity.getEntity(glossaryTerm.getGlossary(), "owner,reviewers", ALL);
glossaryTerm.setOwner(glossary.getOwner());
}
}
if (fields.contains(FIELD_REVIEWERS) && nullOrEmpty(glossaryTerm.getReviewers())) {
if (glossaryTerm.getParent() != null) {
if (parentTerm == null) {
parentTerm = get(null, glossaryTerm.getParent().getId(), getFields("reviewers"));
}
glossaryTerm.setReviewers(parentTerm.getReviewers());
} else {
if (glossary == null) {
glossary = Entity.getEntity(glossaryTerm.getGlossary(), "reviewers", ALL);
}
glossaryTerm.setReviewers(glossary.getReviewers());
}
}
return glossaryTerm;
}
private Integer getUsageCount(GlossaryTerm term) {
return daoCollection
.tagUsageDAO()
@ -109,28 +142,16 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
entity.getParent() != null
? getByName(null, entity.getParent().getFullyQualifiedName(), getFields("owner"))
: null;
List<EntityReference> inheritedReviewers = null;
EntityReference inheritedOwner = null;
if (parentTerm != null) {
entity.setParent(parentTerm.getEntityReference());
inheritedReviewers = parentTerm.getReviewers(); // Inherit reviewers from the parent term
inheritedOwner = parentTerm.getOwner(); // Inherit ownership from the parent term
}
// Validate glossary
Glossary glossary = Entity.getEntity(entity.getGlossary(), "owner,reviewers", Include.NON_DELETED);
Glossary glossary = Entity.getEntity(entity.getGlossary(), "", Include.NON_DELETED);
entity.setGlossary(glossary.getEntityReference());
// If parent term does not have reviewers or owner then inherit from the glossary
inheritedReviewers = inheritedReviewers != null ? inheritedReviewers : glossary.getReviewers();
inheritedOwner = inheritedOwner != null ? inheritedOwner : glossary.getOwner();
validateHierarchy(entity);
// If reviewers and owner are not set for the glossary term, then carry it from the glossary
entity.setReviewers(entity.getReviewers() != null ? entity.getReviewers() : inheritedReviewers);
entity.setOwner(entity.getOwner() != null ? entity.getOwner() : inheritedOwner);
// Validate related terms
EntityUtil.populateEntityReferences(entity.getRelatedTerms());

View File

@ -90,9 +90,9 @@ import org.openmetadata.service.util.ResultList;
public class TableRepository extends EntityRepository<Table> {
// Table fields that can be patched in a PATCH request
static final String TABLE_PATCH_FIELDS = "owner,tags,tableConstraints,tablePartition,extension,followers";
static final String PATCH_FIELDS = "owner,tags,tableConstraints,tablePartition,extension,followers";
// Table fields that can be updated in a PUT request
static final String TABLE_UPDATE_FIELDS = "owner,tags,tableConstraints,tablePartition,dataModel,extension,followers";
static final String UPDATE_FIELDS = "owner,tags,tableConstraints,tablePartition,dataModel,extension,followers";
public static final String FIELD_RELATION_COLUMN_TYPE = "table.columns.column";
public static final String FIELD_RELATION_TABLE_TYPE = "table";
@ -112,8 +112,8 @@ public class TableRepository extends EntityRepository<Table> {
Table.class,
daoCollection.tableDAO(),
daoCollection,
TABLE_PATCH_FIELDS,
TABLE_UPDATE_FIELDS);
PATCH_FIELDS,
UPDATE_FIELDS);
}
@Override
@ -133,16 +133,20 @@ public class TableRepository extends EntityRepository<Table> {
}
@Override
public void setInheritedFields(Table table) throws IOException {
setInheritedProperties(table, table.getDatabaseSchema().getId());
}
public Table setInheritedFields(Table table, Fields fields) throws IOException {
DatabaseSchema schema = null;
// If table does not have owner, then inherit it from parent databaseSchema
if (fields.contains(FIELD_OWNER) && table.getOwner() == null) {
schema = Entity.getEntity(DATABASE_SCHEMA, table.getDatabaseSchema().getId(), "owner", ALL);
table.withOwner(schema.getOwner());
}
public void setInheritedProperties(Table table, UUID schemaId) throws IOException {
// If table does not have retention period, then inherit it from parent databaseSchema
if (table.getRetentionPeriod() == null) {
DatabaseSchema schema = Entity.getEntity(DATABASE_SCHEMA, schemaId, "", ALL);
schema = schema == null ? Entity.getEntity(DATABASE_SCHEMA, table.getDatabaseSchema().getId(), "", ALL) : schema;
table.withRetentionPeriod(schema.getRetentionPeriod());
}
return table;
}
private void setDefaultFields(Table table) throws IOException {
@ -605,18 +609,13 @@ public class TableRepository extends EntityRepository<Table> {
@Override
public void prepare(Table table) throws IOException {
DatabaseSchema schema = Entity.getEntity(table.getDatabaseSchema(), "owner", ALL);
DatabaseSchema schema = Entity.getEntity(table.getDatabaseSchema(), "", ALL);
table
.withDatabaseSchema(schema.getEntityReference())
.withDatabase(schema.getDatabase())
.withService(schema.getService())
.withServiceType(schema.getServiceType());
// Carry forward ownership from database schema
if (table.getOwner() == null && schema.getOwner() != null) {
table.setOwner(schema.getOwner().withDescription("inherited"));
}
// Validate column tags
addDerivedColumnTags(table.getColumns());
validateColumnTags(table.getColumns());

View File

@ -77,7 +77,7 @@ public class UserRepository extends EntityRepository<User> {
List<String> tempFields = getAllowedFieldsCopy();
if (fields != null && fields.equals("*")) {
tempFields.add(AUTH_MECHANISM_FIELD);
return new Fields(tempFields, String.join(",", tempFields));
return new Fields(tempFields);
}
return new Fields(tempFields, fields);
}

View File

@ -951,6 +951,7 @@ public class TableResource extends EntityResource<Table, TableRepository> {
.withViewDefinition(create.getViewDefinition())
.withTableProfilerConfig(create.getTableProfilerConfig())
.withDatabaseSchema(getEntityReference(Entity.DATABASE_SCHEMA, create.getDatabaseSchema())))
.withDatabaseSchema(getEntityReference(Entity.DATABASE_SCHEMA, create.getDatabaseSchema()))
.withRetentionPeriod(create.getRetentionPeriod());
}

View File

@ -32,7 +32,6 @@ import java.util.stream.Collectors;
import javax.ws.rs.WebApplicationException;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
@ -118,8 +117,7 @@ public final class EntityUtil {
public static final BiPredicate<GlossaryTerm, GlossaryTerm> glossaryTermMatch =
(filter1, filter2) -> filter1.getFullyQualifiedName().equals(filter2.getFullyQualifiedName());
public static final BiPredicate<ContainerFileFormat, ContainerFileFormat> containerFileFormatMatch =
(format1, format2) -> format1.equals(format2);
public static final BiPredicate<ContainerFileFormat, ContainerFileFormat> containerFileFormatMatch = Enum::equals;
public static final BiPredicate<TermReference, TermReference> termReferenceMatch =
(ref1, ref2) -> ref1.getName().equals(ref2.getName()) && ref1.getEndpoint().equals(ref2.getEndpoint());
@ -175,6 +173,9 @@ public final class EntityUtil {
public static List<EntityReference> populateEntityReferences(
List<EntityRelationshipRecord> records, @NonNull String entityType) throws IOException {
// if (nullOrEmpty(records)) {
// return null;
// }
List<EntityReference> refs = new ArrayList<>(records.size());
for (EntityRelationshipRecord id : records) {
refs.add(Entity.getEntityReferenceById(entityType, id.getId(), ALL));
@ -217,7 +218,7 @@ public final class EntityUtil {
String extensionName)
throws IOException {
List<String> testCaseFQNHashes =
testCaseFQNs.stream().map(fqn -> FullyQualifiedName.buildHash(fqn)).collect(Collectors.toList());
testCaseFQNs.stream().map(FullyQualifiedName::buildHash).collect(Collectors.toList());
if (testCaseFQNHashes.isEmpty()) return new TestSummary();
@ -293,11 +294,14 @@ public final class EntityUtil {
return ids;
}
@RequiredArgsConstructor
public static class Fields {
public static final Fields EMPTY_FIELDS = new Fields(null, "");
public static final Fields EMPTY_FIELDS = new Fields(Collections.emptyList());
@Getter private final List<String> fieldList;
public Fields(List<String> fieldList) {
this.fieldList = fieldList;
}
public Fields(List<String> allowedFields, String fieldsParam) {
if (nullOrEmpty(fieldsParam)) {
fieldList = new ArrayList<>();
@ -329,10 +333,6 @@ public final class EntityUtil {
return fieldList.toString();
}
public void add(Fields fields) {
fieldList.addAll(fields.fieldList);
}
public boolean contains(String field) {
return fieldList.contains(field);
}

View File

@ -421,7 +421,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
if (runWebhookTests) {
webhookCallbackResource.clearEvents();
EventSubscriptionResourceTest alertResourceTest = new EventSubscriptionResourceTest();
alertResourceTest.startWebhookSubscription(true);
alertResourceTest.startWebhookSubscription();
alertResourceTest.startWebhookEntitySubscriptions(entityType);
}
}

View File

@ -1716,12 +1716,16 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
CreateDatabaseSchema createSchema =
schemaTest.createRequest(test).withDatabase(db.getFullyQualifiedName()).withOwner(null);
DatabaseSchema schema = schemaTest.createEntity(createSchema, ADMIN_AUTH_HEADERS);
assertReference(USER1_REF, schema.getOwner());
assertReference(USER1_REF, schema.getOwner()); // Inherited owner
schema = schemaTest.getEntity(schema.getId(), "owner", ADMIN_AUTH_HEADERS);
assertReference(USER1_REF, schema.getOwner()); // Inherited owner
// Ensure table owner is inherited from databaseSchema
CreateTable createTable = createRequest(test).withOwner(null).withDatabaseSchema(schema.getFullyQualifiedName());
Table table = createEntity(createTable, ADMIN_AUTH_HEADERS);
assertReference(USER1_REF, table.getOwner());
assertReference(USER1_REF, table.getOwner()); // Inherited owner
table = getEntity(table.getId(), "owner", ADMIN_AUTH_HEADERS);
assertReference(USER1_REF, table.getOwner()); // Inherited owner
// Change the ownership of table and ensure further ingestion updates don't overwrite the ownership
String json = JsonUtils.pojoToJson(table);
@ -1730,6 +1734,8 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
assertReference(USER2_REF, table.getOwner());
table = updateEntity(createTable.withOwner(null), OK, ADMIN_AUTH_HEADERS); // Simulate ingestion update
assertReference(USER2_REF, table.getOwner()); // Owner remains the same
table = getEntity(table.getId(), "owner", ADMIN_AUTH_HEADERS);
assertReference(USER2_REF, table.getOwner()); // Owner remains the same
// Change the ownership of schema and ensure further ingestion updates don't overwrite the ownership
json = JsonUtils.pojoToJson(schema);
@ -1738,6 +1744,8 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
assertReference(USER2_REF, schema.getOwner());
schema = schemaTest.updateEntity(createSchema.withOwner(null), OK, ADMIN_AUTH_HEADERS); // Simulate ingestion update
assertReference(USER2_REF, schema.getOwner()); // Owner remains the same
schema = schemaTest.getEntity(schema.getId(), "owner", ADMIN_AUTH_HEADERS);
assertReference(USER2_REF, schema.getOwner()); // Owner remains the same
}
@Test
@ -1748,23 +1756,21 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
assertEquals("P30D", database.getRetentionPeriod());
// Ensure database schema retention period is carried over from the parent database
DatabaseSchemaResourceTest schemaResourceTest = new DatabaseSchemaResourceTest();
DatabaseSchemaResourceTest schemaTest = new DatabaseSchemaResourceTest();
CreateDatabaseSchema createDatabaseSchema =
schemaResourceTest.createRequest(test).withDatabase(database.getFullyQualifiedName());
schemaTest.createRequest(test).withDatabase(database.getFullyQualifiedName());
DatabaseSchema schema =
schemaResourceTest
.createEntity(createDatabaseSchema, ADMIN_AUTH_HEADERS)
.withDatabase(database.getEntityReference());
assertEquals("P30D", schema.getRetentionPeriod());
schema = schemaResourceTest.getEntity(schema.getId(), "", ADMIN_AUTH_HEADERS);
assertEquals("P30D", schema.getRetentionPeriod());
schemaTest.createEntity(createDatabaseSchema, ADMIN_AUTH_HEADERS).withDatabase(database.getEntityReference());
assertEquals("P30D", schema.getRetentionPeriod()); // Retention period is inherited in create response
schema = schemaTest.getEntity(schema.getId(), "", ADMIN_AUTH_HEADERS);
assertEquals("P30D", schema.getRetentionPeriod()); // Retention period is inherited in create response
// Ensure table retention period is carried over from the parent database schema
CreateTable createTable = createRequest(test).withDatabaseSchema(schema.getFullyQualifiedName());
Table table = createEntity(createTable, ADMIN_AUTH_HEADERS).withDatabase(database.getEntityReference());
assertEquals("P30D", table.getRetentionPeriod());
assertEquals("P30D", table.getRetentionPeriod()); // Retention period is inherited in get response
table = getEntity(table.getId(), "", ADMIN_AUTH_HEADERS);
assertEquals("P30D", table.getRetentionPeriod());
assertEquals("P30D", table.getRetentionPeriod()); // Retention period is inherited in get response
}
@Test

View File

@ -354,7 +354,7 @@ public class EventSubscriptionResourceTest extends EntityResourceTest<EventSubsc
* Before a test for every entity resource, create a webhook subscription. At the end of the test, ensure all events
* are delivered over web subscription comparing it with number of events stored in the system.
*/
public void startWebhookSubscription(boolean enabled) throws IOException {
public void startWebhookSubscription() throws IOException {
String baseUri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/healthy";
Webhook webhook = getWebhook(baseUri);
CreateEventSubscription genericWebhookActionRequest = createRequest("healthy").withSubscriptionConfig(webhook);

View File

@ -178,6 +178,9 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
GlossaryTerm t1 = createEntity(create.withName("t1"), ADMIN_AUTH_HEADERS);
assertEntityReferences(glossary.getReviewers(), t1.getReviewers()); // Reviewers are inherited
assertReference(glossary.getOwner(), t1.getOwner()); // Owner is inherited
t1 = getEntity(t1.getId(), "reviewers,owner", ADMIN_AUTH_HEADERS);
assertEntityReferences(glossary.getReviewers(), t1.getReviewers()); // Reviewers are inherited
assertReference(glossary.getOwner(), t1.getOwner()); // Owner is inherited
GlossaryTerm t12 =
createEntity(
@ -188,6 +191,9 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
ADMIN_AUTH_HEADERS);
assertEntityReferences(glossary.getReviewers(), t12.getReviewers()); // Reviewers are inherited
assertReference(glossary.getOwner(), t12.getOwner()); // Owner is inherited
t12 = getEntity(t12.getId(), "reviewers,owner", ADMIN_AUTH_HEADERS);
assertEntityReferences(glossary.getReviewers(), t12.getReviewers()); // Reviewers are inherited
assertReference(glossary.getOwner(), t12.getOwner()); // Owner is inherited
}
@Test