From 56f423531c789de9873ce375b7b8d4a7a800529a Mon Sep 17 00:00:00 2001 From: Aurelien Poscia Date: Tue, 21 Nov 2023 14:45:11 +0100 Subject: [PATCH] SONAR-21058 Add DELETE and PATCH verb for /api/v2/authorizations/groups --- .../controller/DefaultGroupController.java | 51 +++++- .../api/group/controller/GroupController.java | 20 +++ .../group/request/GroupUpdateRestRequest.java | 52 ++++++ .../v2/api/group/request/package-info.java | 23 +++ .../server/v2/common/model/UpdateField.java | 6 + .../v2/config/PlatformLevel4WebConfig.java | 5 +- .../DefaultGroupControllerTest.java | 155 +++++++++++++++++- .../v2/common/model/UpdateFieldTest.java | 47 ++++++ 8 files changed, 342 insertions(+), 17 deletions(-) create mode 100644 server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/GroupUpdateRestRequest.java create mode 100644 server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/package-info.java create mode 100644 server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/model/UpdateFieldTest.java diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/DefaultGroupController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/DefaultGroupController.java index 49a4e4f2f89..72bf4421c6d 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/DefaultGroupController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/DefaultGroupController.java @@ -23,8 +23,10 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.user.GroupDto; 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.GroupUpdateRestRequest; import org.sonar.server.v2.api.group.response.RestGroupResponse; public class DefaultGroupController implements GroupController { @@ -33,24 +35,61 @@ public class DefaultGroupController implements GroupController { private final GroupService groupService; private final DbClient dbClient; private final UserSession userSession; + private final ManagedInstanceChecker managedInstanceChecker; - public DefaultGroupController(GroupService groupService, DbClient dbClient, UserSession userSession) { + public DefaultGroupController(GroupService groupService, DbClient dbClient, ManagedInstanceChecker managedInstanceChecker, UserSession userSession) { this.groupService = groupService; this.dbClient = dbClient; this.userSession = userSession; + this.managedInstanceChecker = managedInstanceChecker; } @Override public RestGroupResponse fetchGroup(String id) { userSession.checkLoggedIn().checkIsSystemAdministrator(); try (DbSession session = dbClient.openSession(false)) { - return groupService.findGroupByUuid(session, id) - .map(DefaultGroupController::groupDtoToResponse) - .orElseThrow(() -> new NotFoundException(String.format(GROUP_NOT_FOUND_MESSAGE, id))); + GroupDto groupDto = findGroupDtoOrThrow(id, session); + return toRestGroup(groupDto); } } - private static RestGroupResponse groupDtoToResponse(GroupDto group) { - return new RestGroupResponse(group.getUuid(), group.getName(), group.getDescription()); + @Override + public void deleteGroup(String id) { + throwIfNotAllowedToChangeGroupName(); + try (DbSession session = dbClient.openSession(false)) { + GroupDto group = findGroupDtoOrThrow(id, session); + groupService.delete(session, group); + session.commit(); + } + } + + @Override + public RestGroupResponse updateGroup(String id, GroupUpdateRestRequest updateRequest) { + throwIfNotAllowedToChangeGroupName(); + try (DbSession session = dbClient.openSession(false)) { + GroupDto group = findGroupDtoOrThrow(id, session); + GroupDto updatedGroup = groupService.updateGroup( + session, + group, + updateRequest.getName().orElse(group.getName()), + updateRequest.getDescription().orElse(group.getDescription()) + ); + session.commit(); + return toRestGroup(updatedGroup); + } + } + + private void throwIfNotAllowedToChangeGroupName() { + userSession.checkIsSystemAdministrator(); + managedInstanceChecker.throwIfInstanceIsManaged(); + } + + private GroupDto findGroupDtoOrThrow(String id, DbSession session) { + return groupService.findGroupByUuid(session, id) + .orElseThrow(() -> new NotFoundException(String.format(GROUP_NOT_FOUND_MESSAGE, id))); + } + + private static RestGroupResponse toRestGroup(GroupDto updatedGroup) { + return new RestGroupResponse(updatedGroup.getUuid(), updatedGroup.getName(), updatedGroup.getDescription()); } } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java index f889fc8b686..dac00c961c3 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java @@ -22,15 +22,22 @@ package org.sonar.server.v2.api.group.controller; 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.GroupUpdateRestRequest; import org.sonar.server.v2.api.group.response.RestGroupResponse; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +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.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.GROUPS_ENDPOINT; +import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; @RequestMapping(GROUPS_ENDPOINT) @RestController @@ -40,4 +47,17 @@ public interface GroupController { @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); + + @DeleteMapping(path = "/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Deletes a group", description = "Deletes a group.") + void deleteGroup(@PathVariable("id") @Parameter(description = "The ID of the group to delete.", required = true, in = ParameterIn.PATH) String id); + + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "Update a user", description = """ + Update a user. + Allows updating user's name, email and SCM accounts. + """) + RestGroupResponse updateGroup(@PathVariable("id") String id, @Valid @RequestBody GroupUpdateRestRequest updateRequest); } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/GroupUpdateRestRequest.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/GroupUpdateRestRequest.java new file mode 100644 index 00000000000..7f6597edcbc --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/GroupUpdateRestRequest.java @@ -0,0 +1,52 @@ +/* + * 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.validation.constraints.Size; +import org.sonar.server.v2.common.model.UpdateField; + +import static org.sonar.api.user.UserGroupValidation.GROUP_NAME_MAX_LENGTH; + +public class GroupUpdateRestRequest { + + private UpdateField name = UpdateField.undefined(); + private UpdateField description = UpdateField.undefined(); + @Size(min=1, max = GROUP_NAME_MAX_LENGTH) + @Schema(implementation = String.class, description = "Group name") + public UpdateField getName() { + return name; + } + + public void setName(String name) { + this.name = UpdateField.withValue(name); + } + + @Size(max = 200) + @Schema(implementation = String.class, description = "Description of the gorup") + public UpdateField getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = UpdateField.withValue(description); + } + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/package-info.java new file mode 100644 index 00000000000..a93ddeb4754 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/request/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.v2.api.group.request; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/model/UpdateField.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/model/UpdateField.java index d32d1457b17..49a80e3eb40 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/model/UpdateField.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/model/UpdateField.java @@ -66,6 +66,12 @@ public class UpdateField { return undefined(); } + @CheckForNull + public T orElse(@Nullable T other) { + return isDefined ? value : other; + } + + @Override public String toString() { return value.toString(); diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java index fa61ea447cc..95530e69891 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java @@ -26,6 +26,7 @@ import org.sonar.server.common.health.CeStatusNodeCheck; import org.sonar.server.common.health.DbConnectionNodeCheck; import org.sonar.server.common.health.EsStatusNodeCheck; import org.sonar.server.common.health.WebServerStatusNodeCheck; +import org.sonar.server.common.management.ManagedInstanceChecker; import org.sonar.server.common.platform.LivenessChecker; import org.sonar.server.common.platform.LivenessCheckerImpl; import org.sonar.server.common.user.service.UserService; @@ -80,8 +81,8 @@ public class PlatformLevel4WebConfig { } @Bean - public GroupController groupController(GroupService groupService, DbClient dbClient, UserSession userSession) { - return new DefaultGroupController(groupService, dbClient, userSession); + public GroupController groupController(GroupService groupService, DbClient dbClient, ManagedInstanceChecker managedInstanceChecker, UserSession userSession) { + return new DefaultGroupController(groupService, dbClient, managedInstanceChecker, userSession); } } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/group/controller/DefaultGroupControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/group/controller/DefaultGroupControllerTest.java index 387b6daa8e4..743a902107e 100644 --- a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/group/controller/DefaultGroupControllerTest.java +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/group/controller/DefaultGroupControllerTest.java @@ -19,37 +19,52 @@ */ package org.sonar.server.v2.api.group.controller; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import java.util.Optional; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.user.GroupDto; import org.sonar.server.common.group.service.GroupService; +import org.sonar.server.common.management.ManagedInstanceChecker; +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.RestGroupResponse; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.server.v2.WebApiEndpoints.GROUPS_ENDPOINT; +import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +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.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@RunWith(MockitoJUnitRunner.class) public class DefaultGroupControllerTest { private static final String GROUP_UUID = "1234"; + private static final Gson GSON = new GsonBuilder().create(); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); - private final GroupService groupService = mock(GroupService.class); - private final DbClient dbClient = mock(DbClient.class); - - private final DbSession dbSession = mock(DbSession.class); - - private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGroupController(groupService, dbClient, userSession)); + private final GroupService groupService = mock(); + 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)); @Before public void setUp() { @@ -80,7 +95,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\"}")); @@ -91,11 +106,133 @@ 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\"}")); + } + + @Test + public void deleteGroup_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + mockMvc.perform( + delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void deleteGroup_whenInstanceIsManaged_shouldReturnException() throws Exception { + userSession.logIn().setSystemAdministrator(); + doThrow(BadRequestException.create("the instance is managed")).when(managedInstanceChecker).throwIfInstanceIsManaged(); + mockMvc.perform( + delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) + .andExpectAll( + status().isBadRequest(), + content().json("{\"message\":\"the instance is managed\"}")); + } + + @Test + public void deleteGroup_whenGroupDoesntExist_shouldReturnNotFound() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.empty()); + mockMvc.perform( + delete(GROUPS_ENDPOINT + "/" + GROUP_UUID).content("{}")) + .andExpectAll( + status().isNotFound(), + content().json("{\"message\":\"Group '1234' not found\"}")); + } + + @Test + public void deleteGroup_whenGroupExists_shouldDeleteAndReturn204() throws Exception { + GroupDto groupDto = new GroupDto().setUuid(GROUP_UUID).setName("name").setDescription("description"); + + when(groupService.findGroupByUuid(dbSession, GROUP_UUID)).thenReturn(Optional.of(groupDto)); + + userSession.logIn().setSystemAdministrator(); + mockMvc.perform( + delete(GROUPS_ENDPOINT + "/" + GROUP_UUID)) + .andExpectAll( + status().isNoContent(), + content().string("")); + } + + @Test + public void patchGroup_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + mockMvc.perform( + patch(GROUPS_ENDPOINT + "/" + GROUP_UUID).contentType(JSON_MERGE_PATCH_CONTENT_TYPE).content("{}") + ) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void patchGroup_whenInstanceIsManaged_shouldReturnException() throws Exception { + 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("{}") + ) + .andExpectAll( + status().isBadRequest(), + content().json("{\"message\":\"the instance is managed\"}")); + } + + @Test + public void patchGroup_whenGroupDoesntExist_shouldReturnNotFound() throws Exception { + 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("{}") + ) .andExpectAll( status().isNotFound(), content().json("{\"message\":\"Group '1234' not found\"}")); } + @Test + public void patchGroup_whenGroupExists_shouldPatchAndReturnNewGroup() throws Exception { + patchGroupAndAssertResponse("newName", "newDescription"); + } + + @Test + public void patchGroup_whenGroupExistsAndRemovingDescription_shouldPatchAndReturnNewGroup() throws Exception { + patchGroupAndAssertResponse("newName", null); + } + + @Test + public void patchGroup_whenGroupExistsAndIdempotent_shouldPatch() throws Exception { + patchGroupAndAssertResponse("newName", "newDescription"); + patchGroupAndAssertResponse("newName", "newDescription"); + } + + 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)); + GroupDto newDto = new GroupDto().setUuid(GROUP_UUID).setName(newName).setDescription(newDescription); + when(groupService.updateGroup(dbSession, groupDto, newName, newDescription)).thenReturn(newDto); + + 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 + "\"") + ) + ) + .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); + } + } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/model/UpdateFieldTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/model/UpdateFieldTest.java new file mode 100644 index 00000000000..2df7530c009 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/model/UpdateFieldTest.java @@ -0,0 +1,47 @@ +/* + * 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.common.model; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class UpdateFieldTest { + + @Test + public void orElse_whenNoValueDefined_useElseValue() { + UpdateField updateField = UpdateField.undefined(); + assertThat(updateField.orElse("foo")).isEqualTo("foo"); + } + + @Test + public void orElse_whenNoNullValueDefined_useValue() { + UpdateField updateField = UpdateField.withValue("bar"); + assertThat(updateField.orElse("foo")).isEqualTo("bar"); + } + + @Test + public void orElse_whenNullValueDefined_useValue() { + UpdateField updateField = UpdateField.withValue(null); + assertThat(updateField.orElse("foo")).isNull(); + } +} -- 2.39.5