Merge pull request #966 from open-metadata/issue965

Fixed 965 Add versioning API support for Team Entity
This commit is contained in:
Suresh Srinivas 2021-10-28 15:11:32 -07:00 committed by GitHub
commit 328db526a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 220 additions and 123 deletions

View File

@ -247,13 +247,13 @@ public interface CollectionDAO {
//
@SqlQuery("SELECT toId, toEntity FROM entity_relationship " +
"WHERE fromId = :fromId AND relation = :relation " +
"ORDER BY fromId")
"ORDER BY toId")
@RegisterRowMapper(ToEntityReferenceMapper.class)
List<EntityReference> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation);
@SqlQuery("SELECT toId FROM entity_relationship " +
"WHERE fromId = :fromId AND relation = :relation AND toEntity = :toEntity " +
"ORDER BY fromId")
"ORDER BY toId")
List<String> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation,
@Bind("toEntity") String toEntity);

View File

@ -31,9 +31,11 @@ import org.openmetadata.catalog.util.EntityUtil.Fields;
import org.openmetadata.catalog.util.JsonUtils;
import java.io.IOException;
import java.net.URI;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@ -194,6 +196,9 @@ public class TeamRepository extends EntityRepository<Team> {
@Override
public Date getUpdatedAt() { return entity.getUpdatedAt(); }
@Override
public URI getHref() { return entity.getHref(); }
@Override
public EntityReference getEntityReference() {
return new EntityReference().withId(getId()).withName(getFullyQualifiedName()).withDescription(getDescription())
@ -226,6 +231,9 @@ public class TeamRepository extends EntityRepository<Team> {
entity.setChangeDescription(changeDescription);
}
@Override
public ChangeDescription getChangeDescription() { return entity.getChangeDescription(); }
@Override
public void setTags(List<TagLabel> tags) { }
}
@ -244,18 +252,26 @@ public class TeamRepository extends EntityRepository<Team> {
if (updated.getEntity().getDeleted() != original.getEntity().getDeleted()) {
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute("Team", "deleted"));
}
recordChange("profile", original.getEntity().getProfile(), updated.getEntity().getProfile());
updateUsers(original.getEntity(), updated.getEntity());
}
private void updateUsers(Team origTeam, Team updatedTeam) {
List<EntityReference> origUsers = Optional.ofNullable(origTeam.getUsers()).orElse(Collections.emptyList());
List<EntityReference> updatedUsers = Optional.ofNullable(updatedTeam.getUsers()).orElse(Collections.emptyList());
// Remove users from original and add users from updated
dao.relationshipDAO().deleteFrom(origTeam.getId().toString(), Relationship.CONTAINS.ordinal(), "user");
for (EntityReference user : Optional.ofNullable(updatedTeam.getUsers()).orElse(Collections.emptyList())) {
// Add relationships
for (EntityReference user : updatedUsers) {
dao.relationshipDAO().insert(updatedTeam.getId().toString(), user.getId().toString(),
"team", "user", Relationship.CONTAINS.ordinal());
}
recordChange("users", origTeam.getUsers(), updatedTeam.getUsers());
// Sort by user Id as string (as done in the database)
updatedUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
origUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
recordChange("users", origUsers.isEmpty() ? null : origUsers, updatedUsers.isEmpty() ? null : updatedUsers);
}
}
}

View File

