Fixes #6844 Ingestion causes Custom Property values to disappear (#6912)

This commit is contained in:
Suresh Srinivas 2022-08-25 14:04:18 -07:00 committed by GitHub
parent ff1d2c251a
commit a8732c8e89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 226 additions and 225 deletions

View File

@ -72,6 +72,7 @@ import org.openmetadata.catalog.jdbi3.CollectionDAO.EntityRelationshipRecord;
import org.openmetadata.catalog.jdbi3.CollectionDAO.EntityVersionPair;
import org.openmetadata.catalog.jdbi3.CollectionDAO.ExtensionRecord;
import org.openmetadata.catalog.jdbi3.TableRepository.TableUpdater;
import org.openmetadata.catalog.security.policyevaluator.SubjectCache;
import org.openmetadata.catalog.type.ChangeDescription;
import org.openmetadata.catalog.type.ChangeEvent;
import org.openmetadata.catalog.type.EntityHistory;
@ -136,7 +137,6 @@ public abstract class EntityRepository<T extends EntityInterface> {
@Getter protected final boolean supportsTags;
@Getter protected final boolean supportsOwner;
protected final boolean supportsFollower;
protected boolean allowEdits = false;
/** Fields that can be updated during PATCH operation */
private final Fields patchFields;
@ -1122,12 +1122,14 @@ public abstract class EntityRepository<T extends EntityInterface> {
protected final Operation operation;
protected final ChangeDescription changeDescription = new ChangeDescription();
protected boolean majorVersionChange = false;
protected final User updatingUser;
private boolean entityRestored = false;
public EntityUpdater(T original, T updated, Operation operation) {
this.original = original;
this.updated = updated;
this.operation = operation;
this.updatingUser = SubjectCache.getInstance().getSubjectContext(updated.getUpdatedBy()).getUser();
}
/** Compare original and updated entities and perform updates. Update the entity version and track changes. */
@ -1154,11 +1156,8 @@ public abstract class EntityRepository<T extends EntityInterface> {
}
private void updateDescription() throws JsonProcessingException {
if (operation.isPut()
&& original.getDescription() != null
&& !original.getDescription().isEmpty()
&& !allowEdits) {
// Update description only when stored is empty to retain user authored descriptions
if (operation.isPut() && !nullOrEmpty(original.getDescription()) && updatedByBot()) {
// Revert change to non-empty description if it is being updated by a bot
updated.setDescription(original.getDescription());
return;
}
@ -1183,11 +1182,8 @@ public abstract class EntityRepository<T extends EntityInterface> {
}
private void updateDisplayName() throws JsonProcessingException {
if (operation.isPut()
&& original.getDisplayName() != null
&& !original.getDisplayName().isEmpty()
&& !allowEdits) {
// Update displayName only when stored is empty to retain user authored descriptions
if (operation.isPut() && !nullOrEmpty(original.getDisplayName()) && updatedByBot()) {
// Revert change to non-empty description if it is being updated by a bot
updated.setDisplayName(original.getDisplayName());
return;
}
@ -1231,9 +1227,14 @@ public abstract class EntityRepository<T extends EntityInterface> {
}
private void updateExtension() throws JsonProcessingException {
if (updatedByBot()) {
// Revert changes to extension field, if being updated by a bot
updated.setExtension(original.getExtension());
return;
}
removeExtension(original);
storeExtension(updated);
// TODO change descriptions for custom attributes
}
public final boolean updateVersion(Double oldVersion) {
@ -1279,7 +1280,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
public final <K> boolean recordChange(
String field, K orig, K updated, boolean jsonValue, BiPredicate<K, K> typeMatch)
throws JsonProcessingException {
if (orig == null && updated == null) {
if (orig == updated) {
return false;
}
FieldChange fieldChange =
@ -1422,5 +1423,9 @@ public abstract class EntityRepository<T extends EntityInterface> {
private void storeNewVersion() throws IOException {
EntityRepository.this.storeEntity(updated, true);
}
public final boolean updatedByBot() {
return Boolean.TRUE.equals(updatingUser.getIsBot());
}
}
}

View File

@ -49,7 +49,6 @@ public class IngestionPipelineRepository extends EntityRepository<IngestionPipel
dao,
PATCH_FIELDS,
UPDATE_FIELDS);
this.allowEdits = true;
this.secretsManager = secretsManager;
}

View File

@ -311,8 +311,8 @@ public class PipelineRepository extends EntityRepository<Pipeline> {
}
private void updateTaskDescription(Task origTask, Task updatedTask) throws JsonProcessingException {
if (operation.isPut() && !nullOrEmpty(origTask.getDescription())) {
// Update description only when stored is empty to retain user authored descriptions
if (operation.isPut() && !nullOrEmpty(origTask.getDescription()) && updatedByBot()) {
// Revert the non-empty task description if being updated by a bot
updatedTask.setDescription(origTask.getDescription());
return;
}

View File

@ -148,7 +148,6 @@ public class PolicyRepository extends EntityRepository<Policy> {
if (listOrEmpty(rules).isEmpty()) {
throw new IllegalArgumentException(CatalogExceptionMessage.EMPTY_RULES_IN_POLICY);
}
System.out.println("XXX rules count " + rules.size());
// Validate all the expressions in the rule
for (Rule rule : rules) {

View File

@ -44,11 +44,7 @@ public abstract class ServiceEntityRepository<
SecretsManager secretsManager,
Class<S> serviceConnectionClass,
ServiceType serviceType) {
super(collectionPath, service, entityDAO.getEntityClass(), entityDAO, dao, "", UPDATE_FIELDS);
this.allowEdits = true;
this.secretsManager = secretsManager;
this.serviceConnectionClass = serviceConnectionClass;
this.serviceType = serviceType;
this(collectionPath, service, dao, entityDAO, secretsManager, serviceConnectionClass, UPDATE_FIELDS, serviceType);
}
protected ServiceEntityRepository(
@ -61,7 +57,6 @@ public abstract class ServiceEntityRepository<
String updatedFields,
ServiceType serviceType) {
super(collectionPath, service, entityDAO.getEntityClass(), entityDAO, dao, "", updatedFields);
this.allowEdits = true;
this.secretsManager = secretsManager;
this.serviceConnectionClass = serviceConnectionClass;
this.serviceType = serviceType;

View File

@ -34,7 +34,6 @@ public class StorageServiceRepository extends EntityRepository<StorageService> {
dao,
"",
UPDATE_FIELDS);
this.allowEdits = true;
}
@Override

View File

@ -17,6 +17,7 @@ import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toUnmodifiableList;
import static org.openmetadata.catalog.Entity.DATABASE_SCHEMA;
import static org.openmetadata.catalog.Entity.FIELD_DESCRIPTION;
import static org.openmetadata.catalog.Entity.FIELD_DISPLAY_NAME;
import static org.openmetadata.catalog.Entity.FIELD_FOLLOWERS;
import static org.openmetadata.catalog.Entity.FIELD_OWNER;
import static org.openmetadata.catalog.Entity.FIELD_TAGS;
@ -842,7 +843,7 @@ public class TableRepository extends EntityRepository<Table> {
* {@code entityRelationType}) are ({@link Table#getFullyQualifiedName()}, "table") and ({@link
* Column#getFullyQualifiedName()}, "table.columns.column").
*
* <p>If for an field relation (any relation between {@code entityFQN} and a FQN from {@code joinedWithList}), after
* <p>If for a field relation (any relation between {@code entityFQN} and a FQN from {@code joinedWithList}), after
* combining the existing list of {@link DailyCount} with join data from {@code joinedWithList}, there are multiple
* {@link DailyCount} with the {@link DailyCount#getDate()}, these will <bold>NOT</bold> be merged - the value of
* {@link JoinedWith#getJoinCount()} will override the current value.
@ -1004,7 +1005,7 @@ public class TableRepository extends EntityRepository<Table> {
.collect(Collectors.toList());
}
private TableJoins getJoins(Table table) throws IOException {
private TableJoins getJoins(Table table) {
String today = RestUtil.DATE_FORMAT.format(new Date());
String todayMinus30Days = CommonUtil.getDateStringByOffset(RestUtil.DATE_FORMAT, today, -30);
return new TableJoins()
@ -1014,7 +1015,7 @@ public class TableRepository extends EntityRepository<Table> {
.withDirectTableJoins(getDirectTableJoins(table));
}
private List<JoinedWith> getDirectTableJoins(Table table) throws IOException {
private List<JoinedWith> getDirectTableJoins(Table table) {
// Pair<toTableFQN, List<DailyCount>>
List<Pair<String, List<DailyCount>>> entityRelations =
daoCollection.fieldRelationshipDAO()
@ -1036,7 +1037,7 @@ public class TableRepository extends EntityRepository<Table> {
.collect(Collectors.toList());
}
private List<ColumnJoin> getColumnJoins(Table table) throws IOException {
private List<ColumnJoin> getColumnJoins(Table table) {
// Triple<fromRelativeColumnName, toFQN, List<DailyCount>>
List<Triple<String, String, List<DailyCount>>> entityRelations =
daoCollection.fieldRelationshipDAO()
@ -1216,6 +1217,7 @@ public class TableRepository extends EntityRepository<Table> {
}
updateColumnDescription(stored, updated);
updateColumnDisplayName(stored, updated);
updateColumnDataLength(stored, updated);
updateColumnPrecision(stored, updated);
updateColumnScale(stored, updated);
@ -1236,8 +1238,8 @@ public class TableRepository extends EntityRepository<Table> {
}
private void updateColumnDescription(Column origColumn, Column updatedColumn) throws JsonProcessingException {
if (operation.isPut() && !nullOrEmpty(origColumn.getDescription())) {
// Update description only when stored is empty to retain user authored descriptions
if (operation.isPut() && !nullOrEmpty(origColumn.getDescription()) && updatedByBot()) {
// Revert the non-empty task description if being updated by a bot
updatedColumn.setDescription(origColumn.getDescription());
return;
}
@ -1245,6 +1247,16 @@ public class TableRepository extends EntityRepository<Table> {
recordChange(columnField, origColumn.getDescription(), updatedColumn.getDescription());
}
private void updateColumnDisplayName(Column origColumn, Column updatedColumn) throws JsonProcessingException {
if (operation.isPut() && !nullOrEmpty(origColumn.getDescription()) && updatedByBot()) {
// Revert the non-empty task description if being updated by a bot
updatedColumn.setDisplayName(origColumn.getDisplayName());
return;
}
String columnField = getColumnField(original, origColumn, FIELD_DISPLAY_NAME);
recordChange(columnField, origColumn.getDisplayName(), updatedColumn.getDisplayName());
}
private void updateColumnConstraint(Column origColumn, Column updatedColumn) throws JsonProcessingException {
String columnField = getColumnField(original, origColumn, "constraint");
recordChange(columnField, origColumn.getConstraint(), updatedColumn.getConstraint());

View File

@ -40,7 +40,6 @@ public class TagCategoryRepository extends EntityRepository<TagCategory> {
public TagCategoryRepository(CollectionDAO dao, TagRepository tagRepository) {
super(TagResource.TAG_COLLECTION_PATH, Entity.TAG_CATEGORY, TagCategory.class, dao.tagCategoryDAO(), dao, "", "");
allowEdits = true;
this.tagRepository = tagRepository;
}

View File

@ -35,7 +35,6 @@ import org.openmetadata.catalog.util.JsonUtils;
public class TagRepository extends EntityRepository<Tag> {
public TagRepository(CollectionDAO dao) {
super(TagResource.TAG_COLLECTION_PATH, Entity.TAG, Tag.class, dao.tagDAO(), dao, "", "");
allowEdits = true;
}
/**

View File

@ -47,7 +47,6 @@ public class TypeRepository extends EntityRepository<Type> {
public TypeRepository(CollectionDAO dao) {
super(TypeResource.COLLECTION_PATH, Entity.TYPE, Type.class, dao.typeEntityDAO(), dao, PATCH_FIELDS, UPDATE_FIELDS);
allowEdits = true;
}
@Override

View File

@ -119,12 +119,9 @@ public class SubjectCache {
}
public List<EntityReference> getRolesForTeams(List<EntityReference> teams) {
System.out.println("Getting roles for teams " + teams);
List<EntityReference> roles = new ArrayList<>();
for (EntityReference teamRef : listOrEmpty(teams)) {
System.out.println("roles for team " + teamRef.getName());
Team team = getTeam(teamRef.getId());
System.out.println("roles for team adding " + team.getDefaultRoles());
roles.addAll(team.getDefaultRoles());
roles.addAll(getRolesForTeams(team.getParents()));
}

View File

@ -1,24 +0,0 @@
package org.openmetadata.catalog.jdbi3;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;
import org.openmetadata.catalog.entity.data.Table;
import org.openmetadata.catalog.type.Column;
public class TableRepositoryUnitTest {
@Test
void testWhenUpdatingAColumnDataLengthWhichWasNotSet_issue6868() throws JsonProcessingException {
TableRepository outerObject = new TableRepository(mock(CollectionDAO.class));
Table origTable = new Table().withFullyQualifiedName("service.db.table");
TableRepository.TableUpdater tableUpdater =
outerObject.new TableUpdater(origTable, new Table(), EntityRepository.Operation.PUT);
Column origColumn = new Column().withFullyQualifiedName("service.db.table.column");
Column newColumn = new Column().withFullyQualifiedName("service.db.table.column").withDataLength(100);
tableUpdater.updateColumnDataLength(origColumn, newColumn);
assertTrue(tableUpdater.majorVersionChange);
}
}

View File

@ -41,6 +41,7 @@ import static org.openmetadata.catalog.exception.CatalogExceptionMessage.readOnl
import static org.openmetadata.catalog.security.SecurityUtil.authHeaders;
import static org.openmetadata.catalog.security.SecurityUtil.getPrincipalName;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.BOT_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.ENTITY_NAME_LENGTH_ERROR;
import static org.openmetadata.catalog.util.TestUtils.LONG_ENTITY_NAME;
import static org.openmetadata.catalog.util.TestUtils.NON_EXISTENT_ENTITY;
@ -104,13 +105,6 @@ import org.openmetadata.catalog.entity.data.GlossaryTerm;
import org.openmetadata.catalog.entity.data.Table;
import org.openmetadata.catalog.entity.policies.Policy;
import org.openmetadata.catalog.entity.policies.accessControl.Rule;
import org.openmetadata.catalog.entity.services.DashboardService;
import org.openmetadata.catalog.entity.services.DatabaseService;
import org.openmetadata.catalog.entity.services.MessagingService;
import org.openmetadata.catalog.entity.services.MlModelService;
import org.openmetadata.catalog.entity.services.PipelineService;
import org.openmetadata.catalog.entity.services.StorageService;
import org.openmetadata.catalog.entity.services.ingestionPipelines.IngestionPipeline;
import org.openmetadata.catalog.entity.teams.Role;
import org.openmetadata.catalog.entity.teams.Team;
import org.openmetadata.catalog.entity.teams.User;
@ -185,6 +179,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
public static User USER2;
public static EntityReference USER2_REF;
public static User USER_TEAM21;
public static User BOT_USER;
public static Team ORG_TEAM;
public static Team TEAM1;
@ -352,6 +347,9 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
}
public final K createRequest(String name, String description, String displayName, EntityReference owner) {
if (!supportsEmptyDescription && description == null) {
throw new IllegalArgumentException("Entity " + entityType + " does not support empty description");
}
return createRequest(name)
.withDescription(description)
.withDisplayName(displayName)
@ -383,17 +381,22 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
public abstract void validateCreatedEntity(T createdEntity, K request, Map<String, String> authHeaders)
throws HttpResponseException;
// Entity specific validate for entity create using PUT
public void validateUpdatedEntity(T updatedEntity, K request, Map<String, String> authHeaders)
// Entity specific validate for entity created using PUT
public void validateUpdatedEntity(T updatedEntity, K request, Map<String, String> authHeaders, UpdateType updateType)
throws HttpResponseException {
validateCommonEntityFields(updatedEntity, request, authHeaders);
if (updateType == NO_CHANGE) {
// Check updated entity only when a change is made
assertListNotNull(updatedEntity.getId(), updatedEntity.getHref(), updatedEntity.getFullyQualifiedName());
return;
}
validateCommonEntityFields(updatedEntity, request, getPrincipalName(authHeaders));
validateCreatedEntity(updatedEntity, request, authHeaders);
}
protected void validateDeletedEntity(
K create, T entityBeforeDeletion, T entityAfterDeletion, Map<String, String> authHeaders)
throws HttpResponseException {
validateCommonEntityFields(entityAfterDeletion, create, authHeaders);
validateCommonEntityFields(entityAfterDeletion, create, getPrincipalName(authHeaders));
validateCreatedEntity(entityAfterDeletion, create, authHeaders);
}
@ -993,31 +996,32 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
@Test
void put_entityNonEmptyDescriptionUpdate_200(TestInfo test) throws IOException {
// Create entity with non-empty description
K request = createRequest(getEntityName(test), "description", "displayName", null);
K request = createRequest(getEntityName(test), supportsEmptyDescription ? null : "description", null, null);
T entity = createAndCheckEntity(request, ADMIN_AUTH_HEADERS);
// Update non-empty description with a new description
Double oldVersion = entity.getVersion();
request = createRequest(getEntityName(test), "updatedDescription", "displayName", null);
entity = updateEntity(request, OK, ADMIN_AUTH_HEADERS);
// For service resources, we allow update of non-empty description via PUT
List<Class<?>> services =
Arrays.asList(
DatabaseService.class,
PipelineService.class,
StorageService.class,
DashboardService.class,
MessagingService.class,
IngestionPipeline.class,
MlModelService.class,
Type.class);
if (services.contains(entity.getClass())) {
assertNotEquals(oldVersion, entity.getVersion()); // Version did change
assertEquals("updatedDescription", entity.getDescription()); // Description did change
} else {
assertEquals(oldVersion, entity.getVersion()); // Version did not change
assertEquals("description", entity.getDescription()); // Description did not change
// BOT user can update empty description and empty displayName
ChangeDescription change = getChangeDescription(entity.getVersion());
request = createRequest(getEntityName(test), "description", "displayName", null);
if (supportsEmptyDescription) {
change.getFieldsAdded().add(new FieldChange().withName("description").withNewValue("description"));
}
change.getFieldsAdded().add(new FieldChange().withName("displayName").withNewValue("displayName"));
entity = updateAndCheckEntity(request, OK, BOT_AUTH_HEADERS, MINOR_UPDATE, change);
// Updating non-empty description and non-empty displayName is allowed for users other than bots
request = createRequest(getEntityName(test), "updatedDescription", "updatedDisplayName", null);
change = getChangeDescription(entity.getVersion());
change
.getFieldsAdded()
.add(new FieldChange().withName("description").withOldValue("description").withNewValue("updatedDescription"));
change
.getFieldsAdded()
.add(new FieldChange().withName("displayName").withOldValue("displayName").withNewValue("updatedDisplayName"));
updateAndCheckEntity(request, OK, ADMIN_AUTH_HEADERS, NO_CHANGE, null);
// Updating non-empty description and non-empty displayName is not allowed for bot users
request = createRequest(getEntityName(test), "updatedDescription2", "updatedDisplayName2", null);
updateAndCheckEntity(request, OK, BOT_AUTH_HEADERS, NO_CHANGE, null);
}
@Test
@ -1322,10 +1326,16 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
entity = patchEntity(entity.getId(), json, entity, ADMIN_AUTH_HEADERS);
assertEquals(JsonUtils.valueToTree(jsonNode), JsonUtils.valueToTree(entity.getExtension()));
// PUT and remove field intA from the the entity extension
// TODO to do change description for stored customProperties
// PUT and remove field intA from the entity extension - for BOT this should be ignored
JsonNode oldNode = JsonUtils.valueToTree(entity.getExtension());
jsonNode.remove("intA");
create = createRequest(test).withExtension(jsonNode);
entity = updateEntity(create, Status.OK, BOT_AUTH_HEADERS);
assertNotEquals(JsonUtils.valueToTree(create.getExtension()), JsonUtils.valueToTree(entity.getExtension()));
assertEquals(oldNode, JsonUtils.valueToTree(entity.getExtension())); // Extension remains as is
// PUT and remove field intA from the the entity extension
// TODO to do change description for stored customProperties
entity = updateEntity(create, Status.OK, ADMIN_AUTH_HEADERS);
assertEquals(JsonUtils.valueToTree(create.getExtension()), JsonUtils.valueToTree(entity.getExtension()));
@ -1596,31 +1606,27 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
return entity;
}
public final T createAndCheckEntity(K create, Map<String, String> authHeaders) throws IOException {
return createAndCheckEntity(create, authHeaders, create);
}
/** Helper function to create an entity, submit POST API request and validate response. */
public final T createAndCheckEntity(K create, Map<String, String> authHeaders, K created) throws IOException {
public final T createAndCheckEntity(K create, Map<String, String> authHeaders) throws IOException {
// Validate an entity that is created has all the information set in create request
String updatedBy = SecurityUtil.getPrincipalName(authHeaders);
T entity = createEntity(create, authHeaders);
assertEquals(updatedBy, entity.getUpdatedBy());
assertEquals(0.1, entity.getVersion()); // First version of the entity
validateCommonEntityFields(entity, created, authHeaders);
validateCreatedEntity(entity, created, authHeaders);
validateCommonEntityFields(entity, create, updatedBy);
validateCreatedEntity(entity, create, authHeaders);
// GET the entity created and ensure it has all the information set in create request
T getEntity = getEntity(entity.getId(), authHeaders);
assertEquals(0.1, entity.getVersion()); // First version of the entity
validateCommonEntityFields(entity, created, authHeaders);
validateCreatedEntity(getEntity, created, authHeaders);
validateCommonEntityFields(entity, create, updatedBy);
validateCreatedEntity(getEntity, create, authHeaders);
getEntity = getEntityByName(entity.getFullyQualifiedName(), allFields, authHeaders);
assertEquals(0.1, entity.getVersion()); // First version of the entity
validateCommonEntityFields(entity, created, authHeaders);
validateCreatedEntity(getEntity, created, authHeaders);
validateCommonEntityFields(entity, create, updatedBy);
validateCreatedEntity(getEntity, create, authHeaders);
// Validate that change event was created
validateChangeEvents(entity, entity.getUpdatedAt(), EventType.ENTITY_CREATED, null, authHeaders);
@ -1635,14 +1641,14 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
ChangeDescription changeDescription)
throws IOException {
T updated = updateEntity(request, status, authHeaders);
validateUpdatedEntity(updated, request, authHeaders);
validateUpdatedEntity(updated, request, authHeaders, updateType);
validateChangeDescription(updated, updateType, changeDescription);
validateEntityHistory(updated.getId(), updateType, changeDescription, authHeaders);
validateLatestVersion(updated, updateType, changeDescription, authHeaders);
// GET the newly updated entity and validate
T getEntity = getEntity(updated.getId(), authHeaders);
validateUpdatedEntity(getEntity, request, authHeaders);
validateUpdatedEntity(getEntity, request, authHeaders, updateType);
validateChangeDescription(getEntity, updateType, changeDescription);
// Check if the entity change events are record
@ -1699,10 +1705,12 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
ChangeDescription expectedChange)
throws IOException {
String updatedBy = updateType == NO_CHANGE ? updated.getUpdatedBy() : getPrincipalName(authHeaders);
// Validate information returned in patch response has the updates
T returned = patchEntity(updated.getId(), originalJson, updated, authHeaders);
validateCommonEntityFields(updated, returned, authHeaders);
validateCommonEntityFields(updated, returned, updatedBy);
compareEntities(updated, returned, authHeaders);
validateChangeDescription(returned, updateType, expectedChange);
validateEntityHistory(returned.getId(), updateType, expectedChange, authHeaders);
@ -1710,7 +1718,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
// GET the entity and Validate information returned
T getEntity = getEntity(returned.getId(), authHeaders);
validateCommonEntityFields(updated, returned, authHeaders);
validateCommonEntityFields(updated, returned, updatedBy);
compareEntities(updated, getEntity, authHeaders);
validateChangeDescription(getEntity, updateType, expectedChange);
@ -1748,24 +1756,24 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
entity, originalJson, authHeaders(userName + "@open-metadata.org"), MINOR_UPDATE, change);
}
protected final void validateCommonEntityFields(T entity, CreateEntity create, Map<String, String> authHeaders) {
protected final void validateCommonEntityFields(T entity, CreateEntity create, String updatedBy) {
assertListNotNull(entity.getId(), entity.getHref(), entity.getFullyQualifiedName());
assertEquals(create.getName(), entity.getName());
assertEquals(create.getDisplayName(), entity.getDisplayName());
assertEquals(create.getDescription(), entity.getDescription());
assertEquals(JsonUtils.valueToTree(create.getExtension()), JsonUtils.valueToTree(entity.getExtension()));
assertReference(create.getOwner(), entity.getOwner());
assertEquals(getPrincipalName(authHeaders), entity.getUpdatedBy());
assertEquals(updatedBy, entity.getUpdatedBy());
}
protected final void validateCommonEntityFields(T expected, T actual, Map<String, String> authHeaders) {
protected final void validateCommonEntityFields(T expected, T actual, String updatedBy) {
assertListNotNull(actual.getId(), actual.getHref(), actual.getFullyQualifiedName());
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDisplayName(), actual.getDisplayName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(JsonUtils.valueToTree(expected.getExtension()), JsonUtils.valueToTree(actual.getExtension()));
assertReference(expected.getOwner(), actual.getOwner());
assertEquals(getPrincipalName(authHeaders), actual.getUpdatedBy());
assertEquals(updatedBy, actual.getUpdatedBy());
}
protected final void validateChangeDescription(T updated, UpdateType updateType, ChangeDescription expectedChange)
@ -1773,9 +1781,9 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
if (updateType == UpdateType.CREATED) {
return; // PUT operation was used to create an entity. No change description expected.
}
TestUtils.validateUpdate(expectedChange.getPreviousVersion(), updated.getVersion(), updateType);
if (updateType != UpdateType.NO_CHANGE) {
TestUtils.validateUpdate(expectedChange.getPreviousVersion(), updated.getVersion(), updateType);
assertChangeDescription(expectedChange, updated.getChangeDescription());
}
}
@ -1866,7 +1874,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
assertEquals(0.1, changeEvent.getPreviousVersion());
assertNull(changeEvent.getChangeDescription());
T changeEventEntity = JsonUtils.readValue((String) changeEvent.getEntity(), entityClass);
validateCommonEntityFields(entity, changeEventEntity, authHeaders);
validateCommonEntityFields(entity, changeEventEntity, getPrincipalName(authHeaders));
compareChangeEventsEntities(entity, changeEventEntity, authHeaders);
} else if (expectedEventType == EventType.ENTITY_UPDATED) {
assertChangeDescription(expectedChangeDescription, changeEvent.getChangeDescription());

View File

@ -38,6 +38,13 @@ class BotResourceTest extends EntityResourceTest<Bot, CreateBot> {
botUserRef = botUser.getEntityReference();
}
@Test
void put_entityNonEmptyDescriptionUpdate_200(TestInfo test) throws IOException {
// PUT based updates are categorized as create operation
// PUT from a bot to update itself is rejected because of that
// TODO turning off the test for now which requires BOT to make update using PUT
}
@Test
void delete_ensureBotUserDelete(TestInfo test) throws IOException {
UserResourceTest userResourceTest = new UserResourceTest();

View File

@ -41,6 +41,7 @@ import static org.openmetadata.catalog.util.EntityUtil.tagLabelMatch;
import static org.openmetadata.catalog.util.FullyQualifiedName.build;
import static org.openmetadata.catalog.util.RestUtil.DATE_FORMAT;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.BOT_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.NON_EXISTENT_ENTITY;
import static org.openmetadata.catalog.util.TestUtils.TEST_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.UpdateType;
@ -290,117 +291,118 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
@Test
void put_tableWithColumnWithOrdinalPositionAndWithoutOrdinalPosition(TestInfo test) throws IOException {
CreateTable create = createRequest(test);
List<Column> columns = new ArrayList<>();
Column column1 = getColumn("column1", INT, null).withOrdinalPosition(1).withDescription("column1");
Column column2 = getColumn("column2", INT, null).withOrdinalPosition(2).withDescription("column2");
List<Column> origColumns = new ArrayList<>();
origColumns.add(column1);
origColumns.add(column2);
// add 2 columns
columns.add(column1);
columns.add(column2);
Column column1 = getColumn("column1", INT, null, "column1", "c1").withOrdinalPosition(1);
Column column2 = getColumn("column2", INT, null, "column2", "c2").withOrdinalPosition(2);
Column column3 =
getColumn("column3", STRING, null, "column3", null)
.withOrdinalPosition(3)
.withTags(List.of(USER_ADDRESS_TAG_LABEL, GLOSSARY1_TERM1_LABEL));
TableConstraint constraint =
new TableConstraint().withConstraintType(ConstraintType.UNIQUE).withColumns(List.of(columns.get(0).getName()));
new TableConstraint().withConstraintType(ConstraintType.UNIQUE).withColumns(List.of(column1.getName()));
TablePartition partition =
new TablePartition()
.withColumns(List.of(columns.get(0).getName(), columns.get(1).getName()))
.withColumns(List.of(column1.getName(), column2.getName()))
.withIntervalType(TablePartition.IntervalType.COLUMN_VALUE)
.withInterval("column");
create.setColumns(columns);
//
// Create a table with two columns - column1, column2, table constraint and table partition
//
create.setColumns(new ArrayList<>(List.of(column1, column2)));
create.setTableConstraints(List.of(constraint));
create.setTablePartition(partition);
Table created = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
Column column = created.getColumns().get(0);
assertEquals("column1", column.getName());
assertEquals("column1", column.getDescription());
assertTablePartition(partition, created.getTablePartition());
createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
// keep original ordinalPosition add a column at the end and do not pass descriptions for the first 2 columns
// we should retain the original description
//
// Update the column description and display name as a BOT user.
// The updates are ignored for a BOT user and the table version does not change
//
create.getColumns().set(0, getColumn("column1", INT, null, "x", "y"));
Table table = updateAndCheckEntity(create, OK, BOT_AUTH_HEADERS, NO_CHANGE, null);
create.getColumns().set(0, column1); // Revert to previous value
Column updateColumn1 = getColumn("column1", INT, null).withOrdinalPosition(1).withDescription("");
Column updateColumn2 = getColumn("column2", INT, null).withOrdinalPosition(2).withDescription("");
Column column3 =
getColumn("column3", STRING, null)
.withOrdinalPosition(3)
.withDescription("column3")
.withTags(List.of(USER_ADDRESS_TAG_LABEL, GLOSSARY1_TERM1_LABEL));
columns = new ArrayList<>();
columns.add(updateColumn1);
columns.add(updateColumn2);
columns.add(column3);
//
// Description and DisplayName can be updated by a non-bot user
// Update column1 description and displayName.
// Remove column2 display name.
// Add a new column column3.
// Update table partition
//
column1.withDescription("").withDisplayName("");
column2.withDisplayName(null);
create.getColumns().add(column3);
partition =
new TablePartition()
.withColumns(List.of(columns.get(2).getName()))
.withColumns(List.of(column3.getName()))
.withIntervalType(TablePartition.IntervalType.COLUMN_VALUE)
.withInterval("column");
create.setColumns(columns);
create.setTableConstraints(List.of(constraint));
create.setTablePartition(partition);
// Update the table with constraints and ensure minor version change
ChangeDescription change = getChangeDescription(created.getVersion());
ChangeDescription change = getChangeDescription(table.getVersion());
change.getFieldsAdded().add(new FieldChange().withName("columns").withNewValue(List.of(column3)));
Table updatedTable = updateEntity(create, OK, ADMIN_AUTH_HEADERS);
origColumns.add(column3);
assertColumns(origColumns, updatedTable.getColumns());
assertTablePartition(partition, updatedTable.getTablePartition());
Table getTable = getEntity(updatedTable.getId(), "tablePartition", ADMIN_AUTH_HEADERS);
assertTablePartition(partition, getTable.getTablePartition());
change
.getFieldsUpdated()
.add(
new FieldChange()
.withName(build("columns", "column1", "description"))
.withOldValue("column1")
.withNewValue(""));
change
.getFieldsUpdated()
.add(
new FieldChange().withName(build("columns", "column1", "displayName")).withOldValue("c1").withNewValue(""));
change
.getFieldsDeleted()
.add(new FieldChange().withName(build("columns", "column2", "displayName")).withOldValue("c2"));
table = updateAndCheckEntity(create, OK, ADMIN_AUTH_HEADERS, MINOR_UPDATE, change);
TestUtils.validateUpdate(created.getVersion(), updatedTable.getVersion(), MINOR_UPDATE);
// keep ordinalPosition and add a column in between
updateColumn1 = getColumn("column1", INT, null).withOrdinalPosition(1).withDescription("");
Column updateColumn4 = getColumn("column4", STRING, null).withOrdinalPosition(2).withDescription("column4");
updateColumn2 = getColumn("column2", INT, null).withOrdinalPosition(3).withDescription("");
Column updateColumn3 = getColumn("column3", STRING, null).withOrdinalPosition(4).withDescription("");
columns = new ArrayList<>();
columns.add(updateColumn1);
columns.add(updateColumn2);
columns.add(updateColumn4);
columns.add(updateColumn3);
create.setColumns(columns);
create.setTableConstraints(List.of(constraint));
//
// Change the ordinal position of column2 from 2 to 3.
// Change the ordinal position of column3 from 3 to 4.
// Add column4 with ordinal position 3.
//
// After the update: TODO is this correct?
// Column 3 must retain the ordinal position as 3
// Column 4 must change to ordinal position as 4
//
column2.setOrdinalPosition(3);
column3.setOrdinalPosition(4);
Column column4 = getColumn("column4", STRING, null, "column4", null).withOrdinalPosition(2);
create.getColumns().add(2, column4);
Double prevVersion = updatedTable.getVersion();
updatedTable = updateEntity(create, OK, ADMIN_AUTH_HEADERS);
TestUtils.validateUpdate(prevVersion, updatedTable.getVersion(), MINOR_UPDATE);
origColumns.add(2, updateColumn4);
assertColumns(origColumns, updatedTable.getColumns());
change = getChangeDescription(table.getVersion());
change.getFieldsAdded().add(new FieldChange().withName("columns").withNewValue(List.of(column4)));
table = updateAndCheckEntity(create, OK, ADMIN_AUTH_HEADERS, MINOR_UPDATE, change);
// Change data type to cause major update
updateColumn3 = getColumn("column3", INT, null).withOrdinalPosition(4).withDescription("");
columns = new ArrayList<>();
columns.add(updateColumn1);
columns.add(updateColumn2);
columns.add(updateColumn4);
columns.add(updateColumn3);
create.setColumns(columns);
create.setTableConstraints(List.of(constraint));
prevVersion = updatedTable.getVersion();
updatedTable = updateEntity(create, OK, ADMIN_AUTH_HEADERS);
TestUtils.validateUpdate(prevVersion, updatedTable.getVersion(), MAJOR_UPDATE);
origColumns.remove(3);
origColumns.add(3, column3.withDataType(INT));
assertColumns(origColumns, updatedTable.getColumns());
// Change column1 data type from INT to STRING to cause major update
Column updatedColumn1 = getColumn("column1", STRING, null, "column1", "c1").withOrdinalPosition(1);
create.getColumns().set(0, updatedColumn1);
change = getChangeDescription(table.getVersion());
change.getFieldsDeleted().add(new FieldChange().withName("columns").withOldValue(List.of(column1)));
change.getFieldsAdded().add(new FieldChange().withName("columns").withNewValue(List.of(updatedColumn1)));
table = updateAndCheckEntity(create, OK, ADMIN_AUTH_HEADERS, MAJOR_UPDATE, change);
// Change the case of the column name and it should't update
updateColumn2 = getColumn("COLUMN2", INT, null).withOrdinalPosition(2).withDescription("");
columns = new ArrayList<>();
columns.add(updateColumn1);
columns.add(updateColumn2);
columns.add(updateColumn4);
columns.add(updateColumn3);
create.setColumns(columns);
create.setTableConstraints(List.of(constraint));
prevVersion = updatedTable.getVersion();
updatedTable = updateEntity(create, OK, ADMIN_AUTH_HEADERS);
TestUtils.validateUpdate(prevVersion, updatedTable.getVersion(), NO_CHANGE);
// Delete column4 to cause major update
create.getColumns().remove(2);
change = getChangeDescription(table.getVersion());
change.getFieldsDeleted().add(new FieldChange().withName("columns").withOldValue(List.of(column4)));
updateAndCheckEntity(create, OK, ADMIN_AUTH_HEADERS, MAJOR_UPDATE, change);
// Change the case of the column name for column2, and it shouldn't update
column2.setName("COLUMN2");
updateAndCheckEntity(create, OK, ADMIN_AUTH_HEADERS, NO_CHANGE, null);
}
public static Column getColumn(String name, ColumnDataType columnDataType, TagLabel tag) {
return getColumn(name, columnDataType, null, tag);
}
public static Column getColumn(
String name, ColumnDataType columnDataType, TagLabel tag, String description, String displayName) {
return getColumn(name, columnDataType, null, tag).withDescription(description).withDisplayName(displayName);
}
private static Column getColumn(String name, ColumnDataType columnDataType, String dataTypeDisplay, TagLabel tag) {
List<TagLabel> tags = tag == null ? new ArrayList<>() : singletonList(tag);
return new Column()
@ -1991,14 +1993,19 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
private static void assertColumns(List<Column> expectedColumns, List<Column> actualColumns)
throws HttpResponseException {
if (expectedColumns == null && actualColumns == null) {
if (expectedColumns == actualColumns) {
return;
}
// Sort columns by name
assertNotNull(expectedColumns);
assertEquals(expectedColumns.size(), actualColumns.size());
for (int i = 0; i < expectedColumns.size(); i++) {
assertColumn(expectedColumns.get(i), actualColumns.get(i));
// Make a copy before sorting in case the lists are immutable
List<Column> expected = new ArrayList<>(expectedColumns);
List<Column> actual = new ArrayList<>(actualColumns);
expected.sort(Comparator.comparing(Column::getName));
actual.sort(Comparator.comparing(Column::getName));
for (int i = 0; i < expected.size(); i++) {
assertColumn(expected.get(i), actual.get(i));
}
}
@ -2353,6 +2360,7 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
validateEntityReference(createdEntity.getDatabase());
validateEntityReference(createdEntity.getService());
validateTableConstraints(createRequest.getTableConstraints(), createdEntity.getTableConstraints());
assertTablePartition(createRequest.getTablePartition(), createdEntity.getTablePartition());
TestUtils.validateTags(createRequest.getTags(), createdEntity.getTags());
TestUtils.validateEntityReferences(createdEntity.getFollowers());
assertListNotNull(createdEntity.getService(), createdEntity.getServiceType());
@ -2421,12 +2429,15 @@ public class TableResourceTest extends EntityResourceTest<Table, CreateTable> {
ColumnConstraint expectedConstraint = (ColumnConstraint) expected;
ColumnConstraint actualConstraint = ColumnConstraint.fromValue((String) actual);
assertEquals(expectedConstraint, actualConstraint);
} else if (fieldName.startsWith("columns")
&& (fieldName.endsWith("description") || fieldName.endsWith("displayName"))) {
assertEquals(expected, actual);
} else if (fieldName.endsWith("tableConstraints")) {
@SuppressWarnings("unchecked")
List<TableConstraint> expectedConstraints = (List<TableConstraint>) expected;
List<TableConstraint> actualConstraints = JsonUtils.readObjects(actual.toString(), TableConstraint.class);
assertEquals(expectedConstraints, actualConstraints);
} else if (fieldName.contains("columns") && !fieldName.endsWith(FIELD_TAGS) && !fieldName.endsWith("description")) {
} else if (fieldName.contains("columns") && !fieldName.endsWith(FIELD_TAGS)) {
@SuppressWarnings("unchecked")
List<Column> expectedRefs = (List<Column>) expected;
List<Column> actualRefs = JsonUtils.readObjects(actual.toString(), Column.class);

View File

@ -4,6 +4,7 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static javax.ws.rs.core.Response.Status.OK;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.openmetadata.catalog.security.SecurityUtil.getPrincipalName;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
import static org.openmetadata.catalog.util.TestUtils.assertResponseContains;
@ -428,7 +429,7 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
@Override
public void validateCreatedEntity(TestCase createdEntity, CreateTestCase request, Map<String, String> authHeaders)
throws HttpResponseException {
validateCommonEntityFields(createdEntity, request, authHeaders);
validateCommonEntityFields(createdEntity, request, getPrincipalName(authHeaders));
assertEquals(request.getEntityLink(), createdEntity.getEntityLink());
assertEquals(request.getTestSuite(), createdEntity.getTestSuite());
assertEquals(request.getTestDefinition(), createdEntity.getTestDefinition());
@ -439,7 +440,7 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
@Override
public void compareEntities(TestCase expected, TestCase updated, Map<String, String> authHeaders)
throws HttpResponseException {
validateCommonEntityFields(expected, updated, authHeaders);
validateCommonEntityFields(expected, updated, getPrincipalName(authHeaders));
assertEquals(expected.getEntityLink(), updated.getEntityLink());
assertEquals(expected.getTestSuite(), updated.getTestSuite());
assertEquals(expected.getTestDefinition(), updated.getTestDefinition());

View File

@ -14,7 +14,6 @@
package org.openmetadata.catalog.resources.locations;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.OK;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.assertListNotNull;
@ -189,17 +188,6 @@ public class LocationResourceTest extends EntityResourceTest<Location, CreateLoc
}
}
@Test
void put_locationNonEmptyDescriptionUpdate_200(TestInfo test) throws IOException {
CreateLocation request =
createRequest(test).withService(AWS_STORAGE_SERVICE_REFERENCE).withDescription("description");
createAndCheckEntity(request, ADMIN_AUTH_HEADERS);
// Updating description is ignored when backend already has description
Location location = updateLocation(request.withDescription("newDescription"), OK, ADMIN_AUTH_HEADERS);
assertEquals("description", location.getDescription());
}
public static Location updateLocation(CreateLocation create, Status status, Map<String, String> authHeaders)
throws HttpResponseException {
return TestUtils.put(getResource("locations"), create, Location.class, status, authHeaders);

View File

@ -187,7 +187,6 @@ public class PolicyResourceTest extends EntityResourceTest<Policy, CreatePolicy>
// Ensure validation API works for the valid conditions
for (String condition : List.of("isOwner()", "!isOwner()", "noOwner()", "isOwner() || noOwner()")) {
System.out.println("XXX condition " + condition);
validateCondition(condition); // No exception should be thrown
}

View File

@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.BOT_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.TEST_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
@ -231,7 +232,7 @@ public class DashboardServiceResourceTest extends EntityResourceTest<DashboardSe
}
assertEquals(expectedSupersetConnection.getHostPort(), actualSupersetConnection.getHostPort());
assertEquals(expectedSupersetConnection.getProvider(), actualSupersetConnection.getProvider());
if (ADMIN_AUTH_HEADERS.equals(authHeaders)) {
if (ADMIN_AUTH_HEADERS.equals(authHeaders) || BOT_AUTH_HEADERS.equals(authHeaders)) {
assertEquals(expectedSupersetConnection.getUsername(), actualSupersetConnection.getUsername());
assertEquals(expectedSupersetConnection.getPassword(), actualSupersetConnection.getPassword());
assertEquals(expectedSupersetConnection.getProvider(), actualSupersetConnection.getProvider());

View File

@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.openmetadata.catalog.resources.services.DatabaseServiceResourceTest.validateMysqlConnection;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.AIRFLOW_CONNECTION;
import static org.openmetadata.catalog.util.TestUtils.BOT_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.MYSQL_DATABASE_CONNECTION;
import static org.openmetadata.catalog.util.TestUtils.TEST_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
@ -274,7 +275,7 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
MysqlConnection expectedMysqlConnection = (MysqlConnection) expectedDatabaseConnection.getConfig();
// Use the database service tests utilities for the comparison
// only admin can see all connection parameters
if (ADMIN_AUTH_HEADERS.equals(authHeaders)) {
if (ADMIN_AUTH_HEADERS.equals(authHeaders) || BOT_AUTH_HEADERS.equals(authHeaders)) {
DatabaseConnection actualDatabaseConnection =
JsonUtils.convertValue(actualAirflowConnection.getConnection(), DatabaseConnection.class);
MysqlConnection actualMysqlConnection =

View File

@ -31,6 +31,7 @@ import static org.openmetadata.catalog.exception.CatalogExceptionMessage.notAdmi
import static org.openmetadata.catalog.exception.CatalogExceptionMessage.permissionNotAllowed;
import static org.openmetadata.catalog.security.SecurityUtil.authHeaders;
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.BOT_USER_NAME;
import static org.openmetadata.catalog.util.TestUtils.TEST_AUTH_HEADERS;
import static org.openmetadata.catalog.util.TestUtils.TEST_USER_NAME;
import static org.openmetadata.catalog.util.TestUtils.UpdateType.MINOR_UPDATE;
@ -122,6 +123,9 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
create = createRequest(test, 2).withTeams(List.of(TEAM21.getId()));
USER_TEAM21 = createEntity(create, ADMIN_AUTH_HEADERS);
USER2_REF = USER2.getEntityReference();
create = createRequest(BOT_USER_NAME).withIsBot(true);
BOT_USER = createEntity(create, ADMIN_AUTH_HEADERS);
}
@Test
@ -246,7 +250,7 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
CreateUser create = createRequest(test).withRoles(roles);
List<UUID> createdRoles = Arrays.asList(role1.getId(), role2.getId());
CreateUser created = createRequest(test).withRoles(createdRoles);
User user = createAndCheckEntity(create, ADMIN_AUTH_HEADERS, created);
User user = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
// Ensure User has relationship to these roles
String[] expectedRoles = createdRoles.stream().map(UUID::toString).sorted().toArray(String[]::new);

View File

@ -82,6 +82,8 @@ public final class TestUtils {
public static final String ADMIN_USER_NAME = "admin";
public static final Map<String, String> ADMIN_AUTH_HEADERS = authHeaders(ADMIN_USER_NAME + "@open-metadata.org");
public static final String BOT_USER_NAME = "bot";
public static final Map<String, String> BOT_AUTH_HEADERS = authHeaders(BOT_USER_NAME + "@open-metadata.org");
public static final String TEST_USER_NAME = "test";
public static final Map<String, String> TEST_AUTH_HEADERS = authHeaders(TEST_USER_NAME + "@open-metadata.org");