diff options
author | Antoine Vigneau <antoine.vigneau@sonarsource.com> | 2023-09-26 16:06:53 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-09-28 20:03:11 +0000 |
commit | 3a1522e5b2a19ee9c62ea9d2cf3dc52241145b96 (patch) | |
tree | 85f710fa4575e0b564ba6e1709b1d25c38bb81b2 /server/sonar-webserver-webapi-v2 | |
parent | b6375cec5bd52fb4d188467ccef4205de1287b50 (diff) | |
download | sonarqube-3a1522e5b2a19ee9c62ea9d2cf3dc52241145b96.tar.gz sonarqube-3a1522e5b2a19ee9c62ea9d2cf3dc52241145b96.zip |
SONAR-20532 Add POST endpoint to create permission mappings
Diffstat (limited to 'server/sonar-webserver-webapi-v2')
8 files changed, 349 insertions, 16 deletions
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsController.java index c6148669832..eb3fcea29db 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsController.java @@ -22,18 +22,18 @@ package org.sonar.server.v2.api.github.permissions.controller; import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.validation.Valid; import org.sonar.server.common.github.permissions.GithubPermissionsMapping; import org.sonar.server.common.github.permissions.GithubPermissionsMappingService; import org.sonar.server.common.github.permissions.PermissionMappingChange; +import org.sonar.server.common.github.permissions.SonarqubePermissions; import org.sonar.server.common.permission.Operation; import org.sonar.server.user.UserSession; import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping; import org.sonar.server.v2.api.github.permissions.request.GithubPermissionMappingUpdateRequest; +import org.sonar.server.v2.api.github.permissions.request.GithubPermissionsMappingPostRequest; import org.sonar.server.v2.api.github.permissions.request.PermissionMappingUpdate; +import org.sonar.server.v2.api.github.permissions.request.RestPermissions; import org.sonar.server.v2.api.github.permissions.response.GithubPermissionsMappingRestResponse; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.CODEVIEWER; @@ -60,7 +60,7 @@ public class DefaultGithubPermissionsController implements GithubPermissionsCont } @Override - public RestGithubPermissionsMapping updateMapping(@PathVariable("githubRole") String githubRole, @Valid @RequestBody GithubPermissionMappingUpdateRequest request) { + public RestGithubPermissionsMapping updateMapping(String githubRole, GithubPermissionMappingUpdateRequest request) { userSession.checkIsSystemAdministrator(); PermissionMappingUpdate update = request.permissions(); Set<PermissionMappingChange> changes = new HashSet<>(); @@ -94,12 +94,43 @@ public class DefaultGithubPermissionsController implements GithubPermissionsCont .toList(); } + @Override + public RestGithubPermissionsMapping createMapping(GithubPermissionsMappingPostRequest request) { + userSession.checkIsSystemAdministrator(); + GithubPermissionsMapping githubPermissionsMapping = new GithubPermissionsMapping(request.githubRole(), false, toSonarqubePermissions(request.permissions())); + return toRestGithubPermissionMapping(githubPermissionsMappingService.createPermissionMapping(githubPermissionsMapping)); + } + + private static SonarqubePermissions toSonarqubePermissions(RestPermissions restPermissions) { + SonarqubePermissions.Builder sonarqubePermissionsBuilder = SonarqubePermissions.Builder.builder(); + + sonarqubePermissionsBuilder.user(restPermissions.user()); + sonarqubePermissionsBuilder.codeViewer(restPermissions.codeViewer()); + sonarqubePermissionsBuilder.issueAdmin(restPermissions.issueAdmin()); + sonarqubePermissionsBuilder.securityHotspotAdmin(restPermissions.securityHotspotAdmin()); + sonarqubePermissionsBuilder.admin(restPermissions.admin()); + sonarqubePermissionsBuilder.scan(restPermissions.scan()); + + return sonarqubePermissionsBuilder.build(); + } + private static RestGithubPermissionsMapping toRestGithubPermissionMapping(GithubPermissionsMapping githubPermissionsMapping) { return new RestGithubPermissionsMapping( - githubPermissionsMapping.roleName(), - githubPermissionsMapping.roleName(), + githubPermissionsMapping.githubRole(), + githubPermissionsMapping.githubRole(), githubPermissionsMapping.isBaseRole(), - githubPermissionsMapping.permissions()); + toRestPermissions(githubPermissionsMapping.permissions())); + } + + private static RestPermissions toRestPermissions(SonarqubePermissions permissions) { + return new RestPermissions( + permissions.user(), + permissions.codeViewer(), + permissions.issueAdmin(), + permissions.securityHotspotAdmin(), + permissions.admin(), + permissions.scan() + ); } } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/GithubPermissionsController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/GithubPermissionsController.java index fddb261ab60..3c7083fb08a 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/GithubPermissionsController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/GithubPermissionsController.java @@ -24,37 +24,44 @@ import javax.validation.Valid; import org.sonar.server.v2.WebApiEndpoints; import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping; import org.sonar.server.v2.api.github.permissions.request.GithubPermissionMappingUpdateRequest; +import org.sonar.server.v2.api.github.permissions.request.GithubPermissionsMappingPostRequest; import org.sonar.server.v2.api.github.permissions.response.GithubPermissionsMappingRestResponse; 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.PostMapping; 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.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(WebApiEndpoints.GITHUB_PERMISSIONS_ENDPOINT) @RestController public interface GithubPermissionsController { - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch the GitHub permissions mapping", description = "Requires Administer System permission.") GithubPermissionsMappingRestResponse fetchAll(); - @PatchMapping(path = "/{githubRole}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{githubRole}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) - @Operation(summary = "Update a single Github permission mapping", description = "Update a single Github permission mapping") + @Operation(summary = "Update a single GitHub permission mapping", description = "Requires Administer System permission.") RestGithubPermissionsMapping updateMapping(@PathVariable("githubRole") String githubRole, @Valid @RequestBody GithubPermissionMappingUpdateRequest request); @DeleteMapping(path = "/{githubRole}") @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "Delete a single Github permission mapping", description = "Delete a single Github permission mapping") + @Operation(summary = "Delete a single GitHub permission mapping", description = "Requires Administer System permission.") void deleteMapping(@PathVariable("githubRole") String githubRole); + @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "Create a permission mapping for a GitHub custom role", description = "Requires Administer System permission.") + RestGithubPermissionsMapping createMapping(@Valid @RequestBody GithubPermissionsMappingPostRequest request); + } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/model/RestGithubPermissionsMapping.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/model/RestGithubPermissionsMapping.java index 89a028d2e82..1952c7c9d19 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/model/RestGithubPermissionsMapping.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/model/RestGithubPermissionsMapping.java @@ -19,7 +19,7 @@ */ package org.sonar.server.v2.api.github.permissions.model; -import org.sonar.server.common.github.permissions.SonarqubePermissions; +import org.sonar.server.v2.api.github.permissions.request.RestPermissions; -public record RestGithubPermissionsMapping(String id, String roleName, boolean isBaseRole, SonarqubePermissions permissions) { +public record RestGithubPermissionsMapping(String id, String githubRole, boolean isBaseRole, RestPermissions permissions) { } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionsMappingPostRequest.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionsMappingPostRequest.java new file mode 100644 index 00000000000..8ff8e54c3cd --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionsMappingPostRequest.java @@ -0,0 +1,35 @@ +/* + * 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.github.permissions.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +public record GithubPermissionsMappingPostRequest( + @NotNull + @Schema(description = "Custom role name on GitHub (case-sensitive)") + String githubRole, + + @NotNull + @Valid + @Schema(description = "Permissions") + RestPermissions permissions) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/RestPermissions.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/RestPermissions.java new file mode 100644 index 00000000000..15ed5286ee6 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/RestPermissions.java @@ -0,0 +1,50 @@ +/* + * 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.github.permissions.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.NotNull; + +public record RestPermissions( + @NotNull + @Schema(description = "Browse") + Boolean user, + + @NotNull + @Schema(description = "See Source Code") + Boolean codeViewer, + + @NotNull + @Schema(description = "Administer Issues") + Boolean issueAdmin, + + @NotNull + @Schema(description = "Administer Security Hotspots") + Boolean securityHotspotAdmin, + + @NotNull + @Schema(description = "Administer") + Boolean admin, + + @NotNull + @Schema(description = "Execute Analysis") + Boolean scan +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandler.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandler.java index dd8d133e37d..18ff785ecc6 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandler.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandler.java @@ -19,6 +19,7 @@ */ package org.sonar.server.v2.common; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import java.util.Optional; import java.util.stream.Collectors; import org.sonar.server.exceptions.BadRequestException; @@ -29,6 +30,7 @@ import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.v2.api.model.RestError; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -78,4 +80,18 @@ public class RestResponseEntityExceptionHandler { return new ResponseEntity<>(new RestError(notFoundException.getMessage()), HttpStatus.NOT_FOUND); } + @ExceptionHandler({HttpMessageNotReadableException.class}) + @ResponseStatus(HttpStatus.BAD_REQUEST) + protected ResponseEntity<RestError> handleHttpMessageNotReadableException(HttpMessageNotReadableException httpMessageNotReadableException) { + String exceptionMessage = getExceptionMessage(httpMessageNotReadableException); + return new ResponseEntity<>(new RestError(exceptionMessage), HttpStatus.BAD_REQUEST); + } + + private static String getExceptionMessage(HttpMessageNotReadableException httpMessageNotReadableException) { + if (httpMessageNotReadableException.getRootCause() instanceof InvalidFormatException invalidFormatException) { + return invalidFormatException.getOriginalMessage(); + } + return Optional.ofNullable(httpMessageNotReadableException.getMessage()).orElse(""); + } + } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsControllerTest.java index dd0282d5079..bb4b9f63965 100644 --- a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsControllerTest.java +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsControllerTest.java @@ -35,11 +35,14 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.v2.api.ControllerTester; import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping; +import org.sonar.server.v2.api.github.permissions.request.GithubPermissionsMappingPostRequest; +import org.sonar.server.v2.api.github.permissions.request.RestPermissions; import org.sonar.server.v2.api.github.permissions.response.GithubPermissionsMappingRestResponse; 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.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -47,9 +50,11 @@ import static org.mockito.Mockito.when; import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.READ_GITHUB_ROLE; import static org.sonar.server.v2.WebApiEndpoints.GITHUB_PERMISSIONS_ENDPOINT; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; 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; @@ -57,6 +62,8 @@ public class DefaultGithubPermissionsControllerTest { public static final String GITHUB_ROLE = "role1"; private static final Gson gson = new GsonBuilder().create(); + public static final GithubPermissionsMappingPostRequest GITHUB_PERMISSIONS_MAPPING_POST_REQUEST = + new GithubPermissionsMappingPostRequest(GITHUB_ROLE, new RestPermissions(true, true, true, true, true, true)); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @@ -97,7 +104,22 @@ public class DefaultGithubPermissionsControllerTest { } private static RestGithubPermissionsMapping toRestGithubPermissionMapping(GithubPermissionsMapping permissionMapping) { - return new RestGithubPermissionsMapping(permissionMapping.roleName(), permissionMapping.roleName(), permissionMapping.isBaseRole(), permissionMapping.permissions()); + return new RestGithubPermissionsMapping( + permissionMapping.githubRole(), + permissionMapping.githubRole(), + permissionMapping.isBaseRole(), + toRestPermissions(permissionMapping.permissions())); + } + + private static RestPermissions toRestPermissions(SonarqubePermissions permissions) { + return new RestPermissions( + permissions.user(), + permissions.codeViewer(), + permissions.issueAdmin(), + permissions.securityHotspotAdmin(), + permissions.admin(), + permissions.scan() + ); } @Test @@ -144,7 +166,7 @@ public class DefaultGithubPermissionsControllerTest { RestGithubPermissionsMapping response = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestGithubPermissionsMapping.class); RestGithubPermissionsMapping expectedResponse = new RestGithubPermissionsMapping(GITHUB_ROLE, GITHUB_ROLE, false, - new SonarqubePermissions(true, false, false, true, true, false)); + new RestPermissions(true, false, false, true, true, false)); assertThat(response).isEqualTo(expectedResponse); ArgumentCaptor<Set<PermissionMappingChange>> permissionMappingChangesCaptor = ArgumentCaptor.forClass(Set.class); @@ -199,4 +221,104 @@ public class DefaultGithubPermissionsControllerTest { verify(githubPermissionsMappingService).deletePermissionMappings(GITHUB_ROLE); } + @Test + public void createMapping_whenNotAdmin_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + mockMvc + .perform( + post(GITHUB_PERMISSIONS_ENDPOINT) + .contentType(APPLICATION_JSON_VALUE) + .content(gson.toJson(GITHUB_PERMISSIONS_MAPPING_POST_REQUEST))) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void createMapping_whenRoleExists_shouldReturnBadRequest() throws Exception { + userSession.logIn().setSystemAdministrator(); + + when(githubPermissionsMappingService.createPermissionMapping(any())) + .thenThrow(new IllegalArgumentException("Exception message")); + + mockMvc + .perform( + post(GITHUB_PERMISSIONS_ENDPOINT) + .contentType(APPLICATION_JSON_VALUE) + .content(gson.toJson(GITHUB_PERMISSIONS_MAPPING_POST_REQUEST))) + .andExpectAll( + status().isBadRequest(), + content().json("{\"message\":\"Exception message\"}")); + } + + @Test + public void createMapping_whenMissingPermission_shouldReturnBadRequest() throws Exception { + userSession.logIn().setSystemAdministrator(); + + mockMvc + .perform( + post(GITHUB_PERMISSIONS_ENDPOINT) + .contentType(APPLICATION_JSON_VALUE) + .content(""" + { + "githubRole": "customRole", + "permissions": { + "user": false, + "codeViewer": false, + "issueAdmin": false, + "securityHotspotAdmin": false, + "admin": false + } + } + """)) + .andExpectAll( + status().isBadRequest(), + content().json("{\"message\":\"Value {} for field permissions.scan was rejected. Error: must not be null.\"}")); + } + + @Test + public void createMapping_whenWrongType_shouldReturnBadRequest() throws Exception { + userSession.logIn().setSystemAdministrator(); + + mockMvc + .perform( + post(GITHUB_PERMISSIONS_ENDPOINT) + .contentType(APPLICATION_JSON_VALUE) + .content(""" + { + "githubRole": "customRole", + "permissions": { + "user": false, + "codeViewer": false, + "issueAdmin": true, + "securityHotspotAdmin": false, + "admin": true, + "scan": "notABooleanType" + } + } + """)) + .andExpect(status().isBadRequest()); + } + @Test + public void createMapping_whenValidRequest_shouldReturnMapping() throws Exception { + userSession.logIn().setSystemAdministrator(); + + GithubPermissionsMapping githubPermissionsMapping = new GithubPermissionsMapping(GITHUB_ROLE, false, new SonarqubePermissions(true, true, true, true, true, true)); + when(githubPermissionsMappingService.createPermissionMapping(githubPermissionsMapping)).thenReturn(githubPermissionsMapping); + + MvcResult mvcResult = mockMvc + .perform( + post(GITHUB_PERMISSIONS_ENDPOINT) + .contentType(APPLICATION_JSON_VALUE) + .content(gson.toJson(GITHUB_PERMISSIONS_MAPPING_POST_REQUEST))) + .andExpect(status().isOk()) + .andReturn(); + + RestGithubPermissionsMapping response = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestGithubPermissionsMapping.class); + + RestGithubPermissionsMapping expectedResponse = new RestGithubPermissionsMapping(GITHUB_ROLE, GITHUB_ROLE, false, new RestPermissions(true, true, true, true, true, true)); + assertThat(response).isEqualTo(expectedResponse); + + } + } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandlerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandlerTest.java new file mode 100644 index 00000000000..b64519d72ad --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/RestResponseEntityExceptionHandlerTest.java @@ -0,0 +1,72 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import org.junit.Test; +import org.sonar.server.v2.api.model.RestError; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RestResponseEntityExceptionHandlerTest { + + private RestResponseEntityExceptionHandler underTest = new RestResponseEntityExceptionHandler(); + + @Test + public void handleHttpMessageNotReadableException_whenCauseIsNotInvalidFormatException_shouldUseMessage() { + + HttpMessageNotReadableException exception = new HttpMessageNotReadableException("Message not readable", new Exception()); + + ResponseEntity<RestError> responseEntity = underTest.handleHttpMessageNotReadableException(exception); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().message()).isEqualTo("Message not readable; nested exception is java.lang.Exception"); + } + + @Test + public void handleHttpMessageNotReadableException_whenCauseIsNotInvalidFormatExceptionAndMessageIsNull_shouldUseEmptyStringAsMessage() { + + HttpMessageNotReadableException exception = new HttpMessageNotReadableException(null, (Exception) null); + + ResponseEntity<RestError> responseEntity = underTest.handleHttpMessageNotReadableException(exception); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().message()).isEmpty(); + } + + @Test + public void handleHttpMessageNotReadableException_whenCauseIsInvalidFormatException_shouldUseMessageFromCause() { + + InvalidFormatException cause = mock(InvalidFormatException.class); + when(cause.getOriginalMessage()).thenReturn("Cause message"); + + HttpMessageNotReadableException exception = new HttpMessageNotReadableException("Message not readable", cause); + + ResponseEntity<RestError> responseEntity = underTest.handleHttpMessageNotReadableException(exception); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().message()).isEqualTo("Cause message"); + } +} |