@ -176,7 +176,6 @@ public class UserRepository extends EntityRepository<User> {
private void assignTeams(User user, List<EntityReference> teams) {
// Query - add team to the user
teams = Optional.ofNullable(teams).orElse(Collections.emptyList());
teams.sort(Comparator.comparing(EntityReference::getId)); // Sort team order to the query order
for (EntityReference team : teams) {
dao.relationshipDAO().insert(team.getId().toString(), user.getId().toString(),
"team", "user", CONTAINS.ordinal());
@ -301,19 +300,13 @@ public class UserRepository extends EntityRepository<User> {
dao.relationshipDAO().deleteTo(origUser.getId().toString(), CONTAINS.ordinal(), "team");
assignTeams(updatedUser, updatedUser.getTeams());
List<EntityReference> origTeams = origUser.getTeams();
List<EntityReference> updatedTeams = updatedUser.getTeams();
if (origTeams == null || origTeams.isEmpty()) {
origTeams = null;
} else {
origTeams.sort(Comparator.comparing(EntityReference::getId));
}
if (updatedTeams == null || updatedTeams.isEmpty()) {
updatedTeams = null;
} else {
updatedTeams.sort(Comparator.comparing(EntityReference::getId));
}
recordChange("teams", origTeams, updatedTeams);
List<EntityReference> origTeams = Optional.ofNullable(origUser.getTeams()).orElse(Collections.emptyList());
List<EntityReference> updatedTeams = Optional.ofNullable(updatedUser.getTeams()).orElse(Collections.emptyList());
// Sort by team Id as string (as done in the database)
origTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
updatedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
recordChange("teams", origTeams.isEmpty() ? null : origTeams, updatedTeams.isEmpty() ? null : updatedTeams);
}
}
}

View File

@ -34,6 +34,7 @@ import org.openmetadata.catalog.jdbi3.TeamRepository;
import org.openmetadata.catalog.resources.Collection;
import org.openmetadata.catalog.security.CatalogAuthorizer;
import org.openmetadata.catalog.security.SecurityUtil;
import org.openmetadata.catalog.type.EntityHistory;
import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.util.EntityUtil;
import org.openmetadata.catalog.util.RestUtil;
@ -48,6 +49,7 @@ import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@ -106,7 +108,7 @@ public class TeamResource {
}
}
private static final String FIELDS = "profile,users,owns";
public static final String FIELDS = "profile,users,owns";
public static final List<String> FIELD_LIST = Arrays.asList(FIELDS.replaceAll(" ", "")
.split(","));
@GET
@ -150,6 +152,22 @@ public class TeamResource {
return teams;
}
@GET
@Path("/{id}/versions")
@Operation(summary = "List team versions", tags = "teams",
description = "Get a list of all the versions of a team identified by `id`",
responses = {@ApiResponse(responseCode = "200", description = "List of team versions",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = EntityHistory.class)))
})
public EntityHistory listVersions(@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "team Id", schema = @Schema(type = "string"))
@PathParam("id") String id)
throws IOException, ParseException, GeneralSecurityException {
return dao.listVersions(id);
}
@GET
@Valid
@Path("/{id}")
@ -192,6 +210,27 @@ public class TeamResource {
return addHref(uriInfo, dao.getByName(name, fields));
}
@GET
@Path("/{id}/versions/{version}")
@Operation(summary = "Get a version of the team", tags = "teams",
description = "Get a version of the team by given `id`",
responses = {
@ApiResponse(responseCode = "200", description = "team",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = Team.class))),
@ApiResponse(responseCode = "404", description = "Team for instance {id} and version {version} is " +
"not found")
})
public Team getVersion(@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Team Id", schema = @Schema(type = "string"))
@PathParam("id") String id,
@Parameter(description = "Team version number in the form `major`.`minor`",
schema = @Schema(type = "string", example = "0.1 or 1.1"))
@PathParam("version") String version) throws IOException, ParseException {
return dao.getVersion(id, version);
}
@POST
@Operation(summary = "Create a team", tags = "teams",
description = "Create a new team.",
@ -205,15 +244,30 @@ public class TeamResource {
@Context SecurityContext securityContext,
@Valid CreateTeam ct) throws IOException, ParseException {
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
Team team = new Team().withId(UUID.randomUUID()).withName(ct.getName()).withDescription(ct.getDescription())
.withDisplayName(ct.getDisplayName()).withProfile(ct.getProfile())
.withUpdatedBy(securityContext.getUserPrincipal().getName())
.withUpdatedAt(new Date())
.withUsers(dao.getUsers(ct.getUsers()));
Team team = getTeam(ct, securityContext);
addHref(uriInfo, dao.create(team));
return Response.created(team.getHref()).entity(team).build();
}
@PUT
@Operation(summary = "Create or Update a team", tags = "teams",
description = "Create or Update a team.",
responses = {
@ApiResponse(responseCode = "200", description = "The team ",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CreateTeam.class))),
@ApiResponse(responseCode = "400", description = "Bad request")
})
public Response createOrUpdateTeam(@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Valid CreateTeam ct) throws IOException, ParseException {
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
Team team = getTeam(ct, securityContext);
RestUtil.PutResponse<Team> response = dao.createOrUpdate(team);
team = addHref(uriInfo, response.getEntity());
return Response.status(response.getStatus()).entity(team).build();
}
@PATCH
@Valid
@Path("/{id}")
@ -252,4 +306,12 @@ public class TeamResource {
dao.delete(UUID.fromString(id));
return Response.ok().build();
}
private Team getTeam(CreateTeam ct, SecurityContext securityContext) throws IOException {
return new Team().withId(UUID.randomUUID()).withName(ct.getName()).withDescription(ct.getDescription())
.withDisplayName(ct.getDisplayName()).withProfile(ct.getProfile())
.withUpdatedBy(securityContext.getUserPrincipal().getName())
.withUpdatedAt(new Date())
.withUsers(dao.getUsers(ct.getUsers()));
}
}

