@@ -63,8 +63,10 @@ public class GroupService { | |||
return dbClient.groupDao().selectByName(dbSession, groupName); | |||
} | |||
public Optional<GroupDto> findGroupByUuid(DbSession dbSession, String groupUuid) { | |||
return Optional.ofNullable(dbClient.groupDao().selectByUuid(dbSession, groupUuid)); | |||
public Optional<GroupInformation> findGroupByUuid(DbSession dbSession, String groupUuid) { | |||
return Optional.ofNullable(dbClient.groupDao().selectByUuid(dbSession, groupUuid)) | |||
.map(group -> groupDtoToGroupInformation(group, dbSession)); | |||
} | |||
public SearchResults<GroupInformation> search(DbSession dbSession, GroupSearchRequest groupSearchRequest) { | |||
@@ -126,18 +128,18 @@ public class GroupService { | |||
removeGroup(dbSession, group); | |||
} | |||
public GroupDto updateGroup(DbSession dbSession, GroupDto group, @Nullable String newName) { | |||
public GroupInformation updateGroup(DbSession dbSession, GroupDto group, @Nullable String newName) { | |||
checkGroupIsNotDefault(dbSession, group); | |||
return updateName(dbSession, group, newName); | |||
return groupDtoToGroupInformation(updateName(dbSession, group, newName), dbSession); | |||
} | |||
public GroupDto updateGroup(DbSession dbSession, GroupDto group, @Nullable String newName, @Nullable String newDescription) { | |||
public GroupInformation updateGroup(DbSession dbSession, GroupDto group, @Nullable String newName, @Nullable String newDescription) { | |||
checkGroupIsNotDefault(dbSession, group); | |||
GroupDto withUpdatedName = updateName(dbSession, group, newName); | |||
return updateDescription(dbSession, withUpdatedName, newDescription); | |||
return groupDtoToGroupInformation(updateDescription(dbSession, withUpdatedName, newDescription), dbSession); | |||
} | |||
public GroupDto createGroup(DbSession dbSession, String name, @Nullable String description) { | |||
public GroupInformation createGroup(DbSession dbSession, String name, @Nullable String description) { | |||
validateGroupName(name); | |||
checkNameDoesNotExist(dbSession, name); | |||
@@ -145,7 +147,12 @@ public class GroupService { | |||
.setUuid(uuidFactory.create()) | |||
.setName(name) | |||
.setDescription(description); | |||
return dbClient.groupDao().insert(dbSession, group); | |||
return groupDtoToGroupInformation(dbClient.groupDao().insert(dbSession, group), dbSession); | |||
} | |||
private GroupInformation groupDtoToGroupInformation(GroupDto groupDto, DbSession dbSession) { | |||
return new GroupInformation(groupDto, managedInstanceService.isGroupManaged(dbSession, groupDto.getUuid()), | |||
defaultGroupFinder.findDefaultGroup(dbSession).getUuid().equals(groupDto.getUuid())); | |||
} | |||
private GroupDto updateName(DbSession dbSession, GroupDto group, @Nullable String newName) { |
@@ -136,13 +136,31 @@ public class GroupServiceTest { | |||
} | |||
@Test | |||
public void findGroupByUuid_whenGroupExists_returnsIt() { | |||
public void findGroupByUuid_whenGroupExistsAndIsManagedAndDefault_returnsItWithCorrectValues() { | |||
GroupDto groupDto = mockGroupDto(); | |||
when(defaultGroupFinder.findDefaultGroup(dbSession)).thenReturn(new GroupDto().setUuid(GROUP_UUID).setName("default-group")); | |||
when(dbClient.groupDao().selectByUuid(dbSession, GROUP_UUID)) | |||
.thenReturn(groupDto); | |||
when(managedInstanceService.isGroupManaged(dbSession, groupDto.getUuid())).thenReturn(true); | |||
GroupInformation expected = new GroupInformation(groupDto, true, true); | |||
assertThat(groupService.findGroupByUuid(dbSession, GROUP_UUID)).contains(expected); | |||
} | |||
@Test | |||
public void findGroupByUuid_whenGroupExistsAndIsNotManagedAndDefault_returnsItWithCorrectValues() { | |||
GroupDto groupDto = mockGroupDto(); | |||
when(defaultGroupFinder.findDefaultGroup(dbSession)).thenReturn(new GroupDto().setUuid("another-uuid").setName("default-group")); | |||
when(dbClient.groupDao().selectByUuid(dbSession, GROUP_UUID)) | |||
.thenReturn(groupDto); | |||
when(managedInstanceService.isGroupManaged(dbSession, groupDto.getUuid())).thenReturn(false); | |||
assertThat(groupService.findGroupByUuid(dbSession, GROUP_UUID)).contains(groupDto); | |||
GroupInformation expected = new GroupInformation(groupDto, false, false); | |||
assertThat(groupService.findGroupByUuid(dbSession, GROUP_UUID)).contains(expected); | |||
} | |||
@Test | |||
@@ -201,8 +219,10 @@ public class GroupServiceTest { | |||
public void updateGroup_updatesGroupNameAndDescription() { | |||
GroupDto group = mockGroupDto(); | |||
GroupDto groupWithUpdatedName = mockGroupDto(); | |||
GroupDto groupWithUpdatedDescription = mockGroupDto(); | |||
mockDefaultGroup(); | |||
when(dbClient.groupDao().update(dbSession, group)).thenReturn(groupWithUpdatedName); | |||
when(dbClient.groupDao().update(dbSession, groupWithUpdatedName)).thenReturn(groupWithUpdatedDescription); | |||
groupService.updateGroup(dbSession, group, "new-name", "New Description"); | |||
verify(group).setName("new-name"); | |||
@@ -216,6 +236,7 @@ public class GroupServiceTest { | |||
GroupDto group = mockGroupDto(); | |||
mockDefaultGroup(); | |||
when(dbClient.groupDao().update(dbSession, group)).thenReturn(group); | |||
groupService.updateGroup(dbSession, group, "new-name"); | |||
verify(group).setName("new-name"); | |||
verify(dbClient.groupDao()).update(dbSession, group); | |||
@@ -240,7 +261,9 @@ public class GroupServiceTest { | |||
GroupDto group = mockGroupDto(); | |||
mockDefaultGroup(); | |||
when(dbClient.groupDao().update(dbSession, group)).thenReturn(group); | |||
groupService.updateGroup(dbSession, group, group.getName(), "New Description"); | |||
verify(group).setDescription("New Description"); | |||
verify(dbClient.groupDao()).update(dbSession, group); | |||
} | |||
@@ -293,14 +316,17 @@ public class GroupServiceTest { | |||
public void createGroup_whenNameAndDescriptionIsProvided_createsGroup() { | |||
when(uuidFactory.create()).thenReturn("1234"); | |||
GroupDto createdGroup = mockGroupDto(); | |||
when(dbClient.groupDao().insert(eq(dbSession), any())).thenReturn(createdGroup); | |||
mockDefaultGroup(); | |||
groupService.createGroup(dbSession, "Name", "Description"); | |||
ArgumentCaptor<GroupDto> groupCaptor = ArgumentCaptor.forClass(GroupDto.class); | |||
verify(dbClient.groupDao()).insert(eq(dbSession), groupCaptor.capture()); | |||
GroupDto createdGroup = groupCaptor.getValue(); | |||
assertThat(createdGroup.getName()).isEqualTo("Name"); | |||
assertThat(createdGroup.getDescription()).isEqualTo("Description"); | |||
assertThat(createdGroup.getUuid()).isEqualTo("1234"); | |||
GroupDto groupToCreate = groupCaptor.getValue(); | |||
assertThat(groupToCreate.getName()).isEqualTo("Name"); | |||
assertThat(groupToCreate.getDescription()).isEqualTo("Description"); | |||
assertThat(groupToCreate.getUuid()).isEqualTo("1234"); | |||
} | |||
@Test | |||
@@ -347,8 +373,7 @@ public class GroupServiceTest { | |||
Map<String, Boolean> groupUuidToManaged = Map.of( | |||
groupDto1.getUuid(), false, | |||
groupDto2.getUuid(), true, | |||
defaultGroup.getUuid(), false | |||
); | |||
defaultGroup.getUuid(), false); | |||
when(managedInstanceService.getGroupUuidToManaged(dbSession, groupUuidToManaged.keySet())).thenReturn(groupUuidToManaged); | |||
when(dbClient.groupDao().countByQuery(eq(dbSession), any())).thenReturn(300); |
@@ -22,7 +22,6 @@ package org.sonar.server.v2.api.group.controller; | |||
import java.util.List; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.server.common.SearchResults; | |||
import org.sonar.server.common.group.service.GroupInformation; | |||
import org.sonar.server.common.group.service.GroupSearchRequest; | |||
@@ -30,10 +29,11 @@ import org.sonar.server.common.group.service.GroupService; | |||
import org.sonar.server.common.management.ManagedInstanceChecker; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.api.group.request.GroupCreateRestRequest; | |||
import org.sonar.server.v2.api.group.request.GroupUpdateRestRequest; | |||
import org.sonar.server.v2.api.group.request.GroupsSearchRestRequest; | |||
import org.sonar.server.v2.api.group.response.GroupsSearchRestResponse; | |||
import org.sonar.server.v2.api.group.response.RestGroupResponse; | |||
import org.sonar.server.v2.api.group.response.GroupRestResponse; | |||
import org.sonar.server.v2.api.model.RestPage; | |||
import org.sonar.server.v2.api.response.PageRestResponse; | |||
@@ -58,63 +58,72 @@ public class DefaultGroupController implements GroupController { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
GroupSearchRequest groupSearchRequest = new GroupSearchRequest(groupsSearchRestRequest.q(), groupsSearchRestRequest.managed(), restPage.pageIndex(), restPage.pageSize()); | |||
SearchResults<GroupInformation> searchResults = groupService.search(dbSession, groupSearchRequest); | |||
List<RestGroupResponse> restGroupResponses = toRestGroupResponses(searchResults); | |||
return new GroupsSearchRestResponse(restGroupResponses, new PageRestResponse(restPage.pageIndex(), restPage.pageSize(), searchResults.total())); | |||
List<GroupRestResponse> groupRestResponses = toGroupRestResponses(searchResults); | |||
return new GroupsSearchRestResponse(groupRestResponses, new PageRestResponse(restPage.pageIndex(), restPage.pageSize(), searchResults.total())); | |||
} | |||
} | |||
private static List<RestGroupResponse> toRestGroupResponses(SearchResults<GroupInformation> searchResults) { | |||
private static List<GroupRestResponse> toGroupRestResponses(SearchResults<GroupInformation> searchResults) { | |||
return searchResults.searchResults().stream() | |||
.map(groupInformation -> toRestGroup(groupInformation.groupDto())) | |||
.map(DefaultGroupController::toRestGroup) | |||
.toList(); | |||
} | |||
@Override | |||
public RestGroupResponse fetchGroup(String id) { | |||
public GroupRestResponse fetchGroup(String id) { | |||
userSession.checkLoggedIn().checkIsSystemAdministrator(); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
GroupDto groupDto = findGroupDtoOrThrow(id, session); | |||
return toRestGroup(groupDto); | |||
GroupInformation groupInformation = findGroupInformationOrThrow(id, session); | |||
return toRestGroup(groupInformation); | |||
} | |||
} | |||
@Override | |||
public void deleteGroup(String id) { | |||
throwIfNotAllowedToChangeGroupName(); | |||
throwIfNotAllowedToModifyGroups(); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
GroupDto group = findGroupDtoOrThrow(id, session); | |||
groupService.delete(session, group); | |||
GroupInformation group = findGroupInformationOrThrow(id, session); | |||
groupService.delete(session, group.groupDto()); | |||
session.commit(); | |||
} | |||
} | |||
@Override | |||
public RestGroupResponse updateGroup(String id, GroupUpdateRestRequest updateRequest) { | |||
throwIfNotAllowedToChangeGroupName(); | |||
public GroupRestResponse updateGroup(String id, GroupUpdateRestRequest updateRequest) { | |||
throwIfNotAllowedToModifyGroups(); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
GroupDto group = findGroupDtoOrThrow(id, session); | |||
GroupDto updatedGroup = groupService.updateGroup( | |||
GroupInformation group = findGroupInformationOrThrow(id, session); | |||
GroupInformation updatedGroup = groupService.updateGroup( | |||
session, | |||
group, | |||
updateRequest.getName().orElse(group.getName()), | |||
updateRequest.getDescription().orElse(group.getDescription()) | |||
); | |||
group.groupDto(), | |||
updateRequest.getName().orElse(group.groupDto().getName()), | |||
updateRequest.getDescription().orElse(group.groupDto().getDescription())); | |||
session.commit(); | |||
return toRestGroup(updatedGroup); | |||
} | |||
} | |||
private void throwIfNotAllowedToChangeGroupName() { | |||
userSession.checkIsSystemAdministrator(); | |||
managedInstanceChecker.throwIfInstanceIsManaged(); | |||
} | |||
private GroupDto findGroupDtoOrThrow(String id, DbSession session) { | |||
private GroupInformation findGroupInformationOrThrow(String id, DbSession session) { | |||
return groupService.findGroupByUuid(session, id) | |||
.orElseThrow(() -> new NotFoundException(String.format(GROUP_NOT_FOUND_MESSAGE, id))); | |||
} | |||
private static RestGroupResponse toRestGroup(GroupDto groupDto) { | |||
return new RestGroupResponse(groupDto.getUuid(), groupDto.getName(), groupDto.getDescription()); | |||
@Override | |||
public GroupRestResponse create(GroupCreateRestRequest request) { | |||
throwIfNotAllowedToModifyGroups(); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
GroupInformation createdGroup = groupService.createGroup(session, request.name(), request.description()); | |||
session.commit(); | |||
return toRestGroup(createdGroup); | |||
} | |||
} | |||
private void throwIfNotAllowedToModifyGroups() { | |||
userSession.checkIsSystemAdministrator(); | |||
managedInstanceChecker.throwIfInstanceIsManaged(); | |||
} | |||
private static GroupRestResponse toRestGroup(GroupInformation group) { | |||
return new GroupRestResponse(group.groupDto().getUuid(), group.groupDto().getName(), group.groupDto().getDescription(), group.isManaged(), group.isDefault()); | |||
} | |||
} |
@@ -23,10 +23,11 @@ import io.swagger.v3.oas.annotations.Operation; | |||
import io.swagger.v3.oas.annotations.Parameter; | |||
import io.swagger.v3.oas.annotations.enums.ParameterIn; | |||
import javax.validation.Valid; | |||
import org.sonar.server.v2.api.group.request.GroupCreateRestRequest; | |||
import org.sonar.server.v2.api.group.request.GroupUpdateRestRequest; | |||
import org.sonar.server.v2.api.group.request.GroupsSearchRestRequest; | |||
import org.sonar.server.v2.api.group.response.GroupsSearchRestResponse; | |||
import org.sonar.server.v2.api.group.response.RestGroupResponse; | |||
import org.sonar.server.v2.api.group.response.GroupRestResponse; | |||
import org.sonar.server.v2.api.model.RestPage; | |||
import org.springdoc.api.annotations.ParameterObject; | |||
import org.springframework.http.HttpStatus; | |||
@@ -35,6 +36,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.PatchMapping; | |||
import org.springframework.web.bind.annotation.PathVariable; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import org.springframework.web.bind.annotation.RequestBody; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.ResponseStatus; | |||
@@ -60,7 +62,12 @@ public interface GroupController { | |||
@GetMapping(path = "/{id}") | |||
@ResponseStatus(HttpStatus.OK) | |||
@Operation(summary = "Fetch a single group", description = "Fetch a single group.") | |||
RestGroupResponse fetchGroup(@PathVariable("id") @Parameter(description = "The id of the group to fetch.", required = true, in = ParameterIn.PATH) String id); | |||
GroupRestResponse fetchGroup(@PathVariable("id") @Parameter(description = "The id of the group to fetch.", required = true, in = ParameterIn.PATH) String id); | |||
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) | |||
@ResponseStatus(HttpStatus.CREATED) | |||
@Operation(summary = "Create a new group", description = "Create a new group.") | |||
GroupRestResponse create(@Valid @RequestBody GroupCreateRestRequest request); | |||
@DeleteMapping(path = "/{id}") | |||
@ResponseStatus(HttpStatus.NO_CONTENT) | |||
@@ -73,5 +80,5 @@ public interface GroupController { | |||
Update a user. | |||
Allows updating user's name, email and SCM accounts. | |||
""") | |||
RestGroupResponse updateGroup(@PathVariable("id") String id, @Valid @RequestBody GroupUpdateRestRequest updateRequest); | |||
GroupRestResponse updateGroup(@PathVariable("id") String id, @Valid @RequestBody GroupUpdateRestRequest updateRequest); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.group.request; | |||
import io.swagger.v3.oas.annotations.media.Schema; | |||
import javax.annotation.Nullable; | |||
import javax.validation.constraints.NotEmpty; | |||
import javax.validation.constraints.Size; | |||
import static org.sonar.api.user.UserGroupValidation.GROUP_NAME_MAX_LENGTH; | |||
public record GroupCreateRestRequest( | |||
@NotEmpty | |||
@Size(min = 1, max = GROUP_NAME_MAX_LENGTH) | |||
@Schema(description = "Name for the new group. Must be unique. The value 'anyone' is reserved and cannot be used.") | |||
String name, | |||
@Nullable | |||
@Size(max = 200) | |||
@Schema(description = "Description for the new group.") | |||
String description | |||
) {} |
@@ -40,7 +40,7 @@ public class GroupUpdateRestRequest { | |||
} | |||
@Size(max = 200) | |||
@Schema(implementation = String.class, description = "Description of the gorup") | |||
@Schema(implementation = String.class, description = "Description of the group") | |||
public UpdateField<String> getDescription() { | |||
return description; | |||
} |
@@ -19,13 +19,19 @@ | |||
*/ | |||
package org.sonar.server.v2.api.group.response; | |||
import com.fasterxml.jackson.annotation.JsonProperty; | |||
import io.swagger.v3.oas.annotations.media.Schema; | |||
import javax.annotation.Nullable; | |||
public record RestGroupResponse( | |||
public record GroupRestResponse( | |||
@Schema(accessMode = Schema.AccessMode.READ_ONLY) | |||
String id, | |||
String name, | |||
@Nullable | |||
String description) { | |||
String description, | |||
@Schema(accessMode = Schema.AccessMode.READ_ONLY) | |||
Boolean managed, | |||
@Schema(accessMode = Schema.AccessMode.READ_ONLY) | |||
@JsonProperty("default") | |||
Boolean isDefault) { | |||
} |
@@ -22,5 +22,5 @@ package org.sonar.server.v2.api.group.response; | |||
import java.util.List; | |||
import org.sonar.server.v2.api.response.PageRestResponse; | |||
public record GroupsSearchRestResponse(List<RestGroupResponse> groups, PageRestResponse page) { | |||
public record GroupsSearchRestResponse(List<GroupRestResponse> groups, PageRestResponse page) { | |||
} |
@@ -19,8 +19,7 @@ | |||
*/ | |||
package org.sonar.server.v2.api.group.controller; | |||
import com.google.gson.Gson; | |||
import com.google.gson.GsonBuilder; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
@@ -45,7 +44,8 @@ import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.v2.api.ControllerTester; | |||
import org.sonar.server.v2.api.group.response.GroupsSearchRestResponse; | |||
import org.sonar.server.v2.api.group.response.RestGroupResponse; | |||
import org.sonar.server.v2.api.group.response.GroupRestResponse; | |||
import org.springframework.http.MediaType; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import org.springframework.test.web.servlet.MvcResult; | |||
@@ -63,6 +63,7 @@ import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_SIZE; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||
@@ -70,7 +71,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. | |||
public class DefaultGroupControllerTest { | |||
private static final String GROUP_UUID = "1234"; | |||
private static final Gson GSON = new GsonBuilder().create(); | |||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@@ -78,7 +79,8 @@ public class DefaultGroupControllerTest { | |||
private final DbClient dbClient = mock(); | |||
private final DbSession dbSession = mock(); | |||
private final ManagedInstanceChecker managedInstanceChecker = mock(); | |||
private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGroupController(groupService, dbClient, managedInstanceChecker, userSession)); | |||
private final MockMvc mockMvc = ControllerTester | |||
.getMockMvc(new DefaultGroupController(groupService, dbClient, managedInstanceChecker, userSession)); | |||
@Before | |||
public void setUp() { | |||
@@ -89,8 +91,9 @@ public class DefaultGroupControllerTest { | |||
public void fetchGroup_whenGroupExists_returnsTheGroup() throws Exception { | |||
GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); | |||
GroupInformation groupInformation = new GroupInformation(groupDto, false, false); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupDto)); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupInformation)); | |||
userSession.logIn().setSystemAdministrator(); | |||
mockMvc.perform(get(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
@@ -100,7 +103,32 @@ public class DefaultGroupControllerTest { | |||
{ | |||
"id": "1234", | |||
"name": "name", | |||
"description": "description" | |||
"description": "description", | |||
"managed": false, | |||
"default": false | |||
} | |||
""")); | |||
} | |||
@Test | |||
public void fetchGroup_whenGroupIsManagedOrDefault_returnsCorrectValues() throws Exception { | |||
GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); | |||
GroupInformation groupInformation = new GroupInformation(groupDto, true, true); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupInformation)); | |||
userSession.logIn().setSystemAdministrator(); | |||
mockMvc.perform(get(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isOk(), | |||
content().json(""" | |||
{ | |||
"id": "1234", | |||
"name": "name", | |||
"description": "description", | |||
"managed": true, | |||
"default": true | |||
} | |||
""")); | |||
} | |||
@@ -109,7 +137,7 @@ public class DefaultGroupControllerTest { | |||
public void fetchGroup_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
mockMvc.perform( | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().json("{\"message\":\"Insufficient privileges\"}")); | |||
@@ -120,7 +148,7 @@ public class DefaultGroupControllerTest { | |||
userSession.logIn().setSystemAdministrator(); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.empty()); | |||
mockMvc.perform( | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID).content("{}")) | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID).content("{}")) | |||
.andExpectAll( | |||
status().isNotFound(), | |||
content().json("{\"message\":\"Group '1234' not found\"}")); | |||
@@ -130,7 +158,7 @@ public class DefaultGroupControllerTest { | |||
public void deleteGroup_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
mockMvc.perform( | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().json("{\"message\":\"Insufficient privileges\"}")); | |||
@@ -141,7 +169,7 @@ public class DefaultGroupControllerTest { | |||
userSession.logIn().setSystemAdministrator(); | |||
doThrow(BadRequestException.create("the instance is managed")).when(managedInstanceChecker).throwIfInstanceIsManaged(); | |||
mockMvc.perform( | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isBadRequest(), | |||
content().json("{\"message\":\"the instance is managed\"}")); | |||
@@ -152,7 +180,7 @@ public class DefaultGroupControllerTest { | |||
userSession.logIn().setSystemAdministrator(); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.empty()); | |||
mockMvc.perform( | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID).content("{}")) | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID).content("{}")) | |||
.andExpectAll( | |||
status().isNotFound(), | |||
content().json("{\"message\":\"Group '1234' not found\"}")); | |||
@@ -161,12 +189,13 @@ public class DefaultGroupControllerTest { | |||
@Test | |||
public void deleteGroup_whenGroupExists_shouldDeleteAndReturn204() throws Exception { | |||
GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); | |||
GroupInformation groupInformation = new GroupInformation(groupDto, false, false); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupDto)); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupInformation)); | |||
userSession.logIn().setSystemAdministrator(); | |||
mockMvc.perform( | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isNoContent(), | |||
content().string("")); | |||
@@ -176,8 +205,7 @@ public class DefaultGroupControllerTest { | |||
public void patchGroup_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
mockMvc.perform( | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}") | |||
) | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}")) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().json("{\"message\":\"Insufficient privileges\"}")); | |||
@@ -188,8 +216,7 @@ public class DefaultGroupControllerTest { | |||
userSession.logIn().setSystemAdministrator(); | |||
doThrow(BadRequestException.create("the instance is managed")).when(managedInstanceChecker).throwIfInstanceIsManaged(); | |||
mockMvc.perform( | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}") | |||
) | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}")) | |||
.andExpectAll( | |||
status().isBadRequest(), | |||
content().json("{\"message\":\"the instance is managed\"}")); | |||
@@ -200,8 +227,7 @@ public class DefaultGroupControllerTest { | |||
userSession.logIn().setSystemAdministrator(); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.empty()); | |||
mockMvc.perform( | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}") | |||
) | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}")) | |||
.andExpectAll( | |||
status().isNotFound(), | |||
content().json("{\"message\":\"Group '1234' not found\"}")); | |||
@@ -223,38 +249,142 @@ public class DefaultGroupControllerTest { | |||
patchGroupAndAssertResponse("newName", "newDescription"); | |||
} | |||
private void patchGroupAndAssertResponse(@Nullable String newName,@Nullable String newDescription) throws Exception { | |||
private void patchGroupAndAssertResponse(@Nullable String newName, @Nullable String newDescription) throws Exception { | |||
userSession.logIn().setSystemAdministrator(); | |||
GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupDto)); | |||
GroupInformation groupInformation = new GroupInformation(groupDto, false, false); | |||
GroupDto newDto = new GroupDto().setUuid(GROUP_UUID).setName(newName).setDescription(newDescription); | |||
when(groupService.updateGroup(dbSession, groupDto, newName, newDescription)).thenReturn(newDto); | |||
GroupInformation newGroupInformation = new GroupInformation(newDto, false, false); | |||
when(groupService.findGroupByUuid(dbSession, GROUP_UUID)) | |||
.thenReturn(Optional.of(groupInformation)); | |||
when(groupService.updateGroup(dbSession, groupDto, newName, newDescription)).thenReturn(newGroupInformation); | |||
MvcResult mvcResult = mockMvc.perform( | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content( | |||
""" | |||
{ | |||
"name": "%s", | |||
"description": %s | |||
} | |||
""".formatted(newName, newDescription == null ? "null" : "\"" + newDescription + "\"") | |||
) | |||
) | |||
patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content( | |||
""" | |||
{ | |||
"name": "%s", | |||
"description": %s | |||
} | |||
""".formatted(newName, newDescription == null ? "null" : "\"" + newDescription + "\""))) | |||
.andExpect(status().isOk()) | |||
.andReturn(); | |||
RestGroupResponse restGroupResponse = GSON.fromJson(mvcResult.getResponse().getContentAsString(), RestGroupResponse.class); | |||
assertThat(restGroupResponse.id()).isEqualTo(GROUP_UUID); | |||
assertThat(restGroupResponse.name()).isEqualTo(newName); | |||
assertThat(restGroupResponse.description()).isEqualTo(newDescription); | |||
GroupRestResponse groupRestResponse = OBJECT_MAPPER.readValue(mvcResult.getResponse().getContentAsString(), GroupRestResponse.class); | |||
assertThat(groupRestResponse.id()).isEqualTo(GROUP_UUID); | |||
assertThat(groupRestResponse.name()).isEqualTo(newName); | |||
assertThat(groupRestResponse.description()).isEqualTo(newDescription); | |||
} | |||
@Test | |||
public void create_whenInstanceIsManaged_shouldReturnException() throws Exception { | |||
userSession.logIn().setSystemAdministrator(); | |||
doThrow(BadRequestException.create("the instance is managed")).when(managedInstanceChecker).throwIfInstanceIsManaged(); | |||
mockMvc.perform( | |||
post(GROUPS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON_VALUE) | |||
.content(""" | |||
{ | |||
"name": "name", | |||
"description": "description" | |||
} | |||
""")) | |||
.andExpectAll( | |||
status().isBadRequest(), | |||
content().json("{\"message\":\"the instance is managed\"}")); | |||
} | |||
@Test | |||
public void create_whenCallersIsNotAdmin_shouldReturnForbidden() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
mockMvc.perform( | |||
post(GROUPS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON_VALUE) | |||
.content(""" | |||
{ | |||
"name": "name", | |||
"description": "description" | |||
} | |||
""")) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().json("{\"message\":\"Insufficient privileges\"}")); | |||
} | |||
@Test | |||
public void create_whenUserIsAnAdmin_shouldReturnCreatedGroup() throws Exception { | |||
userSession.logIn().setSystemAdministrator(); | |||
GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); | |||
GroupInformation groupInformation = new GroupInformation(groupDto, false, false); | |||
when(groupService.createGroup(dbSession, "name", "description")).thenReturn(groupInformation); | |||
mockMvc.perform( | |||
post(GROUPS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON_VALUE) | |||
.content(""" | |||
{ | |||
"name": "name", | |||
"description": "description" | |||
} | |||
""")) | |||
.andExpectAll( | |||
status().isCreated(), | |||
content().json(""" | |||
{ | |||
"id": "1234", | |||
"name": "name", | |||
"description": "description", | |||
"managed": false, | |||
"default": false | |||
} | |||
""")); | |||
} | |||
@Test | |||
public void create_whenNameIsTooLong_returnBadRequest() throws Exception { | |||
userSession.logIn().setSystemAdministrator(); | |||
String tooLongName = "a".repeat(501); | |||
mockMvc.perform( | |||
post(GROUPS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON_VALUE) | |||
.content(""" | |||
{ | |||
"name": "%s", | |||
"description": "description" | |||
} | |||
""".formatted(tooLongName))) | |||
.andExpectAll( | |||
status().isBadRequest()); | |||
} | |||
@Test | |||
public void create_whenDescriptionIsTooLong_returnBadRequest() throws Exception { | |||
userSession.logIn().setSystemAdministrator(); | |||
String tooLongDescription = "a".repeat(201); | |||
mockMvc.perform( | |||
post(GROUPS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON_VALUE) | |||
.content(""" | |||
{ | |||
"name": "name", | |||
"description": "%s" | |||
} | |||
""".formatted(tooLongDescription))) | |||
.andExpectAll( | |||
status().isBadRequest()); | |||
} | |||
@Test | |||
public void search_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
mockMvc.perform( | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID) | |||
) | |||
get(GROUPS_ENDPOINT + "/" + GROUP_UUID)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().json("{\"message\":\"Insufficient privileges\"}")); | |||
@@ -281,10 +411,10 @@ public class DefaultGroupControllerTest { | |||
when(groupService.search(eq(dbSession), any())).thenReturn(new SearchResults<>(List.of(), 0)); | |||
mockMvc.perform(get(GROUPS_ENDPOINT) | |||
.param("managed", "true") | |||
.param("q", "q") | |||
.param("pageSize", "100") | |||
.param("pageIndex", "2")) | |||
.param("managed", "true") | |||
.param("q", "q") | |||
.param("pageSize", "100") | |||
.param("pageIndex", "2")) | |||
.andExpect(status().isOk()); | |||
ArgumentCaptor<GroupSearchRequest> requestCaptor = ArgumentCaptor.forClass(GroupSearchRequest.class); | |||
@@ -310,9 +440,9 @@ public class DefaultGroupControllerTest { | |||
.andExpect(status().isOk()) | |||
.andReturn(); | |||
GroupsSearchRestResponse actualGroupsSearchRestResponse = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GroupsSearchRestResponse.class); | |||
Map<String, RestGroupResponse> groupIdToGroupResponse = actualGroupsSearchRestResponse.groups().stream() | |||
.collect(Collectors.toMap(RestGroupResponse::id, Function.identity())); | |||
GroupsSearchRestResponse actualGroupsSearchRestResponse = OBJECT_MAPPER.readValue(mvcResult.getResponse().getContentAsString(), GroupsSearchRestResponse.class); | |||
Map<String, GroupRestResponse> groupIdToGroupResponse = actualGroupsSearchRestResponse.groups().stream() | |||
.collect(Collectors.toMap(GroupRestResponse::id, Function.identity())); | |||
assertResponseContains(groupIdToGroupResponse, group1); | |||
assertResponseContains(groupIdToGroupResponse, group2); | |||
@@ -324,19 +454,20 @@ public class DefaultGroupControllerTest { | |||
} | |||
private void assertResponseContains(Map<String, RestGroupResponse> groupIdToGroupResponse, GroupInformation expectedGroup) { | |||
RestGroupResponse restGroup = groupIdToGroupResponse.get(expectedGroup.groupDto().getUuid()); | |||
private void assertResponseContains(Map<String, GroupRestResponse> groupIdToGroupResponse, GroupInformation expectedGroup) { | |||
GroupRestResponse restGroup = groupIdToGroupResponse.get(expectedGroup.groupDto().getUuid()); | |||
assertThat(restGroup).isNotNull(); | |||
assertThat(restGroup.name()).isEqualTo(expectedGroup.groupDto().getName()); | |||
assertThat(restGroup.description()).isEqualTo(expectedGroup.groupDto().getDescription()); | |||
//TODO add assertions for managed & default flag | |||
assertThat(restGroup.managed()).isEqualTo(expectedGroup.isManaged()); | |||
assertThat(restGroup.isDefault()).isEqualTo(expectedGroup.isDefault()); | |||
} | |||
private GroupInformation generateGroupSearchResult(String id, boolean managed, boolean isDefault) { | |||
GroupDto groupDto = new GroupDto() | |||
.setUuid(id) | |||
.setName("name_"+id) | |||
.setDescription("description_"+id); | |||
.setName("name_" + id) | |||
.setDescription("description_" + id); | |||
return new GroupInformation(groupDto, managed, isDefault); | |||
} | |||
} |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.usergroups.ws; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.server.ws.Change; | |||
@@ -59,6 +60,10 @@ public class CreateActionIT { | |||
private final CreateAction underTest = new CreateAction(db.getDbClient(), userSession, groupService, managedInstanceChecker); | |||
private final WsActionTester tester = new WsActionTester(underTest); | |||
@Before | |||
public void setUp() { | |||
db.users().insertDefaultGroup(); | |||
} | |||
@Test | |||
public void define_create_action() { | |||
WebService.Action action = tester.getDef(); |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.usergroups.ws; | |||
import java.util.Optional; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
@@ -54,6 +55,11 @@ public class ExternalGroupServiceIT { | |||
private final ExternalGroupService externalGroupService = new ExternalGroupService(dbClient, groupService); | |||
@Before | |||
public void setUp() { | |||
dbTester.users().insertDefaultGroup(); | |||
} | |||
@Test | |||
public void createOrUpdateExternalGroup_whenNewGroup_shouldCreateIt() { | |||
externalGroupService.createOrUpdateExternalGroup(dbSession, new GroupRegistration(EXTERNAL_ID, EXTERNAL_IDENTITY_PROVIDER, GROUP_NAME)); | |||
@@ -67,13 +73,12 @@ public class ExternalGroupServiceIT { | |||
externalGroupService.createOrUpdateExternalGroup(dbSession, new GroupRegistration(EXTERNAL_ID, EXTERNAL_IDENTITY_PROVIDER, GROUP_NAME)); | |||
assertThat(dbTester.users().countAllGroups()).isEqualTo(1); | |||
assertThat(dbTester.users().countAllGroups()).isEqualTo(2); | |||
assertGroupAndExternalGroup(); | |||
} | |||
@Test | |||
public void createOrUpdateExternalGroup_whenExistingExternalGroup_shouldUpdate() { | |||
dbTester.users().insertDefaultGroup(); | |||
GroupDto existingGroupDto = dbTester.users().insertGroup(GROUP_NAME); | |||
dbTester.users().insertExternalGroup(new ExternalGroupDto(existingGroupDto.getUuid(), EXTERNAL_ID, EXTERNAL_IDENTITY_PROVIDER)); | |||
@@ -88,7 +88,7 @@ public class CreateAction implements UserGroupsWsAction { | |||
managedInstanceChecker.throwIfInstanceIsManaged(); | |||
String groupName = request.mandatoryParam(PARAM_GROUP_NAME); | |||
String groupDescription = request.param(PARAM_GROUP_DESCRIPTION); | |||
GroupDto group = groupService.createGroup(dbSession, groupName, groupDescription); | |||
GroupDto group = groupService.createGroup(dbSession, groupName, groupDescription).groupDto(); | |||
dbSession.commit(); | |||
writeResponse(request, response, group); | |||
} |
@@ -72,7 +72,7 @@ public class ExternalGroupService { | |||
return groupDto.get(); | |||
} else { | |||
LOG.debug("Creating new group {}", groupRegistration.name()); | |||
return groupService.createGroup(dbSession, groupRegistration.name(), null); | |||
return groupService.createGroup(dbSession, groupRegistration.name(), null).groupDto(); | |||
} | |||
} | |||
@@ -29,8 +29,8 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.UserMembershipQuery; | |||
import org.sonar.server.common.group.service.GroupService; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.common.management.ManagedInstanceChecker; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.UserGroups; | |||
@@ -107,7 +107,7 @@ public class UpdateAction implements UserGroupsWsAction { | |||
String newName = request.param(PARAM_GROUP_NAME); | |||
String description = request.param(PARAM_GROUP_DESCRIPTION); | |||
GroupDto updatedGroup = groupService.updateGroup(dbSession, group, newName, description); | |||
GroupDto updatedGroup = groupService.updateGroup(dbSession, group, newName, description).groupDto(); | |||
dbSession.commit(); | |||
writeResponse(dbSession, request, response, updatedGroup); |