From d57c3727ee2d02e2b2f4c899647d4d9de7e72b43 Mon Sep 17 00:00:00 2001 From: "Singal, Kapil (ks220y)" Date: Fri, 10 Jan 2020 15:16:15 -0500 Subject: Refactoring Pom and Fixing Junits Refactoring DepeendencyManagement section in parent pom and fixed Junit failing over Windows Issue-ID: CCSDK-2023 Signed-off-by: Singal, Kapil (ks220y) Change-Id: I5e09c4c6d6307c1dd93a40ab3601713b956dfc72 --- ms/blueprintsprocessor/application/pom.xml | 5 - .../cds/blueprintsprocessor/uat/JsonNormalizer.kt | 78 ----- .../blueprintsprocessor/uat/PathDeserializer.kt | 52 --- .../uat/RequiredMapEntriesMatcher.kt | 34 -- .../cds/blueprintsprocessor/uat/UatDefinition.kt | 102 ------ .../cds/blueprintsprocessor/uat/UatExecutor.kt | 344 -------------------- .../cds/blueprintsprocessor/uat/UatServices.kt | 123 ------- .../blueprintsprocessor/uat/logging/ColorMarker.kt | 24 -- .../blueprintsprocessor/uat/logging/LogColor.kt | 45 --- .../uat/logging/MockInvocationLogger.kt | 65 ---- .../uat/logging/SmartColorDiscriminator.kt | 41 --- .../cds/blueprintsprocessor/uat/BaseUatTest.kt | 2 + .../uat/BlueprintsAcceptanceTest.kt | 2 + .../uat/ExtendedTemporaryFolder.kt | 60 ---- .../blueprintsprocessor/uat/MarkedSlf4jNotifier.kt | 43 --- .../uat/TestSecuritySettings.kt | 45 --- .../cds/blueprintsprocessor/uat/UatServicesTest.kt | 4 + .../uat/WorkingFoldersInitializer.kt | 52 --- .../blueprintsprocessor/uat/logging/ColorMarker.kt | 24 ++ .../blueprintsprocessor/uat/logging/LogColor.kt | 45 +++ .../uat/logging/MockInvocationLogger.kt | 65 ++++ .../uat/logging/SmartColorDiscriminator.kt | 41 +++ .../uat/utils/ExtendedTemporaryFolder.kt | 60 ++++ .../uat/utils/JsonNormalizer.kt | 84 +++++ .../uat/utils/MarkedSlf4jNotifier.kt | 43 +++ .../uat/utils/PathDeserializer.kt | 52 +++ .../uat/utils/RequiredMapEntriesMatcher.kt | 34 ++ .../uat/utils/TestSecuritySettings.kt | 45 +++ .../blueprintsprocessor/uat/utils/UatDefinition.kt | 102 ++++++ .../blueprintsprocessor/uat/utils/UatExecutor.kt | 359 +++++++++++++++++++++ .../blueprintsprocessor/uat/utils/UatServices.kt | 125 +++++++ .../uat/utils/WorkingFoldersInitializer.kt | 52 +++ ms/blueprintsprocessor/parent/pom.xml | 88 ++--- ms/sdclistener/application/pom.xml | 2 +- pom.xml | 2 +- 35 files changed, 1193 insertions(+), 1151 deletions(-) delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/JsonNormalizer.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/PathDeserializer.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/RequiredMapEntriesMatcher.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatDefinition.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatExecutor.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServices.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt delete mode 100644 ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt delete mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ExtendedTemporaryFolder.kt delete mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/MarkedSlf4jNotifier.kt delete mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/TestSecuritySettings.kt delete mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/WorkingFoldersInitializer.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/ExtendedTemporaryFolder.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/JsonNormalizer.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/MarkedSlf4jNotifier.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/PathDeserializer.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/RequiredMapEntriesMatcher.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/TestSecuritySettings.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatDefinition.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatServices.kt create mode 100644 ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/WorkingFoldersInitializer.kt diff --git a/ms/blueprintsprocessor/application/pom.xml b/ms/blueprintsprocessor/application/pom.xml index a566c8447..a4c8ad05d 100755 --- a/ms/blueprintsprocessor/application/pom.xml +++ b/ms/blueprintsprocessor/application/pom.xml @@ -45,7 +45,6 @@ - org.onap.ccsdk.cds.blueprintsprocessor blueprint-core @@ -87,12 +86,10 @@ org.onap.ccsdk.cds.blueprintsprocessor health-api - 0.7.0-SNAPSHOT org.onap.ccsdk.cds.blueprintsprocessor health-api-common - 0.7.0-SNAPSHOT @@ -162,12 +159,10 @@ com.nhaarman.mockitokotlin2 mockito-kotlin - 2.2.0 com.schibsted.spt.data jslt - 0.1.8 org.apache.httpcomponents diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/JsonNormalizer.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/JsonNormalizer.kt deleted file mode 100644 index c5821bed1..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/JsonNormalizer.kt +++ /dev/null @@ -1,78 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.node.ContainerNode -import com.fasterxml.jackson.databind.node.ObjectNode -import com.schibsted.spt.data.jslt.Parser - -internal class JsonNormalizer { - - companion object { - - fun getNormalizer(mapper: ObjectMapper, jsltSpec: JsonNode?): (String) -> String { - if (jsltSpec == null) { - return { it } - } - return { s: String -> - val input = mapper.readTree(s) - val expandedJstlSpec = expandJstlSpec(jsltSpec) - val jslt = Parser.compileString(expandedJstlSpec) - val output = jslt.apply(input) - output.toString() - } - } - - /** - * Creates an extended JSTL spec by appending the "*: ." wildcard pattern to every inner JSON object, and - * removing the extra quotes added by the standard YAML/JSON converters on fields prefixed by "?". - * - * @param jstlSpec the JSTL spec as a structured JSON object. - * @return the string representation of the extended JSTL spec. - */ - private fun expandJstlSpec(jstlSpec: JsonNode): String { - val extendedJstlSpec = updateObjectNodes(jstlSpec, "*", ".") - return extendedJstlSpec.toString() - // Handle the "?" as a prefix to literal/non-quoted values - .replace("\"\\?([^\"]+)\"".toRegex(), "$1") - // Also, remove the quotes added by Jackson for key and value of the wildcard matcher - .replace("\"([.*])\"".toRegex(), "$1") - } - - /** - * Expands a structured JSON object, by adding the given key and value to every nested ObjectNode. - * - * @param jsonNode the root node. - * @param fieldName the fixed field name. - * @param fieldValue the fixed field value. - */ - private fun updateObjectNodes(jsonNode: JsonNode, fieldName: String, fieldValue: String): JsonNode { - if (jsonNode is ContainerNode<*>) { - (jsonNode as? ObjectNode)?.put(fieldName, fieldValue) - jsonNode.forEach { child -> - updateObjectNodes(child, fieldName, fieldValue) - } - } - return jsonNode - } - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/PathDeserializer.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/PathDeserializer.kt deleted file mode 100644 index 710a65c6f..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/PathDeserializer.kt +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.deser.std.StdDeserializer - -internal class PathDeserializer : StdDeserializer(String::class.java) { - override fun deserialize(jp: JsonParser, ctxt: DeserializationContext?): String { - val path = jp.codec.readValue(jp, Any::class.java) - return flatJoin(path) - } - - /** - * Join a multilevel lists of strings. - * Example: flatJoin(listOf("a", listOf("b", "c"), "d")) will result in "a/b/c/d". - */ - private fun flatJoin(path: Any): String { - fun flatJoinTo(sb: StringBuilder, path: Any): StringBuilder { - when (path) { - is List<*> -> path.filterNotNull().forEach { flatJoinTo(sb, it) } - is String -> { - if (sb.isNotEmpty()) { - sb.append('/') - } - sb.append(path) - } - else -> throw IllegalArgumentException("Unsupported type: ${path.javaClass}") - } - return sb - } - return flatJoinTo(StringBuilder(), path).toString() - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/RequiredMapEntriesMatcher.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/RequiredMapEntriesMatcher.kt deleted file mode 100644 index 163544fc9..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/RequiredMapEntriesMatcher.kt +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.google.common.collect.Maps -import org.mockito.ArgumentMatcher - -class RequiredMapEntriesMatcher(private val requiredEntries: Map) : ArgumentMatcher> { - override fun matches(argument: Map?): Boolean { - val missingEntries = Maps.difference(requiredEntries, argument).entriesOnlyOnLeft() - return missingEntries.isEmpty() - } - - override fun toString(): String { - return requiredEntries.toString() - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatDefinition.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatDefinition.kt deleted file mode 100644 index cc7ac69f0..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatDefinition.kt +++ /dev/null @@ -1,102 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.fasterxml.jackson.annotation.JsonAlias -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.module.kotlin.convertValue -import org.yaml.snakeyaml.DumperOptions -import org.yaml.snakeyaml.Yaml -import org.yaml.snakeyaml.nodes.Tag - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class ProcessDefinition( - val name: String, - val request: JsonNode, - val expectedResponse: JsonNode? = null, - val responseNormalizerSpec: JsonNode? = null -) - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class RequestDefinition( - val method: String, - @JsonDeserialize(using = PathDeserializer::class) - val path: String, - val headers: Map = emptyMap(), - val body: JsonNode? = null -) - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class ResponseDefinition(val status: Int = 200, val body: JsonNode? = null) { - - companion object { - val DEFAULT_RESPONSE = ResponseDefinition() - } -} - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class ExpectationDefinition( - val request: RequestDefinition, - val response: ResponseDefinition = ResponseDefinition.DEFAULT_RESPONSE -) - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class ServiceDefinition(val selector: String, val expectations: List) - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -data class UatDefinition( - val processes: List, - @JsonAlias("external-services") - val externalServices: List = emptyList() -) { - - fun dump(mapper: ObjectMapper, excludedProperties: List = emptyList()): String { - val uatAsMap: Map = mapper.convertValue(this) - if (excludedProperties.isNotEmpty()) { - pruneTree(uatAsMap, excludedProperties) - } - return Yaml().dumpAs(uatAsMap, Tag.MAP, DumperOptions.FlowStyle.BLOCK) - } - - fun toBare(): UatDefinition { - val newProcesses = processes.map { p -> - ProcessDefinition(p.name, p.request, null, p.responseNormalizerSpec) - } - return UatDefinition(newProcesses) - } - - private fun pruneTree(node: Any?, excludedProperties: List) { - when (node) { - is MutableMap<*, *> -> { - excludedProperties.forEach { key -> node.remove(key) } - node.forEach { (_, value) -> pruneTree(value, excludedProperties) } - } - is List<*> -> node.forEach { value -> pruneTree(value, excludedProperties) } - } - } - - companion object { - fun load(mapper: ObjectMapper, spec: String): UatDefinition = - mapper.convertValue(Yaml().load(spec), UatDefinition::class.java) - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatExecutor.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatExecutor.kt deleted file mode 100644 index 89ba1500b..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatExecutor.kt +++ /dev/null @@ -1,344 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.argThat -import com.nhaarman.mockitokotlin2.atLeast -import com.nhaarman.mockitokotlin2.atLeastOnce -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions -import com.nhaarman.mockitokotlin2.whenever -import org.apache.http.HttpHeaders -import org.apache.http.HttpStatus -import org.apache.http.client.HttpClient -import org.apache.http.client.methods.HttpPost -import org.apache.http.entity.ContentType -import org.apache.http.entity.StringEntity -import org.apache.http.entity.mime.HttpMultipartMode -import org.apache.http.entity.mime.MultipartEntityBuilder -import org.apache.http.impl.client.HttpClientBuilder -import org.apache.http.message.BasicHeader -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.MatcherAssert.assertThat -import org.mockito.Answers -import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService -import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService -import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_MOCKITO -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.markerOf -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.MockInvocationLogger -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.core.env.ConfigurableEnvironment -import org.springframework.http.MediaType -import org.springframework.stereotype.Component -import org.springframework.util.Base64Utils -import java.util.concurrent.ConcurrentHashMap - -/** - * Assumptions: - * - * - Application HTTP service is bound to loopback interface; - * - Password is either defined in plain (with "{noop}" prefix), or it's the same of username. - * - * @author Eliezio Oliveira - */ -@Component -class UatExecutor( - private val environment: ConfigurableEnvironment, - private val restClientFactory: BluePrintRestLibPropertyService, - private val mapper: ObjectMapper -) { - - companion object { - private const val NOOP_PASSWORD_PREFIX = "{noop}" - - private val log: Logger = LoggerFactory.getLogger(UatExecutor::class.java) - private val mockLoggingListener = MockInvocationLogger(markerOf(COLOR_MOCKITO)) - } - - // use lazy evaluation to postpone until localServerPort is injected by Spring - private val baseUrl: String by lazy { - "http://127.0.0.1:${localServerPort()}" - } - - @Throws(AssertionError::class) - fun execute(uatSpec: String, cbaBytes: ByteArray) { - val uat = UatDefinition.load(mapper, uatSpec) - execute(uat, cbaBytes) - } - - /** - * - * The UAT can range from minimum to completely defined. - * - * @return an updated UAT with all NB and SB messages. - */ - @Throws(AssertionError::class) - fun execute(uat: UatDefinition, cbaBytes: ByteArray): UatDefinition { - val defaultHeaders = listOf(BasicHeader(HttpHeaders.AUTHORIZATION, clientAuthToken())) - val httpClient = HttpClientBuilder.create() - .setDefaultHeaders(defaultHeaders) - .build() - // Only if externalServices are defined - val mockInterceptor = MockPreInterceptor() - // Always defined and used, whatever the case - val spyInterceptor = SpyPostInterceptor(mapper) - restClientFactory.setInterceptors(mockInterceptor, spyInterceptor) - try { - // Configure mocked external services and save their expected requests for further validation - val requestsPerClient = uat.externalServices.associateBy( - { service -> - createRestClientMock(service.expectations).also { restClient -> - // side-effect: register restClient to override real instance - mockInterceptor.registerMock(service.selector, restClient) - } - }, - { service -> service.expectations.map { it.request } } - ) - - val newProcesses = httpClient.use { client -> - uploadBlueprint(client, cbaBytes) - - // Run processes - uat.processes.map { process -> - log.info("Executing process '${process.name}'") - val responseNormalizer = JsonNormalizer.getNormalizer(mapper, process.responseNormalizerSpec) - val actualResponse = processBlueprint( - client, process.request, - process.expectedResponse, responseNormalizer - ) - ProcessDefinition(process.name, process.request, actualResponse, process.responseNormalizerSpec) - } - } - - // Validate requests to external services - for ((mockClient, requests) in requestsPerClient) { - requests.forEach { request -> - verify(mockClient, atLeastOnce()).exchangeResource( - eq(request.method), - eq(request.path), - argThat { assertJsonEquals(request.body, this) }, - argThat(RequiredMapEntriesMatcher(request.headers)) - ) - } - // Don't mind the invocations to the overloaded exchangeResource(String, String, String) - verify(mockClient, atLeast(0)).exchangeResource(any(), any(), any()) - verifyNoMoreInteractions(mockClient) - } - - val newExternalServices = spyInterceptor.getSpies() - .map(SpyService::asServiceDefinition) - - return UatDefinition(newProcesses, newExternalServices) - } finally { - restClientFactory.clearInterceptors() - } - } - - private fun createRestClientMock(restExpectations: List): - BlueprintWebClientService { - val restClient = mock( - defaultAnswer = Answers.RETURNS_SMART_NULLS, - // our custom verboseLogging handler - invocationListeners = arrayOf(mockLoggingListener) - ) - - // Delegates to overloaded exchangeResource(String, String, String, Map) - whenever(restClient.exchangeResource(any(), any(), any())) - .thenAnswer { invocation -> - val method = invocation.arguments[0] as String - val path = invocation.arguments[1] as String - val request = invocation.arguments[2] as String - restClient.exchangeResource(method, path, request, emptyMap()) - } - for (expectation in restExpectations) { - whenever( - restClient.exchangeResource( - eq(expectation.request.method), - eq(expectation.request.path), - any(), - any() - ) - ) - .thenReturn(WebClientResponse(expectation.response.status, expectation.response.body.toString())) - } - return restClient - } - - @Throws(AssertionError::class) - private fun uploadBlueprint(client: HttpClient, cbaBytes: ByteArray) { - val multipartEntity = MultipartEntityBuilder.create() - .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) - .addBinaryBody("file", cbaBytes, ContentType.DEFAULT_BINARY, "cba.zip") - .build() - val request = HttpPost("$baseUrl/api/v1/blueprint-model/publish").apply { - entity = multipartEntity - } - client.execute(request) { response -> - val statusLine = response.statusLine - assertThat(statusLine.statusCode, equalTo(HttpStatus.SC_OK)) - } - } - - @Throws(AssertionError::class) - private fun processBlueprint( - client: HttpClient, - requestBody: JsonNode, - expectedResponse: JsonNode?, - responseNormalizer: (String) -> String - ): JsonNode { - val stringEntity = StringEntity(mapper.writeValueAsString(requestBody), ContentType.APPLICATION_JSON) - val request = HttpPost("$baseUrl/api/v1/execution-service/process").apply { - entity = stringEntity - } - val response = client.execute(request) { response -> - val statusLine = response.statusLine - assertThat(statusLine.statusCode, equalTo(HttpStatus.SC_OK)) - val entity = response.entity - assertThat("Response contains no content", entity, notNullValue()) - entity.content.bufferedReader().use { it.readText() } - } - val actualResponse = responseNormalizer(response) - if (expectedResponse != null) { - assertJsonEquals(expectedResponse, actualResponse) - } - return mapper.readTree(actualResponse)!! - } - - @Throws(AssertionError::class) - private fun assertJsonEquals(expected: JsonNode?, actual: String): Boolean { - // special case - if ((expected == null) && actual.isBlank()) { - return true - } - // general case - JSONAssert.assertEquals(expected?.toString(), actual, JSONCompareMode.LENIENT) - // assertEquals throws an exception whenever match fails - return true - } - - private fun localServerPort(): Int = - (environment.getProperty("local.server.port") - ?: environment.getRequiredProperty("blueprint.httpPort")).toInt() - - private fun clientAuthToken(): String { - val username = environment.getRequiredProperty("security.user.name") - val password = environment.getRequiredProperty("security.user.password") - val plainPassword = when { - password.startsWith(NOOP_PASSWORD_PREFIX) -> password.substring(NOOP_PASSWORD_PREFIX.length) - else -> username - } - return "Basic " + Base64Utils.encodeToString("$username:$plainPassword".toByteArray()) - } - - private class MockPreInterceptor : BluePrintRestLibPropertyService.PreInterceptor { - private val mocks = ConcurrentHashMap() - - override fun getInstance(jsonNode: JsonNode): BlueprintWebClientService? { - TODO("jsonNode-keyed services not yet supported") - } - - override fun getInstance(selector: String): BlueprintWebClientService? = - mocks[selector] - - fun registerMock(selector: String, client: BlueprintWebClientService) { - mocks[selector] = client - } - } - - private class SpyPostInterceptor(private val mapper: ObjectMapper) : BluePrintRestLibPropertyService.PostInterceptor { - - private val spies = ConcurrentHashMap() - - override fun getInstance(jsonNode: JsonNode, service: BlueprintWebClientService): BlueprintWebClientService { - TODO("jsonNode-keyed services not yet supported") - } - - override fun getInstance(selector: String, service: BlueprintWebClientService): BlueprintWebClientService { - val spiedService = SpyService(mapper, selector, service) - spies[selector] = spiedService - return spiedService - } - - fun getSpies(): List = - spies.values.toList() - } - - private class SpyService( - private val mapper: ObjectMapper, - val selector: String, - private val realService: BlueprintWebClientService - ) : - BlueprintWebClientService by realService { - - private val expectations: MutableList = mutableListOf() - - override fun exchangeResource(methodType: String, path: String, request: String): WebClientResponse = - exchangeResource(methodType, path, request, DEFAULT_HEADERS) - - override fun exchangeResource( - methodType: String, - path: String, - request: String, - headers: Map - ): WebClientResponse { - val requestDefinition = RequestDefinition(methodType, path, headers, toJson(request)) - val realAnswer = realService.exchangeResource(methodType, path, request, headers) - val responseBody = when { - // TODO: confirm if we need to normalize the response here - realAnswer.status == HttpStatus.SC_OK -> toJson(realAnswer.body) - else -> null - } - val responseDefinition = ResponseDefinition(realAnswer.status, responseBody) - expectations.add(ExpectationDefinition(requestDefinition, responseDefinition)) - return realAnswer - } - - override suspend fun retry(times: Int, initialDelay: Long, delay: Long, block: suspend (Int) -> T): T { - return super.retry(times, initialDelay, delay, block) - } - - fun asServiceDefinition() = - ServiceDefinition(selector, expectations) - - private fun toJson(str: String): JsonNode? { - return when { - str.isNotBlank() -> mapper.readTree(str) - else -> null - } - } - - companion object { - private val DEFAULT_HEADERS = mapOf( - HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE - ) - } - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServices.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServices.kt deleted file mode 100644 index 5b62f1296..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServices.kt +++ /dev/null @@ -1,123 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.fasterxml.jackson.databind.ObjectMapper -import kotlinx.coroutines.runBlocking -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_SERVICES -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.resetContextColor -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.setContextColor -import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.UAT_SPECIFICATION_FILE -import org.springframework.context.annotation.Profile -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.codec.multipart.FilePart -import org.springframework.security.access.prepost.PreAuthorize -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestPart -import org.springframework.web.bind.annotation.RestController -import org.springframework.web.server.ResponseStatusException -import java.io.File -import java.util.zip.ZipFile - -/** - * Supporting services to help creating UAT specifications. - * - * @author Eliezio Oliveira - */ -@RestController -@RequestMapping("/api/v1/uat") -@Profile("uat") -open class UatServices(private val uatExecutor: UatExecutor, private val mapper: ObjectMapper) { - - @PostMapping("/verify", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - @PreAuthorize("hasRole('USER')") - @Suppress("BlockingMethodInNonBlockingContext") - open fun verify(@RequestPart("cba") cbaFile: FilePart) = runBlocking { - setContextColor(COLOR_SERVICES) - val tempFile = createTempFile() - try { - cbaFile.transferTo(tempFile) - val uatSpec = readZipEntryAsText(tempFile, UAT_SPECIFICATION_FILE) - val cbaBytes = tempFile.readBytes() - uatExecutor.execute(uatSpec, cbaBytes) - } catch (e: AssertionError) { - throw ResponseStatusException(HttpStatus.BAD_REQUEST, e.message) - } catch (t: Throwable) { - throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, t.message, t) - } finally { - tempFile.delete() - resetContextColor() - } - } - - @PostMapping("/spy", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], produces = ["text/vnd.yaml"]) - @PreAuthorize("hasRole('USER')") - @Suppress("BlockingMethodInNonBlockingContext") - open fun spy( - @RequestPart("cba") cbaFile: FilePart, - @RequestPart("uat", required = false) uatFile: FilePart? - ): String = runBlocking { - val tempFile = createTempFile() - setContextColor(COLOR_SERVICES) - try { - cbaFile.transferTo(tempFile) - val uatSpec = when { - uatFile != null -> uatFile.readText() - else -> readZipEntryAsText(tempFile, UAT_SPECIFICATION_FILE) - } - val uat = UatDefinition.load(mapper, uatSpec) - val cbaBytes = tempFile.readBytes() - val updatedUat = uatExecutor.execute(uat, cbaBytes) - return@runBlocking updatedUat.dump(mapper, FIELDS_TO_EXCLUDE) - } catch (t: Throwable) { - throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, t.message, t) - } finally { - tempFile.delete() - resetContextColor() - } - } - - private fun FilePart.readText(): String { - val tempFile = createTempFile() - try { - transferTo(tempFile).block() - return tempFile.readText() - } finally { - tempFile.delete() - } - } - - @Suppress("SameParameterValue") - private fun readZipEntryAsText(file: File, entryName: String): String { - return ZipFile(file).use { zipFile -> zipFile.readEntryAsText(entryName) } - } - - private fun ZipFile.readEntryAsText(entryName: String): String { - val zipEntry = getEntry(entryName) - return getInputStream(zipEntry).readBytes().toString(Charsets.UTF_8) - } - - companion object { - // Fields that can be safely ignored from BPP response, and can be omitted on the UAT specification. - private val FIELDS_TO_EXCLUDE = listOf("timestamp") - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt deleted file mode 100644 index 9ae3ff805..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt +++ /dev/null @@ -1,24 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging - -import org.slf4j.Marker - -class ColorMarker internal constructor(private val dlg: Marker) : Marker by dlg diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt deleted file mode 100644 index f0cba2670..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging - -import org.slf4j.MDC -import org.slf4j.MarkerFactory - -object LogColor { - - const val COLOR_SERVICES = "green" - const val COLOR_TEST_CLIENT = "yellow" - const val COLOR_MOCKITO = "cyan" - const val COLOR_WIREMOCK = "blue" - - // The Slf4j MDC key that will hold the global color - const val MDC_COLOR_KEY = "color" - - fun setContextColor(color: String) { - MDC.put(MDC_COLOR_KEY, color) - } - - fun resetContextColor() { - MDC.remove(MDC_COLOR_KEY) - } - - fun markerOf(color: String): ColorMarker = - ColorMarker(MarkerFactory.getMarker(color)) -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt deleted file mode 100644 index f8e6bd486..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt +++ /dev/null @@ -1,65 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging - -import org.mockito.listeners.InvocationListener -import org.mockito.listeners.MethodInvocationReport -import org.slf4j.LoggerFactory -import org.slf4j.Marker -import java.util.concurrent.atomic.AtomicInteger - -/** - * Logs all Mockito's mock/spy invocations. - * - * Used for debugging interactions with a mock. - */ -class MockInvocationLogger(private val marker: Marker) : InvocationListener { - - private val mockInvocationsCounter = AtomicInteger() - - override fun reportInvocation(report: MethodInvocationReport) { - val sb = StringBuilder() - sb.appendln("Method invocation #${mockInvocationsCounter.incrementAndGet()} on mock/spy") - report.locationOfStubbing?.let { location -> - sb.append(INDENT).append("stubbed ").appendln(location) - } - sb.appendln(report.invocation) - sb.append(INDENT).append("invoked ").appendln(report.invocation.location) - if (report.threwException()) { - sb.append(INDENT).append("has thrown -> ").append(report.throwable.javaClass.name) - report.throwable.message?.let { message -> - sb.append(" with message ").append(message) - } - sb.appendln() - } else { - sb.append(INDENT).append("has returned -> \"").append(report.returnedValue).append('"') - report.returnedValue?.let { value -> - sb.append(" (").append(value.javaClass.name).append(')') - } - sb.appendln() - } - log.info(marker, sb.toString()) - } - - companion object { - private const val INDENT = " " - private val log = LoggerFactory.getLogger(MockInvocationLogger::class.java) - } -} diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt deleted file mode 100644 index cad235450..000000000 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging - -import ch.qos.logback.classic.spi.ILoggingEvent -import ch.qos.logback.core.sift.AbstractDiscriminator -import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.MDC_COLOR_KEY - -class SmartColorDiscriminator : AbstractDiscriminator() { - var defaultValue: String = "white" - - override fun getKey(): String { - return MDC_COLOR_KEY - } - - fun setKey() { - throw UnsupportedOperationException("Key not settable. Using $MDC_COLOR_KEY") - } - - override fun getDiscriminatingValue(e: ILoggingEvent): String = - (e.marker as? ColorMarker)?.name - ?: e.mdcPropertyMap?.get(MDC_COLOR_KEY) - ?: defaultValue -} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BaseUatTest.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BaseUatTest.kt index 0ff5dc55d..7f38608c9 100644 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BaseUatTest.kt +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BaseUatTest.kt @@ -23,6 +23,8 @@ import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_TEST_CLIENT import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.resetContextColor import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.setContextColor +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.TestSecuritySettings +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.WorkingFoldersInitializer import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BlueprintsAcceptanceTest.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BlueprintsAcceptanceTest.kt index ad97ce82a..ff7cd78c0 100644 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BlueprintsAcceptanceTest.kt +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/BlueprintsAcceptanceTest.kt @@ -24,6 +24,8 @@ import org.junit.ClassRule import org.junit.Rule import org.junit.runner.RunWith import org.junit.runners.Parameterized +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.ExtendedTemporaryFolder +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.UatExecutor import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.UAT_SPECIFICATION_FILE import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils.Companion.compressToBytes import org.springframework.beans.factory.annotation.Autowired diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ExtendedTemporaryFolder.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ExtendedTemporaryFolder.kt deleted file mode 100644 index c483d90b3..000000000 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ExtendedTemporaryFolder.kt +++ /dev/null @@ -1,60 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import java.io.File -import java.io.IOException -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes -import javax.annotation.PreDestroy - -class ExtendedTemporaryFolder { - private val tempFolder = createTempDir("uat") - - @PreDestroy - fun delete() = tempFolder.deleteRecursively() - - /** - * A delegate to org.junit.rules.TemporaryFolder.TemporaryFolder.newFolder(String). - */ - fun newFolder(folderName: String): File { - val dir = File(tempFolder, folderName) - if (!dir.mkdir()) { - throw IOException("Unable to create temporary directory $dir.") - } - return dir - } - - /** - * Delete all files under the root temporary folder recursively. The folders are preserved. - */ - fun deleteAllFiles() { - Files.walkFileTree(tempFolder.toPath(), object : SimpleFileVisitor() { - @Throws(IOException::class) - override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult { - file?.toFile()?.delete() - return FileVisitResult.CONTINUE - } - }) - } -} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/MarkedSlf4jNotifier.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/MarkedSlf4jNotifier.kt deleted file mode 100644 index 13ebd9e4b..000000000 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/MarkedSlf4jNotifier.kt +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import com.github.tomakehurst.wiremock.common.Notifier -import org.slf4j.LoggerFactory -import org.slf4j.Marker - -class MarkedSlf4jNotifier(private val marker: Marker) : Notifier { - - override fun info(message: String) { - log.info(marker, message) - } - - override fun error(message: String) { - log.error(marker, message) - } - - override fun error(message: String, t: Throwable) { - log.error(marker, message, t) - } - - companion object { - private val log = LoggerFactory.getLogger("uat.WireMock") - } -} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/TestSecuritySettings.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/TestSecuritySettings.kt deleted file mode 100644 index b0917cb7d..000000000 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/TestSecuritySettings.kt +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import org.springframework.context.ApplicationContextInitializer -import org.springframework.context.ConfigurableApplicationContext -import org.springframework.test.context.support.TestPropertySourceUtils -import org.springframework.util.Base64Utils - -class TestSecuritySettings { - companion object { - private const val authUsername = "walter.white" - private const val authPassword = "Heisenberg" - - fun clientAuthToken() = - "Basic " + Base64Utils.encodeToString("$authUsername:$authPassword".toByteArray()) - } - - class ServerContextInitializer : ApplicationContextInitializer { - override fun initialize(context: ConfigurableApplicationContext) { - TestPropertySourceUtils.addInlinedPropertiesToEnvironment( - context, - "security.user.name=$authUsername", - "security.user.password={noop}$authPassword" - ) - } - } -} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServicesTest.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServicesTest.kt index 2df5f2940..688ba663c 100644 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServicesTest.kt +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/UatServicesTest.kt @@ -44,6 +44,10 @@ import org.hamcrest.Matchers.equalToIgnoringCase import org.jetbrains.kotlin.konan.util.prefixIfNot import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_WIREMOCK import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.markerOf +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.MarkedSlf4jNotifier +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.ServiceDefinition +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.TestSecuritySettings +import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.UatDefinition import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.UAT_SPECIFICATION_FILE import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils.Companion.compressToBytes import org.skyscreamer.jsonassert.JSONAssert diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/WorkingFoldersInitializer.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/WorkingFoldersInitializer.kt deleted file mode 100644 index 3c1757432..000000000 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/WorkingFoldersInitializer.kt +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat - -import org.springframework.beans.factory.support.BeanDefinitionBuilder -import org.springframework.beans.factory.support.BeanDefinitionRegistry -import org.springframework.context.ApplicationContextInitializer -import org.springframework.context.ConfigurableApplicationContext -import org.springframework.stereotype.Component -import org.springframework.test.context.support.TestPropertySourceUtils - -@Component -class WorkingFoldersInitializer : ApplicationContextInitializer { - - override fun initialize(context: ConfigurableApplicationContext) { - val tempFolder = ExtendedTemporaryFolder() - val properties = listOf("Deploy", "Archive", "Working") - .map { "blueprintsprocessor.blueprint${it}Path=${tempFolder.newFolder(it)}" } - .toTypedArray() - TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, *properties) - // Expose tempFolder as a bean so it can be accessed via DI - registerSingleton(context, "tempFolder", ExtendedTemporaryFolder::class.java, tempFolder) - } - - @Suppress("SameParameterValue") - private fun registerSingleton( - context: ConfigurableApplicationContext, - beanName: String, - beanClass: Class, - instance: T - ) { - val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass) { instance } - (context.beanFactory as BeanDefinitionRegistry).registerBeanDefinition(beanName, builder.beanDefinition) - } -} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt new file mode 100644 index 000000000..9ae3ff805 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/ColorMarker.kt @@ -0,0 +1,24 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging + +import org.slf4j.Marker + +class ColorMarker internal constructor(private val dlg: Marker) : Marker by dlg diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt new file mode 100644 index 000000000..f0cba2670 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/LogColor.kt @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging + +import org.slf4j.MDC +import org.slf4j.MarkerFactory + +object LogColor { + + const val COLOR_SERVICES = "green" + const val COLOR_TEST_CLIENT = "yellow" + const val COLOR_MOCKITO = "cyan" + const val COLOR_WIREMOCK = "blue" + + // The Slf4j MDC key that will hold the global color + const val MDC_COLOR_KEY = "color" + + fun setContextColor(color: String) { + MDC.put(MDC_COLOR_KEY, color) + } + + fun resetContextColor() { + MDC.remove(MDC_COLOR_KEY) + } + + fun markerOf(color: String): ColorMarker = + ColorMarker(MarkerFactory.getMarker(color)) +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt new file mode 100644 index 000000000..f8e6bd486 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/MockInvocationLogger.kt @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging + +import org.mockito.listeners.InvocationListener +import org.mockito.listeners.MethodInvocationReport +import org.slf4j.LoggerFactory +import org.slf4j.Marker +import java.util.concurrent.atomic.AtomicInteger + +/** + * Logs all Mockito's mock/spy invocations. + * + * Used for debugging interactions with a mock. + */ +class MockInvocationLogger(private val marker: Marker) : InvocationListener { + + private val mockInvocationsCounter = AtomicInteger() + + override fun reportInvocation(report: MethodInvocationReport) { + val sb = StringBuilder() + sb.appendln("Method invocation #${mockInvocationsCounter.incrementAndGet()} on mock/spy") + report.locationOfStubbing?.let { location -> + sb.append(INDENT).append("stubbed ").appendln(location) + } + sb.appendln(report.invocation) + sb.append(INDENT).append("invoked ").appendln(report.invocation.location) + if (report.threwException()) { + sb.append(INDENT).append("has thrown -> ").append(report.throwable.javaClass.name) + report.throwable.message?.let { message -> + sb.append(" with message ").append(message) + } + sb.appendln() + } else { + sb.append(INDENT).append("has returned -> \"").append(report.returnedValue).append('"') + report.returnedValue?.let { value -> + sb.append(" (").append(value.javaClass.name).append(')') + } + sb.appendln() + } + log.info(marker, sb.toString()) + } + + companion object { + private const val INDENT = " " + private val log = LoggerFactory.getLogger(MockInvocationLogger::class.java) + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt new file mode 100644 index 000000000..cad235450 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/logging/SmartColorDiscriminator.kt @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.logging + +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.sift.AbstractDiscriminator +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.MDC_COLOR_KEY + +class SmartColorDiscriminator : AbstractDiscriminator() { + var defaultValue: String = "white" + + override fun getKey(): String { + return MDC_COLOR_KEY + } + + fun setKey() { + throw UnsupportedOperationException("Key not settable. Using $MDC_COLOR_KEY") + } + + override fun getDiscriminatingValue(e: ILoggingEvent): String = + (e.marker as? ColorMarker)?.name + ?: e.mdcPropertyMap?.get(MDC_COLOR_KEY) + ?: defaultValue +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/ExtendedTemporaryFolder.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/ExtendedTemporaryFolder.kt new file mode 100644 index 000000000..9090361fb --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/ExtendedTemporaryFolder.kt @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import java.io.File +import java.io.IOException +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes +import javax.annotation.PreDestroy + +class ExtendedTemporaryFolder { + private val tempFolder = createTempDir("uat") + + @PreDestroy + fun delete() = tempFolder.deleteRecursively() + + /** + * A delegate to org.junit.rules.TemporaryFolder.TemporaryFolder.newFolder(String). + */ + fun newFolder(folderName: String): File { + val dir = File(tempFolder, folderName) + if (!dir.mkdir()) { + throw IOException("Unable to create temporary directory $dir.") + } + return dir + } + + /** + * Delete all files under the root temporary folder recursively. The folders are preserved. + */ + fun deleteAllFiles() { + Files.walkFileTree(tempFolder.toPath(), object : SimpleFileVisitor() { + @Throws(IOException::class) + override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult { + file?.toFile()?.delete() + return FileVisitResult.CONTINUE + } + }) + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/JsonNormalizer.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/JsonNormalizer.kt new file mode 100644 index 000000000..39caa0178 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/JsonNormalizer.kt @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.node.ContainerNode +import com.fasterxml.jackson.databind.node.ObjectNode +import com.schibsted.spt.data.jslt.Parser + +internal class JsonNormalizer { + + companion object { + + fun getNormalizer(mapper: ObjectMapper, jsltSpec: JsonNode?): (String) -> String { + if (jsltSpec == null) { + return { it } + } + return { s: String -> + val input = mapper.readTree(s) + val expandedJstlSpec = + expandJstlSpec(jsltSpec) + val jslt = Parser.compileString(expandedJstlSpec) + val output = jslt.apply(input) + output.toString() + } + } + + /** + * Creates an extended JSTL spec by appending the "*: ." wildcard pattern to every inner JSON object, and + * removing the extra quotes added by the standard YAML/JSON converters on fields prefixed by "?". + * + * @param jstlSpec the JSTL spec as a structured JSON object. + * @return the string representation of the extended JSTL spec. + */ + private fun expandJstlSpec(jstlSpec: JsonNode): String { + val extendedJstlSpec = + updateObjectNodes(jstlSpec, "*", ".") + return extendedJstlSpec.toString() + // Handle the "?" as a prefix to literal/non-quoted values + .replace("\"\\?([^\"]+)\"".toRegex(), "$1") + // Also, remove the quotes added by Jackson for key and value of the wildcard matcher + .replace("\"([.*])\"".toRegex(), "$1") + } + + /** + * Expands a structured JSON object, by adding the given key and value to every nested ObjectNode. + * + * @param jsonNode the root node. + * @param fieldName the fixed field name. + * @param fieldValue the fixed field value. + */ + private fun updateObjectNodes(jsonNode: JsonNode, fieldName: String, fieldValue: String): JsonNode { + if (jsonNode is ContainerNode<*>) { + (jsonNode as? ObjectNode)?.put(fieldName, fieldValue) + jsonNode.forEach { child -> + updateObjectNodes( + child, + fieldName, + fieldValue + ) + } + } + return jsonNode + } + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/MarkedSlf4jNotifier.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/MarkedSlf4jNotifier.kt new file mode 100644 index 000000000..e6198b1ba --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/MarkedSlf4jNotifier.kt @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.github.tomakehurst.wiremock.common.Notifier +import org.slf4j.LoggerFactory +import org.slf4j.Marker + +class MarkedSlf4jNotifier(private val marker: Marker) : Notifier { + + override fun info(message: String) { + log.info(marker, message) + } + + override fun error(message: String) { + log.error(marker, message) + } + + override fun error(message: String, t: Throwable) { + log.error(marker, message, t) + } + + companion object { + private val log = LoggerFactory.getLogger("uat.WireMock") + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/PathDeserializer.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/PathDeserializer.kt new file mode 100644 index 000000000..6c5759155 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/PathDeserializer.kt @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.deser.std.StdDeserializer + +internal class PathDeserializer : StdDeserializer(String::class.java) { + override fun deserialize(jp: JsonParser, ctxt: DeserializationContext?): String { + val path = jp.codec.readValue(jp, Any::class.java) + return flatJoin(path) + } + + /** + * Join a multilevel lists of strings. + * Example: flatJoin(listOf("a", listOf("b", "c"), "d")) will result in "a/b/c/d". + */ + private fun flatJoin(path: Any): String { + fun flatJoinTo(sb: StringBuilder, path: Any): StringBuilder { + when (path) { + is List<*> -> path.filterNotNull().forEach { flatJoinTo(sb, it) } + is String -> { + if (sb.isNotEmpty()) { + sb.append('/') + } + sb.append(path) + } + else -> throw IllegalArgumentException("Unsupported type: ${path.javaClass}") + } + return sb + } + return flatJoinTo(StringBuilder(), path).toString() + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/RequiredMapEntriesMatcher.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/RequiredMapEntriesMatcher.kt new file mode 100644 index 000000000..0f98d7213 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/RequiredMapEntriesMatcher.kt @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.google.common.collect.Maps +import org.mockito.ArgumentMatcher + +class RequiredMapEntriesMatcher(private val requiredEntries: Map) : ArgumentMatcher> { + override fun matches(argument: Map?): Boolean { + val missingEntries = Maps.difference(requiredEntries, argument).entriesOnlyOnLeft() + return missingEntries.isEmpty() + } + + override fun toString(): String { + return requiredEntries.toString() + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/TestSecuritySettings.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/TestSecuritySettings.kt new file mode 100644 index 000000000..888ab8dcd --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/TestSecuritySettings.kt @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.test.context.support.TestPropertySourceUtils +import org.springframework.util.Base64Utils + +class TestSecuritySettings { + companion object { + private const val authUsername = "walter.white" + private const val authPassword = "Heisenberg" + + fun clientAuthToken() = + "Basic " + Base64Utils.encodeToString("$authUsername:$authPassword".toByteArray()) + } + + class ServerContextInitializer : ApplicationContextInitializer { + override fun initialize(context: ConfigurableApplicationContext) { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment( + context, + "security.user.name=$authUsername", + "security.user.password={noop}$authPassword" + ) + } + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatDefinition.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatDefinition.kt new file mode 100644 index 000000000..c45ac45c6 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatDefinition.kt @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.fasterxml.jackson.annotation.JsonAlias +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.module.kotlin.convertValue +import org.yaml.snakeyaml.DumperOptions +import org.yaml.snakeyaml.Yaml +import org.yaml.snakeyaml.nodes.Tag + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class ProcessDefinition( + val name: String, + val request: JsonNode, + val expectedResponse: JsonNode? = null, + val responseNormalizerSpec: JsonNode? = null +) + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class RequestDefinition( + val method: String, + @JsonDeserialize(using = PathDeserializer::class) + val path: String, + val headers: Map = emptyMap(), + val body: JsonNode? = null +) + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class ResponseDefinition(val status: Int = 200, val body: JsonNode? = null) { + + companion object { + val DEFAULT_RESPONSE = ResponseDefinition() + } +} + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class ExpectationDefinition( + val request: RequestDefinition, + val response: ResponseDefinition = ResponseDefinition.DEFAULT_RESPONSE +) + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class ServiceDefinition(val selector: String, val expectations: List) + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class UatDefinition( + val processes: List, + @JsonAlias("external-services") + val externalServices: List = emptyList() +) { + + fun dump(mapper: ObjectMapper, excludedProperties: List = emptyList()): String { + val uatAsMap: Map = mapper.convertValue(this) + if (excludedProperties.isNotEmpty()) { + pruneTree(uatAsMap, excludedProperties) + } + return Yaml().dumpAs(uatAsMap, Tag.MAP, DumperOptions.FlowStyle.BLOCK) + } + + fun toBare(): UatDefinition { + val newProcesses = processes.map { p -> + ProcessDefinition(p.name, p.request, null, p.responseNormalizerSpec) + } + return UatDefinition(newProcesses) + } + + private fun pruneTree(node: Any?, excludedProperties: List) { + when (node) { + is MutableMap<*, *> -> { + excludedProperties.forEach { key -> node.remove(key) } + node.forEach { (_, value) -> pruneTree(value, excludedProperties) } + } + is List<*> -> node.forEach { value -> pruneTree(value, excludedProperties) } + } + } + + companion object { + fun load(mapper: ObjectMapper, spec: String): UatDefinition = + mapper.convertValue(Yaml().load(spec), UatDefinition::class.java) + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt new file mode 100644 index 000000000..a904fa9b6 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt @@ -0,0 +1,359 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argThat +import com.nhaarman.mockitokotlin2.atLeast +import com.nhaarman.mockitokotlin2.atLeastOnce +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions +import com.nhaarman.mockitokotlin2.whenever +import org.apache.http.HttpHeaders +import org.apache.http.HttpStatus +import org.apache.http.client.HttpClient +import org.apache.http.client.methods.HttpPost +import org.apache.http.entity.ContentType +import org.apache.http.entity.StringEntity +import org.apache.http.entity.mime.HttpMultipartMode +import org.apache.http.entity.mime.MultipartEntityBuilder +import org.apache.http.impl.client.HttpClientBuilder +import org.apache.http.message.BasicHeader +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.CoreMatchers.notNullValue +import org.hamcrest.MatcherAssert.assertThat +import org.mockito.Answers +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_MOCKITO +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.markerOf +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.MockInvocationLogger +import org.skyscreamer.jsonassert.JSONAssert +import org.skyscreamer.jsonassert.JSONCompareMode +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.core.env.ConfigurableEnvironment +import org.springframework.http.MediaType +import org.springframework.stereotype.Component +import org.springframework.util.Base64Utils +import java.util.concurrent.ConcurrentHashMap + +/** + * Assumptions: + * + * - Application HTTP service is bound to loopback interface; + * - Password is either defined in plain (with "{noop}" prefix), or it's the same of username. + * + * @author Eliezio Oliveira + */ +@Component +class UatExecutor( + private val environment: ConfigurableEnvironment, + private val restClientFactory: BluePrintRestLibPropertyService, + private val mapper: ObjectMapper +) { + + companion object { + private const val NOOP_PASSWORD_PREFIX = "{noop}" + + private val log: Logger = LoggerFactory.getLogger(UatExecutor::class.java) + private val mockLoggingListener = MockInvocationLogger(markerOf(COLOR_MOCKITO)) + } + + // use lazy evaluation to postpone until localServerPort is injected by Spring + private val baseUrl: String by lazy { + "http://127.0.0.1:${localServerPort()}" + } + + @Throws(AssertionError::class) + fun execute(uatSpec: String, cbaBytes: ByteArray) { + val uat = UatDefinition.load(mapper, uatSpec) + execute(uat, cbaBytes) + } + + /** + * + * The UAT can range from minimum to completely defined. + * + * @return an updated UAT with all NB and SB messages. + */ + @Throws(AssertionError::class) + fun execute(uat: UatDefinition, cbaBytes: ByteArray): UatDefinition { + val defaultHeaders = listOf(BasicHeader(HttpHeaders.AUTHORIZATION, clientAuthToken())) + val httpClient = HttpClientBuilder.create() + .setDefaultHeaders(defaultHeaders) + .build() + // Only if externalServices are defined + val mockInterceptor = MockPreInterceptor() + // Always defined and used, whatever the case + val spyInterceptor = SpyPostInterceptor(mapper) + restClientFactory.setInterceptors(mockInterceptor, spyInterceptor) + try { + // Configure mocked external services and save their expected requests for further validation + val requestsPerClient = uat.externalServices.associateBy( + { service -> + createRestClientMock(service.expectations).also { restClient -> + // side-effect: register restClient to override real instance + mockInterceptor.registerMock(service.selector, restClient) + } + }, + { service -> service.expectations.map { it.request } } + ) + + val newProcesses = httpClient.use { client -> + uploadBlueprint(client, cbaBytes) + + // Run processes + uat.processes.map { process -> + log.info("Executing process '${process.name}'") + val responseNormalizer = JsonNormalizer.getNormalizer(mapper, process.responseNormalizerSpec) + val actualResponse = processBlueprint( + client, process.request, + process.expectedResponse, responseNormalizer + ) + ProcessDefinition( + process.name, + process.request, + actualResponse, + process.responseNormalizerSpec + ) + } + } + + // Validate requests to external services + for ((mockClient, requests) in requestsPerClient) { + requests.forEach { request -> + verify(mockClient, atLeastOnce()).exchangeResource( + eq(request.method), + eq(request.path), + argThat { assertJsonEquals(request.body, this) }, + argThat(RequiredMapEntriesMatcher(request.headers)) + ) + } + // Don't mind the invocations to the overloaded exchangeResource(String, String, String) + verify(mockClient, atLeast(0)).exchangeResource(any(), any(), any()) + verifyNoMoreInteractions(mockClient) + } + + val newExternalServices = spyInterceptor.getSpies() + .map(SpyService::asServiceDefinition) + + return UatDefinition(newProcesses, newExternalServices) + } finally { + restClientFactory.clearInterceptors() + } + } + + private fun createRestClientMock(restExpectations: List): + BlueprintWebClientService { + val restClient = mock( + defaultAnswer = Answers.RETURNS_SMART_NULLS, + // our custom verboseLogging handler + invocationListeners = arrayOf(mockLoggingListener) + ) + + // Delegates to overloaded exchangeResource(String, String, String, Map) + whenever(restClient.exchangeResource(any(), any(), any())) + .thenAnswer { invocation -> + val method = invocation.arguments[0] as String + val path = invocation.arguments[1] as String + val request = invocation.arguments[2] as String + restClient.exchangeResource(method, path, request, emptyMap()) + } + for (expectation in restExpectations) { + whenever( + restClient.exchangeResource( + eq(expectation.request.method), + eq(expectation.request.path), + any(), + any() + ) + ) + .thenReturn(WebClientResponse(expectation.response.status, expectation.response.body.toString())) + } + return restClient + } + + @Throws(AssertionError::class) + private fun uploadBlueprint(client: HttpClient, cbaBytes: ByteArray) { + val multipartEntity = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .addBinaryBody("file", cbaBytes, ContentType.DEFAULT_BINARY, "cba.zip") + .build() + val request = HttpPost("$baseUrl/api/v1/blueprint-model/publish").apply { + entity = multipartEntity + } + client.execute(request) { response -> + val statusLine = response.statusLine + assertThat(statusLine.statusCode, equalTo(HttpStatus.SC_OK)) + } + } + + @Throws(AssertionError::class) + private fun processBlueprint( + client: HttpClient, + requestBody: JsonNode, + expectedResponse: JsonNode?, + responseNormalizer: (String) -> String + ): JsonNode { + val stringEntity = StringEntity(mapper.writeValueAsString(requestBody), ContentType.APPLICATION_JSON) + val request = HttpPost("$baseUrl/api/v1/execution-service/process").apply { + entity = stringEntity + } + val response = client.execute(request) { response -> + val statusLine = response.statusLine + assertThat(statusLine.statusCode, equalTo(HttpStatus.SC_OK)) + val entity = response.entity + assertThat("Response contains no content", entity, notNullValue()) + entity.content.bufferedReader().use { it.readText() } + } + val actualResponse = responseNormalizer(response) + if (expectedResponse != null) { + assertJsonEquals(expectedResponse, actualResponse) + } + return mapper.readTree(actualResponse)!! + } + + @Throws(AssertionError::class) + private fun assertJsonEquals(expected: JsonNode?, actual: String): Boolean { + // special case + if ((expected == null) && actual.isBlank()) { + return true + } + // general case + JSONAssert.assertEquals(expected?.toString(), actual, JSONCompareMode.LENIENT) + // assertEquals throws an exception whenever match fails + return true + } + + private fun localServerPort(): Int = + (environment.getProperty("local.server.port") + ?: environment.getRequiredProperty("blueprint.httpPort")).toInt() + + private fun clientAuthToken(): String { + val username = environment.getRequiredProperty("security.user.name") + val password = environment.getRequiredProperty("security.user.password") + val plainPassword = when { + password.startsWith(NOOP_PASSWORD_PREFIX) -> password.substring( + NOOP_PASSWORD_PREFIX.length) + else -> username + } + return "Basic " + Base64Utils.encodeToString("$username:$plainPassword".toByteArray()) + } + + private class MockPreInterceptor : BluePrintRestLibPropertyService.PreInterceptor { + private val mocks = ConcurrentHashMap() + + override fun getInstance(jsonNode: JsonNode): BlueprintWebClientService? { + TODO("jsonNode-keyed services not yet supported") + } + + override fun getInstance(selector: String): BlueprintWebClientService? = + mocks[selector] + + fun registerMock(selector: String, client: BlueprintWebClientService) { + mocks[selector] = client + } + } + + private class SpyPostInterceptor(private val mapper: ObjectMapper) : BluePrintRestLibPropertyService.PostInterceptor { + + private val spies = ConcurrentHashMap() + + override fun getInstance(jsonNode: JsonNode, service: BlueprintWebClientService): BlueprintWebClientService { + TODO("jsonNode-keyed services not yet supported") + } + + override fun getInstance(selector: String, service: BlueprintWebClientService): BlueprintWebClientService { + val spiedService = SpyService(mapper, selector, service) + spies[selector] = spiedService + return spiedService + } + + fun getSpies(): List = + spies.values.toList() + } + + private class SpyService( + private val mapper: ObjectMapper, + val selector: String, + private val realService: BlueprintWebClientService + ) : + BlueprintWebClientService by realService { + + private val expectations: MutableList = mutableListOf() + + override fun exchangeResource(methodType: String, path: String, request: String): WebClientResponse = + exchangeResource(methodType, path, request, + DEFAULT_HEADERS + ) + + override fun exchangeResource( + methodType: String, + path: String, + request: String, + headers: Map + ): WebClientResponse { + val requestDefinition = + RequestDefinition(methodType, path, headers, toJson(request)) + val realAnswer = realService.exchangeResource(methodType, path, request, headers) + val responseBody = when { + // TODO: confirm if we need to normalize the response here + realAnswer.status == HttpStatus.SC_OK -> toJson(realAnswer.body) + else -> null + } + val responseDefinition = + ResponseDefinition(realAnswer.status, responseBody) + expectations.add( + ExpectationDefinition( + requestDefinition, + responseDefinition + ) + ) + return realAnswer + } + + override suspend fun retry(times: Int, initialDelay: Long, delay: Long, block: suspend (Int) -> T): T { + return super.retry(times, initialDelay, delay, block) + } + + fun asServiceDefinition() = + ServiceDefinition(selector, expectations) + + private fun toJson(str: String): JsonNode? { + return when { + str.isNotBlank() -> mapper.readTree(str) + else -> null + } + } + + companion object { + private val DEFAULT_HEADERS = mapOf( + HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE + ) + } + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatServices.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatServices.kt new file mode 100644 index 000000000..f40b903de --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatServices.kt @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import com.fasterxml.jackson.databind.ObjectMapper +import kotlinx.coroutines.runBlocking +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.COLOR_SERVICES +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.resetContextColor +import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor.setContextColor +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.UAT_SPECIFICATION_FILE +import org.springframework.context.annotation.Profile +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.codec.multipart.FilePart +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.server.ResponseStatusException +import java.io.File +import java.util.zip.ZipFile + +/** + * Supporting services to help creating UAT specifications. + * + * @author Eliezio Oliveira + */ +@RestController +@RequestMapping("/api/v1/uat") +@Profile("uat") +open class UatServices(private val uatExecutor: UatExecutor, private val mapper: ObjectMapper) { + + @PostMapping("/verify", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) + @PreAuthorize("hasRole('USER')") + @Suppress("BlockingMethodInNonBlockingContext") + open fun verify(@RequestPart("cba") cbaFile: FilePart) = runBlocking { + setContextColor(COLOR_SERVICES) + val tempFile = createTempFile() + try { + cbaFile.transferTo(tempFile) + val uatSpec = readZipEntryAsText(tempFile, UAT_SPECIFICATION_FILE) + val cbaBytes = tempFile.readBytes() + uatExecutor.execute(uatSpec, cbaBytes) + } catch (e: AssertionError) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, e.message) + } catch (t: Throwable) { + throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, t.message, t) + } finally { + tempFile.delete() + resetContextColor() + } + } + + @PostMapping("/spy", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], produces = ["text/vnd.yaml"]) + @PreAuthorize("hasRole('USER')") + @Suppress("BlockingMethodInNonBlockingContext") + open fun spy( + @RequestPart("cba") cbaFile: FilePart, + @RequestPart("uat", required = false) uatFile: FilePart? + ): String = runBlocking { + val tempFile = createTempFile() + setContextColor(COLOR_SERVICES) + try { + cbaFile.transferTo(tempFile) + val uatSpec = when { + uatFile != null -> uatFile.readText() + else -> readZipEntryAsText(tempFile, UAT_SPECIFICATION_FILE) + } + val uat = UatDefinition.load(mapper, uatSpec) + val cbaBytes = tempFile.readBytes() + val updatedUat = uatExecutor.execute(uat, cbaBytes) + return@runBlocking updatedUat.dump(mapper, + FIELDS_TO_EXCLUDE + ) + } catch (t: Throwable) { + throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, t.message, t) + } finally { + tempFile.delete() + resetContextColor() + } + } + + private fun FilePart.readText(): String { + val tempFile = createTempFile() + try { + transferTo(tempFile).block() + return tempFile.readText() + } finally { + tempFile.delete() + } + } + + @Suppress("SameParameterValue") + private fun readZipEntryAsText(file: File, entryName: String): String { + return ZipFile(file).use { zipFile -> zipFile.readEntryAsText(entryName) } + } + + private fun ZipFile.readEntryAsText(entryName: String): String { + val zipEntry = getEntry(entryName) + return getInputStream(zipEntry).readBytes().toString(Charsets.UTF_8) + } + + companion object { + // Fields that can be safely ignored from BPP response, and can be omitted on the UAT specification. + private val FIELDS_TO_EXCLUDE = listOf("timestamp") + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/WorkingFoldersInitializer.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/WorkingFoldersInitializer.kt new file mode 100644 index 000000000..001dcbec4 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/WorkingFoldersInitializer.kt @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.ccsdk.cds.blueprintsprocessor.uat.utils + +import org.springframework.beans.factory.support.BeanDefinitionBuilder +import org.springframework.beans.factory.support.BeanDefinitionRegistry +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.stereotype.Component +import org.springframework.test.context.support.TestPropertySourceUtils + +@Component +class WorkingFoldersInitializer : ApplicationContextInitializer { + + override fun initialize(context: ConfigurableApplicationContext) { + val tempFolder = ExtendedTemporaryFolder() + val properties = listOf("Deploy", "Archive", "Working") + .map { "blueprintsprocessor.blueprint${it}Path=${tempFolder.newFolder(it).absolutePath.replace("\\", "/")}" } + .toTypedArray() + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, *properties) + // Expose tempFolder as a bean so it can be accessed via DI + registerSingleton(context, "tempFolder", ExtendedTemporaryFolder::class.java, tempFolder) + } + + @Suppress("SameParameterValue") + private fun registerSingleton( + context: ConfigurableApplicationContext, + beanName: String, + beanClass: Class, + instance: T + ) { + val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass) { instance } + (context.beanFactory as BeanDefinitionRegistry).registerBeanDefinition(beanName, builder.beanDefinition) + } +} diff --git a/ms/blueprintsprocessor/parent/pom.xml b/ms/blueprintsprocessor/parent/pom.xml index 4f8ff35b4..5caac2f69 100755 --- a/ms/blueprintsprocessor/parent/pom.xml +++ b/ms/blueprintsprocessor/parent/pom.xml @@ -54,6 +54,7 @@ 2.0.26.Final 2.2.0 0.1.55 + 0.1.8 2.7.1 2.5.1 1.7 @@ -160,6 +161,11 @@ jinjava ${jinja.version} + + com.schibsted.spt.data + jslt + ${jslt.version} + com.google.guava guava @@ -411,135 +417,138 @@ org.onap.ccsdk.cds.blueprintsprocessor processor-core - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor atomix-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor db-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor rest-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor nats-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor ssh-lib - ${project.version} + ${ccsdk.cds.version} + org.onap.ccsdk.cds.blueprintsprocessor message-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor dmaap-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor grpc-lib - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor execution-service - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor workflow-service - ${project.version} + ${ccsdk.cds.version} - - org.onap.ccsdk.cds.blueprintsprocessor configs-api - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor designer-api - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor resource-api - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor selfservice-api - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor application - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions resource-resolution - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions python-executor - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions ansible-awx-executor - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions netconf-executor - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions restconf-executor - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions cli-executor - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions config-snapshots - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor.functions message-prioritizaion - ${project.version} + ${ccsdk.cds.version} + + + org.onap.ccsdk.cds.blueprintsprocessor + health-api + ${ccsdk.cds.version} + + + org.onap.ccsdk.cds.blueprintsprocessor + health-api-common + ${ccsdk.cds.version} @@ -558,22 +567,22 @@ org.onap.ccsdk.cds.blueprintsprocessor resource-dict - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor blueprint-core - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor blueprint-proto - ${project.version} + ${ccsdk.cds.version} org.onap.ccsdk.cds.blueprintsprocessor blueprint-validation - ${project.version} + ${ccsdk.cds.version} @@ -603,6 +612,12 @@ ${powermock.version} test + + com.nhaarman.mockitokotlin2 + mockito-kotlin + 2.2.0 + test + org.jetbrains.kotlin kotlin-test-junit @@ -615,6 +630,7 @@ ${kotlin.couroutines.version} test + io.grpc grpc-testing diff --git a/ms/sdclistener/application/pom.xml b/ms/sdclistener/application/pom.xml index 39fa259c1..2d42d206e 100644 --- a/ms/sdclistener/application/pom.xml +++ b/ms/sdclistener/application/pom.xml @@ -32,7 +32,7 @@ 3.6.1 - ${parent.version} + ${project.parent.version} diff --git a/pom.xml b/pom.xml index 65ee5c18a..447a6846b 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ limitations under the License. ms - cds-ui + components -- cgit 1.2.3-korg