diff options
author | Serge Simard <serge@agilitae.com> | 2019-06-18 10:36:57 -0400 |
---|---|---|
committer | Serge Simard <serge@agilitae.com> | 2019-06-18 10:36:57 -0400 |
commit | d1e26003105404f974f9fa45d542f658706ad3cb (patch) | |
tree | 154fbabc9232146e518a25dee845ee16ec4f2405 | |
parent | 39167cccae3271603819aa39c6476e434c759533 (diff) |
Create REST API layer for resource resolution stored configlet
Issue-ID: CCSDK-1407
Signed-off-by: Serge Simard <serge@agilitae.com>
Change-Id: I18db6b654cbf4f416af54596ee71f56eaa860d32
10 files changed, 609 insertions, 10 deletions
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<String, Any>, 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 @@ <name>Blueprints Processor Resource API</name> <description>Blueprints Processor Resource API</description> + <dependencies> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> + <artifactId>blueprint-core</artifactId> + </dependency> + <!--dependency> + <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> + <artifactId>db-resources</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> + <artifactId>blueprint-validation</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> + <artifactId>blueprint-scripts</artifactId> + </dependency--> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project> 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<String> = 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<ErrorMessage> { + 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<ErrorMessage> { + 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<ErrorMessage> { + 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<ErrorMessage> { + 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<ErrorMessage> { + 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 @@ +<!--
+ ~ Copyright © 2017-2018 AT&T 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.
+ -->
+
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <!-- encoders are assigned the type
+ ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+
+ <logger name="org.springframework" level="warn"/>
+ <logger name="org.hibernate" level="info"/>
+ <logger name="org.onap.ccsdk.cds.blueprintsprocessor" level="info"/>
+
+ <root level="info">
+ <appender-ref ref="STDOUT"/>
+ </root>
+
+</configuration>
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 Binary files differnew file mode 100644 index 000000000..785ec6c00 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/test/resources/test-cba.zip |