From e7aaae39c99fff1561638e486c5d3368eba1a2ca Mon Sep 17 00:00:00 2001 From: rameshiyer27 Date: Fri, 19 Aug 2022 10:08:16 +0100 Subject: Add REST Endpoints for ACM test microservice REST APIs for activating, deactivating and fetching the element config. Issue-ID: POLICY-4305 Signed-off-by: zrrmmua Change-Id: Ib3cf41fe5419c9fd05743bb3c66b19e95a797b98 --- .../clamp/acm/element/config/FilterConfig.java | 44 +++++ .../clamp/acm/element/handler/MessageHandler.java | 10 +- .../acm/element/handler/MessagePublisher.java | 4 +- .../element/main/rest/AbstractRestController.java | 96 +++++++++++ .../acm/element/main/rest/AcElementController.java | 177 ++++++++++++++++++++- .../rest/GlobalControllerExceptionHandler.java | 6 +- .../clamp/acm/element/service/ConfigService.java | 6 +- .../acm/element/rest/AcElementControllerTest.java | 169 ++++++++++++++++++++ .../src/test/resources/config.json | 14 ++ 9 files changed, 510 insertions(+), 16 deletions(-) create mode 100644 participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/config/FilterConfig.java create mode 100644 participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AbstractRestController.java create mode 100644 participant/participant-impl/participant-impl-acelement/src/test/java/org/onap/policy/clamp/acm/element/rest/AcElementControllerTest.java create mode 100644 participant/participant-impl/participant-impl-acelement/src/test/resources/config.json (limited to 'participant') diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/config/FilterConfig.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/config/FilterConfig.java new file mode 100644 index 000000000..1b447a0d5 --- /dev/null +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/config/FilterConfig.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.element.config; + +import org.onap.policy.clamp.common.acm.rest.RequestResponseLoggingFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FilterConfig { + + /** + * Logging Filter configuration. + * + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean loggingFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + + registrationBean.setFilter(new RequestResponseLoggingFilter()); + registrationBean.addUrlPatterns("/onap/policy/clamp/acelement/v2/*"); + return registrationBean; + } +} diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessageHandler.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessageHandler.java index 540c133f0..63b0ebcfd 100644 --- a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessageHandler.java +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessageHandler.java @@ -29,10 +29,10 @@ import lombok.Getter; import lombok.NonNull; import org.onap.policy.clamp.acm.element.main.parameters.AcElement; import org.onap.policy.clamp.acm.element.service.ElementService; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException; import org.onap.policy.clamp.models.acm.messages.dmaap.element.ElementMessage; import org.onap.policy.clamp.models.acm.messages.rest.element.ElementConfig; import org.onap.policy.clamp.models.acm.messages.rest.element.ElementType; -import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.springframework.stereotype.Component; @@ -75,10 +75,10 @@ public class MessageHandler { */ public void update(@NonNull ElementConfig elementConfig) { if (elementType == null) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, "ElementType not defined!"); + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "ElementType not defined!"); } if (!elementType.equals(elementConfig.getElementType())) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, "wrong ElementType!"); + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "wrong ElementType!"); } getActiveService().update(elementConfig); } @@ -90,11 +90,11 @@ public class MessageHandler { */ public ElementService getActiveService() { if (elementType == null) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, "ElementType not defined!"); + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "ElementType not defined!"); } var service = map.get(elementType); if (service == null) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, "ElementService not found!"); + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "ElementService not found!"); } return service; } diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessagePublisher.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessagePublisher.java index ef0a72f1f..928a4fe04 100644 --- a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessagePublisher.java +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/handler/MessagePublisher.java @@ -22,10 +22,10 @@ package org.onap.policy.clamp.acm.element.handler; import java.util.List; import javax.ws.rs.core.Response; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException; import org.onap.policy.clamp.models.acm.messages.dmaap.element.ElementMessage; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient; -import org.onap.policy.models.base.PfModelRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -58,7 +58,7 @@ public class MessagePublisher { */ public void publishMsg(final ElementMessage msg) { if (!active) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, NOT_ACTIVE_TEXT); + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, NOT_ACTIVE_TEXT); } topicSinkClient.send(msg); diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AbstractRestController.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AbstractRestController.java new file mode 100644 index 000000000..408458f99 --- /dev/null +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AbstractRestController.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.element.main.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.BasicAuthDefinition; +import io.swagger.annotations.Info; +import io.swagger.annotations.SecurityDefinition; +import io.swagger.annotations.SwaggerDefinition; +import io.swagger.annotations.Tag; +import java.net.HttpURLConnection; +import javax.ws.rs.core.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Common superclass to provide REST endpoints for the AC element. + */ +// @formatter:off +@RequestMapping( + value = "/v2", + produces = { + MediaType.APPLICATION_JSON, + AbstractRestController.APPLICATION_YAML + } +) +@Api(value = "AC Element API") +@SwaggerDefinition( + info = @Info( + description = "AC Element", + version = "v1.0", + title = "AC Element" + ), + consumes = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML}, + produces = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML}, + schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, + tags = { + @Tag(name = "acelement", description = "Ac element implementation") + }, + securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")}) +) +// @formatter:on +public abstract class AbstractRestController { + public static final String APPLICATION_YAML = "application/yaml"; + + public static final String EXTENSION_NAME = "interface info"; + + public static final String API_VERSION_NAME = "api-version"; + public static final String API_VERSION = "1.0.0"; + + public static final String LAST_MOD_NAME = "last-mod-release"; + public static final String LAST_MOD_RELEASE = "Dublin"; + + public static final String VERSION_MINOR_NAME = "X-MinorVersion"; + public static final String VERSION_MINOR_DESCRIPTION = + "Used to request or communicate a MINOR version back from the client" + + " to the server, and from the server back to the client"; + + public static final String VERSION_PATCH_NAME = "X-PatchVersion"; + public static final String VERSION_PATCH_DESCRIPTION = "Used only to communicate a PATCH version in a response for" + + " troubleshooting purposes only, and will not be provided by" + " the client on request"; + + public static final String VERSION_LATEST_NAME = "X-LatestVersion"; + public static final String VERSION_LATEST_DESCRIPTION = "Used only to communicate an API's latest version"; + + public static final String REQUEST_ID_NAME = "X-ONAP-RequestID"; + public static final String REQUEST_ID_HDR_DESCRIPTION = "Used to track REST transactions for logging purpose"; + + public static final String AUTHORIZATION_TYPE = "basicAuth"; + + public static final int AUTHENTICATION_ERROR_CODE = HttpURLConnection.HTTP_UNAUTHORIZED; + public static final int AUTHORIZATION_ERROR_CODE = HttpURLConnection.HTTP_FORBIDDEN; + public static final int SERVER_ERROR_CODE = HttpURLConnection.HTTP_INTERNAL_ERROR; + + public static final String AUTHENTICATION_ERROR_MESSAGE = "Authentication Error"; + public static final String AUTHORIZATION_ERROR_MESSAGE = "Authorization Error"; + public static final String SERVER_ERROR_MESSAGE = "Internal Server Error"; + +} \ No newline at end of file diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AcElementController.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AcElementController.java index 833819a13..7a8662c34 100644 --- a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AcElementController.java +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/AcElementController.java @@ -20,10 +20,181 @@ package org.onap.policy.clamp.acm.element.main.rest; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; +import io.swagger.annotations.ResponseHeader; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.onap.policy.clamp.acm.element.service.ConfigService; +import org.onap.policy.clamp.models.acm.messages.rest.element.ElementConfig; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController -public class AcElementController { +@RequiredArgsConstructor +public class AcElementController extends AbstractRestController { - //TODO : Implement REST methods for configuring Dmaap topic -} + private final ConfigService configService; + + + /** + * REST endpoint to get the existing element config. + * + * @return the element config params + */ + // @formatter:off + @GetMapping(path = "/config", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation( + value = "Return the element config", + response = ElementConfig.class, + tags = { + "Clamp Automation Composition AC Element Impl API" + }, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + }) + @ApiResponses( + value = { + @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE) + } + ) + // @formatter:on + public ResponseEntity getElementConfig() { + return new ResponseEntity<>(configService.getElementConfig(), HttpStatus.OK); + } + + /** + * REST endpoint to activate the element. + * + * @param params element parameters for this ac element + */ + // @formatter:off + @PostMapping(path = "/activate", consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation( + value = "Activates the element config", + response = ElementConfig.class, + tags = { + "Clamp Automation Composition AC Element Impl API" + }, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class) + }, + extensions = { + @Extension ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } + ) + @ApiResponses( + value = { + @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE) + } + ) + // formatter:on + public ResponseEntity activateElement(@RequestBody ElementConfig params) { + configService.activateElement(params); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + /** + * REST endpoint to delete the element config. + * + * @return Status of operation + */ + // @formatter:off + @DeleteMapping(path = "/deactivate") + @ApiOperation( + value = "Delete the element config", + response = ElementConfig.class, + tags = { + "Clamp Automation Composition AC Element Impl API" + }, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } + ) + @ApiResponses( + value = { + @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE) + } + ) + // @formatter:on + public ResponseEntity deleteConfig() { + configService.deleteConfig(); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + + } +} \ No newline at end of file diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/GlobalControllerExceptionHandler.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/GlobalControllerExceptionHandler.java index bb56bf993..41dcbef81 100644 --- a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/GlobalControllerExceptionHandler.java +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/main/rest/GlobalControllerExceptionHandler.java @@ -22,7 +22,7 @@ package org.onap.policy.clamp.acm.element.main.rest; -import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException; import org.onap.policy.clamp.models.acm.messages.rest.SimpleResponse; import org.onap.policy.clamp.models.acm.rest.RestUtils; import org.springframework.http.ResponseEntity; @@ -38,8 +38,8 @@ public class GlobalControllerExceptionHandler { * @param ex AutomationCompositionException * @return ResponseEntity */ - @ExceptionHandler(AutomationCompositionException.class) - public ResponseEntity handleBadRequest(AutomationCompositionException ex) { + @ExceptionHandler(AutomationCompositionRuntimeException.class) + public ResponseEntity handleBadRequest(AutomationCompositionRuntimeException ex) { return RestUtils.toSimpleResponse(ex); } } diff --git a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/service/ConfigService.java b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/service/ConfigService.java index f542be201..f8f9024f8 100644 --- a/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/service/ConfigService.java +++ b/participant/participant-impl/participant-impl-acelement/src/main/java/org/onap/policy/clamp/acm/element/service/ConfigService.java @@ -26,11 +26,11 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.onap.policy.clamp.acm.element.handler.MessageActivator; import org.onap.policy.clamp.acm.element.handler.MessageHandler; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException; import org.onap.policy.clamp.models.acm.messages.dmaap.element.ElementMessage; import org.onap.policy.clamp.models.acm.messages.rest.element.ElementConfig; import org.onap.policy.common.endpoints.parameters.TopicParameterGroup; import org.onap.policy.common.endpoints.parameters.TopicParameters; -import org.onap.policy.models.base.PfModelRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -64,12 +64,12 @@ public class ConfigService { parameters.setTopicSources(List.of(topicParameters)); if (!parameters.isValid()) { - throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, + throw new AutomationCompositionRuntimeException(Response.Status.BAD_REQUEST, "Validation failed for topic parameter group. Kafka config not activated"); } if (messageActivator.isAlive()) { - throw new PfModelRuntimeException(Response.Status.CONFLICT, + throw new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "Service Manager already running, cannot add Topic endpoint management"); } diff --git a/participant/participant-impl/participant-impl-acelement/src/test/java/org/onap/policy/clamp/acm/element/rest/AcElementControllerTest.java b/participant/participant-impl/participant-impl-acelement/src/test/java/org/onap/policy/clamp/acm/element/rest/AcElementControllerTest.java new file mode 100644 index 000000000..c40cdeabc --- /dev/null +++ b/participant/participant-impl/participant-impl-acelement/src/test/java/org/onap/policy/clamp/acm/element/rest/AcElementControllerTest.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.element.rest; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import javax.ws.rs.core.Response; +import org.apache.commons.io.FileUtils; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.onap.policy.clamp.acm.element.main.parameters.AcElement; +import org.onap.policy.clamp.acm.element.main.rest.AcElementController; +import org.onap.policy.clamp.acm.element.service.ConfigService; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException; +import org.onap.policy.clamp.models.acm.messages.rest.element.ElementConfig; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + + +@ExtendWith(SpringExtension.class) +@WebMvcTest(value = AcElementController.class) +@EnableConfigurationProperties(value = AcElement.class) +class AcElementControllerTest { + + private static final Coder CODER = new StandardCoder(); + private static final String ELEMENT_CONFIG_YAML = "src/test/resources/config.json"; + private static final String RETRIEVE_CONFIG = "/v2/config"; + private static final String ACTIVATE_CONFIG = "/v2/activate"; + private static final String DEACTIVATE_CONFIG = "/v2/deactivate"; + private static ElementConfig config; + + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ConfigService configService; + + @Autowired + private WebApplicationContext context; + + /** + * Read input element config json. + * @throws CoderException in case of error. + */ + @BeforeAll + static void setupParams() throws CoderException { + config = CODER.decode(new File(ELEMENT_CONFIG_YAML), ElementConfig.class); + } + + /** + * Mock service layer in Controller. + */ + @BeforeEach + void mockServiceClass() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + when(configService.getElementConfig()).thenReturn(config); + } + + /** + * Test endpoint for retrieving element config. + * @throws Exception in case of error. + */ + @Test + void retrieveElementConfig() throws Exception { + var requestBuilder = MockMvcRequestBuilders.get(RETRIEVE_CONFIG) + .accept(MediaType.APPLICATION_JSON_VALUE); + + mockMvc.perform(requestBuilder).andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.elementType", is("STARTER"))); + } + + /** + * Test endpoint for activating element config. + * @throws Exception in case of error. + */ + @Test + void activateConfig() throws Exception { + //Mocking successful activation of element config + doNothing().when(configService).activateElement(config); + + var requestBuilder = MockMvcRequestBuilders.post(ACTIVATE_CONFIG) + .accept(MediaType.APPLICATION_JSON_VALUE) + .content(getElementConfigJson()) + .contentType(MediaType.APPLICATION_JSON_VALUE); + + mockMvc.perform(requestBuilder).andExpect(status().isCreated()); + + doThrow(new AutomationCompositionRuntimeException(Response.Status.CONFLICT, "service manager already running")) + .when(configService).activateElement(any()); + + //Activate Invalid config, expects HTTP status CONFLICT + requestBuilder = MockMvcRequestBuilders.post(ACTIVATE_CONFIG).accept(MediaType.APPLICATION_JSON_VALUE) + .content(getInvalidJson()) + .contentType(MediaType.APPLICATION_JSON_VALUE); + + mockMvc.perform(requestBuilder).andExpect(status().isConflict()) + .andExpect(result -> assertEquals("service manager already running", + result.getResolvedException().getMessage())); + } + + /** + * Test endpoint for deactivating element config. + * @throws Exception in case of error. + */ + @Test + void deActivateConfig() throws Exception { + + //Mocking successful deactivation of element config + doNothing().when(configService).deleteConfig(); + + var requestBuilder = MockMvcRequestBuilders.delete(DEACTIVATE_CONFIG); + + mockMvc.perform(requestBuilder).andExpect(status().isNoContent()); + } + + private String getInvalidJson() { + return new JSONObject().toString(); + } + + private String getElementConfigJson() throws IOException { + return FileUtils.readFileToString(new File(ELEMENT_CONFIG_YAML), StandardCharsets.UTF_8); + } + +} diff --git a/participant/participant-impl/participant-impl-acelement/src/test/resources/config.json b/participant/participant-impl/participant-impl-acelement/src/test/resources/config.json new file mode 100644 index 000000000..bf4518255 --- /dev/null +++ b/participant/participant-impl/participant-impl-acelement/src/test/resources/config.json @@ -0,0 +1,14 @@ +{ + "elementId":{ + "name":"onap.policy.clamp.ac.element2", + "version":"1.0.0" + }, + "timerSec":2000, + "elementType":"STARTER", + "topicParameterGroup":{ + "server":"localhost", + "topic":"POLICY_UPDATE_MSG", + "fetchTimeout":15000, + "topicCommInfrastructure":"dmaap" + } +} \ No newline at end of file -- cgit 1.2.3-korg