From 7f7704977116ead5bc3ae8cba4afdf698d08bce7 Mon Sep 17 00:00:00 2001 From: Michal Banka Date: Mon, 8 Feb 2021 12:42:52 +0100 Subject: Add ves-openapi-manager implementation Change-Id: I923fa43028c78989604547b365a3326a1f8e9548 Signed-off-by: Michal Banka Issue-ID: DCAEGEN2-2572 --- .gitignore | 31 +++ Changelog.md | 8 + Dockerfile | 4 + Makefile | 24 +++ README.md | 68 ++++++ docker-compose.yml | 11 + environment.config | 13 ++ pom.xml | 235 +++++++++++++++++++++ .../java/org/onap/ves/openapi/manager/Main.java | 93 ++++++++ .../manager/config/DistributionClientConfig.java | 130 ++++++++++++ .../manager/config/ValidatorProperties.java | 39 ++++ .../manager/exceptions/ArtifactException.java | 26 +++ .../onap/ves/openapi/manager/model/Artifact.java | 37 ++++ .../manager/model/ArtifactValidationResult.java | 40 ++++ .../manager/model/DistributionStatusMessage.java | 63 ++++++ .../model/FinalDistributionStatusMessage.java | 59 ++++++ .../onap/ves/openapi/manager/model/SchemaMap.java | 48 +++++ .../manager/service/ArtifactsCollector.java | 99 +++++++++ .../openapi/manager/service/ClientCallback.java | 143 +++++++++++++ .../ArtifactsCollectorStatusSender.java | 93 ++++++++ .../service/notification/FinalStatusSender.java | 85 ++++++++ .../notification/ValidationStatusSender.java | 89 ++++++++ .../serialization/SchemaMapDeserializer.java | 71 +++++++ .../VesEventsArtifactDeserializer.java | 69 ++++++ .../service/validation/ArtifactsValidator.java | 35 +++ .../validation/SchemaReferenceValidator.java | 158 ++++++++++++++ src/main/resources/application.yml | 20 ++ src/main/resources/schema-map.json | 58 +++++ .../config/DistributionClientConfigTest.java | 89 ++++++++ .../manager/config/ValidatorPropertiesTest.java | 60 ++++++ .../model/DistributionStatusMessageTest.java | 56 +++++ .../manager/service/ServiceFunctionalTest.java | 94 +++++++++ .../ArtifactsCollectorStatusSenderTest.java | 118 +++++++++++ .../notification/ArtifactsCollectorTest.java | 106 ++++++++++ .../service/notification/ClientCallbackTest.java | 153 ++++++++++++++ .../notification/ValidationStatusSenderTest.java | 84 ++++++++ .../serialization/SchemaMapDeserializerTest.java | 84 ++++++++ .../VesEventsArtifactDeserializerTest.java | 73 +++++++ .../manager/service/testModel/ArtifactInfo.java | 121 +++++++++++ .../manager/service/testModel/Resource.java | 161 ++++++++++++++ .../openapi/manager/service/testModel/Service.java | 136 ++++++++++++ .../validation/SchemaReferenceValidatorTest.java | 120 +++++++++++ src/test/resources/test-schema-map.json | 14 ++ .../ves_artifact_invalid_stndDefined_events.yaml | 107 ++++++++++ .../resources/ves_artifact_stndDefined_events.yaml | 107 ++++++++++ version.properties | 6 + 46 files changed, 3538 insertions(+) create mode 100644 .gitignore create mode 100644 Changelog.md create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 environment.config create mode 100644 pom.xml create mode 100644 src/main/java/org/onap/ves/openapi/manager/Main.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/model/Artifact.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java create mode 100644 src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/schema-map.json create mode 100644 src/test/java/org/onap/ves/openapi/manager/config/DistributionClientConfigTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/config/ValidatorPropertiesTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/model/DistributionStatusMessageTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/ServiceFunctionalTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSenderTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/notification/ClientCallbackTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSenderTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializerTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializerTest.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/testModel/ArtifactInfo.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/testModel/Resource.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/testModel/Service.java create mode 100644 src/test/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidatorTest.java create mode 100644 src/test/resources/test-schema-map.json create mode 100644 src/test/resources/ves_artifact_invalid_stndDefined_events.yaml create mode 100644 src/test/resources/ves_artifact_stndDefined_events.yaml create mode 100644 version.properties diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd9be1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build +/artifactInfos + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + + +# dependencies +target +*.iml +.idea +node_modules +package-lock.json +build \ No newline at end of file diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..812816c --- /dev/null +++ b/Changelog.md @@ -0,0 +1,8 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [1.0.0] - 09/02/2020 + - [DCAEGEN2-2572](https://jira.onap.org/browse/DCAEGEN2-2572) - Add ves-openapi-manager implementation diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..67275d9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM onap/integration-java11:8.0.0 +COPY ./src/main/resources/schema-map.json /app/schema-map.json +COPY target/ves-openapi-manager.jar /app/ +ENTRYPOINT java -jar /app/ves-openapi-manager.jar \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fcf3f44 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +include environment.config + +all: build docker run cleanup + +port-forward: + @echo "Forwarding ports. To cancel forwarding press CTRL+C." + @$(SSH) -L 3904:$(WORKER_IP):$(MESSAGE_ROUTER_PORT) ubuntu@$(RKE_IP) -i $(SSH_LAB_KEY_PATH) -N + +build: + @echo "Building ves-openapi-manager" + @$(MVN) clean package + +docker: + @echo "Building ves-openapi-manager docker image" + @$(DOCKER) build --tag ves-openapi-manager:latest . + +run: + @echo "Starting ves-openapi-manager docker containers" + @$(COMPOSE) --file ./docker-compose.yml up + +cleanup: + @echo "Cleaning up ves-openapi-manager project, removing containers" + @rm -rf ./target + @$(COMPOSE) --file ./docker-compose.yml down diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d74f51 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# VES OpenApi Manager + +# Description +This application should partially validate incoming service distributions in SDC. It validates each artifact of type +VES_EVENT. Its purpose is to check whether schemaReferences of stndDefined events included in VES_EVENT artifacts are +matching the schemas which VES Collector contains. + +# Instructions + +## How to prepare environment for local ves-openapi-manager with lab connection + +1. Connect to lab and expose ports of message-router service by setting *spec.type* to NodePort. + +2. Add to /etc/hosts new entry: +``` + sdc-be.onap +``` + +3. Get exposed port of 3904 internal port of message-router. + + Set up connection configuration in *environment.config* file. + - MESSAGE_ROUTER_PORT - exposed port of message-router. + - RKE_IP - IP of lab RKE node. + - WORKER_IP - IP of lab worker node. + - SSH_LAB_KEY_PATH - path to lab SSH key. + +4. Local port forwarding is required to set up proper connection from local environment to message-router on the lab. + + Run this to enable port-forwarding (CTRL+C to end): + ``` + make port-forwarding + ``` +## How to locally start ves-openapi-manager +Currently, there are two common ways to run application, both described below. + +### Start in IntelliJ +Right click on Main class, then Run or Debug button. + +### Start as Docker container +Run: +``` +make all +``` + +### Lab connection verification +Correctly connected to lab application should print logs: +``` +distribution client initialized successfuly +``` +and +``` +distribution client started successfuly +``` + +## How to use ves-openapi-manager +After preparing environment, starting ves-openapi-manager and successful connection to lab, application will listen for +service distributions taking place in SDC. + +1. In SDC UI, create Service with Resource (e.g. PNF) containing VES_EVENT artifact. +2. (Re)distribute created Service. + +When distribution takes place, ves-openapi-manager downloads each VES_EVENT artifact to validate its stndDefined events. + +Results of validation are visible in two places: +- In SDC UI in Service -> Distributions view under specific distribution as component *ves-openapi-manager*. + It might take few minutes to show results after service distribution. +- In logs of ves-openapi-manager, right after validation takes place. + \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d708fd8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3' + +services: + ves-openapi-manager: + image: ves-openapi-manager:latest + container_name: ves-openapi-manager + hostname: ves-openapi-manager + environment: + - SCHEMA_MAP_PATH=/app/schema-map.json + - ASDC_ADDRESS=sdc-be.onap:30204 + network_mode: host diff --git a/environment.config b/environment.config new file mode 100644 index 0000000..0d34eef --- /dev/null +++ b/environment.config @@ -0,0 +1,13 @@ +# Configuration file for ves-openapi-manager Makefile + +# consts +COMPOSE = docker-compose +MVN = mvn +DOCKER = docker +SSH = ssh + +# Port-forwarding configuration +RKE_IP=10.129.36.103 +WORKER_IP=10.129.36.116 +MESSAGE_ROUTER_PORT=30000 +SSH_LAB_KEY_PATH=~/Scripts/labs_keys/onap-8414.pem diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..93140cd --- /dev/null +++ b/pom.xml @@ -0,0 +1,235 @@ + + + 4.0.0 + + + org.onap.oparent + oparent + 3.2.0 + + + + org.onap.dcaegen2.platform + ves-openapi-manager + 1.0.0 + jar + + + 1.4.2 + 5.2.0 + 11 + 11 + 5.2.0 + 1.2.0 + ${mockito-core.version} + UTF-8 + UTF-8 + 6.1.6.Final + 2.9.4 + 2.22.0 + 2.4.2 + 0.31.0 + false + https://nexus.onap.org + /content/repositories/snapshots/ + /content/repositories/releases/ + /content/repositories/staging/ + onap + org.onap.dcaegen2.platform + yyyyMMdd'T'HHmmss + 3.5.1 + 0.13 + + + + ves-openapi-manager + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + + org.junit.platform + junit-platform-surefire-provider + ${platform.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit5.version} + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.version} + + + + repackage + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + docker + + false + + + linux + x86_64 + ${os.detected.name}-${os.detected.arch} + + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + docker-build-image + package + + build + + + + docker-push-image + deploy + + push + + + + + ${skipDockerPush} + true + IfNotPresent + + + ${project.artifactId} + ${docker-image.namespace}/${docker-image.name.prefix}.${project.artifactId} + ${onap.nexus.dockerregistry.daily} + + ${project.basedir} + + ${project.version}-STAGE-${maven.build.timestamp}Z + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.version} + pom + import + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + org.projectlombok + lombok + true + + + org.onap.sdc.sdc-distribution-client + sdc-distribution-client + ${sdc-distribution-client.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-databind.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson-databind.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-databind.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-core + ${mockito-core.version} + test + + + com.google.code.bean-matchers + bean-matchers + ${bean-matchers.version} + test + + + + + + ecomp-releases + Integration simulators Release Repository + ${nexusproxy}${releaseNexusPath} + + + ecomp-snapshots + Integration simulators Snapshot Repository + ${nexusproxy}${snapshotNexusPath} + + + ecomp-site + dav:${nexusproxy}${sitePath} + + + + diff --git a/src/main/java/org/onap/ves/openapi/manager/Main.java b/src/main/java/org/onap/ves/openapi/manager/Main.java new file mode 100644 index 0000000..209c05b --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/Main.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.http.HttpAsdcClient; +import org.onap.sdc.http.HttpClientFactory; +import org.onap.sdc.http.HttpRequestFactory; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.service.ArtifactsCollector; +import org.onap.ves.openapi.manager.service.ClientCallback; +import org.onap.ves.openapi.manager.service.notification.ArtifactsCollectorStatusSender; +import org.onap.ves.openapi.manager.service.notification.FinalStatusSender; +import org.onap.ves.openapi.manager.service.notification.ValidationStatusSender; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +@Log4j2 +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } + + /** + * Creates bean of SdcConnectorClient + * @param clientConfig DistributionClientConfig object with configuration properties + * @return SdcConnectorClient + */ + @Bean + public SdcConnectorClient getSdcConnectorClient(DistributionClientConfig clientConfig) { + HttpRequestFactory requestFactory = new HttpRequestFactory(clientConfig.getUser(), clientConfig.getPassword()); + HttpClientFactory clientFactory = new HttpClientFactory(clientConfig); + return new SdcConnectorClient(clientConfig, new HttpAsdcClient(clientConfig.getAsdcAddress(), clientFactory, requestFactory)); + } + + /** + * Creates bean of DistributionClientImpl + * @param clientConfig DistributionClientConfig object with configuration properties + * @param validators List of objects implementing ArtifactValidator interface + * @param artifactsCollector ArtifactsCollector object which downloads artifacts contents + * @return DistributionClientImpl + */ + @Bean + public DistributionClientImpl getDistributionClientImpl(DistributionClientConfig clientConfig, + List validators, + ArtifactsCollector artifactsCollector) { + DistributionClientImpl client = new DistributionClientImpl(); + ClientCallback callback = new ClientCallback(validators, artifactsCollector, + new ArtifactsCollectorStatusSender(client), new ValidationStatusSender(client), + new FinalStatusSender(client)); + + log.info(ClientCallback.SEPARATOR); + IDistributionClientResult initResult = client.init(clientConfig, callback); + log.info(initResult.getDistributionMessageResult()); + log.info(ClientCallback.SEPARATOR); + + log.info(ClientCallback.SEPARATOR); + IDistributionClientResult startResult = client.start(); + log.info(startResult.getDistributionMessageResult()); + log.info(ClientCallback.SEPARATOR); + + return client; + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java b/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java new file mode 100644 index 0000000..188cced --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java @@ -0,0 +1,130 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.config; + +import lombok.Getter; +import lombok.Setter; +import org.onap.sdc.api.consumer.IConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.Collections; +import java.util.List; + +/** + * DistributionClientConfig - properties required by DistributionClientImpl, values mapped from application.yml + */ +@Configuration +@ConfigurationProperties(prefix = "vesopenapimanager.distribution") +@Getter +@Setter +public class DistributionClientConfig implements IConfiguration { + + public static final String VES_EVENTS_ARTIFACT_TYPE = "VES_EVENTS"; + + private String asdcAddress; + private String msgBusAddress; + private String user; + private String password; + private Integer pollingInterval; + private Integer pollingTimeout; + private String consumerGroup; + private String environmentName; + private String consumerID; + private Boolean activateServerTLSAuth; + private Boolean isFilterInEmptyResources; + private Boolean isUseHttpsWithDmaap; + + @Override + public String getAsdcAddress() { + return asdcAddress; + } + + @Override + public List getMsgBusAddress() { + return Collections.singletonList(msgBusAddress); + } + + @Override + public String getUser() { + return user; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public int getPollingInterval() { + return pollingInterval; + } + + @Override + public int getPollingTimeout() { + return pollingTimeout; + } + + @Override + public List getRelevantArtifactTypes() { + return Collections.singletonList(VES_EVENTS_ARTIFACT_TYPE); + } + + @Override + public String getConsumerGroup() { + return consumerGroup; + } + + @Override + public String getEnvironmentName() { + return environmentName; + } + + @Override + public String getConsumerID() { + return consumerID; + } + + @Override + public String getKeyStorePath() { + return null; + } + + @Override + public String getKeyStorePassword() { + return null; + } + + @Override + public boolean activateServerTLSAuth() { + return activateServerTLSAuth; + } + + @Override + public boolean isFilterInEmptyResources() { + return isFilterInEmptyResources; + } + + @Override + public Boolean isUseHttpsWithDmaap() { + return isUseHttpsWithDmaap; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java b/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java new file mode 100644 index 0000000..11beb22 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * ValidatorProperties - properties required by SchemaReferenceValidator, values mapped from application.yml + */ +@Configuration +@ConfigurationProperties(prefix = "vesopenapimanager.validation") +@Getter +@Setter +public class ValidatorProperties { + private String schemaMapPath; + private String eventDomainPath; + private String eventSchemaReferencePath; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java b/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java new file mode 100644 index 0000000..c51face --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.exceptions; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class ArtifactException extends RuntimeException { } diff --git a/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java b/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java new file mode 100644 index 0000000..8cc54ac --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.onap.sdc.api.notification.IArtifactInfo; + +/** + * Artifact - model class that contains description and content of artifact + */ +@AllArgsConstructor +@Getter +@EqualsAndHashCode +public class Artifact { + private final IArtifactInfo description; + private final byte[] content; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java b/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java new file mode 100644 index 0000000..f672bb5 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; + +/** + * ArtifactValidationResult - model class for result of artifact validation + */ +@AllArgsConstructor +@Getter +@EqualsAndHashCode +public class ArtifactValidationResult { + private final IArtifactInfo artifact; + private final boolean isValid; + private final String message; + private final ArtifactsValidator validator; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java b/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java new file mode 100644 index 0000000..f25e6e0 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + +/** + * DistributionStatusMessage - model class for operation status sent to SDC + */ +@AllArgsConstructor +public class DistributionStatusMessage implements IDistributionStatusMessage { + + private final String artifactUrl; + private final String distributionId; + private final String consumerId; + private final long timestamp; + private final DistributionStatusEnum status; + + @Override + public String getArtifactURL() { + return artifactUrl; + } + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java b/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java new file mode 100644 index 0000000..de8836d --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import org.onap.sdc.api.consumer.IFinalDistrStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + + +/** + * FinalDistributionStatusMessage - model class for final ves-openapi-manager's validation message sent to SDC + */ +@AllArgsConstructor +public class FinalDistributionStatusMessage implements IFinalDistrStatusMessage { + + private final String distributionId; + private final long timestamp; + private final DistributionStatusEnum status; + private final String consumerId; + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } + + @Override + public String getConsumerID() { + return consumerId; + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java b/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java new file mode 100644 index 0000000..b275e7f --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * SchemaMap - model class with list of mappings of publicly stored OpenApi schemas to schemas stored locally in VES. + */ +@AllArgsConstructor +@Getter +public class SchemaMap { + private final List mappings; + + /** + * Single schemas mapping, + * publicURL contains URL to externally located schema, + * localURL contains URL located in VES container + */ + @NoArgsConstructor + @Getter + public static class Mapping { + private String publicURL; + private String localURL; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java b/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java new file mode 100644 index 0000000..52f1b0e --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java @@ -0,0 +1,99 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientDownloadResultImpl; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.exceptions.ArtifactException; +import org.onap.ves.openapi.manager.model.Artifact; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * ArtifactsCollector - Collector of artifact contents from distributed service, + * downloads artifacts contents basing on artifacts descriptions + */ +@Log4j2 +@Component +public class ArtifactsCollector { + + private static final String QUOTATION_MARK = "\""; + private static final int ARTIFACT_NAME_INDEX_NO_QUOTATION = 0; + private static final int ARTIFACT_NAME_INDEX_WITH_QUOTATION = 1; + private static final int NAME_WITH_QUOTATION_LENGTH = 2; + + private final SdcConnectorClient sdcConnectorClient; + + /** + * Constructor of ArtifactsCollector + * @param sdcConnectorClient SdcConnectorClient object + */ + @Autowired + public ArtifactsCollector(SdcConnectorClient sdcConnectorClient) { + this.sdcConnectorClient = sdcConnectorClient; + } + + /** + * @param artifacts List of IArtifactInfo objects, which are descriptions of artifacts + * @return List of Artifacts, each object contains description and content of artifact + */ + public List pullArtifacts(List artifacts) { + log.info("Downloading artifacts"); + List artifactDescriptions = filterVesEventsArtifacts(artifacts); + return artifactDescriptions.stream() + .map(sdcConnectorClient::downloadArtifact) + .map(downloadResult -> mapDownloadResultToArtifactContent(downloadResult, artifactDescriptions)) + .collect(Collectors.toList()); + } + + private List filterVesEventsArtifacts(List artifacts) { + return artifacts.stream() + .filter(artifactInfo -> + artifactInfo.getArtifactType().equals(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE)) + .collect(Collectors.toList()); + } + + private Artifact mapDownloadResultToArtifactContent(DistributionClientDownloadResultImpl downloadResult, + List artifactDescriptions) { + String artifactName = parseArtifactName(downloadResult); + Optional artifact = findArtifactDescription(artifactDescriptions, artifactName); + return artifact.map(artifactInfo -> + new Artifact(artifactInfo, downloadResult.getArtifactPayload())) + .orElseThrow(ArtifactException::new); + } + + private String parseArtifactName(DistributionClientDownloadResultImpl artifact) { + String[] name = artifact.getArtifactName().split(QUOTATION_MARK); + boolean doesContainQuotationMark = name.length >= NAME_WITH_QUOTATION_LENGTH; + return doesContainQuotationMark ? name[ARTIFACT_NAME_INDEX_WITH_QUOTATION] : name[ARTIFACT_NAME_INDEX_NO_QUOTATION]; + } + + private Optional findArtifactDescription(List artifacts, String artifactName) { + return artifacts.stream().filter(a -> a.getArtifactName().equals(artifactName)).findFirst(); + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java b/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java new file mode 100644 index 0000000..720ab8c --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java @@ -0,0 +1,143 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.consumer.INotificationCallback; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.notification.IResourceInstance; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.service.notification.ArtifactsCollectorStatusSender; +import org.onap.ves.openapi.manager.service.notification.FinalStatusSender; +import org.onap.ves.openapi.manager.service.notification.ValidationStatusSender; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Log4j2 +public class ClientCallback implements INotificationCallback { + + public static final String SEPARATOR = "==================================="; + private final List validators; + private final ValidationStatusSender validationStatusSender; + private final ArtifactsCollectorStatusSender artifactsCollectorStatusSender; + private final ArtifactsCollector artifactsCollector; + private final FinalStatusSender finalStatusSender; + + /** + * Constructor of ClientCallback + * @param validators List of objects implementing ArtifactValidator interface + * @param artifactsCollector ArtifactsCollector object which downloads artifacts contents + * @param artifactsCollectorStatusSender ArtifactsCollectorStatusSender which sends download results back to SDC + * @param validationStatusSender ValidationStatusSender which sends validation results to SDC + * @param finalStatusSender FinalStatusSender which sends final status of VES OpenApi Manager workflow + */ + public ClientCallback(List validators, ArtifactsCollector artifactsCollector, + ArtifactsCollectorStatusSender artifactsCollectorStatusSender, + ValidationStatusSender validationStatusSender, FinalStatusSender finalStatusSender) { + this.validators = validators; + this.validationStatusSender = validationStatusSender; + this.artifactsCollectorStatusSender = artifactsCollectorStatusSender; + this.artifactsCollector = artifactsCollector; + this.finalStatusSender = finalStatusSender; + } + + /** + * Callback method of distribution listener. Each time a service distribution takes place it's executed. + * @param service Distributed service information. + */ + @Override + public void activateCallback(INotificationData service) { + logServiceInfo(service); + String distributionID = service.getDistributionID(); + + List artifacts = downloadArtifacts(service); + List validationResults = validate(distributionID, artifacts); + sendFinalStatus(distributionID, validationResults); + } + + private void logServiceInfo(INotificationData service) { + log.info(SEPARATOR); + log.info("Distributed service information"); + log.info("Service UUID: {}", service.getServiceUUID()); + log.info("Service name: {}", service.getServiceName()); + List resources = service.getResources(); + log.info("Service resources:"); + resources.forEach(resource -> { + log.info(" - Resource: {}", resource.getResourceName()); + log.info(" Artifacts:"); + resource.getArtifacts().forEach(artifact -> log.info(" - Name: {}", artifact.getArtifactName())); + }); + log.info(SEPARATOR); + } + + private List downloadArtifacts(INotificationData service) { + List artifactInfos = getArtifactInfos(service); + List artifacts = artifactsCollector.pullArtifacts(artifactInfos); + sendDownloadStatuses(service, artifactInfos, artifacts); + return artifacts; + } + + private void sendDownloadStatuses(INotificationData service, List artifactInfos, List artifacts) { + Map> artifactsDownloadResults = artifacts.stream() + .collect(Collectors.partitioningBy(this::isContentDownloaded)); + artifactsDownloadResults.get(Boolean.TRUE).forEach(artifact -> + artifactsCollectorStatusSender.sendDownloadOk(service.getDistributionID(), artifactInfos)); + artifactsDownloadResults.get(Boolean.FALSE).forEach(artifact -> + artifactsCollectorStatusSender.sendDownloadError(service.getDistributionID(), artifactInfos)); + } + + private boolean isContentDownloaded(Artifact artifact) { + return artifact.getContent() != null && artifact.getContent().length > 0; + } + + private List getArtifactInfos(INotificationData service) { + return service.getResources().stream() + .map(IResourceInstance::getArtifacts) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List validate(String distributionID, List artifacts) { + return validators.stream() + .map(validator -> { + List validationResults = validator.validate(artifacts); + validationStatusSender.send(distributionID, validationResults); + return validationResults; + }) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private void sendFinalStatus(String distributionID, List validationResults) { + boolean areAllArtifactsValid = validationResults.stream().allMatch(ArtifactValidationResult::isValid); + if (areAllArtifactsValid) { + finalStatusSender.sendFinalStatusOk(distributionID); + } else { + finalStatusSender.sendFinalStatusError(distributionID); + } + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java new file mode 100644 index 0000000..0829855 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.DistributionStatusMessage; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +/** + * ArtifactsCollectorStatusSender - sender of DistributionStatusMessage with artifacts download status to SDC + */ +@Log4j2 +public class ArtifactsCollectorStatusSender { + + private static final String DOWNLOAD_ERROR_MESSAGE = "Couldn't download artifact"; + private final DistributionClientImpl distributionClient; + + /** + * Constructor of ArtifactsCollectorStatusSender + * @param distributionClient DistributionClientImpl object + */ + public ArtifactsCollectorStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends DOWNLOAD_OK status to SDC + * @param distributionId Service distribution ID + * @param downloadedArtifacts Artifacts which are successfully downloaded + * @return List of IDistributionClientResult, results of sending status + */ + public List sendDownloadOk(String distributionId, List downloadedArtifacts) { + return downloadedArtifacts.stream() + .map(artifact -> { + DistributionStatusMessage distributionMessage = getDownloadMessage(distributionId, + artifact.getArtifactURL(), DistributionStatusEnum.DOWNLOAD_OK); + return distributionClient.sendDownloadStatus(distributionMessage); + }) + .collect(Collectors.toList()); + } + + /** + * Sends DOWNLOAD_ERROR status to SDC + * @param distributionId Service distribution ID + * @param downloadedArtifacts Artifacts which could not be downloaded + * @return List of IDistributionClientResult, results of sending status + */ + public List sendDownloadError(String distributionId, List downloadedArtifacts) { + return downloadedArtifacts.stream() + .map(artifact -> { + DistributionStatusMessage distributionMessage = getDownloadMessage(distributionId, + artifact.getArtifactURL(), DistributionStatusEnum.DOWNLOAD_ERROR); + return distributionClient.sendDownloadStatus(distributionMessage, DOWNLOAD_ERROR_MESSAGE); + }) + .collect(Collectors.toList()); + } + + private DistributionStatusMessage getDownloadMessage(String distributionId, String artifactURL, DistributionStatusEnum downloadStatus) { + return new DistributionStatusMessage( + artifactURL, + distributionId, + distributionClient.getConfiguration().getConsumerID(), + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), + downloadStatus); + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java new file mode 100644 index 0000000..e21ab70 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.FinalDistributionStatusMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +/** + * FinalStatusSender - sender of FinalDistributionStatusMessage with final status to SDC + */ +@Log4j2 +@Service +public class FinalStatusSender { + + private static final String INVALID_ARTIFACTS_MESSAGE = "At least one VES_EVENT artifact is invalid"; + private final DistributionClientImpl distributionClient; + + /** + * Constructor of FinalStatusSender + * @param distributionClient DistributionClientImpl object + */ + @Autowired + public FinalStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends final message COMPONENT_DONE_OK to SDC + * @param distributionId Service distribution ID + * @return IDistributionClientResult, result of sending status + */ + public IDistributionClientResult sendFinalStatusOk(String distributionId) { + DistributionStatusEnum okStatus = DistributionStatusEnum.COMPONENT_DONE_OK; + FinalDistributionStatusMessage message = getMessage(distributionId, okStatus); + log.info("All VES_EVENT artifacts are valid, sending final status {}", okStatus.name()); + return distributionClient.sendFinalDistrStatus(message); + } + + /** + * Sends final message COMPONENT_DONE_ERROR to SDC + * @param distributionId Service distribution ID + * @return IDistributionClientResult, result of sending status + */ + public IDistributionClientResult sendFinalStatusError(String distributionId) { + DistributionStatusEnum errorStatus = DistributionStatusEnum.COMPONENT_DONE_ERROR; + FinalDistributionStatusMessage message = getMessage(distributionId, errorStatus); + log.info("At least one VES_EVENT artifact is invalid, sending final status {}", errorStatus.name()); + return distributionClient.sendFinalDistrStatus(message, INVALID_ARTIFACTS_MESSAGE); + } + + private FinalDistributionStatusMessage getMessage(String distributionId, DistributionStatusEnum distributionStatus) { + return new FinalDistributionStatusMessage( + distributionId, + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), + distributionStatus, + distributionClient.getConfiguration().getConsumerID()); + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java new file mode 100644 index 0000000..ae11791 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java @@ -0,0 +1,89 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.model.DistributionStatusMessage; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +/** + * ValidationStatusSender - sender of DistributionStatusMessage with validation status to SDC + */ +@Log4j2 +public class ValidationStatusSender { + + private final DistributionClientImpl distributionClient; + + /** + * Constructor of ValidationStatusSender + * @param distributionClient DistributionClientImpl object + */ + public ValidationStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends validation result status to SDC + * @param distributionId Service distribution ID + * @param validationResults Validation results + * @return List of IDistributionClientResult, results of sending status + */ + public List send(String distributionId, List validationResults) { + return validationResults.stream() + .map(validationResult -> sendValidationResult(distributionId, validationResult)) + .collect(Collectors.toList()); + } + + private IDistributionClientResult sendValidationResult(String distributionId, ArtifactValidationResult validationResult) { + DistributionStatusMessage distributionMessage = getDistributionMessage(distributionId, validationResult); + String artifactName = validationResult.getArtifact().getArtifactName(); + + if (validationResult.isValid()) { + log.warn("Artifact {} is valid", artifactName); + return distributionClient.sendDeploymentStatus(distributionMessage); + } else { + String message = validationResult.getMessage(); + log.warn("Artifact {} is invalid", artifactName); + log.warn("Validation message: {}", message); + return distributionClient.sendDeploymentStatus(distributionMessage, message); + } + } + + private DistributionStatusMessage getDistributionMessage(String distributionId, ArtifactValidationResult validationResult) { + String artifactURL = validationResult.getArtifact().getArtifactURL(); + DistributionStatusEnum status = getErrorStatus(validationResult); + return new DistributionStatusMessage(artifactURL, distributionId, + distributionClient.getConfiguration().getConsumerID(), + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), status); + } + + private DistributionStatusEnum getErrorStatus(ArtifactValidationResult validationResult) { + return validationResult.isValid() ? DistributionStatusEnum.DEPLOY_OK : DistributionStatusEnum.DEPLOY_ERROR; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java b/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java new file mode 100644 index 0000000..8ea434e --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.serialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; +import org.onap.ves.openapi.manager.model.SchemaMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * SchemaMapDeserializer - Deserializer of JSON file contents to SchemaMap objects + */ +@Log4j2 +@Service +public class SchemaMapDeserializer { + + private static final String COULD_NOT_READ_SCHEMA_MAP_MESSAGE = "Couldn't read schema map from path: "; + private final ObjectMapper objectMapper; + + /** + * Constructor of SchemaMapDeserializer + * @param objectMapper ObjectMapper for YAML parsing + */ + @Autowired + public SchemaMapDeserializer(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Deserializes file content to SchemaMap object + * @param schemaMapPath Path to file containing JSON formatted SchemaMap + * @return SchemaMap + */ + public SchemaMap getSchemaMapFromFile(String schemaMapPath) { + SchemaMap schemaMap; + try { + File file = new File(schemaMapPath); + List mappings = Arrays.asList(objectMapper.readValue(file, SchemaMap.Mapping[].class)); + schemaMap = new SchemaMap(mappings); + } catch (IOException e) { + schemaMap = new SchemaMap(Collections.emptyList()); + log.error(COULD_NOT_READ_SCHEMA_MAP_MESSAGE + schemaMapPath, e); + } + return schemaMap; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java b/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java new file mode 100644 index 0000000..4bd6761 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.serialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLParser; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** + * VesEventsArtifactDeserializer - Deserializer of byte array of MultiDocument YAML to ObjectNodes + */ +@Log4j2 +@Service +public class VesEventsArtifactDeserializer { + + private static final String COULD_NOT_READ_ARTIFACT_CONTENT_MESSAGE = "Couldn't read artifact content"; + private final ObjectMapper objectMapper; + + /** + * Constructor of VesEventsArtifactDeserializer + * @param objectMapper ObjectMapper for YAML parsing + */ + @Autowired + public VesEventsArtifactDeserializer(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Deserializes MultiDocument YAML given as byte array + * @param data MultiDocument YAML as byte array + * @return List of ObjectNodes, each Document is separate ObjectNode + */ + public List deserializeMultiDocumentYaml(byte[] data) { + List events = Collections.emptyList(); + try { + YAMLParser yamlParser = new YAMLFactory().createParser(data); + events = objectMapper.readValues(yamlParser, ObjectNode.class).readAll(); + } catch (IOException e) { + log.error(COULD_NOT_READ_ARTIFACT_CONTENT_MESSAGE, e); + } + return events; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java b/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java new file mode 100644 index 0000000..5963c6b --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.validation; + +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; + +import java.util.List; + +public interface ArtifactsValidator { + /** + * Validates given VES_EVENT type artifacts + * @param artifacts List of artifacts: descriptions and contents + * @return List of ArtifactValidationResult, validation results + */ + List validate(List artifacts); +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java b/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java new file mode 100644 index 0000000..dd97b09 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java @@ -0,0 +1,158 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.validation; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.ves.openapi.manager.config.ValidatorProperties; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.model.SchemaMap; +import org.onap.ves.openapi.manager.service.serialization.SchemaMapDeserializer; +import org.onap.ves.openapi.manager.service.serialization.VesEventsArtifactDeserializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * SchemaReferenceValidator - validator of schemaReference field in VES_EVENTS artifacts + */ +@Log4j2 +@Service +public class SchemaReferenceValidator implements ArtifactsValidator { + + private static final String HASH_KEY = "#"; + private static final String NEW_LINE = "\n"; + static final String STND_DEFINED_DOMAIN = "stndDefined"; + static final String SCHEMA_REFERENCE_ERROR_MESSAGE = "Schema reference is not present in VES schema map."; + + private final VesEventsArtifactDeserializer vesEventsArtifactDeserializer; + private final SchemaMapDeserializer schemaMapDeserializer; + private final ValidatorProperties validatorProperties; + + /** + * Constructor of SchemaReferenceValidator + * @param vesEventsArtifactDeserializer Deserializer of VES_EVENT type artifact + * @param schemaMapDeserializer Deserializer of Schema Map + * @param validatorProperties Properties required by validator + */ + @Autowired + public SchemaReferenceValidator(VesEventsArtifactDeserializer vesEventsArtifactDeserializer, + SchemaMapDeserializer schemaMapDeserializer, + ValidatorProperties validatorProperties) { + this.vesEventsArtifactDeserializer = vesEventsArtifactDeserializer; + this.schemaMapDeserializer = schemaMapDeserializer; + this.validatorProperties = validatorProperties; + } + + /** + * Validates given VES_EVENT type artifacts + * @param artifacts List of artifacts: descriptions and contents + * @return List of ArtifactValidationResult, validation results + */ + @Override + public List validate(List artifacts) { + return artifacts.stream() + .map(this::getArtifactValidationResult) + .collect(Collectors.toList()); + } + + private ArtifactValidationResult getArtifactValidationResult(Artifact artifact) { + List stndDefinedEvents = getStndDefinedEvents(artifact.getContent()); + List publicUrls = getPublicUrls(); + + Set invalidSchemaReferences = stndDefinedEvents.stream() + .map(event -> getInvalidReferences(event, publicUrls)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + return getValidationResult(artifact.getDescription(), invalidSchemaReferences); + } + + private ArtifactValidationResult getValidationResult(IArtifactInfo artifact, Set invalidReferences) { + boolean isValid = invalidReferences.isEmpty(); + String message = getMessage(invalidReferences); + return new ArtifactValidationResult(artifact, isValid, message, this); + } + + private String getMessage(Set invalidSchemaReferences) { + final String emptyMessage = ""; + return invalidSchemaReferences.isEmpty() ? emptyMessage : generateMessage(invalidSchemaReferences); + } + + private String generateMessage(Set invalidSchemaReferences) { + return SCHEMA_REFERENCE_ERROR_MESSAGE + ":" + NEW_LINE + String.join(NEW_LINE, invalidSchemaReferences); + } + + private List getStndDefinedEvents(byte[] artifactData) { + List events = vesEventsArtifactDeserializer.deserializeMultiDocumentYaml(artifactData); + return events.stream() + .filter(this::isStndDefinedEvent) + .collect(Collectors.toList()); + } + + private boolean isStndDefinedEvent(ObjectNode event) { + String actualDomain = event.at(validatorProperties.getEventDomainPath()).asText(); + return actualDomain.equals(STND_DEFINED_DOMAIN); + } + + private List getPublicUrls() { + String schemaMapPath = validatorProperties.getSchemaMapPath(); + List mappings = schemaMapDeserializer.getSchemaMapFromFile(schemaMapPath).getMappings(); + return mappings.stream() + .map(SchemaMap.Mapping::getPublicURL) + .collect(Collectors.toList()); + } + + private List getInvalidReferences(JsonNode event, List publicUrls) { + String schemaReferencePath = validatorProperties.getEventSchemaReferencePath(); + JsonNode schemaReference = event.at(schemaReferencePath); + Stream schemaReferenceStream = Stream.empty(); + + if (schemaReference.isArray()) { + schemaReferenceStream = StreamSupport.stream(schemaReference.spliterator(), false); + } else if (schemaReference.isValueNode()) { + schemaReferenceStream = Stream.of(schemaReference); + } + + return getInvalidSchemaReferences(schemaReferenceStream, publicUrls); + } + + private List getInvalidSchemaReferences(Stream schemaReferencesStream, List publicUrls) { + return schemaReferencesStream + .map(this::fetchUrlFromSchemaReference) + .filter(reference -> !publicUrls.contains(reference)) + .collect(Collectors.toList()); + } + + private String fetchUrlFromSchemaReference(JsonNode schemaReference) { + final int urlPartIndex = 0; + return schemaReference.asText().split(HASH_KEY)[urlPartIndex]; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..f179544 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,20 @@ +vesopenapimanager: + validation: + schemaMapPath: ${SCHEMA_MAP_PATH:./src/main/resources/schema-map.json} + eventDomainPath: /event/structure/commonEventHeader/structure/domain/value + eventSchemaReferencePath: /event/structure/stndDefinedFields/structure/schemaReference/value + distribution: + asdcAddress: ${ASDC_ADDRESS:sdc-be.onap:30204} + msgBusAddress: message-router.onap + user: dcae + password: Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U + pollingInterval: 20 + pollingTimeout: 20 + consumerGroup: ves-openapi-manager + environmentName: AUTO + consumerID: ves-openapi-manager + activateServerTLSAuth: false + isFilterInEmptyResources: false + isUseHttpsWithDmaap: false + + diff --git a/src/main/resources/schema-map.json b/src/main/resources/schema-map.json new file mode 100644 index 0000000..359014c --- /dev/null +++ b/src/main/resources/schema-map.json @@ -0,0 +1,58 @@ +[ + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/blob/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/5gcNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/invalid.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerDataFileReportMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/comDefs.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/comDefs.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/coslaNrm.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/coslaNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/faultMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/blob/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/genericNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/faultMnS_dcae.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/heartbeatNtf.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/nrNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/provMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/provMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/sliceNrm.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/sliceNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/streamingDataMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/streamingDataMnS.yaml" + } +] \ No newline at end of file diff --git a/src/test/java/org/onap/ves/openapi/manager/config/DistributionClientConfigTest.java b/src/test/java/org/onap/ves/openapi/manager/config/DistributionClientConfigTest.java new file mode 100644 index 0000000..9118f82 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/config/DistributionClientConfigTest.java @@ -0,0 +1,89 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.config; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.bind.BindResult; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DistributionClientConfigTest { + + @Test + void shouldCreateDistributionClientConfig() { + //given + String asdcAddress = "sdc-be.onap:8443"; + String msgBusAddress = "message-router.onap"; + String user = "dcae"; + String password = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"; + Integer pollingInterval = 20; + Integer pollingTimeout = 20; + String consumerGroup = "ves-openapi-manager"; + String environmentName = "AUTO"; + String consumerID = "ves-openapi-manager"; + Map properties = new HashMap<>(); + properties.put("vesopenapimanager.distribution.asdcAddress", asdcAddress); + properties.put("vesopenapimanager.distribution.msgBusAddress", msgBusAddress); + properties.put("vesopenapimanager.distribution.user", user); + properties.put("vesopenapimanager.distribution.password", password); + properties.put("vesopenapimanager.distribution.pollingInterval", pollingInterval); + properties.put("vesopenapimanager.distribution.pollingTimeout", pollingTimeout); + properties.put("vesopenapimanager.distribution.consumerGroup", consumerGroup); + properties.put("vesopenapimanager.distribution.environmentName", environmentName); + properties.put("vesopenapimanager.distribution.consumerID", consumerID); + properties.put("vesopenapimanager.distribution.activateServerTLSAuth", false); + properties.put("vesopenapimanager.distribution.isFilterInEmptyResources", false); + properties.put("vesopenapimanager.distribution.isUseHttpsWithDmaap", false); + ConfigurationPropertySource source = new MapConfigurationPropertySource(properties); + Binder binder = new Binder(source); + + //when + BindResult result = binder.bind("vesopenapimanager.distribution", DistributionClientConfig.class); + + //then + assertThat(result.isBound()).isTrue(); + DistributionClientConfig config = result.get(); + assertThat(config.getAsdcAddress()).isEqualTo(asdcAddress); + assertThat(config.getMsgBusAddress()).isEqualTo(List.of(msgBusAddress)); + assertThat(config.getUser()).isEqualTo(user); + assertThat(config.getPassword()).isEqualTo(password); + assertThat(config.getPollingInterval()).isEqualTo(pollingInterval); + assertThat(config.getPollingTimeout()).isEqualTo(pollingTimeout); + assertThat(config.getRelevantArtifactTypes()).isEqualTo(Collections.singletonList("VES_EVENTS")); + assertThat(config.getConsumerGroup()).isEqualTo(consumerGroup); + assertThat(config.getEnvironmentName()).isEqualTo(environmentName); + assertThat(config.getConsumerID()).isEqualTo(consumerID); + assertThat(config.getKeyStorePath()).isNull(); + assertThat(config.getKeyStorePassword()).isNull(); + assertThat(config.activateServerTLSAuth()).isFalse(); + assertThat(config.isFilterInEmptyResources()).isFalse(); + assertThat(config.activateServerTLSAuth()).isFalse(); + assertThat(config.isUseHttpsWithDmaap()).isFalse(); + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/config/ValidatorPropertiesTest.java b/src/test/java/org/onap/ves/openapi/manager/config/ValidatorPropertiesTest.java new file mode 100644 index 0000000..57b3725 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/config/ValidatorPropertiesTest.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.ves.openapi.manager.config; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.bind.BindResult; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ValidatorPropertiesTest { + + @Test + void shouldCreateDistributionClientConfig() { + //given + String schemaMapPath = "schema-map.json"; + String eventDomainPath = "/event/structure/commonEventHeader/structure/domain/value"; + String eventSchemaReferencePath = "/event/structure/stndDefinedFields/structure/schemaReference/value"; + + Map properties = new HashMap<>(); + properties.put("vesopenapimanager.validation.schemaMapPath", schemaMapPath); + properties.put("vesopenapimanager.validation.eventDomainPath", eventDomainPath); + properties.put("vesopenapimanager.validation.eventSchemaReferencePath", eventSchemaReferencePath); + + ConfigurationPropertySource source = new MapConfigurationPropertySource(properties); + Binder binder = new Binder(source); + + //when + BindResult result = binder.bind("vesopenapimanager.validation", ValidatorProperties.class); + + //then + assertThat(result.isBound()).isTrue(); + ValidatorProperties config = result.get(); + assertThat(config.getSchemaMapPath()).isEqualTo(schemaMapPath); + assertThat(config.getEventDomainPath()).isEqualTo(eventDomainPath); + assertThat(config.getEventSchemaReferencePath()).isEqualTo(eventSchemaReferencePath); + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/model/DistributionStatusMessageTest.java b/src/test/java/org/onap/ves/openapi/manager/model/DistributionStatusMessageTest.java new file mode 100644 index 0000000..e84b919 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/model/DistributionStatusMessageTest.java @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.model; + +import org.junit.jupiter.api.Test; +import org.onap.sdc.utils.DistributionStatusEnum; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class DistributionStatusMessageTest { + @Test + void shouldCreateDistributionStatusMessage() { + //given + long timestamp = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(); + String consumerId = "ves-consumer"; + String artifactUrl = "http://artifact-url:1234/test"; + String distributionId = "distribution-id"; + + //when + DistributionStatusMessage distributionStatusMessage = new DistributionStatusMessage( + artifactUrl, + distributionId, + consumerId, + timestamp, + DistributionStatusEnum.DOWNLOAD_OK); + + //then + assertThat(distributionStatusMessage.getArtifactURL()).isEqualTo(artifactUrl); + assertThat(distributionStatusMessage.getDistributionID()).isEqualTo(distributionId); + assertThat(distributionStatusMessage.getConsumerID()).isEqualTo(consumerId); + assertThat(distributionStatusMessage.getTimestamp()).isEqualTo(timestamp); + assertThat(distributionStatusMessage.getStatus()).isEqualTo(DistributionStatusEnum.DOWNLOAD_OK); + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/ServiceFunctionalTest.java b/src/test/java/org/onap/ves/openapi/manager/service/ServiceFunctionalTest.java new file mode 100644 index 0000000..a3beb4e --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/ServiceFunctionalTest.java @@ -0,0 +1,94 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientDownloadResultImpl; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.config.ValidatorProperties; +import org.onap.ves.openapi.manager.service.notification.ArtifactsCollectorStatusSender; +import org.onap.ves.openapi.manager.service.notification.FinalStatusSender; +import org.onap.ves.openapi.manager.service.notification.ValidationStatusSender; +import org.onap.ves.openapi.manager.service.serialization.SchemaMapDeserializer; +import org.onap.ves.openapi.manager.service.serialization.VesEventsArtifactDeserializer; +import org.onap.ves.openapi.manager.service.testModel.Service; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; +import org.onap.ves.openapi.manager.service.validation.SchemaReferenceValidator; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ServiceFunctionalTest { + + private final DistributionClientImpl distributionClient = mock(DistributionClientImpl.class); + private final SdcConnectorClient sdcConnectorClient = mock(SdcConnectorClient.class); + private final DistributionClientConfig config = mock(DistributionClientConfig.class); + private final ValidatorProperties validatorProperties = mock(ValidatorProperties.class); + + private final ObjectMapper objectMapper = new ObjectMapper(); + private final VesEventsArtifactDeserializer vesEventsArtifactDeserializer = new VesEventsArtifactDeserializer(objectMapper); + private final SchemaMapDeserializer schemaMapDeserializer = new SchemaMapDeserializer(objectMapper); + + private final List validators = List.of(new SchemaReferenceValidator(vesEventsArtifactDeserializer, schemaMapDeserializer, validatorProperties)); + private final ArtifactsCollector artifactsCollector = new ArtifactsCollector(sdcConnectorClient); + private final ArtifactsCollectorStatusSender artifactsCollectorStatusSender = new ArtifactsCollectorStatusSender(distributionClient); + private final ValidationStatusSender validationStatusSender = new ValidationStatusSender(distributionClient); + private final FinalStatusSender finalStatusSender = new FinalStatusSender(distributionClient); + private final ClientCallback clientCallback = new ClientCallback(validators, artifactsCollector, artifactsCollectorStatusSender, validationStatusSender, finalStatusSender); + + private final INotificationData service = new Service(); + + + @Test + void shouldNotThrowExceptionWhenCallingCallbackAndArtifactIsValid() throws IOException { + //given + byte[] payload = Files.readAllBytes(Paths.get("src/test/resources/ves_artifact_stndDefined_events.yaml")); + DistributionClientDownloadResultImpl message = new DistributionClientDownloadResultImpl( + DistributionActionResultEnum.SUCCESS, "message", "artifact-name", payload); + DistributionClientDownloadResultImpl responseStatus = new DistributionClientDownloadResultImpl(DistributionActionResultEnum.SUCCESS, "OK"); + + when(sdcConnectorClient.downloadArtifact(any())).thenReturn(message); + when(distributionClient.sendDownloadStatus(any())).thenReturn(responseStatus); + when(distributionClient.sendDeploymentStatus(any())).thenReturn(responseStatus); + when(distributionClient.getConfiguration()).thenReturn(config); + when(distributionClient.sendFinalDistrStatus(any())).thenReturn(responseStatus); + when(config.getConsumerID()).thenReturn("consumer-id"); + when(validatorProperties.getSchemaMapPath()).thenReturn("src/test/resources/test-schema-map.json"); + when(validatorProperties.getEventDomainPath()).thenReturn("/event/structure/commonEventHeader/structure/domain/value"); + when(validatorProperties.getEventSchemaReferencePath()).thenReturn("/event/structure/stndDefinedFields/structure/schemaReference/value"); + + //when + //then + assertDoesNotThrow(() -> clientCallback.activateCallback(service)); + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSenderTest.java b/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSenderTest.java new file mode 100644 index 0000000..377cc4b --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSenderTest.java @@ -0,0 +1,118 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.consumer.IConfiguration; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.impl.DistributionClientResultImpl; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.model.DistributionStatusMessage; +import org.onap.ves.openapi.manager.service.testModel.ArtifactInfo; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ArtifactsCollectorStatusSenderTest { + + private final IConfiguration configuration = mock(IConfiguration.class); + private final DistributionClientImpl distributionClient = mock(DistributionClientImpl.class); + private final ArtifactsCollectorStatusSender sender = new ArtifactsCollectorStatusSender(distributionClient); + + @Test + void shouldSuccessfullySendStatusToEachDownloadedArtifacts() { + //given + DistributionClientResultImpl expectedResponse = new DistributionClientResultImpl( + DistributionActionResultEnum.SUCCESS, "sample-response-message"); + List expectedResponses = List.of(expectedResponse, expectedResponse); + + ArtifactInfo artifact = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = List.of(artifact, artifact); + String consumerId = "ves-consumer"; + + when(distributionClient.sendDownloadStatus(any())).thenReturn(expectedResponse); + when(distributionClient.getConfiguration()).thenReturn(configuration); + when(configuration.getConsumerID()).thenReturn(consumerId); + + //when + List responses = sender.sendDownloadOk("distribution-id", artifacts); + + //then + assertThat(responses).isEqualTo(expectedResponses); + } + + @Test + void shouldSendDownloadErrorStatusToEachDownloadedArtifacts() { + //given + DistributionClientResultImpl expectedResponse = new DistributionClientResultImpl( + DistributionActionResultEnum.GENERAL_ERROR, "sample-response-message"); + List expectedResponses = List.of(expectedResponse, expectedResponse); + + ArtifactInfo artifact = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = List.of(artifact, artifact); + String consumerId = "ves-consumer"; + when(distributionClient.sendDownloadStatus(any(),any())).thenReturn(expectedResponse); + when(distributionClient.getConfiguration()).thenReturn(configuration); + when(configuration.getConsumerID()).thenReturn(consumerId); + long timestamp = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(); + + DistributionStatusMessage dm = new DistributionStatusMessage( + artifact.getArtifactURL(), + "distribution-id", + distributionClient.getConfiguration().getConsumerID(), + timestamp, + DistributionStatusEnum.DOWNLOAD_OK); + + //when + List responses = sender.sendDownloadError("distribution-id", artifacts); + + //then + assertThat(responses).isEqualTo(expectedResponses); + assertThat(dm.getArtifactURL()).isEqualTo(artifact.getArtifactURL()); + assertThat(dm.getDistributionID()).isEqualTo("distribution-id"); + assertThat(dm.getTimestamp()).isEqualTo(timestamp); + assertThat(dm.getStatus()).isEqualTo(DistributionStatusEnum.DOWNLOAD_OK); + } + + @Test + void shouldNotSendAnyStatusWhenNoArtifactsAreDownloaded() { + //given + List expectedResponses = List.of(); + List artifacts = List.of(); + + //when + List responses = sender.sendDownloadOk("distribution-id", artifacts); + + //then + assertThat(responses).isEqualTo(expectedResponses); + } + +} \ No newline at end of file diff --git a/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorTest.java b/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorTest.java new file mode 100644 index 0000000..3da47f7 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorTest.java @@ -0,0 +1,106 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientDownloadResultImpl; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.exceptions.ArtifactException; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.service.ArtifactsCollector; +import org.onap.ves.openapi.manager.service.testModel.ArtifactInfo; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ArtifactsCollectorTest { + + private static final String NOT_VES_ARTIFACT = "NOT_VES_ARTIFACT"; + private final SdcConnectorClient sdcConnectorClient = mock(SdcConnectorClient.class); + private final ArtifactsCollector artifactsCollector = new ArtifactsCollector(sdcConnectorClient); + + @Test + void shouldReturnArtifactsContentWhenVESArtifactsAreDistributed() throws IOException { + //given + IArtifactInfo vesArtifact = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = List.of(vesArtifact); + + byte[] payload = getVesArtifactPayload(); + DistributionClientDownloadResultImpl artifactDownloadResult = new DistributionClientDownloadResultImpl( + DistributionActionResultEnum.SUCCESS, "sample-message", "artifact-name", + payload); + when(sdcConnectorClient.downloadArtifact(vesArtifact)).thenReturn(artifactDownloadResult); + List expectedArtifacts = List.of(new Artifact(vesArtifact, payload)); + + //when + List artifactContents = artifactsCollector.pullArtifacts(artifacts); + + //then + assertThat(artifactContents).isEqualTo(expectedArtifacts); + } + + @Test + void shouldNotReturnArtifactsContentWhenNoVESArtifactsAreDistributed() { + //given + IArtifactInfo notVesArtifact = new ArtifactInfo(NOT_VES_ARTIFACT); + List artifactsDefinitions = List.of(notVesArtifact); + List expectedArtifacts = List.of(); + + //when + List artifacts = artifactsCollector.pullArtifacts(artifactsDefinitions); + + //then + assertThat(artifacts).isEqualTo(expectedArtifacts); + } + + @Test + void shouldThrowExceptionWhenArtifactNameIsEmpty() { + //given + IArtifactInfo vesArtifact = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = List.of(vesArtifact); + + byte[] payload = new byte[0]; + DistributionClientDownloadResultImpl artifactDownloadResult = new DistributionClientDownloadResultImpl( + DistributionActionResultEnum.SUCCESS, "sample-message", "", + payload); + when(sdcConnectorClient.downloadArtifact(vesArtifact)).thenReturn(artifactDownloadResult); + + //when then + assertThrows( + ArtifactException.class, + () -> artifactsCollector.pullArtifacts(artifacts) + ); + } + + private byte[] getVesArtifactPayload() throws IOException { + return Files.readAllBytes(Paths.get("src/test/resources/ves_artifact_stndDefined_events.yaml")); + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/notification/ClientCallbackTest.java b/src/test/java/org/onap/ves/openapi/manager/service/notification/ClientCallbackTest.java new file mode 100644 index 0000000..91dfda7 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/notification/ClientCallbackTest.java @@ -0,0 +1,153 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.service.ArtifactsCollector; +import org.onap.ves.openapi.manager.service.ClientCallback; +import org.onap.ves.openapi.manager.service.testModel.Service; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class ClientCallbackTest { + + private ArtifactsCollector artifactsCollector; + private ArtifactsCollectorStatusSender artifactsCollectorStatusSender; + private ValidationStatusSender validationStatusSender; + private FinalStatusSender finalStatusSender; + private ArtifactsValidator artifactsValidator; + private List validators; + private ClientCallback callback; + + @BeforeEach + void setUpMocks() { + artifactsCollector = mock(ArtifactsCollector.class); + artifactsCollectorStatusSender = mock(ArtifactsCollectorStatusSender.class); + validationStatusSender = mock(ValidationStatusSender.class); + finalStatusSender = mock(FinalStatusSender.class); + artifactsValidator = mock(ArtifactsValidator.class); + validators = new ArrayList<>(); + validators.add(artifactsValidator); + + callback = new ClientCallback(validators, artifactsCollector, artifactsCollectorStatusSender, + validationStatusSender, finalStatusSender); + } + + @Test + void shouldNotValidateAnyArtifactsOrSendAnyStatusIfPulledArtifactsListIsEmpty() { + testClientCallback(0); + } + + @Test + void shouldValidateArtifactUsingValidatorAndSendStatusIfPulledArtifactsListContainsOneArtifact() { + testClientCallback(1); + } + + @Test + void shouldValidateArtifactsUsingValidatorAndSendStatusesIfPulledArtifactsListContainsMultipleArtifacts() { + testClientCallback(3); + } + + @Test + void shouldValidateArtifactUsingMultipleValidatorsAndSendStatusIfPulledArtifactsListContainsOneArtifact() { + ArtifactsValidator extraArtifactsValidator = mock(ArtifactsValidator.class); + testClientCallback(1, extraArtifactsValidator); + } + + @Test + void shouldValidateArtifactUsingMultipleValidatorsAndSendStatusIfPulledArtifactsListContainsMultipleArtifacts() { + ArtifactsValidator extraArtifactsValidator = mock(ArtifactsValidator.class); + testClientCallback(3, extraArtifactsValidator); + } + + private void testClientCallback(int numberOfPulledArtefacts, ArtifactsValidator... extraValidators) { + // given + validators.addAll(Arrays.asList(extraValidators)); + final INotificationData service = new Service(numberOfPulledArtefacts); + ExpectedTestParameters testParameters = setupCallbackTest(service); + + // when + callback.activateCallback(service); + + // then + verifyMockedMethodCalls(testParameters, numberOfPulledArtefacts); + for(ArtifactsValidator validator: extraValidators) { + verify(validator, times(1)).validate(eq(testParameters.getExpectedPulledArtifacts())); + } + } + + private ExpectedTestParameters setupCallbackTest(INotificationData service) { + final List expectedArtifactsList = service.getResources().get(0).getArtifacts(); + + final List expectedPulledArtifacts = new ArrayList<>(); + final List expectedValidationResults = new ArrayList<>(); + for(IArtifactInfo artifactInfo: expectedArtifactsList) { + final Artifact artifact = setUpTestArtifact(artifactInfo); + expectedPulledArtifacts.add(artifact); + final ArtifactValidationResult expectedValidationResult = new ArtifactValidationResult( + artifactInfo, true, artifactInfo.getArtifactName() + " validated", artifactsValidator + ); + expectedValidationResults.add(expectedValidationResult); + } + + when(artifactsCollector.pullArtifacts(expectedArtifactsList)).thenReturn(expectedPulledArtifacts); + when(artifactsValidator.validate(expectedPulledArtifacts)).thenReturn(expectedValidationResults); + + return new ExpectedTestParameters(expectedPulledArtifacts, expectedValidationResults, expectedArtifactsList); + } + + private Artifact setUpTestArtifact(IArtifactInfo artifactInfo) { + final byte[] expectedArtifactContent = ("test content " + artifactInfo.getArtifactName()).getBytes(); + return new Artifact(artifactInfo, expectedArtifactContent); + } + + private void verifyMockedMethodCalls(ExpectedTestParameters testParameters, int numberOfPulledArtifacts) { + verify(artifactsCollector, times(1)).pullArtifacts(eq(testParameters.getExpectedArtifactsList())); + verify(artifactsCollectorStatusSender, times(numberOfPulledArtifacts)).sendDownloadOk(any(), eq(testParameters.getExpectedArtifactsList())); + verify(validationStatusSender, times(1)).send(any(), eq(testParameters.getExpectedValidationResults())); + validators.forEach(validator -> verify(validator, times(1)).validate(eq(testParameters.getExpectedPulledArtifacts()))); + } + + @Getter + @AllArgsConstructor + private static class ExpectedTestParameters { + final private List expectedPulledArtifacts; + final private List expectedValidationResults; + final private List expectedArtifactsList; + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSenderTest.java b/src/test/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSenderTest.java new file mode 100644 index 0000000..e4bb504 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSenderTest.java @@ -0,0 +1,84 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.notification; + +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.consumer.IConfiguration; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.impl.DistributionClientResultImpl; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.service.testModel.ArtifactInfo; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; +import org.onap.ves.openapi.manager.service.validation.SchemaReferenceValidator; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ValidationStatusSenderTest { + + private final ArtifactsValidator validator = mock(SchemaReferenceValidator.class); + private final IConfiguration configuration = mock(IConfiguration.class); + private final DistributionClientImpl distributionClient = mock(DistributionClientImpl.class); + private final ValidationStatusSender statusSender = new ValidationStatusSender(distributionClient); + + @Test + void shouldSendValidationStatusForEachValidationResult() { + //given + String distributionId = "distribution-id"; + String consumerId = "ves-consumer"; + + DistributionClientResultImpl sendingResult = + new DistributionClientResultImpl(DistributionActionResultEnum.SUCCESS, "sample-message"); + List expectedSendingResults = List.of(sendingResult, sendingResult); + + ArtifactInfo artifact = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List validationResults = getValidationResults(artifact); + + when(distributionClient.sendDeploymentStatus(any())).thenReturn(sendingResult); + when(distributionClient.sendDeploymentStatus(any(), anyString())).thenReturn(sendingResult); + when(distributionClient.getConfiguration()).thenReturn(configuration); + when(configuration.getConsumerID()).thenReturn(consumerId); + + //when + List sendingResults = statusSender.send(distributionId, validationResults); + + //then + assertThat(sendingResults).isEqualTo(expectedSendingResults); + + } + + private List getValidationResults(ArtifactInfo artifactInfo) { + ArtifactValidationResult validationResultValid = new ArtifactValidationResult(artifactInfo, true, + "sample-message", validator); + ArtifactValidationResult validationResultInvalid = new ArtifactValidationResult(artifactInfo, false, + "sample-message", validator); + return List.of(validationResultValid, validationResultInvalid); + } + +} \ No newline at end of file diff --git a/src/test/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializerTest.java b/src/test/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializerTest.java new file mode 100644 index 0000000..6b16c89 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializerTest.java @@ -0,0 +1,84 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.serialization; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.onap.ves.openapi.manager.model.SchemaMap; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +class SchemaMapDeserializerTest { + + final ObjectMapper objectMapper = new ObjectMapper(); + private final SchemaMapDeserializer deserializer = + new SchemaMapDeserializer(objectMapper); + + @Test + void shouldReturnSchemaMapFromFileWhenFileExists() { + //given + List expectedPublicURLs = getExpectedPublicURLs(); + List expectedLocalURLs = getExpectedLocalURLs(); + String schemaMapPath = "src/test/resources/test-schema-map.json"; + + //when + SchemaMap schemaMap = deserializer.getSchemaMapFromFile(schemaMapPath); + + //then + assertThat(schemaMap.getMappings().size()).isEqualTo(3); + assertThat(schemaMap.getMappings().stream().map(SchemaMap.Mapping::getPublicURL).collect(Collectors.toList())) + .isEqualTo(expectedPublicURLs); + assertThat(schemaMap.getMappings().stream().map(SchemaMap.Mapping::getLocalURL).collect(Collectors.toList())) + .isEqualTo(expectedLocalURLs); + } + + @Test + void shouldReturnEmptySchemaMapWhenFileDoesNotExist() { + //given + String schemaMapPath = "src/test/resources/not-existing-schema-map.yaml"; + + //when + SchemaMap schemaMap = deserializer.getSchemaMapFromFile(schemaMapPath); + + //then + assertThat(schemaMap.getMappings().size()).isZero(); + } + + private List getExpectedPublicURLs() { + return List.of( + "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml", + "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", + "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml" + ); + } + + private List getExpectedLocalURLs() { + return List.of( + "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml", + "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", + "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml" + ); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializerTest.java b/src/test/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializerTest.java new file mode 100644 index 0000000..6c35b18 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializerTest.java @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.serialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.function.Predicate; + +import static org.assertj.core.api.Assertions.assertThat; + +class VesEventsArtifactDeserializerTest { + + private static final String EVENT_DOMAIN_PATH = "/event/structure/commonEventHeader/structure/domain/value"; + private static final String STND_DEFINED_DOMAIN = "stndDefined"; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final VesEventsArtifactDeserializer deserializer = new VesEventsArtifactDeserializer(objectMapper); + + + @Test + void shouldReturnObjectNodesPerEachYamlDocumentWhenByteCodeIsCorrect() throws IOException { + //given + byte[] bytecode = Files.readAllBytes(Paths.get("src/test/resources/ves_artifact_stndDefined_events.yaml")); + int expectedDocuments = 3; + + //when + List objectNodes = deserializer.deserializeMultiDocumentYaml(bytecode); + + //then + assertThat(objectNodes.size()).isEqualTo(expectedDocuments); + assertThat(objectNodes).anyMatch(isStndDefinedEvent()); + } + + @Test + void shouldReturnEmptyListWhenInvalidYamlByteCodeIsGiven() { + //given + byte[] invalidBytecode = new byte[] {'i','n','v','a','l','i', 'd'}; + //when + List objectNodes = deserializer.deserializeMultiDocumentYaml(invalidBytecode); + + //then + assertThat(objectNodes.size()).isZero(); + } + + private Predicate isStndDefinedEvent() { + return event -> event.at(EVENT_DOMAIN_PATH).asText() + .equals(STND_DEFINED_DOMAIN); + } + +} \ No newline at end of file diff --git a/src/test/java/org/onap/ves/openapi/manager/service/testModel/ArtifactInfo.java b/src/test/java/org/onap/ves/openapi/manager/service/testModel/ArtifactInfo.java new file mode 100644 index 0000000..5c7ea56 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/testModel/ArtifactInfo.java @@ -0,0 +1,121 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.testModel; + +import org.onap.sdc.api.notification.IArtifactInfo; + +import java.util.ArrayList; +import java.util.List; + + +public class ArtifactInfo implements IArtifactInfo { + + private final String artifactName; + private final String artifactType; + private final String artifactURL; + private String artifactChecksum; + private Integer artifactTimeout; + private String artifactDescription; + private String artifactVersion; + private String artifactUUID; + private IArtifactInfo generatedArtifact; + private List relatedArtifacts; + + public ArtifactInfo(String artifactType) { + this.artifactName = "artifact-name"; + this.artifactType = artifactType; + this.artifactURL = "http://artifact-url:1234/test"; + } + + private ArtifactInfo(IArtifactInfo iArtifactInfo) { + artifactName = iArtifactInfo.getArtifactName(); + artifactType = iArtifactInfo.getArtifactType(); + artifactURL = iArtifactInfo.getArtifactURL(); + artifactChecksum = iArtifactInfo.getArtifactChecksum(); + artifactDescription = iArtifactInfo.getArtifactDescription(); + artifactTimeout = iArtifactInfo.getArtifactTimeout(); + artifactVersion = iArtifactInfo.getArtifactVersion(); + artifactUUID = iArtifactInfo.getArtifactUUID(); + generatedArtifact = iArtifactInfo.getGeneratedArtifact(); + relatedArtifacts = iArtifactInfo.getRelatedArtifacts(); + + } + + @Override + public String getArtifactName() { + return artifactName; + } + + @Override + public String getArtifactType() { + return artifactType; + } + + @Override + public String getArtifactURL() { + return artifactURL; + } + + @Override + public String getArtifactChecksum() { + return artifactChecksum; + } + + @Override + public Integer getArtifactTimeout() { + return artifactTimeout; + } + + @Override + public String getArtifactDescription() { + return artifactDescription; + } + + @Override + public String getArtifactVersion() { + return artifactVersion; + } + + @Override + public String getArtifactUUID() { + return artifactUUID; + } + + @Override + public IArtifactInfo getGeneratedArtifact() { + return generatedArtifact; + } + + @Override + public List getRelatedArtifacts() { + return relatedArtifacts; + } + + public static List convertToArtifactInfoImpl(List list) { + List ret = new ArrayList<>(); + if (list != null) { + for (IArtifactInfo artifactInfo : list) { + ret.add(new ArtifactInfo(artifactInfo)); + } + } + return ret; + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/testModel/Resource.java b/src/test/java/org/onap/ves/openapi/manager/service/testModel/Resource.java new file mode 100644 index 0000000..130de6f --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/testModel/Resource.java @@ -0,0 +1,161 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.testModel; + +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.IResourceInstance; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Resource implements IResourceInstance { + + private String resourceInstanceName; + private String resourceCustomizationUUID; + private String resourceName; + private String resourceVersion; + private String resourceType; + private String resourceUUID; + private String resourceInvariantUUID; + private String category; + private String subcategory; + private List artifacts; + + public Resource(int numberOfArtifacts) { + this.artifacts = Stream.generate(() -> new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE)) + .limit(numberOfArtifacts) + .collect(Collectors.toList()); + } + + public Resource() { + this.artifacts = List.of(new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE)); + } + + private Resource(IResourceInstance resourceInstance) { + resourceInstanceName = resourceInstance.getResourceInstanceName(); + resourceCustomizationUUID = resourceInstance.getResourceCustomizationUUID(); + resourceName = resourceInstance.getResourceName(); + resourceVersion = resourceInstance.getResourceVersion(); + resourceType = resourceInstance.getResourceType(); + resourceUUID = resourceInstance.getResourceUUID(); + resourceInvariantUUID = resourceInstance.getResourceInvariantUUID(); + category = resourceInstance.getCategory(); + subcategory = resourceInstance.getSubcategory(); + artifacts = ArtifactInfo.convertToArtifactInfoImpl(resourceInstance.getArtifacts()); + } + + public static List convertToJsonContainer(List resources) { + return resources.stream().map(Resource::new).collect(Collectors.toList()); + } + + @Override + public String getResourceInstanceName() { + return resourceInstanceName; + } + + public void setResourceInstanceName(String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + } + + @Override + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + @Override + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + @Override + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + @Override + public String getResourceUUID() { + return resourceUUID; + } + + public void setResourceUUID(String resourceUUID) { + this.resourceUUID = resourceUUID; + } + + @Override + public List getArtifacts() { + return List.copyOf(artifacts); + } + + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + + public List getArtifactsImpl() { + return artifacts; + } + + @Override + public String getResourceInvariantUUID() { + return resourceInvariantUUID; + } + + public void setResourceInvariantUUID(String resourceInvariantUUID) { + this.resourceInvariantUUID = resourceInvariantUUID; + } + + public String getResourceCustomizationUUID() { + return resourceCustomizationUUID; + } + + public void setResourceCustomizationUUID(String resourceCustomizationUUID) { + this.resourceCustomizationUUID = resourceCustomizationUUID; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubcategory() { + return subcategory; + } + + public void setSubcategory(String subcategory) { + this.subcategory = subcategory; + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/testModel/Service.java b/src/test/java/org/onap/ves/openapi/manager/service/testModel/Service.java new file mode 100644 index 0000000..0dae772 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/testModel/Service.java @@ -0,0 +1,136 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.ves.openapi.manager.service.testModel; + +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.notification.IResourceInstance; + +import java.util.ArrayList; +import java.util.List; + +public class Service implements INotificationData { + + private String distributionID; + private String serviceName; + private String serviceVersion; + private String serviceUUID; + private String serviceDescription; + private String serviceInvariantUUID; + private List resources; + private List serviceArtifacts; + private String workloadContext; + + public Service(int numberOfArtifacts) { + this.resources = List.of(new Resource(numberOfArtifacts)); + this.serviceUUID = "UUID"; + this.serviceName = "testService"; + } + + public Service() { + this.resources = List.of(new Resource()); + this.serviceUUID = "UUID"; + this.serviceName = "testService"; + } + + @Override + public String getDistributionID() { + return distributionID; + } + + @Override + public String getServiceName() { + return serviceName; + } + + @Override + public String getServiceVersion() { + return serviceVersion; + } + + @Override + public String getServiceUUID() { + return serviceUUID; + } + + public String getServiceDescription() { + return serviceDescription; + } + + @Override + public String getWorkloadContext() { + return workloadContext; + } + + @Override + public void setWorkloadContext(String workloadContext) { + this.workloadContext = workloadContext; + } + + @Override + public String toString() { + return "NotificationDataImpl [distributionID=" + distributionID + ", serviceName=" + serviceName + + ", serviceVersion=" + serviceVersion + ", serviceUUID=" + serviceUUID + ", serviceDescription=" + + serviceDescription + ", serviceInvariantUUID=" + serviceInvariantUUID + ", resources=" + resources + + ", serviceArtifacts=" + serviceArtifacts + ", workloadContext=" + workloadContext + "]"; + } + + @Override + public List getResources() { + return List.copyOf(resources); + } + + @Override + public List getServiceArtifacts() { + return List.copyOf(serviceArtifacts); + } + + @Override + public String getServiceInvariantUUID() { + return serviceInvariantUUID; + } + + @Override + public IArtifactInfo getArtifactMetadataByUUID(String artifactUUID) { + IArtifactInfo ret = findArtifactInfoByUUID(artifactUUID, serviceArtifacts); + if (ret == null && resources != null) { + for (Resource currResourceInstance : resources) { + ret = findArtifactInfoByUUID(artifactUUID, currResourceInstance.getArtifactsImpl()); + if (ret != null) { + break; + } + } + } + return ret; + } + + private IArtifactInfo findArtifactInfoByUUID(String artifactUUID, List listToCheck) { + IArtifactInfo ret = null; + if (listToCheck != null) { + for (IArtifactInfo curr : listToCheck) { + if (curr.getArtifactUUID().equals(artifactUUID)) { + ret = curr; + break; + } + } + } + return ret; + } +} diff --git a/src/test/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidatorTest.java b/src/test/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidatorTest.java new file mode 100644 index 0000000..fc17564 --- /dev/null +++ b/src/test/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidatorTest.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ves.openapi.manager.service.validation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.util.Strings; +import org.junit.jupiter.api.Test; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.config.ValidatorProperties; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.service.serialization.SchemaMapDeserializer; +import org.onap.ves.openapi.manager.service.serialization.VesEventsArtifactDeserializer; +import org.onap.ves.openapi.manager.service.testModel.ArtifactInfo; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class SchemaReferenceValidatorTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + private final VesEventsArtifactDeserializer vesEventsArtifactDeserializer = + new VesEventsArtifactDeserializer(objectMapper); + private final SchemaMapDeserializer schemaMapDeserializer = new SchemaMapDeserializer(objectMapper); + private final String schemaMapPath = "src/test/resources/test-schema-map.json"; + private final String eventDomain = "/event/structure/commonEventHeader/structure/domain/value"; + private final String schemaReference = "/event/structure/stndDefinedFields/structure/schemaReference/value"; + private final ValidatorProperties validatorProperties = mock(ValidatorProperties.class); + + private final SchemaReferenceValidator validator = new SchemaReferenceValidator(vesEventsArtifactDeserializer, + schemaMapDeserializer, validatorProperties); + + @Test + void shouldReturnSuccessValidationResultWhenValidVesArtifactIsGiven() throws IOException { + //given + ArtifactInfo artifactInfo = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = getArtifacts(artifactInfo, + "src/test/resources/ves_artifact_stndDefined_events.yaml"); + List expectedValidationResults = + getExpectedResults(artifactInfo, true, Strings.EMPTY); + + when(validatorProperties.getSchemaMapPath()).thenReturn(schemaMapPath); + when(validatorProperties.getEventDomainPath()).thenReturn(eventDomain); + when(validatorProperties.getEventSchemaReferencePath()).thenReturn(schemaReference); + + //when + List validationResults = validator.validate(artifacts); + + //then + assertThat(validationResults).isEqualTo(expectedValidationResults); + } + + @Test + void shouldReturnFailedValidationResultWhenInvalidVesArtifactIsGiven() throws IOException { + //given + ArtifactInfo artifactInfo = new ArtifactInfo(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE); + List artifacts = getArtifacts(artifactInfo, + "src/test/resources/ves_artifact_invalid_stndDefined_events.yaml"); + List expectedValidationResults = getExpectedResults(artifactInfo, false, + SchemaReferenceValidator.SCHEMA_REFERENCE_ERROR_MESSAGE); + + when(validatorProperties.getSchemaMapPath()).thenReturn(schemaMapPath); + when(validatorProperties.getEventDomainPath()).thenReturn(eventDomain); + when(validatorProperties.getEventSchemaReferencePath()).thenReturn(schemaReference); + + //when + List validationResults = validator.validate(artifacts); + List validationResultsMessages = + validationResults.stream() + .map(result -> SchemaReferenceValidator.SCHEMA_REFERENCE_ERROR_MESSAGE) + .collect(Collectors.toList()); + + //then + assertThat(validationResults).usingElementComparatorIgnoringFields("message") + .isEqualTo(expectedValidationResults); + assertThat(validationResultsMessages) + .isNotEmpty() + .allMatch(message -> message.contains(SchemaReferenceValidator.SCHEMA_REFERENCE_ERROR_MESSAGE)); + } + + private List getArtifacts(IArtifactInfo artifactInfo, String artifactFilePath) throws IOException { + Path path = Paths.get(artifactFilePath); + byte[] artifactByteCode = Files.readAllBytes(path); + Artifact artifact = new Artifact(artifactInfo, artifactByteCode); + return List.of(artifact); + } + + private List getExpectedResults(IArtifactInfo artifactInfo, boolean isValid, String message) { + ArtifactValidationResult result = new ArtifactValidationResult(artifactInfo, isValid, + message, validator); + return List.of(result); + } +} \ No newline at end of file diff --git a/src/test/resources/test-schema-map.json b/src/test/resources/test-schema-map.json new file mode 100644 index 0000000..2317f9f --- /dev/null +++ b/src/test/resources/test-schema-map.json @@ -0,0 +1,14 @@ +[ + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml" + } +] \ No newline at end of file diff --git a/src/test/resources/ves_artifact_invalid_stndDefined_events.yaml b/src/test/resources/ves_artifact_invalid_stndDefined_events.yaml new file mode 100644 index 0000000..08d4716 --- /dev/null +++ b/src/test/resources/ves_artifact_invalid_stndDefined_events.yaml @@ -0,0 +1,107 @@ +--- +event: + presence: required + action: [ any, any, null, null, null ] + comment: " + ALARM NAME: LogHasReachedFullCapacity, + ALARM DESCRIPTION: 'Log Has Reached Full Capacity', + ALARM EFFECT: 'See alarm OPI x/2223-ABC 123 4567/1 Uen', + MANAGED OBJECT CLASSES: Log, + EVENT TYPE: 'PROCESSINGERRORALARM', + PROBABLE CAUSE: 'FileError', + PROPOSED REPAIR ACTIONS: 'See alarm OPI x/3334-ABC 123 4567/1 Uen', + CLEARING TYPE: Automatic + " + structure: + commonEventHeader: + presence: required + structure: + version: {presence: required, value: 4.0.1} + vesEventListenerVersion: {presence: required, value: 7.0.1} + domain: {presence: required, value: fault} + eventName: {presence: required, value: Fault_MyPnf-Acme_LogHasReachedFullCapacity} + eventId: {presence: required} + sequence: {presence: required} + priority: {presence: required, value: Normal} + reportingEntityName: {presence: required} + sourceName: {presence: required} + nfVendorName: {presence: required, value: Acme} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + timeZoneOffset: {presence: required} + faultFields: + presence: required + structure: + faultFieldsVersion: {presence: required, value: 4.0} + alarmCondition: {presence: required, value: 'LogHasReachedFullCapacity'} + eventCategory: {presence: required, value: 'PROCESSINGERRORALARM'} + eventSourceType: {presence: required} + specificProblem: {presence: required, value: 'Log Has Reached Full Capacity'} + eventSeverity: {presence: required} + vfStatus: {presence: required, value: Active} + alarmAdditionalInformation: {presence: required, structure: { + keyValuePair: {presence: required, structure: {key: {presence: required, value: source},value: {presence: required}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: probableCause},value: {presence: required, value: 'FileError'}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalText},value: {presence: optional}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalInfo},value: {presence: optional}}}} + } +... +--- +event: + presence: required + comment: "stndDefined event to support 3GPP FaultSupervision NotifyNewAlarm notification" + structure: + commonEventHeader: + presence: required + structure: + domain: {presence: required, value: stndDefined} + eventName: {presence: required, value: stndDefined-gNB-Nokia-Notification} + priority: {presence: required, value: Normal} + eventId: {presence: required} + reportingEntityId: {presence: required} + reportingEntityName: {presence: required} + sequence: {presence: required, value: 0} + sourceId: {presence: required} + sourceName: {presence: required} + version: {presence: required, value: 4.1} + vesEventListenerVersion: {presence: required, value: 7.2} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + stndDefinedNamespace: {presence: required, value: "3GPP-FaultSupervision"} + stndDefinedFields: + presence: required + structure: + schemaReference: { presence: required, value: "https://forge.3gpp.org/rep/invalid" } + data: {presence: required} + stndDefinedFieldsVersion: {presence: required, value: "1.0"} + +... +--- +event: + presence: required + comment: "stndDefined event to support 3GPP FaultSupervision NotifyNewAlarm notification" + structure: + commonEventHeader: + presence: required + structure: + domain: {presence: required, value: stndDefined} + eventName: {presence: required, value: stndDefined-gNB-Nokia-Notification} + priority: {presence: required, value: Normal} + eventId: {presence: required} + reportingEntityId: {presence: required} + reportingEntityName: {presence: required} + sequence: {presence: required, value: 0} + sourceId: {presence: required} + sourceName: {presence: required} + version: {presence: required, value: 4.1} + vesEventListenerVersion: {presence: required, value: 7.2} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + stndDefinedNamespace: {presence: required, value: "3GPP-FaultSupervision"} + stndDefinedFields: + presence: required + structure: + schemaReference: { presence: required, value: ["https://forge.3gpp.org/rep/sa5/MnS/tree/another_invalid.yaml", "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml"] } + data: {presence: required} + stndDefinedFieldsVersion: {presence: required, value: "1.0"} +... \ No newline at end of file diff --git a/src/test/resources/ves_artifact_stndDefined_events.yaml b/src/test/resources/ves_artifact_stndDefined_events.yaml new file mode 100644 index 0000000..11f805b --- /dev/null +++ b/src/test/resources/ves_artifact_stndDefined_events.yaml @@ -0,0 +1,107 @@ +--- +event: + presence: required + action: [ any, any, null, null, null ] + comment: " + ALARM NAME: LogHasReachedFullCapacity, + ALARM DESCRIPTION: 'Log Has Reached Full Capacity', + ALARM EFFECT: 'See alarm OPI x/2223-ABC 123 4567/1 Uen', + MANAGED OBJECT CLASSES: Log, + EVENT TYPE: 'PROCESSINGERRORALARM', + PROBABLE CAUSE: 'FileError', + PROPOSED REPAIR ACTIONS: 'See alarm OPI x/3334-ABC 123 4567/1 Uen', + CLEARING TYPE: Automatic + " + structure: + commonEventHeader: + presence: required + structure: + version: {presence: required, value: 4.0.1} + vesEventListenerVersion: {presence: required, value: 7.0.1} + domain: {presence: required, value: fault} + eventName: {presence: required, value: Fault_MyPnf-Acme_LogHasReachedFullCapacity} + eventId: {presence: required} + sequence: {presence: required} + priority: {presence: required, value: Normal} + reportingEntityName: {presence: required} + sourceName: {presence: required} + nfVendorName: {presence: required, value: Acme} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + timeZoneOffset: {presence: required} + faultFields: + presence: required + structure: + faultFieldsVersion: {presence: required, value: 4.0} + alarmCondition: {presence: required, value: 'LogHasReachedFullCapacity'} + eventCategory: {presence: required, value: 'PROCESSINGERRORALARM'} + eventSourceType: {presence: required} + specificProblem: {presence: required, value: 'Log Has Reached Full Capacity'} + eventSeverity: {presence: required} + vfStatus: {presence: required, value: Active} + alarmAdditionalInformation: {presence: required, structure: { + keyValuePair: {presence: required, structure: {key: {presence: required, value: source},value: {presence: required}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: probableCause},value: {presence: required, value: 'FileError'}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalText},value: {presence: optional}}}, + keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalInfo},value: {presence: optional}}}} + } +... +--- +event: + presence: required + comment: "stndDefined event to support 3GPP FaultSupervision NotifyNewAlarm notification" + structure: + commonEventHeader: + presence: required + structure: + domain: {presence: required, value: stndDefined} + eventName: {presence: required, value: stndDefined-gNB-Nokia-Notification} + priority: {presence: required, value: Normal} + eventId: {presence: required} + reportingEntityId: {presence: required} + reportingEntityName: {presence: required} + sequence: {presence: required, value: 0} + sourceId: {presence: required} + sourceName: {presence: required} + version: {presence: required, value: 4.1} + vesEventListenerVersion: {presence: required, value: 7.2} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + stndDefinedNamespace: {presence: required, value: "3GPP-FaultSupervision"} + stndDefinedFields: + presence: required + structure: + schemaReference: { presence: required, value: "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml" } + data: {presence: required} + stndDefinedFieldsVersion: {presence: required, value: "1.0"} + +... +--- +event: + presence: required + comment: "stndDefined event to support 3GPP FaultSupervision NotifyNewAlarm notification" + structure: + commonEventHeader: + presence: required + structure: + domain: {presence: required, value: stndDefined} + eventName: {presence: required, value: stndDefined-gNB-Nokia-Notification} + priority: {presence: required, value: Normal} + eventId: {presence: required} + reportingEntityId: {presence: required} + reportingEntityName: {presence: required} + sequence: {presence: required, value: 0} + sourceId: {presence: required} + sourceName: {presence: required} + version: {presence: required, value: 4.1} + vesEventListenerVersion: {presence: required, value: 7.2} + startEpochMicrosec: {presence: required} + lastEpochMicrosec: {presence: required} + stndDefinedNamespace: {presence: required, value: "3GPP-FaultSupervision"} + stndDefinedFields: + presence: required + structure: + schemaReference: { presence: required, value: ["https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml"] } + data: {presence: required} + stndDefinedFieldsVersion: {presence: required, value: "1.0"} +... \ No newline at end of file diff --git a/version.properties b/version.properties new file mode 100644 index 0000000..32acbf9 --- /dev/null +++ b/version.properties @@ -0,0 +1,6 @@ +major=1 +minor=0 +patch=0 +base_version=${major}.${minor}.${patch} +release_version=${base_version} +snapshot_version=${base_version}-SNAPSHOT \ No newline at end of file -- cgit 1.2.3-korg