From 7851a89c67279990a6d1b063ca62d49fdcb5be87 Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Thu, 7 Jan 2021 15:42:31 +0100 Subject: [PATCH] Change to use checked exceptions in rAPP Catalogue MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add the parameter “unhandledException” with value “true” to the generator to make the delegated implementation able to handle checked exceptions. Change the service's exceptions to be checked and adapt the code accordingly. Change-Id: I15cab337826b48d21ae83521d149f177d8dce00d Issue-ID: NONRTRIC-373 Signed-off-by: elinuxhenrik --- r-app-catalogue/pom.xml | 1 + .../api/GeneralRappCatalogueControllerAdvisor.java | 9 +- .../rappcatalogue/api/ServicesApiDelegateImpl.java | 288 +++++------ .../rappcatalogue/exception/HeaderException.java | 2 +- .../exception/InvalidServiceException.java | 2 +- .../exception/ServiceNotFoundException.java | 2 +- .../api/ServicesApiDelegateImplTest.java | 546 +++++++++++---------- 7 files changed, 429 insertions(+), 421 deletions(-) diff --git a/r-app-catalogue/pom.xml b/r-app-catalogue/pom.xml index a2e05656..0ceb7bbf 100644 --- a/r-app-catalogue/pom.xml +++ b/r-app-catalogue/pom.xml @@ -180,6 +180,7 @@ org.oransc.rappcatalogue true + true diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java index 939f7bf9..072a5a0e 100644 --- a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java +++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java @@ -35,22 +35,19 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep @ControllerAdvice public class GeneralRappCatalogueControllerAdvisor extends ResponseEntityExceptionHandler { @ExceptionHandler(InvalidServiceException.class) - public ResponseEntity handleInvalidServiceException( - InvalidServiceException ex) { + public ResponseEntity handleInvalidServiceException(InvalidServiceException ex) { return new ResponseEntity<>(getErrorInformation(ex, BAD_REQUEST), BAD_REQUEST); } @ExceptionHandler(ServiceNotFoundException.class) - public ResponseEntity handleServiceNotFoundException( - ServiceNotFoundException ex) { + public ResponseEntity handleServiceNotFoundException(ServiceNotFoundException ex) { return new ResponseEntity<>(getErrorInformation(ex, NOT_FOUND), NOT_FOUND); } @ExceptionHandler(HeaderException.class) - public ResponseEntity handleHeaderException( - HeaderException ex) { + public ResponseEntity handleHeaderException(HeaderException ex) { return new ResponseEntity<>(getErrorInformation(ex, INTERNAL_SERVER_ERROR), INTERNAL_SERVER_ERROR); } diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java index bb3a6dc6..4615d69c 100644 --- a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java +++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java @@ -1,141 +1,147 @@ -/*- - * ========================LICENSE_START================================= - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================LICENSE_END=================================== - */ - -package org.oransc.rappcatalogue.api; - -import java.io.IOException; -import java.sql.Date; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.oransc.rappcatalogue.exception.HeaderException; -import org.oransc.rappcatalogue.exception.InvalidServiceException; -import org.oransc.rappcatalogue.exception.ServiceNotFoundException; -import org.oransc.rappcatalogue.model.InputService; -import org.oransc.rappcatalogue.model.Service; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.context.request.NativeWebRequest; - -@org.springframework.stereotype.Service -public class ServicesApiDelegateImpl implements ServicesApiDelegate { - - private static final String LOCATION_HEADER = "Location"; - - @Autowired - private NativeWebRequest nativeWebRequest; - - private ConcurrentHashMap registeredServices = new ConcurrentHashMap<>(); - - ServicesApiDelegateImpl(NativeWebRequest nativeWebRequest) { - this.nativeWebRequest = nativeWebRequest; - } - - @Override - public Optional getRequest() { - return Optional.of(nativeWebRequest); - } - - @Override - public ResponseEntity getIndividualService(String serviceName) { - Service service = registeredServices.get(serviceName); - if (service != null) { - return ResponseEntity.ok(service); - } else { - throw new ServiceNotFoundException(serviceName); - } - } - - @Override - public ResponseEntity> getServices() { - return ResponseEntity.ok(new ArrayList<>(registeredServices.values())); - } - - @Override - public ResponseEntity putIndividualService(String serviceName, InputService inputService) { - if (isServiceValid(inputService)) { - if (registeredServices.put(serviceName, createService(serviceName, inputService)) == null) { - try { - getRequest().ifPresent(request -> addLocationHeaderToResponse(serviceName, request)); - } catch (Exception e) { - registeredServices.remove(serviceName); - throw e; - } - return new ResponseEntity<>(HttpStatus.CREATED); - } else { - return new ResponseEntity<>(HttpStatus.OK); - } - } else { - throw new InvalidServiceException(); - } - } - - private void addLocationHeaderToResponse(String serviceName, NativeWebRequest request) { - try { - HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); - HttpServletResponse nativeResponse = request.getNativeResponse(HttpServletResponse.class); - if (nativeRequest != null && nativeResponse != null) { - StringBuffer requestURL = nativeRequest.getRequestURL(); - nativeResponse.addHeader(LOCATION_HEADER, requestURL.toString()); - nativeResponse.getWriter().print(""); - } else { - throw new HeaderException(LOCATION_HEADER, serviceName, - new Exception("Native Request or Response missing")); - } - } catch (IOException e) { - throw new HeaderException(LOCATION_HEADER, serviceName, e); - } - } - - @Override - public ResponseEntity deleteIndividualService(String serviceName) { - registeredServices.remove(serviceName); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /* - * java:S2589: Boolean expressions should not be gratuitous. - * Even though the version property is marked as @NotNull, it might be null coming from the client, hence the null - * check is needed. - */ - @SuppressWarnings("java:S2589") - private boolean isServiceValid(InputService service) { - String version = service.getVersion(); - return version != null && !version.isBlank(); - } - - private Service createService(String serviceName, InputService inputService) { - Service service = new Service(); - service.setName(serviceName); - service.setDescription(inputService.getDescription()); - service.setDisplayName(inputService.getDisplayName()); - service.setVersion(inputService.getVersion()); - service.setRegistrationDate(getTodaysDate()); - return service; - } - - private String getTodaysDate() { - long millis = System.currentTimeMillis(); - Date date = new Date(millis); - return date.toString(); - } -} +/*- + * ========================LICENSE_START================================= + * Copyright (C) 2020 Nordix Foundation. All rights reserved. + * ====================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================LICENSE_END=================================== + */ + +package org.oransc.rappcatalogue.api; + +import java.io.IOException; +import java.sql.Date; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.oransc.rappcatalogue.exception.HeaderException; +import org.oransc.rappcatalogue.exception.InvalidServiceException; +import org.oransc.rappcatalogue.exception.ServiceNotFoundException; +import org.oransc.rappcatalogue.model.InputService; +import org.oransc.rappcatalogue.model.Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.context.request.NativeWebRequest; + +@org.springframework.stereotype.Service +public class ServicesApiDelegateImpl implements ServicesApiDelegate { + + private static final String LOCATION_HEADER = "Location"; + + @Autowired + private NativeWebRequest nativeWebRequest; + + private ConcurrentHashMap registeredServices = new ConcurrentHashMap<>(); + + ServicesApiDelegateImpl(NativeWebRequest nativeWebRequest) { + this.nativeWebRequest = nativeWebRequest; + } + + @Override + public Optional getRequest() { + return Optional.of(nativeWebRequest); + } + + @Override + public ResponseEntity getIndividualService(String serviceName) throws ServiceNotFoundException { + Service service = registeredServices.get(serviceName); + if (service != null) { + return ResponseEntity.ok(service); + } else { + throw new ServiceNotFoundException(serviceName); + } + } + + @Override + public ResponseEntity> getServices() { + return ResponseEntity.ok(new ArrayList<>(registeredServices.values())); + } + + @Override + public ResponseEntity putIndividualService(String serviceName, InputService inputService) + throws InvalidServiceException, HeaderException { + if (isServiceValid(inputService)) { + if (registeredServices.put(serviceName, createService(serviceName, inputService)) == null) { + try { + Optional request = getRequest(); + if (request.isPresent()) { + addLocationHeaderToResponse(serviceName, request.get()); + } + } catch (HeaderException e) { + registeredServices.remove(serviceName); + throw e; + } + return new ResponseEntity<>(HttpStatus.CREATED); + } else { + return new ResponseEntity<>(HttpStatus.OK); + } + } else { + throw new InvalidServiceException(); + } + } + + private void addLocationHeaderToResponse(String serviceName, NativeWebRequest request) throws HeaderException { + try { + HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); + HttpServletResponse nativeResponse = request.getNativeResponse(HttpServletResponse.class); + if (nativeRequest != null && nativeResponse != null) { + StringBuffer requestURL = nativeRequest.getRequestURL(); + nativeResponse.addHeader(LOCATION_HEADER, requestURL.toString()); + nativeResponse.getWriter().print(""); + } else { + throw new HeaderException(LOCATION_HEADER, serviceName, + new Exception("Native Request or Response missing")); + } + } catch (IOException e) { + throw new HeaderException(LOCATION_HEADER, serviceName, e); + } + } + + @Override + public ResponseEntity deleteIndividualService(String serviceName) { + registeredServices.remove(serviceName); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + /* + * java:S2589: Boolean expressions should not be gratuitous. Even though the + * version property is marked as @NotNull, it might be null coming from the + * client, hence the null check is needed. + */ + @SuppressWarnings("java:S2589") + private boolean isServiceValid(InputService service) { + String version = service.getVersion(); + return version != null && !version.isBlank(); + } + + private Service createService(String serviceName, InputService inputService) { + Service service = new Service(); + service.setName(serviceName); + service.setDescription(inputService.getDescription()); + service.setDisplayName(inputService.getDisplayName()); + service.setVersion(inputService.getVersion()); + service.setRegistrationDate(getTodaysDate()); + return service; + } + + private String getTodaysDate() { + long millis = System.currentTimeMillis(); + Date date = new Date(millis); + return date.toString(); + } +} diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java index 676ae1c1..8f64449f 100644 --- a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java +++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java @@ -18,7 +18,7 @@ package org.oransc.rappcatalogue.exception; -public class HeaderException extends RuntimeException { +public class HeaderException extends Exception { private static final long serialVersionUID = -7798178963078284655L; diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java index dce815b9..45ec7692 100644 --- a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java +++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java @@ -18,7 +18,7 @@ package org.oransc.rappcatalogue.exception; -public class InvalidServiceException extends RuntimeException { +public class InvalidServiceException extends Exception { private static final long serialVersionUID = 3849219105170316564L; public InvalidServiceException() { diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java index 26b4b271..8411cf42 100644 --- a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java +++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java @@ -18,7 +18,7 @@ package org.oransc.rappcatalogue.exception; -public class ServiceNotFoundException extends RuntimeException { +public class ServiceNotFoundException extends Exception { private static final long serialVersionUID = 6579271315716003988L; public ServiceNotFoundException(String serviceName) { diff --git a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java index f2f30ff6..dd10a650 100644 --- a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java +++ b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java @@ -1,271 +1,275 @@ -package org.oransc.rappcatalogue.api; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.NO_CONTENT; -import static org.springframework.http.HttpStatus.OK; - -import java.io.IOException; -import java.io.PrintWriter; -import java.sql.Date; -import java.util.Arrays; -import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.oransc.rappcatalogue.exception.HeaderException; -import org.oransc.rappcatalogue.exception.InvalidServiceException; -import org.oransc.rappcatalogue.exception.ServiceNotFoundException; -import org.oransc.rappcatalogue.model.InputService; -import org.oransc.rappcatalogue.model.Service; -import org.springframework.http.ResponseEntity; -import org.springframework.web.context.request.NativeWebRequest; - -@ExtendWith(MockitoExtension.class) -class ServicesApiDelegateImplTest { - - @Mock - NativeWebRequest webRequestMock; - - private static final String INVALID_SERVICE_MESSAGE = "Service is missing required property: version"; - private static final String SERVICE_NAME = "Service Name"; - private static final String SERVICE_DESCRIPTION = "description"; - private static final String SERVICE_VERSION = "1.0"; - private static final String SERVICE_DISPLAY_NAME = "Display Name"; - - @Test - void getAddedService_shouldReturnService() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - InputService service = new InputService(); - service.setDescription(SERVICE_DESCRIPTION); - service.setVersion(SERVICE_VERSION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - whenPrintResponseShouldWork(); - - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - - ResponseEntity response = delegateUnderTest.getIndividualService(SERVICE_NAME); - - assertThat(response.getStatusCode()).isEqualTo(OK); - assertThat(response.getBody().getName()).isEqualTo(SERVICE_NAME); - } - - @Test - void getMissingService_shouldThrowException() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); - - Exception exception = assertThrows(ServiceNotFoundException.class, () -> { - delegateUnderTest.getIndividualService(SERVICE_NAME); - }); - - String expectedMessage = "Service " + SERVICE_NAME + " not found"; - String actualMessage = exception.getMessage(); - - assertThat(actualMessage).isEqualTo(expectedMessage); - } - - @Test - void putNewValidService_shouldBeCreatedAndRegisteredAndUrlToNewServiceAddedToLocationHeaderInResponse() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - InputService service = new InputService(); - service.setDescription(SERVICE_DESCRIPTION); - service.setVersion(SERVICE_VERSION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - String urlToCreatedService = "URL to created Service"; - HttpServletResponse servletResponseMock = whenPrintResponseShouldWork(urlToCreatedService); - - ResponseEntity putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service); - - assertThat(putResponse.getStatusCode()).isEqualTo(CREATED); - verify(servletResponseMock).addHeader("Location", urlToCreatedService); - - ResponseEntity getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME); - - assertThat(getResponse.getStatusCode()).isEqualTo(OK); - Service body = getResponse.getBody(); - assertThat(body.getName()).isEqualTo(SERVICE_NAME); - assertThat(body.getRegistrationDate()).isEqualTo(getTodaysDate()); - } - - @Test - void putModifiedService_shouldBeModified() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - InputService service = new InputService(); - service.setDescription(SERVICE_DESCRIPTION); - service.setVersion(SERVICE_VERSION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - whenPrintResponseShouldWork(); - - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - - String newDescription = "New description"; - service.setDescription(newDescription); - ResponseEntity putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service); - - assertThat(putResponse.getStatusCode()).isEqualTo(OK); - - ResponseEntity getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME); - - assertThat(getResponse.getStatusCode()).isEqualTo(OK); - assertThat(getResponse.getBody().getDescription()).isEqualTo(newDescription); - } - - @Test - void putServiceWithVersionNull_shouldThrowException() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); - - InputService service = new InputService(); - service.setDescription(SERVICE_DESCRIPTION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - Exception exception = assertThrows(InvalidServiceException.class, () -> { - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - }); - - assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE); - } - - @Test - void putServiceWithBlankVersion_shouldThrowException() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); - - InputService service = new InputService(); - service.setVersion(""); - service.setDescription(SERVICE_DESCRIPTION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - Exception exception = assertThrows(InvalidServiceException.class, () -> { - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - }); - - assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE); - } - - @Test - void putServiceWhenIoExceptionAddingHeader_shouldThrowExceptionAndNoServiceCreated() throws Exception { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - whenGetRequestUrlThenReturnUrl(); - HttpServletResponse servletResponseMock = mock(HttpServletResponse.class); - when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock); - when(servletResponseMock.getWriter()).thenThrow(new IOException("Error")); - - InputService service = new InputService(); - service.setVersion("1.0"); - service.setDescription(SERVICE_DESCRIPTION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - Exception exception = assertThrows(HeaderException.class, () -> { - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - }); - - assertThat(exception.getMessage()) - .isEqualTo("Unable to set header Location in put response for service " + SERVICE_NAME + ". Cause: Error"); - - ResponseEntity> response = delegateUnderTest.getServices(); - assertThat(response.getBody()).isEmpty(); - } - - @Test - void getServices_shouldProvideArrayOfAddedServiceNames() throws Exception { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - InputService service1 = new InputService(); - service1.setDescription("description 1"); - service1.setVersion(SERVICE_VERSION); - service1.setDisplayName("Display Name 1"); - - InputService service2 = new InputService(); - service2.setDescription("description 2"); - service2.setVersion(SERVICE_VERSION); - service2.setDisplayName("Display Name 2"); - - whenPrintResponseShouldWork(); - - String serviceName1 = "Service Name 1"; - delegateUnderTest.putIndividualService(serviceName1, service1); - String serviceName2 = "Service Name 2"; - delegateUnderTest.putIndividualService(serviceName2, service2); - - ResponseEntity> response = delegateUnderTest.getServices(); - - assertThat(response.getStatusCode()).isEqualTo(OK); - List services = response.getBody(); - assertThat(services).hasSize(2); - List expectedServiceNames = Arrays.asList(serviceName1, serviceName2); - assertThat(expectedServiceNames).contains(services.get(0).getName()) // - .contains(services.get(1).getName()); - } - - @Test - void deleteService_shouldBeOk() { - ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); - - InputService service = new InputService(); - service.setDescription(SERVICE_DESCRIPTION); - service.setVersion(SERVICE_VERSION); - service.setDisplayName(SERVICE_DISPLAY_NAME); - - whenPrintResponseShouldWork(); - - delegateUnderTest.putIndividualService(SERVICE_NAME, service); - - ResponseEntity> servicesResponse = delegateUnderTest.getServices(); - - assertThat(servicesResponse.getBody()).hasSize(1); - - ResponseEntity deleteResponse = delegateUnderTest.deleteIndividualService(SERVICE_NAME); - - assertThat(deleteResponse.getStatusCode()).isEqualTo(NO_CONTENT); - - servicesResponse = delegateUnderTest.getServices(); - - assertThat(servicesResponse.getBody()).isEmpty(); - } - - private void whenGetRequestUrlThenReturnUrl() { - whenGetRequestUrlThenReturnUrl("URL"); - } - - private void whenGetRequestUrlThenReturnUrl(String url) { - HttpServletRequest servletRequestMock = mock(HttpServletRequest.class); - when(webRequestMock.getNativeRequest(HttpServletRequest.class)).thenReturn(servletRequestMock); - when(servletRequestMock.getRequestURL()).thenReturn(new StringBuffer(url)); - } - - private HttpServletResponse whenPrintResponseShouldWork() { - return whenPrintResponseShouldWork("URL"); - } - - private HttpServletResponse whenPrintResponseShouldWork(String url) { - whenGetRequestUrlThenReturnUrl(url); - HttpServletResponse servletResponseMock = mock(HttpServletResponse.class); - when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock); - PrintWriter printWriterMock = mock(PrintWriter.class); - try { - when(servletResponseMock.getWriter()).thenReturn(printWriterMock); - } catch (IOException e) { - // Nothing - } - return servletResponseMock; - } - - private String getTodaysDate() { - long millis = System.currentTimeMillis(); - Date date = new Date(millis); - return date.toString(); - } -} + +package org.oransc.rappcatalogue.api; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.NO_CONTENT; +import static org.springframework.http.HttpStatus.OK; + +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Date; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.oransc.rappcatalogue.exception.HeaderException; +import org.oransc.rappcatalogue.exception.InvalidServiceException; +import org.oransc.rappcatalogue.exception.ServiceNotFoundException; +import org.oransc.rappcatalogue.model.InputService; +import org.oransc.rappcatalogue.model.Service; +import org.springframework.http.ResponseEntity; +import org.springframework.web.context.request.NativeWebRequest; + +@ExtendWith(MockitoExtension.class) +class ServicesApiDelegateImplTest { + + @Mock + NativeWebRequest webRequestMock; + + private static final String INVALID_SERVICE_MESSAGE = "Service is missing required property: version"; + private static final String SERVICE_NAME = "Service Name"; + private static final String SERVICE_DESCRIPTION = "description"; + private static final String SERVICE_VERSION = "1.0"; + private static final String SERVICE_DISPLAY_NAME = "Display Name"; + + @Test + void getAddedService_shouldReturnService() throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + InputService service = new InputService(); + service.setDescription(SERVICE_DESCRIPTION); + service.setVersion(SERVICE_VERSION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + whenPrintResponseShouldWork(); + + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + + ResponseEntity response = delegateUnderTest.getIndividualService(SERVICE_NAME); + + assertThat(response.getStatusCode()).isEqualTo(OK); + assertThat(response.getBody().getName()).isEqualTo(SERVICE_NAME); + } + + @Test + void getMissingService_shouldThrowException() { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); + + Exception exception = assertThrows(ServiceNotFoundException.class, () -> { + delegateUnderTest.getIndividualService(SERVICE_NAME); + }); + + String expectedMessage = "Service " + SERVICE_NAME + " not found"; + String actualMessage = exception.getMessage(); + + assertThat(actualMessage).isEqualTo(expectedMessage); + } + + @Test + void putNewValidService_shouldBeCreatedAndRegisteredAndUrlToNewServiceAddedToLocationHeaderInResponse() + throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + InputService service = new InputService(); + service.setDescription(SERVICE_DESCRIPTION); + service.setVersion(SERVICE_VERSION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + String urlToCreatedService = "URL to created Service"; + HttpServletResponse servletResponseMock = whenPrintResponseShouldWork(urlToCreatedService); + + ResponseEntity putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service); + + assertThat(putResponse.getStatusCode()).isEqualTo(CREATED); + verify(servletResponseMock).addHeader("Location", urlToCreatedService); + + ResponseEntity getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME); + + assertThat(getResponse.getStatusCode()).isEqualTo(OK); + Service body = getResponse.getBody(); + assertThat(body.getName()).isEqualTo(SERVICE_NAME); + assertThat(body.getRegistrationDate()).isEqualTo(getTodaysDate()); + } + + @Test + void putModifiedService_shouldBeModified() throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + InputService service = new InputService(); + service.setDescription(SERVICE_DESCRIPTION); + service.setVersion(SERVICE_VERSION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + whenPrintResponseShouldWork(); + + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + + String newDescription = "New description"; + service.setDescription(newDescription); + ResponseEntity putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service); + + assertThat(putResponse.getStatusCode()).isEqualTo(OK); + + ResponseEntity getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME); + + assertThat(getResponse.getStatusCode()).isEqualTo(OK); + assertThat(getResponse.getBody().getDescription()).isEqualTo(newDescription); + } + + @Test + void putServiceWithVersionNull_shouldThrowException() { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); + + InputService service = new InputService(); + service.setDescription(SERVICE_DESCRIPTION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + Exception exception = assertThrows(InvalidServiceException.class, () -> { + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + }); + + assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE); + } + + @Test + void putServiceWithBlankVersion_shouldThrowException() { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null); + + InputService service = new InputService(); + service.setVersion(""); + service.setDescription(SERVICE_DESCRIPTION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + Exception exception = assertThrows(InvalidServiceException.class, () -> { + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + }); + + assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE); + } + + @Test + void putServiceWhenIoExceptionAddingHeader_shouldThrowExceptionAndNoServiceCreated() throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + whenGetRequestUrlThenReturnUrl(); + HttpServletResponse servletResponseMock = mock(HttpServletResponse.class); + when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock); + when(servletResponseMock.getWriter()).thenThrow(new IOException("Error")); + + InputService service = new InputService(); + service.setVersion("1.0"); + service.setDescription(SERVICE_DESCRIPTION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + Exception exception = assertThrows(HeaderException.class, () -> { + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + }); + + assertThat(exception.getMessage()) + .isEqualTo("Unable to set header Location in put response for service " + SERVICE_NAME + ". Cause: Error"); + + ResponseEntity> response = delegateUnderTest.getServices(); + assertThat(response.getBody()).isEmpty(); + } + + @Test + void getServices_shouldProvideArrayOfAddedServiceNames() throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + InputService service1 = new InputService(); + service1.setDescription("description 1"); + service1.setVersion(SERVICE_VERSION); + service1.setDisplayName("Display Name 1"); + + InputService service2 = new InputService(); + service2.setDescription("description 2"); + service2.setVersion(SERVICE_VERSION); + service2.setDisplayName("Display Name 2"); + + whenPrintResponseShouldWork(); + + String serviceName1 = "Service Name 1"; + delegateUnderTest.putIndividualService(serviceName1, service1); + String serviceName2 = "Service Name 2"; + delegateUnderTest.putIndividualService(serviceName2, service2); + + ResponseEntity> response = delegateUnderTest.getServices(); + + assertThat(response.getStatusCode()).isEqualTo(OK); + List services = response.getBody(); + assertThat(services).hasSize(2); + List expectedServiceNames = Arrays.asList(serviceName1, serviceName2); + assertThat(expectedServiceNames).contains(services.get(0).getName()) // + .contains(services.get(1).getName()); + } + + @Test + void deleteService_shouldBeOk() throws Exception { + ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock); + + InputService service = new InputService(); + service.setDescription(SERVICE_DESCRIPTION); + service.setVersion(SERVICE_VERSION); + service.setDisplayName(SERVICE_DISPLAY_NAME); + + whenPrintResponseShouldWork(); + + delegateUnderTest.putIndividualService(SERVICE_NAME, service); + + ResponseEntity> servicesResponse = delegateUnderTest.getServices(); + + assertThat(servicesResponse.getBody()).hasSize(1); + + ResponseEntity deleteResponse = delegateUnderTest.deleteIndividualService(SERVICE_NAME); + + assertThat(deleteResponse.getStatusCode()).isEqualTo(NO_CONTENT); + + servicesResponse = delegateUnderTest.getServices(); + + assertThat(servicesResponse.getBody()).isEmpty(); + } + + private void whenGetRequestUrlThenReturnUrl() { + whenGetRequestUrlThenReturnUrl("URL"); + } + + private void whenGetRequestUrlThenReturnUrl(String url) { + HttpServletRequest servletRequestMock = mock(HttpServletRequest.class); + when(webRequestMock.getNativeRequest(HttpServletRequest.class)).thenReturn(servletRequestMock); + when(servletRequestMock.getRequestURL()).thenReturn(new StringBuffer(url)); + } + + private HttpServletResponse whenPrintResponseShouldWork() { + return whenPrintResponseShouldWork("URL"); + } + + private HttpServletResponse whenPrintResponseShouldWork(String url) { + whenGetRequestUrlThenReturnUrl(url); + HttpServletResponse servletResponseMock = mock(HttpServletResponse.class); + when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock); + PrintWriter printWriterMock = mock(PrintWriter.class); + try { + when(servletResponseMock.getWriter()).thenReturn(printWriterMock); + } catch (IOException e) { + // Nothing + } + return servletResponseMock; + } + + private String getTodaysDate() { + long millis = System.currentTimeMillis(); + Date date = new Date(millis); + return date.toString(); + } +} -- 2.16.6