From d1e26003105404f974f9fa45d542f658706ad3cb Mon Sep 17 00:00:00 2001 From: Serge Simard Date: Tue, 18 Jun 2019 10:36:57 -0400 Subject: Create REST API layer for resource resolution stored configlet Issue-ID: CCSDK-1407 Signed-off-by: Serge Simard Change-Id: I18db6b654cbf4f416af54596ee71f56eaa860d32 --- .../BlueprintProcessorApplication.java | 5 + .../db/ResourceResolutionResultService.kt | 32 ++- .../modules/inbounds/resource-api/pom.xml | 27 +++ .../api/ResolutionResultsServiceController.kt | 104 ++++++++++ .../ResolutionResultsServiceExceptionHandler.kt | 97 ++++++++++ .../api/ResolutionResultsServiceHandler.kt | 71 +++++++ .../api/ResolutionResultsServiceHandlerTest.kt | 215 +++++++++++++++++++++ .../src/test/resources/application-test.properties | 33 ++++ .../resource-api/src/test/resources/logback.xml | 35 ++++ .../resource-api/src/test/resources/test-cba.zip | Bin 0 -> 9554 bytes 10 files changed, 609 insertions(+), 10 deletions(-) create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceController.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceExceptionHandler.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandler.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandlerTest.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/application-test.properties create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/logback.xml create mode 100644 ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/test-cba.zip (limited to 'ms') diff --git a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.java b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.java index 85268c7fa..2b6f8bcf1 100644 --- a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.java +++ b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.java @@ -34,6 +34,11 @@ import org.springframework.context.annotation.ComponentScan; public class BlueprintProcessorApplication { public static void main(String[] args) { + + // This is required for ResolutionResultsServiceController.getStoredResult to accept a content-type value + // as a request parameter, e.g. &format=application%2Fxml is accepted + System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); + SpringApplication.run(BlueprintProcessorApplication.class, args); } } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionResultService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionResultService.kt index cbc68bbc9..3cb9dec63 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionResultService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionResultService.kt @@ -29,6 +29,21 @@ import java.util.* @Service class ResourceResolutionResultService(private val resourceResolutionRepository: ResourceResolutionRepository) { + suspend fun read(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactPrefix: String, + resolutionKey: String): String = withContext(Dispatchers.IO) { + + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION] + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME] + + resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix).result!! + } + suspend fun write(properties: Map, result: String, bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactPrefix: String) = withContext(Dispatchers.IO) { @@ -50,18 +65,15 @@ class ResourceResolutionResultService(private val resourceResolutionRepository: } } - suspend fun read(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactPrefix: String, - resolutionKey: String): String = withContext(Dispatchers.IO) { + suspend fun readByKey(resolutionResultId: String): String = withContext(Dispatchers.IO) { - val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + resourceResolutionRepository.getOne(resolutionResultId).result!! + } - val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION] - val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME] + suspend fun deleteByKey(resolutionResultId: String): Unit = withContext(Dispatchers.IO) { - resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( - resolutionKey, - blueprintName, - blueprintVersion, - artifactPrefix).result!! + val row = resourceResolutionRepository.getOne(resolutionResultId) + resourceResolutionRepository.delete(row) + resourceResolutionRepository.flush() } } \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/pom.xml b/ms/blueprintsprocessor/modules/inbounds/resource-api/pom.xml index d5acf4f93..5dbbc71de 100644 --- a/ms/blueprintsprocessor/modules/inbounds/resource-api/pom.xml +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/pom.xml @@ -27,4 +27,31 @@ Blueprints Processor Resource API Blueprints Processor Resource API + + + org.springframework.security + spring-security-core + + + org.onap.ccsdk.cds.controllerblueprints + blueprint-core + + + + com.h2database + h2 + test + + diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceController.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceController.kt new file mode 100644 index 000000000..61a9541d3 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceController.kt @@ -0,0 +1,104 @@ +/* + * Copyright © 2018-2019 Bell Canada Intellectual Property. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.resolutionresults.api + +import io.swagger.annotations.ApiOperation +import kotlinx.coroutines.runBlocking +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.* + +/** + * Exposes Resolution Results API to store and retrieve resource resolution results from external processes, + * like python or ansible scripts + * + * @author Serge Simard + * @version 1.0 + */ +@RestController +@RequestMapping("/api/v1/resolution-results") +open class ResolutionResultsServiceController { + + @Autowired + lateinit var resolutionResultsServiceHandler: ResolutionResultsServiceHandler + + @RequestMapping(path = ["/ping"], method = [RequestMethod.GET], produces = [MediaType.APPLICATION_JSON_VALUE]) + @ResponseBody + fun ping(): String = runBlocking { + "Success" + } + + @RequestMapping(path = ["/{resolution_result_id}"], method = [RequestMethod.GET], produces = [MediaType.TEXT_PLAIN_VALUE]) + @ApiOperation(value = "Fetch a stored result by ID", + notes = "Loads a stored result using the resolution_result_id primary key") + @ResponseBody + @PreAuthorize("hasRole('USER')") + fun getStoredResultById(@PathVariable(value = "resolution_result_id") resolutionResultId: String) + : String = runBlocking { + resolutionResultsServiceHandler.loadStoredResultById(resolutionResultId) + } + + @RequestMapping(path = ["/"], method = [RequestMethod.GET], produces = [MediaType.TEXT_PLAIN_VALUE]) + @ApiOperation(value = "Fetch a stored result ", + notes = "Loads a stored result using the blueprint metadata, artifact name and resolution-key") + @ResponseBody + @PreAuthorize("hasRole('USER')") + fun getStoredResult(@RequestParam(value = "bpName") bpName: String, + @RequestParam(value = "bpVersion") bpVersion: String, + @RequestParam(value = "artifactName") artifactName: String, + @RequestParam(value = "resolutionKey") resolutionKey: String, + @RequestParam(value = "format", required = false, defaultValue = "text/plain") format: String) + : ResponseEntity = runBlocking { + + val payload = resolutionResultsServiceHandler.loadStoredResult(bpName, bpVersion, artifactName, resolutionKey) + + var expectedContentType = format + if (expectedContentType.indexOf('/') < 0) { + expectedContentType = "application/$expectedContentType" + } + val expectedMediaType : MediaType = MediaType.valueOf(expectedContentType) + + ResponseEntity.ok().contentType(expectedMediaType).body(payload) + } + + + @PostMapping("/{bpName}/{bpVersion}/{artifactName}/{resolutionKey}", produces = [MediaType.TEXT_PLAIN_VALUE]) + @ApiOperation(value = "Store result ", + notes = "Store result under resolution-key for the specified blueprint/version/artifact.") + @ResponseBody + @PreAuthorize("hasRole('USER')") + fun putStoredResult(@PathVariable(value = "bpName") bpName: String, + @PathVariable(value = "bpVersion") bpVersion: String, + @PathVariable(value = "artifactName") artifactName: String, + @PathVariable(value = "resolutionKey") resolutionKey: String, + @RequestBody result : String): String? = runBlocking { + resolutionResultsServiceHandler.saveNewStoredResult(bpName, bpVersion, artifactName, resolutionKey, result).id + } + + + @DeleteMapping(path = ["/{resolution_result_id}"]) + @ApiOperation(value = "Deletes a stored result by ID", + notes = "Removes a stored result, using the resolution_result_id primary key") + @ResponseBody + @PreAuthorize("hasRole('USER')") + fun deleteStoredResult(@PathVariable(value = "resolution_result_id") resolutionResultId: String) = runBlocking { + resolutionResultsServiceHandler.removeStoredResultById(resolutionResultId) + } + +} diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceExceptionHandler.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceExceptionHandler.kt new file mode 100644 index 000000000..69641c628 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceExceptionHandler.kt @@ -0,0 +1,97 @@ +/* + * Copyright © 2018-2019 Bell Canada Intellectual Property. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.resolutionresults.api + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.annotation.JsonTypeName +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.orm.jpa.JpaObjectRetrievalFailureException +import org.springframework.dao.EmptyResultDataAccessException +import org.springframework.web.server.ServerWebInputException +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice +import java.io.Serializable +import java.util.* + +/** + * Handle exceptions in Resolution Results API and provide relevant HTTP status codes and messages + * + * @author Serge Simard + * @version 1.0 + */ +@RestControllerAdvice("org.onap.ccsdk.cds.blueprintsprocessor.resolutionresults") +open class ResolutionResultsServiceExceptionHandler { + + private val log = LoggerFactory.getLogger(ResolutionResultsServiceExceptionHandler::class.toString()) + + private val debugMsg = "ResolutionResultsService_Error_Message" + + @ExceptionHandler + fun ResolutionResultsServiceExceptionHandler(e: BluePrintProcessorException): ResponseEntity { + log.error(e.message) + val errorCode = ErrorCode.BLUEPRINT_PATH_MISSING + val errorMessage = ErrorMessage(errorCode.message(e.message!!), errorCode.value, debugMsg) + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode.httpCode)) + } + + @ExceptionHandler + fun ResolutionResultsServiceExceptionHandler(e: ServerWebInputException): ResponseEntity { + log.error(e.message) + val errorCode = ErrorCode.INVALID_REQUEST_FORMAT + val errorMessage = ErrorMessage(errorCode.message(e.message!!), errorCode.value, debugMsg) + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode.httpCode)) + } + + @ExceptionHandler + fun ResolutionResultsServiceExceptionHandler(e: EmptyResultDataAccessException): ResponseEntity { + log.error(e.message) + var errorCode = ErrorCode.RESOURCE_NOT_FOUND + val errorMessage = ErrorMessage(errorCode.message(e.message!!), errorCode.value, debugMsg) + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode.httpCode)) + } + + @ExceptionHandler + fun ResolutionResultsServiceExceptionHandler(e: JpaObjectRetrievalFailureException): ResponseEntity { + log.error(e.message) + + var errorCode = ErrorCode.RESOURCE_NOT_FOUND + val errorMessage = ErrorMessage(errorCode.message(e.message!!), errorCode.value, debugMsg) + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode.httpCode)) + } + + @ExceptionHandler + fun ResolutionResultsServiceExceptionHandler(e: Exception): ResponseEntity { + log.error(e.message, e) + var errorCode = ErrorCode.GENERIC_FAILURE + val errorMessage = ErrorMessage(errorCode.message(e.message!!), errorCode.value, debugMsg) + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode.httpCode)) + } +} + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonTypeName("errorMessage") +@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) +class ErrorMessage(var message: String?, var code: Int?, var debugMessage: String?) : Serializable { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + var timestamp = Date() +} \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandler.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandler.kt new file mode 100644 index 000000000..1fb34d789 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandler.kt @@ -0,0 +1,71 @@ +/* + * Copyright © 2018-2019 Bell Canada Intellectual Property. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.resolutionresults.api + +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionResult +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionResultService +import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService +import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils +import org.springframework.stereotype.Service +import java.util.* + +/** + * Process Resolution Results API request to store and retrieve resource resolution results using database acess layer + * ResourceResolutionResultService and corresponding entities + * + * @author Serge Simard + * @version 1.0 + */ +@Service +class ResolutionResultsServiceHandler(private val bluePrintCatalogService: BluePrintCatalogService, + private var resolutionResultService: ResourceResolutionResultService) { + + suspend fun loadStoredResultById(resolutionResultId: String): String { + + return resolutionResultService.readByKey(resolutionResultId) + } + + suspend fun loadStoredResult(blueprintName : String, blueprintVersion : String, artifactTemplate: String, + resolutionKey: String): String { + + val basePath = bluePrintCatalogService.getFromDatabase(blueprintName, blueprintVersion) + val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(UUID.randomUUID().toString(), + basePath.toString()) + + return resolutionResultService.read(blueprintRuntimeService, artifactTemplate, resolutionKey) + } + + suspend fun saveNewStoredResult(blueprintName : String, blueprintVersion : String, artifactTemplate: String, + resolutionKey: String, result: String): ResourceResolutionResult { + + val basePath = bluePrintCatalogService.getFromDatabase(blueprintName, blueprintVersion) + val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(UUID.randomUUID().toString(), + basePath.toString()) + + val properties = mapOf(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY to resolutionKey) + + val resultStored = resolutionResultService.write(properties, result, blueprintRuntimeService, artifactTemplate) + + return resultStored + } + + suspend fun removeStoredResultById(resolutionResultId: String): Unit { + + return resolutionResultService.deleteByKey(resolutionResultId) + } +} \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandlerTest.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandlerTest.kt new file mode 100644 index 000000000..813c900d7 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resolutionresults/api/ResolutionResultsServiceHandlerTest.kt @@ -0,0 +1,215 @@ +/* + * Copyright © 2019 Bell Canada. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.resolutionresults.api + +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration +import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir +import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.security.SecurityProperties +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest +import org.springframework.context.annotation.ComponentScan +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.web.reactive.function.BodyInserters +import java.io.File +import java.nio.file.Paths +import java.util.* +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.assertTrue + +@RunWith(SpringRunner::class) +@WebFluxTest +@ContextConfiguration(classes = [ResolutionResultsServiceHandler::class, BluePrintCoreConfiguration::class, + BluePrintCatalogService::class, SecurityProperties::class]) +@ComponentScan(basePackages = ["org.onap.ccsdk.cds.blueprintsprocessor", "org.onap.ccsdk.cds.controllerblueprints"]) +@TestPropertySource(locations = ["classpath:application-test.properties"]) +class ResolutionResultsServiceHandlerTest { + + private val log = LoggerFactory.getLogger(ResolutionResultsServiceHandlerTest::class.toString()) + + @Autowired + lateinit var blueprintCatalog: BluePrintCatalogService + @Autowired + lateinit var webTestClient: WebTestClient + + var resolutionKey = "7cafa9f3-bbc8-49ec-8f25-fcaa6ac3ff08" + val blueprintName = "baseconfiguration" + val blueprintVersion = "1.0.0" + val templatePrefix = "activate" + val payloadDummyTemplateData = "PAYLOAD DATA" + + @BeforeTest + fun init() { + runBlocking { + deleteDir("target", "blueprints") + blueprintCatalog.saveToDatabase(UUID.randomUUID().toString(), loadTestCbaFile()) + } + } + + @AfterTest + fun cleanDir() { + deleteDir("target", "blueprints") + } + + @Test + fun `ping return Success`() { + runBlocking { + + webTestClient.get().uri("/api/v1/resolution-results/ping") + .exchange() + .expectStatus().isOk + .expectBody().equals("Success") + } + } + + @Test + fun `store-retrieve-delete result by path or UUID`() { + runBlocking { + createRetrieveDelete() + } + } + + @Test + fun `get returns requested JSON content-type`() { + runBlocking { + createRetrieveDelete("json") + } + } + + @Test + fun `get returns requested XML content-type`() { + runBlocking { + createRetrieveDelete("xml") + } + } + + private fun createRetrieveDelete(expectedType : String? = null): WebTestClient.ResponseSpec { + var uuid = "MISSING" + + // Store new result for blueprint/artifact/resolutionkey + webTestClient + .post() + .uri("/api/v1/resolution-results/$blueprintName/$blueprintVersion/$templatePrefix/$resolutionKey/") + .body(BodyInserters.fromObject(payloadDummyTemplateData)) + .exchange() + .expectStatus().is2xxSuccessful + .expectBody() + .consumeWith { + uuid = String(it.responseBody) + log.info("Stored result under UUID $uuid") + } + // Retrieve same payload + var requestArguments = "bpName=$blueprintName&bpVersion=$blueprintVersion" + + "&artifactName=$templatePrefix&resolutionKey=$resolutionKey" + if (expectedType != null) { + requestArguments = "$requestArguments&format=$expectedType" + webTestClient + .get() + .uri("/api/v1/resolution-results/?$requestArguments") + .exchange() + .expectStatus().is2xxSuccessful + .expectHeader().contentType(MediaType.valueOf("application/$expectedType")) + .expectBody().equals(payloadDummyTemplateData) + } else { + webTestClient + .get() + .uri("/api/v1/resolution-results/?$requestArguments") + .exchange() + .expectStatus().is2xxSuccessful + .expectHeader().contentType(MediaType.TEXT_PLAIN) + .expectBody().equals(payloadDummyTemplateData) + } + // And delete by UUID + return webTestClient + .delete() + .uri("/api/v1/resolution-results/$uuid/") + .exchange() + .expectStatus().is2xxSuccessful + } + + /* + * Error cases + */ + @Test + fun `get returns 400 error if missing arg`() { + runBlocking { + val arguments = "bpBADName=$blueprintName" + + "&bpBADVersion=$blueprintVersion" + + "&artifactName=$templatePrefix" + + "&resolutionKey=$resolutionKey" + + webTestClient.get().uri("/api/v1/resolution-results/?$arguments") + .exchange() + .expectStatus().isBadRequest + } + } + + @Test + fun `get returns 503 error if Blueprint not found`() { + runBlocking { + val arguments = "bpName=BAD_BP_NAME" + + "&bpVersion=BAD_BP_VERSION" + + "&artifactName=$templatePrefix" + + "&resolutionKey=$resolutionKey" + + webTestClient.get().uri("/api/v1/resolution-results/?$arguments") + .exchange() + .expectStatus().isEqualTo(HttpStatus.SERVICE_UNAVAILABLE) + } + } + + @Test + fun `get returns 404 if entry not found`() { + runBlocking { + + webTestClient + .get() + .uri("/api/v1/resolution-results/?bpName=$blueprintName&bpVersion=$blueprintVersion" + + "&artifactName=$templatePrefix&resolutionKey=$resolutionKey") + .exchange() + .expectStatus().isNotFound + } + } + + @Test + fun `get returns 404 if UUID not found`() { + runBlocking { + + webTestClient + .get() + .uri("/api/v1/resolution-results/234234234234/") + .exchange() + .expectStatus().isNotFound + } + } + + private fun loadTestCbaFile(): File { + val testCbaFile = Paths.get("./src/test/resources/test-cba.zip").toFile() + assertTrue(testCbaFile.exists(), "couldn't get file ${testCbaFile.absolutePath}") + return testCbaFile + } +} \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/application-test.properties b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/application-test.properties new file mode 100644 index 000000000..ebd5dc859 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/application-test.properties @@ -0,0 +1,33 @@ +# +# Copyright © 2017-2018 AT&T Intellectual Property. +# +# Modifications Copyright © 2019 IBM, Bell Canada. +# +# 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. +# +blueprintsprocessor.db.primary.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +blueprintsprocessor.db.primary.username=sa +blueprintsprocessor.db.primary.password= +blueprintsprocessor.db.primary.driverClassName=org.h2.Driver +blueprintsprocessor.db.primary.hibernateHbm2ddlAuto=create-drop +blueprintsprocessor.db.primary.hibernateDDLAuto=update +blueprintsprocessor.db.primary.hibernateNamingStrategy=org.hibernate.cfg.ImprovedNamingStrategy +blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect +# Controller Blueprints Core Configuration +blueprintsprocessor.blueprintDeployPath=./target/blueprints/deploy +blueprintsprocessor.blueprintWorkingPath=./target/blueprints/work +blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive + +# Python executor +blueprints.processor.functions.python.executor.executionPath=./../../../../components/scripts/python/ccsdk_blueprints +blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_blueprints diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/logback.xml b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/logback.xml new file mode 100644 index 000000000..56b077424 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/logback.xml @@ -0,0 +1,35 @@ + + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n + + + + + + + + + + + + + diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/test-cba.zip b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/test-cba.zip new file mode 100644 index 000000000..785ec6c00 Binary files /dev/null and b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/test-cba.zip differ -- cgit 1.2.3-korg