View File

@ -176,7 +176,6 @@ public class UserResource {
return dao.listVersions(id);
}
@GET
@Valid
@Path("/{id}")

View File

@ -55,7 +55,8 @@
},
"users" : {
"description": "Users that are part of the team.",
"$ref": "../../type/entityReference.json#/definitions/entityReferenceList"
"$ref": "../../type/entityReference.json#/definitions/entityReferenceList",
"default": null
},
"owns" : {
"description": "List of entities owned by the team.",

View File

@ -26,15 +26,18 @@ import org.openmetadata.catalog.api.teams.CreateTeam;
import org.openmetadata.catalog.entity.teams.Team;
import org.openmetadata.catalog.entity.teams.User;
import org.openmetadata.catalog.exception.CatalogExceptionMessage;
import org.openmetadata.catalog.jdbi3.TeamRepository.TeamEntityInterface;
import org.openmetadata.catalog.jdbi3.UserRepository.UserEntityInterface;
import org.openmetadata.catalog.resources.EntityResourceTest;
import org.openmetadata.catalog.resources.databases.TableResourceTest;
import org.openmetadata.catalog.resources.teams.TeamResource.TeamList;
import org.openmetadata.catalog.type.ChangeDescription;
import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.ImageList;
import org.openmetadata.catalog.type.Profile;
import org.openmetadata.catalog.util.EntityInterface;
import org.openmetadata.catalog.util.JsonUtils;
import org.openmetadata.catalog.util.TestUtils;
import org.openmetadata.catalog.util.TestUtils.UpdateType;
import org.openmetadata.common.utils.JsonSchemaUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -45,6 +48,7 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -62,17 +66,20 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.openmetadata.catalog.exception.CatalogExceptionMessage.entityNotFound;
import static org.openmetadata.catalog.resources.teams.UserResourceTest.createUser;
import static org.openmetadata.catalog.util.TestUtils.UpdateType.MINOR_UPDATE;
import static org.openmetadata.catalog.util.TestUtils.UpdateType.NO_CHANGE;
import static org.openmetadata.catalog.util.TestUtils.adminAuthHeaders;
import static org.openmetadata.catalog.util.TestUtils.assertEntityPagination;
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
import static org.openmetadata.catalog.util.TestUtils.authHeaders;
import static org.openmetadata.catalog.util.TestUtils.validateEntityReference;
public class TeamResourceTest extends CatalogApplicationTest {
public class TeamResourceTest extends EntityResourceTest<Team> {
private static final Logger LOG = LoggerFactory.getLogger(TeamResourceTest.class);
final Profile PROFILE = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
public TeamResourceTest() {
super(Team.class, "teams", TeamResource.FIELDS);
}
@Test
public void post_teamWithLongName_400_badRequest(TestInfo test) {
// Create team with mandatory name field empty
@ -102,19 +109,19 @@ public class TeamResourceTest extends CatalogApplicationTest {
public void post_validTeams_as_admin_200_OK(TestInfo test) throws HttpResponseException {
// Create team with different optional fields
CreateTeam create = create(test, 1);
createAndCheckTeam(create, adminAuthHeaders());
createAndCheckEntity(create, adminAuthHeaders());
create = create(test, 2).withDisplayName("displayName");
createAndCheckTeam(create, adminAuthHeaders());
createAndCheckEntity(create, adminAuthHeaders());
create = create(test, 3).withDescription("description");
createAndCheckTeam(create, adminAuthHeaders());
createAndCheckEntity(create, adminAuthHeaders());
create = create(test, 4).withProfile(PROFILE);
createAndCheckTeam(create, adminAuthHeaders());
createAndCheckEntity(create, adminAuthHeaders());
create = create(test, 5).withDisplayName("displayName").withDescription("description").withProfile(PROFILE);
createAndCheckTeam(create, adminAuthHeaders());
createAndCheckEntity(create, adminAuthHeaders());
}
@Test
@ -122,7 +129,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
// Create team with different optional fields
Map<String, String> authHeaders = authHeaders("test@open-metadata.org");
CreateTeam create = create(test, 1);
HttpResponseException exception = assertThrows(HttpResponseException.class, () -> createAndCheckTeam(create,
HttpResponseException exception = assertThrows(HttpResponseException.class, () -> createAndCheckEntity(create,
authHeaders));
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
}
@ -137,7 +144,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
List<UUID> users = Arrays.asList(user1.getId(), user2.getId());
CreateTeam create = create(test).withDisplayName("displayName").withDescription("description")
.withProfile(PROFILE).withUsers(users);
Team team = createAndCheckTeam(create, adminAuthHeaders());
Team team = createAndCheckEntity(create, adminAuthHeaders());
// Make sure the user entity has relationship to the team
user1 = UserResourceTest.getUser(user1.getId(), "teams", authHeaders("test@open-metadata.org"));
@ -293,7 +300,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
User user1 = createUser(UserResourceTest.create(test, 1), adminAuthHeaders());
List<UUID> users = Collections.singletonList(user1.getId());
CreateTeam create = create(test).withUsers(users);
Team team = createAndCheckTeam(create, adminAuthHeaders());
Team team = createAndCheckEntity(create, adminAuthHeaders());
deleteTeam(team.getId(), adminAuthHeaders());
// Make sure team is no longer there
@ -312,7 +319,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
authHeaders("test@open-metadata.org"));
List<UUID> users = Collections.singletonList(user1.getId());
CreateTeam create = create(test).withUsers(users);
Team team = createAndCheckTeam(create, adminAuthHeaders());
Team team = createAndCheckEntity(create, adminAuthHeaders());
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
deleteTeam(team.getId(), authHeaders("test@open-metadata.org")));
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
@ -340,7 +347,9 @@ public class TeamResourceTest extends CatalogApplicationTest {
@Test
public void patch_teamAttributes_as_admin_200_ok(TestInfo test)
throws HttpResponseException, JsonProcessingException {
//
// Create table without any attributes
//
Team team = createTeam(create(test), adminAuthHeaders());
assertNull(team.getDisplayName());
assertNull(team.getDescription());
@ -356,80 +365,50 @@ public class TeamResourceTest extends CatalogApplicationTest {
new UserEntityInterface(user2).getEntityReference());
Profile profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
//
// Add previously absent attributes
team = patchTeamAttributesAndCheck(team, "displayName", "description", profile, users,
adminAuthHeaders(), MINOR_UPDATE);
//
String originalJson = JsonUtils.pojoToJson(team);
team.withDisplayName("displayName").withDescription("description").withProfile(profile).withUsers(users);
ChangeDescription change = getChangeDescription(team.getVersion())
.withFieldsAdded(Arrays.asList("displayName", "description", "profile", "users"));
team = patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
team.getUsers().get(0).setHref(null);
team.getUsers().get(1).setHref(null);
//
// Replace the attributes
//
users = Arrays.asList(new UserEntityInterface(user1).getEntityReference(),
new UserEntityInterface(user3).getEntityReference()); // user2 dropped and user3 is added
profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image1.com")));
team = patchTeamAttributesAndCheck(team, "displayName1", "description1", profile, users,
adminAuthHeaders(), MINOR_UPDATE);
originalJson = JsonUtils.pojoToJson(team);
team.withDisplayName("displayName1").withDescription("description1").withProfile(profile).withUsers(users);
change = getChangeDescription(team.getVersion())
.withFieldsUpdated(Arrays.asList("displayName", "description", "profile", "users"));
team = patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
// Remove the attributes
patchTeamAttributesAndCheck(team, null, null, null, null,
adminAuthHeaders(), MINOR_UPDATE);
originalJson = JsonUtils.pojoToJson(team);
team.withDisplayName(null).withDescription(null).withProfile(null).withUsers(null);
change = getChangeDescription(team.getVersion())
.withFieldsDeleted(Arrays.asList("displayName", "description", "profile", "users"));
patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
}
@Test
public void patch_teamAttributes_as_non_admin_401(TestInfo test) throws HttpResponseException {
public void patch_teamAttributes_as_non_admin_403(TestInfo test) throws HttpResponseException,
JsonProcessingException {
// Create table without any attributes
Team team = createTeam(create(test), adminAuthHeaders());
assertNull(team.getDisplayName());
assertNull(team.getDescription());
assertNull(team.getProfile());
assertNull(team.getDeleted());
assertNull(team.getUsers());
User user1 = createUser(UserResourceTest.create(test, 1), authHeaders("test@open-metadata.org"));
User user2 = createUser(UserResourceTest.create(test, 2), authHeaders("test@open-metadata.org"));
User user3 = createUser(UserResourceTest.create(test, 3), authHeaders("test@open-metadata.org"));
List<EntityReference> users = Arrays.asList(new UserEntityInterface(user1).getEntityReference(),
new UserEntityInterface(user2).getEntityReference(),
new UserEntityInterface(user3).getEntityReference());
Profile profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
// Patching as a non-admin should is disallowed
String originalJson = JsonUtils.pojoToJson(team);
team.setDisplayName("newDisplayName");
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
patchTeamAttributesAndCheck(team, "displayName", "description", profile, users,
authHeaders("test@open-metadata.org"), NO_CHANGE));
patchTeam(team.getId(), originalJson, team, authHeaders("test@open-metadata.org")));
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
}
// @Test
// public void patch_updateInvalidUsers_404_notFound(TestInfo test) throws HttpResponseException {
// CreateTeam create = create(test);
// Team team = createAndCheckTeam(create);
//
// // User patch to add team to user relationship to an invalid user
// List<UUID> users = Collections.singletonList(UUID.randomUUID() /* invalid userId */);
// UpdateTeam update = new UpdateTeam().withUsers(users);
// HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
// updateTeam(team.getId(), update));
// assertEquals(Response.Status.NOT_FOUND.getStatusCode(), exception.getStatusCode());
// }
public static Team createAndCheckTeam(CreateTeam create, Map<String, String> authHeaders)
throws HttpResponseException {
String updatedBy = TestUtils.getPrincipal(authHeaders);
Team team = createTeam(create, authHeaders);
assertEquals(0.1, team.getVersion());
List<EntityReference> expectedUsers = new ArrayList<>();
for (UUID teamId : Optional.ofNullable(create.getUsers()).orElse(Collections.emptyList())) {
expectedUsers.add(new EntityReference().withId(teamId).withType(Entity.USER));
}
assertEquals(team.getName(), create.getName());
validateTeam(team, create.getDescription(), create.getDisplayName(), create.getProfile(), expectedUsers, updatedBy);
// Get the newly created team and validate it
Team getTeam = getTeam(team.getId(), "profile,users", authHeaders);
assertEquals(team.getName(), create.getName());
validateTeam(getTeam, create.getDescription(), create.getDisplayName(), create.getProfile(), expectedUsers,
updatedBy);
return team;
}
public static Team createTeam(CreateTeam create, Map<String, String> authHeaders) throws HttpResponseException {
return TestUtils.post(CatalogApplicationTest.getResource("teams"), create, Team.class, authHeaders);
@ -521,30 +500,6 @@ public class TeamResourceTest extends CatalogApplicationTest {
return patchTeam(updated.getId(), originalJson, updated, authHeaders);
}
private Team patchTeamAttributesAndCheck(Team before, String displayName, String description, Profile profile,
List<EntityReference> users, Map<String, String> authHeaders, UpdateType updateType)
throws JsonProcessingException, HttpResponseException {
String updatedBy = TestUtils.getPrincipal(authHeaders);
Optional.ofNullable(before.getUsers()).orElse(Collections.emptyList()).forEach(t -> t.setHref(null)); // Remove href
String tableJson = JsonUtils.pojoToJson(before);
// Update the table attributes
before.setDisplayName(displayName);
before.setDescription(description);
before.setProfile(profile);
before.setUsers(users);
// Validate information returned in patch response has the updates
Team updatedTeam = patchTeam(tableJson, before, authHeaders);
validateTeam(updatedTeam, description, displayName, profile, users, updatedBy);
TestUtils.validateUpdate(before.getVersion(), updatedTeam.getVersion(), updateType);
// GET the table and Validate information returned
Team getTeam = getTeam(before.getId(), "users,profile", authHeaders);
validateTeam(getTeam, description, displayName, profile, users, updatedBy);
return getTeam;
}
public void deleteTeam(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
TestUtils.delete(CatalogApplicationTest.getResource("teams/" + id), authHeaders);
}
@ -560,4 +515,71 @@ public class TeamResourceTest extends CatalogApplicationTest {
public static String getTeamName(TestInfo test) {
return String.format("team_%s", test.getDisplayName());
}
@Override
public Object createRequest(TestInfo test, String description, String displayName, EntityReference owner) {
return create(test).withDescription(description).withDisplayName(displayName);
}
@Override
public void validateCreatedEntity(Team team, Object request, Map<String, String> authHeaders) {
CreateTeam createRequest = (CreateTeam) request;
validateCommonEntityFields(getEntityInterface(team), createRequest.getDescription(),
TestUtils.getPrincipal(authHeaders), null);
assertEquals(createRequest.getDisplayName(), team.getDisplayName());
assertEquals(createRequest.getProfile(), team.getProfile());
List<EntityReference> expectedUsers = new ArrayList<>();
for (UUID teamId : Optional.ofNullable(createRequest.getUsers()).orElse(Collections.emptyList())) {
expectedUsers.add(new EntityReference().withId(teamId).withType(Entity.USER));
}
List<EntityReference> actualUsers = Optional.ofNullable(team.getUsers()).orElse(Collections.emptyList());
if (!expectedUsers.isEmpty()) {
assertEquals(expectedUsers.size(), actualUsers.size());
for (EntityReference user : actualUsers) {
TestUtils.validateEntityReference(user);
boolean foundUser = false;
for (EntityReference expectedEntity : expectedUsers) {
if (expectedEntity.getId().equals(user.getId())) {
foundUser = true;
break;
}
}
assertTrue(foundUser);
}
}
TestUtils.validateEntityReference(team.getOwns());
}
@Override
public void validateUpdatedEntity(Team updatedEntity, Object request, Map<String, String> authHeaders) {
validateCreatedEntity(updatedEntity, request, authHeaders);
}
@Override
public void validatePatchedEntity(Team expected, Team updated, Map<String, String> authHeaders) {
validateCommonEntityFields(getEntityInterface(updated), expected.getDescription(),
TestUtils.getPrincipal(authHeaders), null);
assertEquals(expected.getDisplayName(), updated.getDisplayName());
assertEquals(expected.getProfile(), updated.getProfile());
List<EntityReference> expectedUsers = Optional.ofNullable(expected.getUsers()).orElse(Collections.emptyList());
List<EntityReference> actualUsers = Optional.ofNullable(updated.getUsers()).orElse(Collections.emptyList());
actualUsers.forEach(TestUtils::validateEntityReference);
actualUsers.forEach(user -> user.setHref(null));
// Note ordering is same as server side ordering by ID as string
// Patch requests work only if the same ordering of users on the server side
actualUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
expectedUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
assertEquals(expectedUsers, actualUsers);
TestUtils.validateEntityReference(updated.getOwns());
}
@Override
public EntityInterface<Team> getEntityInterface(Team entity) {
return new TeamEntityInterface(entity);
}
}

View File

@ -448,7 +448,9 @@ public class UserResourceTest extends EntityResourceTest<User> {
.withFieldsUpdated(Arrays.asList("teams", "timezone", "profile", "isBot"));
user = patchEntityAndCheck(user, origJson, adminAuthHeaders(), MINOR_UPDATE, change);
//
// Remove the attributes
//
origJson = JsonUtils.pojoToJson(user);
user.withTeams(null).withTimezone(null).withDisplayName(null).withProfile(null)
.withIsBot(null).withIsAdmin(false);
@ -654,8 +656,10 @@ public class UserResourceTest extends EntityResourceTest<User> {
updatedTeams.forEach(TestUtils::validateEntityReference);
expectedTeams.sort(Comparator.comparing(EntityReference::getName));
updatedTeams.sort(Comparator.comparing(EntityReference::getName));
// Note ordering is same as server side ordering by ID as string
// Patch requests work only if the same ordering of users on the server side
expectedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
updatedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
updatedTeams.forEach(t -> t.setHref(null));
assertEquals(expectedTeams, updatedTeams);
if (expected.getProfile() != null) {