diff options
Diffstat (limited to 'components/bbs-event-processor')
79 files changed, 10054 insertions, 0 deletions
diff --git a/components/bbs-event-processor/LICENSE.txt b/components/bbs-event-processor/LICENSE.txt new file mode 100644 index 00000000..97ba6f64 --- /dev/null +++ b/components/bbs-event-processor/LICENSE.txt @@ -0,0 +1,36 @@ +/* +* ============LICENSE_START========================================== +* =================================================================== +* Copyright (c) 2019 NOKIA Intellectual Property. All rights reserved. +* =================================================================== +* +* Unless otherwise specified, all software contained herein is licensed +* under the Apache License, Version 2.0 (the "License"); +* you may not use this software 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. +* +* +* +* Unless otherwise specified, all documentation contained herein is licensed +* under the Creative Commons License, Attribution 4.0 Intl. (the "License"); +* you may not use this documentation except in compliance with the License. +* You may obtain a copy of the License at +* +* https://creativecommons.org/licenses/by/4.0/ +* +* Unless required by applicable law or agreed to in writing, documentation +* 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============================================ +*/
\ No newline at end of file diff --git a/components/bbs-event-processor/README.md b/components/bbs-event-processor/README.md new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/components/bbs-event-processor/README.md diff --git a/components/bbs-event-processor/dpo/blueprints/bbs-event-processor-input.yaml b/components/bbs-event-processor/dpo/blueprints/bbs-event-processor-input.yaml new file mode 100644 index 00000000..97bb138e --- /dev/null +++ b/components/bbs-event-processor/dpo/blueprints/bbs-event-processor-input.yaml @@ -0,0 +1,29 @@ +#============LICENSE_START======================================================== +#================================================================================= +# Copyright (c) 2018 AT&T Intellectual Property. 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========================================================= + + +tag_version: nexus3.onap.org:10003/dcae-services/org.onap.dcaegen2.services.components.bbs-event-processor:1.0.0-SNAPSHOT +pnf_reregistration_url: http:message-router:3904/events/unauthenticated.PNF_UPDATE +cpe_authentication_url: http:message-router:3904/events/unauthenticated.CPE_AUTHENTICATION +close_loop_url: http:message-router:3904/events/unauthenticated.DCAE_CL_OUTPUT +application_rereg_policy_scope: policyScopeReReg +application_rereg_cl_control_name: clControlNameReReg +application_cpeAuth_policy_scope: policyScopeCpeAuth +application_cpeAuth_cl_control_name: clControlNameCpeAuth +application_cbs_polling_interval_sec: 120 +dmaap_consumer_id: c12 +dmaap_consumer_group: OpenDcae-c12 diff --git a/components/bbs-event-processor/dpo/blueprints/k8s-bbs-event-processor.yaml-template b/components/bbs-event-processor/dpo/blueprints/k8s-bbs-event-processor.yaml-template new file mode 100644 index 00000000..3468d7f6 --- /dev/null +++ b/components/bbs-event-processor/dpo/blueprints/k8s-bbs-event-processor.yaml-template @@ -0,0 +1,130 @@ +# -*- indent-tabs-mode: nil -*- # vi: set expandtab: +# +# ============LICENSE_START==================================================== +# ============================================================================= +# Copyright (c) 2019 AT&T, NOKIA +# ============================================================================= +# 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====================================================== + +tosca_definitions_version: cloudify_dsl_1_3 + +imports: + - "http://www.getcloudify.org/spec/cloudify/3.4/types.yaml" + - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2_platform_plugins_releases }}/k8splugin/1.4.5/k8splugin_types.yaml + +inputs: + aai_enrichment_host: + type: string + default: "aai" + aai_enrichment_port: + type: integer + default: 8443 + aai_enrichment_protocol: + type: string + default: "https" + tag_version: + type: string + replicas: + type: integer + description: number of instances + default: 1 + host_port: + description: port on Kubernetes host where bbs-event-processor API will be exposed + default: 0 + pnf_reregistration_url: + type: string + cpe_authentication_url: + type: string + close_loop_url: + type: string + application_rereg_policy_scope: + description: Policy Scope value for building PNF relocation CL event + type: string + application_rereg_cl_control_name: + description: Close Loop control name value for building PNF relocation CL event + type: string + application_cpeAuth_policy_scope: + description: Policy Scope value for building CPE Authentication CL event + type: string + application_cpeAuth_cl_control_name: + description: Close Loop control name value for building CPE Authentication CL event + type: string + application_cbs_polling_interval_sec: + type: integer + default: 300 + dmaap_consumer_id: + type: string + dmaap_consumer_group: + type: string +node_templates: + bbs-event-processor: + type: dcae.nodes.ContainerizedPlatformComponent + properties: + application_config: + streams_subscribes: + pnf_reregistration: + type: message_router + dmaap_info: + topic_url: { get_input: pnf_reregistration_url } + cpe_authentication: + type: message_router + dmaap_info: + topic_url: { get_input: cpe_authentication_url } + streams_publishes: + close_loop: + type: message_router + dmaap_info: + topic_url: { get_input: close_loop_url } + dmaap.protocol: "http" + dmaap.contentType: "application/json" + dmaap.consumer.consumerId: { get_input: dmaap_consumer_id } + dmaap.consumer.consumerGroup: { get_input: dmaap_consumer_group } + dmaap.messageLimit: -1 + dmaap.timeoutMs: -1 + aai.host: { get_input: aai_enrichment_host } + aai.port: { get_input: aai_enrichment_port } + aai.protocol: { get_input: aai_enrichment_protocol } + aai.username: "AAI" + aai.password: "AAI" + aai.aaiIgnoreSslCertificateErrors: true + application.pipelinesPollingIntervalSec: 30 + application.pipelinesTimeoutSec: 15 + application.cbsPollingIntervalSec: { get_input: application_cbs_polling_interval_sec } + application.reregistration.policyScope: { get_input: application_rereg_policy_scope } + application.reregistration.clControlName: { get_input: application_rereg_cl_control_name } + application.cpe.authentication.policyScope: { get_input: application_cpeAuth_policy_scope } + application.cpe.authentication.clControlName: { get_input: application_cpeAuth_cl_control_name } + application.reregistration.configKey: "pnf_reregistration" + application.cpeAuth.configKey: "cpe_authentication" + application.closeLoop.configKey: "close_loop" + host_port: + { get_input: host_port } + container_port: + 8100 + docker_config: + healthcheck: + endpoint: /heartbeat + interval: 180s + timeout: 5s + type: http + image: + { get_input: tag_version } + replicas: {get_input: replicas} + name: 'bbs-event-processor' + dns_name: 'bbs-event-processor' + log_info: + log_directory: "/opt/app/bbs-event-processor/logs" + tls_info: + cert_directory: '/opt/app/bbs-event-processor/etc/cert/' + use_tls: false diff --git a/components/bbs-event-processor/dpo/data-formats/aai-interaction.json b/components/bbs-event-processor/dpo/data-formats/aai-interaction.json new file mode 100644 index 00000000..e502d866 --- /dev/null +++ b/components/bbs-event-processor/dpo/data-formats/aai-interaction.json @@ -0,0 +1,11 @@ +{ + "self": { + "name": "AAI_Interaction", + "version": "1.0.0", + "description": "Messages exchanged between a microservice and AAI" + }, + "dataformatversion": "1.0.0", + "unstructured": { + "encoding": "UTF-8" + } +} diff --git a/components/bbs-event-processor/dpo/data-formats/pnf-reregistration.json b/components/bbs-event-processor/dpo/data-formats/pnf-reregistration.json new file mode 100644 index 00000000..f6fcbe6d --- /dev/null +++ b/components/bbs-event-processor/dpo/data-formats/pnf-reregistration.json @@ -0,0 +1,11 @@ +{ + "self": { + "name": "PNF_Reregistration_internal", + "version": "1.0.0", + "description": "Internal event sent by PRH for PNF re-registration" + }, + "dataformatversion": "1.0.0", + "unstructured": { + "encoding": "UTF-8" + } +} diff --git a/components/bbs-event-processor/dpo/spec/bbs-event-processor-spec.json b/components/bbs-event-processor/dpo/spec/bbs-event-processor-spec.json new file mode 100644 index 00000000..b1329bef --- /dev/null +++ b/components/bbs-event-processor/dpo/spec/bbs-event-processor-spec.json @@ -0,0 +1,251 @@ +{ + "self": { + "version": "1.0.0", + "name": "dcae-bbs-event-processor", + "description": "Processes events for PNF relocation and CPE authentication", + "component_type": "docker" + }, + "streams": { + "subscribes": [ + { + "format": "PNF_Reregistration_internal", + "version": "1.0.0", + "type": "message_router", + "config_key" : "pnf_reregistration" + }, + { + "format": "VES_specification", + "version": "7.30.1", + "type": "message_router", + "config_key" : "cpe_authentication" + } + ], + "publishes": [ + { + "format": "DCAE_CL_Output", + "version": "1.0.1", + "type": "message_router", + "config_key": "close_loop" + } + ] + }, + "services": { + "calls": [ + { + "config_key": "aai-interaction", + "request": { + "format": "AAI_Interaction", + "version": "1.0.0" + }, + "response": { + "format": "AAI_Interaction", + "version": "1.0.0" + } + } + ], + "provides": [] + }, + "parameters": [ + { + "name": "dmaap.protocol", + "value": "http", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "DmaaP protocol used for any DMaaP interaction" + }, + { + "name": "dmaap.contentType", + "value": "application/json", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "DmaaP content type" + }, + { + "name": "dmaap.consumer.consumerId", + "value": "c12", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "DmaaP consumer consumer ID" + }, + { + "name": "dmaap.consumer.consumerGroup", + "value": "OpenDcae-c12", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "DmaaP consumer consumer group" + }, + { + "name": "dmaap.messageLimit", + "value": 1, + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "DmaaP message limit" + }, + { + "name": "dmaap.timeoutMs", + "value": -1, + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "DmaaP timeout in millis" + }, + { + "name": "aai.host", + "value": "aai.onap.svc.cluster.local", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "AAI enrichment host" + }, + { + "name": "aai.port", + "value": 8443, + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "AAI enrichment port" + }, + { + "name": "aai.protocol", + "value": "https", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "AAI protocol" + }, + { + "name": "aai.username", + "value": "AAI", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "AAI username" + }, + { + "name": "aai.password", + "value": "AAI", + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "AAI password" + }, + { + "name": "aai.aaiIgnoreSslCertificateErrors", + "value": true, + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "Ignore SSL Certificate errors for AAI" + }, + { + "name": "application.pipelinesPollingIntervalSec", + "value": 30, + "constraints": [ + { + "greater_or_equal": 15 + } + ], + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "Polling interval in seconds for executing event processing reactive pipelines" + }, + { + "name": "application.pipelinesTimeoutSec", + "value": 15, + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": false, + "description": "Timeout in seconds to wait in reactive pipelines processing" + }, + { + "name": "application.cbsPollingIntervalSec", + "value": 300, + "constraints": [ + { + "greater_or_equal": 20 + } + ], + "designer_editable": true, + "policy_editable": false, + "sourced_at_deployment": true, + "description": "Polling interval in seconds for fetching configuration from Consul via CBS service" + }, + { + "name": "application.reregistration.policyScope", + "value": "policyScope", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Hard-coded value for Policy Scope parameter in Policy triggering event to be published" + }, + { + "name": "application.reregistration.clControlName", + "value": "controlName", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Hard-coded value for CL control name parameter in Policy triggering event to be published" + }, + { + "name": "application.cpe.authentication.policyScope", + "value": "policyScope", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Hard-coded value for CL control nam parameter in Policy triggering event to be published" + }, + { + "name": "application.cpe.authentication.clControlName", + "value": "controlName", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Hard-coded value for CL control nam parameter in Policy triggering event to be published" + }, + { + "name": "application.reregistration.configKey", + "value": "pnf_reregistration", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Config-key for PNF re-registration" + } + , + { + "name": "application.cpeAuth.configKey", + "value": "cpe_authentication", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Config-key for CPE authentication" + }, + { + "name": "application.closeLoop.configKey", + "value": "close_loop", + "designer_editable": false, + "policy_editable": true, + "sourced_at_deployment": true, + "description": "Config-key for Close Loop" + } + ], + "auxilary": { + "healthcheck": { + "type": "http", + "interval": "180s", + "timeout": "5s", + "endpoint": "/heartbeat" + } + }, + "artifacts": [ + { + "uri": "nexus3.onap.org:10003/dcae-services/org.onap.dcaegen2.services.components.bbs-event-processor:1.0.0-SNAPSHOT", + "type": "docker image" + } + ] +} diff --git a/components/bbs-event-processor/pom.xml b/components/bbs-event-processor/pom.xml new file mode 100644 index 00000000..8ee2e22e --- /dev/null +++ b/components/bbs-event-processor/pom.xml @@ -0,0 +1,401 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.oparent</groupId> + <artifactId>oparent</artifactId> + <version>1.2.3</version> + </parent> + + <groupId>org.onap.dcaegen2.services.components</groupId> + <artifactId>bbs-event-processor</artifactId> + <version>1.0.0-SNAPSHOT</version> + + <name>bbs-event-processor</name> + <description>BBS Re-Registration and CPE Authentication Handler</description> + <packaging>jar</packaging> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <properties> + <java.version>8</java.version> + <immutables.version>2.7.5</immutables.version> + <spring.version>5.1.2.RELEASE</spring.version> + <spring-boot.version>2.1.0.RELEASE</spring-boot.version> + <tomcat.version>8.5.32</tomcat.version> + <slf4j.version>1.7.25</slf4j.version> + <junit-platform.version>1.1.0</junit-platform.version> + <jacoco.version>0.8.2</jacoco.version> + <sdk.version>1.1.2-SNAPSHOT</sdk.version> + <common.sdk.version>1.1.3</common.sdk.version> + <cbs.version>1.1.3</cbs.version> + <hibernate-validator.version>5.2.4.Final</hibernate-validator.version> + <wiremock.version>2.21.0</wiremock.version> + <springfox-swagger.version>2.8.0</springfox-swagger.version> + <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + <bbs-event-processor.main.class>org.onap.bbs.event.processor.Application</bbs-event-processor.main.class> + <dependency.dir.name>libs</dependency.dir.name> + <dependency.dir.location>${project.build.directory}/${dependency.dir.name}</dependency.dir.location> + <docker.artifact.dir>/opt</docker.artifact.dir> + <docker.image.name>dcae-services/${project.groupId}.${project.artifactId}</docker.image.name> + <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>cbs-client</artifactId> + <version>${cbs.version}</version> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>aai-client</artifactId> + <version>${sdk.version}</version> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>dmaap-client</artifactId> + <version>${sdk.version}</version> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>common-dependency</artifactId> + <version>${common.sdk.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${springfox-swagger.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${springfox-swagger.version}</version> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + <version>${immutables.version}</version> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>gson</artifactId> + <version>${immutables.version}</version> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-validator</artifactId> + <version>${hibernate-validator.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>${spring-boot.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock-jre8</artifactId> + <version>${wiremock.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>cbs-client</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>aai-client</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>dmaap-client</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>common-dependency</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + </dependency> + <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-el</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-websocket</artifactId> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-validator</artifactId> + </dependency> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock-jre8</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.7.0</version> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + <encoding>${project.build.sourceEncoding}</encoding> + <showWarnings>true</showWarnings> + <showDeprecation>true</showDeprecation> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>3.1.0</version> + <configuration> + <encoding>${project.build.sourceEncoding}</encoding> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${spring-boot.version}</version> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + <version>2.2.6</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.1.1</version> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.2.0</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.19.1</version> + <dependencies> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-surefire-provider</artifactId> + <version>${junit-platform.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </pluginManagement> + <plugins> + <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + <configuration> + <dateFormat>${maven.build.timestamp.format}</dateFormat> + <generateGitPropertiesFile>true</generateGitPropertiesFile> + <format>json</format> + <generateGitPropertiesFilename>${project.build.outputDirectory}/git_info.json</generateGitPropertiesFilename> + </configuration> + <executions> + <execution> + <id>get-git-info</id> + <goals> + <goal>revision</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <classpathPrefix>./${dependency.dir.name}/</classpathPrefix> + <useUniqueVersions>false</useUniqueVersions> + <mainClass>${bbs-event-processor.main.class}</mainClass> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + </manifest> + <manifestEntries> + <Build-Time>${maven.build.timestamp}</Build-Time> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <configuration> + <outputDirectory>${dependency.dir.location}</outputDirectory> + <includeScope>runtime</includeScope> + <silent>true</silent> + </configuration> + <executions> + <execution> + <id>copy-external-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <configuration> + <serverId>${onap.nexus.dockerregistry.daily}</serverId> + <imageName>${docker.image.name}</imageName> + <imageTags> + <tag>latest</tag> + </imageTags> + <baseImage>openjdk:${java.version}-jre-alpine</baseImage> + <workdir>${docker.artifact.dir}</workdir> + <resources> + <resource> + <directory>${dependency.dir.location}</directory> + <targetPath>${dependency.dir.name}</targetPath> + </resource> + <resource> + <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> + </resource> + </resources> + <exposes> + <expose>8100</expose> + </exposes> + <entryPoint>["java", "-jar", "${project.build.finalName}.jar"]</entryPoint> + </configuration> + <executions> + <execution> + <id>build-bbs-event-processor-image</id> + <phase>deploy</phase> + <goals> + <goal>build</goal> + </goals> + </execution> + <execution> + <id>tag-and-push-image-with-version</id> + <phase>deploy</phase> + <goals> + <goal>tag</goal> + </goals> + <configuration> + <image>${docker.image.name}:latest</image> + <newName>${onap.nexus.dockerregistry.daily}/${docker.image.name}:${project.version}</newName> + <pushImage>true</pushImage> + </configuration> + </execution> + <execution> + <id>tag-and-push-image-with-version-and-date</id> + <phase>deploy</phase> + <goals> + <goal>tag</goal> + </goals> + <configuration> + <image>${docker.image.name}:latest</image> + <newName>${onap.nexus.dockerregistry.daily}/${docker.image.name}:${project.version}-${maven.build.timestamp}Z</newName> + <pushImage>true</pushImage> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/Application.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/Application.java new file mode 100644 index 00000000..66e1f86d --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/Application.java @@ -0,0 +1,84 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor; + +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.INVOCATION_ID; +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.REQUEST_ID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.Map; +import java.util.ServiceLoader; +import java.util.UUID; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +@SpringBootApplication +@Configuration +public class Application { + + private Logger logger = LoggerFactory.getLogger(Application.class); + + private static final int THREADS_IN_POOL = 5; + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + Map<String, String> mdcContextMap() { + MDC.put(REQUEST_ID, "SampleRequestID"); + MDC.put(INVOCATION_ID, UUID.randomUUID().toString()); + return MDC.getCopyOfContextMap(); + } + + @Bean + Gson gson() { + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + return gsonBuilder.create(); + } + + @Bean + TaskScheduler threadPoolTaskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(THREADS_IN_POOL); + scheduler.setThreadNamePrefix("pipeline-thrd-"); + return scheduler; + } + + @PostConstruct + public void postConstructionSetup() { + logger.info("bbs-event-processor application started"); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientConfiguration.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientConfiguration.java new file mode 100644 index 00000000..93754ebc --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientConfiguration.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import java.io.Serializable; +import java.util.Map; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.springframework.stereotype.Component; + +@Component +@Value.Immutable(prehash = true) +@Value.Style(builder = "new") +@Gson.TypeAdapters +public abstract class AaiClientConfiguration implements Serializable { + + private static final long serialVersionUID = 1L; + + @Value.Parameter + public abstract String aaiHost(); + + @Value.Parameter + public abstract Integer aaiPort(); + + @Value.Parameter + public abstract String aaiProtocol(); + + @Value.Parameter + public abstract String aaiUserName(); + + @Value.Parameter + public abstract String aaiUserPassword(); + + @Value.Parameter + public abstract Boolean aaiIgnoreSslCertificateErrors(); + + @Value.Parameter + public abstract Map<String, String> aaiHeaders(); + + @Value.Parameter + public abstract String trustStorePath(); + + @Value.Parameter + public abstract String trustStorePasswordPath(); + + @Value.Parameter + public abstract String keyStorePath(); + + @Value.Parameter + public abstract String keyStorePasswordPath(); + + @Value.Parameter + public abstract Boolean enableAaiCertAuth(); + +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientProperties.java new file mode 100644 index 00000000..97970c7f --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/AaiClientProperties.java @@ -0,0 +1,66 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import java.util.Map; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.aai.client") +@Getter +@Setter +@Validated +public class AaiClientProperties { + + @NotBlank + private String aaiHost; + + @Min(1025) + @Max(65536) + private int aaiPort; + + @NotBlank + @Pattern(regexp = "(http|https)") + private String aaiProtocol; + + @NotBlank + private String aaiUserName; + + @NotBlank + private String aaiUserPassword; + + private boolean aaiIgnoreSslCertificateErrors; + + @NotNull + private Map<String, String> aaiHeaders; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConfiguration.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConfiguration.java new file mode 100644 index 00000000..5277f3cd --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConfiguration.java @@ -0,0 +1,362 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.onap.bbs.event.processor.config.ApplicationConstants.STREAMS_TYPE; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +import org.onap.bbs.event.processor.exceptions.ApplicationEnvironmentException; +import org.onap.bbs.event.processor.exceptions.ConfigurationParsingException; +import org.onap.bbs.event.processor.model.GeneratedAppConfigObject; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapPublisherConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapPublisherConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ApplicationConfiguration implements ConfigurationChangeObservable { + + private final AaiClientProperties aaiClientProperties; + private final DmaapReRegistrationConsumerProperties dmaapReRegistrationConsumerProperties; + private final DmaapCpeAuthenticationConsumerProperties dmaapCpeAuthenticationConsumerProperties; + private final DmaapProducerProperties dmaapProducerProperties; + private final SecurityProperties securityProperties; + private final GenericProperties genericProperties; + + private DmaapConsumerConfiguration dmaapReRegistrationConsumerConfiguration; + private DmaapConsumerConfiguration dmaapCpeAuthenticationConsumerConfiguration; + private DmaapPublisherConfiguration dmaapPublisherConfiguration; + private AaiClientConfiguration aaiClientConfiguration; + private Set<ConfigurationChangeObserver> observers; + + private int cbsPollingInterval; + + /** + * Construct BBS event processor application configuration object. + * @param aaiClientProperties Properties for AAI client setup + * @param dmaapReRegistrationConsumerProperties Properties for DMaaP client setup (PNF re-registration) + * @param dmaapCpeAuthenticationConsumerProperties Properties for DMaaP client setup (CPE authentication) + * @param dmaapProducerProperties Properties for DMaaP client setup (Close Loop) + * @param securityProperties General security properties + * @param genericProperties General application properties + */ + @Autowired + public ApplicationConfiguration(AaiClientProperties aaiClientProperties, + DmaapReRegistrationConsumerProperties dmaapReRegistrationConsumerProperties, + DmaapCpeAuthenticationConsumerProperties dmaapCpeAuthenticationConsumerProperties, + DmaapProducerProperties dmaapProducerProperties, + SecurityProperties securityProperties, + GenericProperties genericProperties) { + this.aaiClientProperties = aaiClientProperties; + this.dmaapReRegistrationConsumerProperties = dmaapReRegistrationConsumerProperties; + this.dmaapCpeAuthenticationConsumerProperties = dmaapCpeAuthenticationConsumerProperties; + this.dmaapProducerProperties = dmaapProducerProperties; + this.securityProperties = securityProperties; + this.genericProperties = genericProperties; + observers = new HashSet<>(); + constructConfigurationObjects(); + } + + @Override + public synchronized void register(ConfigurationChangeObserver observer) { + observers.add(observer); + } + + @Override + public synchronized void unRegister(ConfigurationChangeObserver observer) { + observers.remove(observer); + } + + @Override + public synchronized void notifyObservers() { + observers.forEach(o -> o.updateConfiguration(this)); + } + + public DmaapConsumerConfiguration getDmaapReRegistrationConsumerConfiguration() { + return dmaapReRegistrationConsumerConfiguration; + } + + public DmaapConsumerConfiguration getDmaapCpeAuthenticationConsumerConfiguration() { + return dmaapCpeAuthenticationConsumerConfiguration; + } + + public DmaapPublisherConfiguration getDmaapPublisherConfiguration() { + return dmaapPublisherConfiguration; + } + + public AaiClientConfiguration getAaiClientConfiguration() { + return aaiClientConfiguration; + } + + public int getPipelinesPollingIntervalInSeconds() { + return genericProperties.getPipelinesPollingIntervalSec(); + } + + public int getPipelinesTimeoutInSeconds() { + return genericProperties.getPipelinesTimeoutSec(); + } + + public int getCbsPollingInterval() { + return cbsPollingInterval; + } + + public String getReRegistrationCloseLoopPolicyScope() { + + return genericProperties.getReRegistration().getPolicyScope(); + } + + public String getReRegistrationCloseLoopControlName() { + return genericProperties.getReRegistration().getClControlName(); + } + + public String getCpeAuthenticationCloseLoopPolicyScope() { + return genericProperties.getCpeAuthentication().getPolicyScope(); + } + + public String getCpeAuthenticationCloseLoopControlName() { + return genericProperties.getCpeAuthentication().getClControlName(); + } + + /** + * Update current configuration based on the new configuration object fetched from Consul via CBS service of DCAE. + * @param newConfiguration updated configuration object + */ + public void updateCurrentConfiguration(GeneratedAppConfigObject newConfiguration) { + + cbsPollingInterval = newConfiguration.cbsPollingIntervalSec(); + + GeneratedAppConfigObject.StreamsObject reRegObject = getStreamsObject(newConfiguration.streamSubscribesMap(), + newConfiguration.reRegConfigKey(), "PNF Re-Registration"); + TopicUrlInfo topicUrlInfo = parseTopicUrl(reRegObject.dmaapInfo().topicUrl()); + dmaapReRegistrationConsumerProperties.setDmaapHostName(topicUrlInfo.getHost()); + dmaapReRegistrationConsumerProperties.setDmaapPortNumber(topicUrlInfo.getPort()); + dmaapReRegistrationConsumerProperties.setDmaapProtocol(newConfiguration.dmaapProtocol()); + dmaapReRegistrationConsumerProperties.setDmaapContentType(newConfiguration.dmaapContentType()); + dmaapReRegistrationConsumerProperties.setDmaapTopicName(topicUrlInfo.getTopicName()); + dmaapReRegistrationConsumerProperties.setConsumerId(newConfiguration.dmaapConsumerConsumerId()); + dmaapReRegistrationConsumerProperties.setConsumerGroup(newConfiguration.dmaapConsumerConsumerGroup()); + dmaapReRegistrationConsumerProperties.setMessageLimit(newConfiguration.dmaapMessageLimit()); + dmaapReRegistrationConsumerProperties.setTimeoutMs(newConfiguration.dmaapTimeoutMs()); + constructDmaapReRegistrationConfiguration(); + + GeneratedAppConfigObject.StreamsObject cpeAuthObject = getStreamsObject(newConfiguration.streamSubscribesMap(), + newConfiguration.cpeAuthConfigKey(), "CPE Authentication"); + topicUrlInfo = parseTopicUrl(cpeAuthObject.dmaapInfo().topicUrl()); + dmaapCpeAuthenticationConsumerProperties.setDmaapHostName(topicUrlInfo.getHost()); + dmaapCpeAuthenticationConsumerProperties.setDmaapPortNumber(topicUrlInfo.getPort()); + dmaapCpeAuthenticationConsumerProperties.setDmaapProtocol(newConfiguration.dmaapProtocol()); + dmaapCpeAuthenticationConsumerProperties.setDmaapContentType(newConfiguration.dmaapContentType()); + dmaapCpeAuthenticationConsumerProperties.setDmaapTopicName(topicUrlInfo.getTopicName()); + dmaapCpeAuthenticationConsumerProperties.setConsumerId(newConfiguration.dmaapConsumerConsumerId()); + dmaapCpeAuthenticationConsumerProperties.setConsumerGroup(newConfiguration.dmaapConsumerConsumerGroup()); + dmaapCpeAuthenticationConsumerProperties.setMessageLimit(newConfiguration.dmaapMessageLimit()); + dmaapCpeAuthenticationConsumerProperties.setTimeoutMs(newConfiguration.dmaapTimeoutMs()); + constructDmaapCpeAuthenticationConfiguration(); + + GeneratedAppConfigObject.StreamsObject closeLoopObject = getStreamsObject(newConfiguration.streamPublishesMap(), + newConfiguration.closeLoopConfigKey(), "Close Loop"); + topicUrlInfo = parseTopicUrl(closeLoopObject.dmaapInfo().topicUrl()); + dmaapProducerProperties.setDmaapHostName(topicUrlInfo.getHost()); + dmaapProducerProperties.setDmaapPortNumber(topicUrlInfo.getPort()); + dmaapProducerProperties.setDmaapProtocol(newConfiguration.dmaapProtocol()); + dmaapProducerProperties.setDmaapContentType(newConfiguration.dmaapContentType()); + dmaapProducerProperties.setDmaapTopicName(topicUrlInfo.getTopicName()); + constructDmaapProducerConfiguration(); + + aaiClientProperties.setAaiHost(newConfiguration.aaiHost()); + aaiClientProperties.setAaiPort(newConfiguration.aaiPort()); + aaiClientProperties.setAaiProtocol(newConfiguration.aaiProtocol()); + aaiClientProperties.setAaiUserName(newConfiguration.aaiUsername()); + aaiClientProperties.setAaiUserPassword(newConfiguration.aaiPassword()); + aaiClientProperties.setAaiIgnoreSslCertificateErrors(newConfiguration.aaiIgnoreSslCertificateErrors()); + constructAaiConfiguration(); + + + genericProperties.setPipelinesPollingIntervalSec(newConfiguration.pipelinesPollingIntervalSec()); + genericProperties.setPipelinesTimeoutSec(newConfiguration.pipelinesTimeoutSec()); + genericProperties.getReRegistration().setPolicyScope(newConfiguration.reRegistrationPolicyScope()); + genericProperties.getReRegistration().setClControlName(newConfiguration.reRegistrationClControlName()); + genericProperties.getCpeAuthentication().setPolicyScope(newConfiguration.cpeAuthPolicyScope()); + genericProperties.getCpeAuthentication().setClControlName(newConfiguration.cpeAuthClControlName()); + + notifyObservers(); + } + + @NotNull + private GeneratedAppConfigObject.StreamsObject getStreamsObject( + Map<String, GeneratedAppConfigObject.StreamsObject> map, String configKey, String messageName) { + GeneratedAppConfigObject.StreamsObject streamsObject = map.get(configKey); + if (!streamsObject.type().equals(STREAMS_TYPE)) { + throw new ApplicationEnvironmentException(String.format("%s requires information about" + + " message-router topic in ONAP", messageName)); + } + return streamsObject; + } + + private void constructConfigurationObjects() { + constructDmaapReRegistrationConfiguration(); + constructDmaapCpeAuthenticationConfiguration(); + constructDmaapProducerConfiguration(); + constructAaiConfiguration(); + } + + private void constructDmaapReRegistrationConfiguration() { + dmaapReRegistrationConsumerConfiguration = new ImmutableDmaapConsumerConfiguration.Builder() + .dmaapHostName(dmaapReRegistrationConsumerProperties.getDmaapHostName()) + .dmaapPortNumber(dmaapReRegistrationConsumerProperties.getDmaapPortNumber()) + .dmaapProtocol(dmaapReRegistrationConsumerProperties.getDmaapProtocol()) + .dmaapTopicName(dmaapReRegistrationConsumerProperties.getDmaapTopicName()) + .dmaapUserName( + dmaapReRegistrationConsumerProperties.getDmaapUserName() == null ? "" : + dmaapReRegistrationConsumerProperties.getDmaapUserName()) + .dmaapUserPassword( + dmaapReRegistrationConsumerProperties.getDmaapUserPassword() == null ? "" : + dmaapReRegistrationConsumerProperties.getDmaapUserPassword()) + .dmaapContentType(dmaapReRegistrationConsumerProperties.getDmaapContentType()) + .consumerId(dmaapReRegistrationConsumerProperties.getConsumerId()) + .consumerGroup(dmaapReRegistrationConsumerProperties.getConsumerGroup()) + .timeoutMs(dmaapReRegistrationConsumerProperties.getTimeoutMs()) + .messageLimit(dmaapReRegistrationConsumerProperties.getMessageLimit()) + .enableDmaapCertAuth(securityProperties.isEnableDmaapCertAuth()) + .keyStorePath(securityProperties.getKeyStorePath()) + .keyStorePasswordPath(securityProperties.getKeyStorePasswordPath()) + .trustStorePath(securityProperties.getTrustStorePath()) + .trustStorePasswordPath(securityProperties.getTrustStorePasswordPath()) + .build(); + } + + private void constructDmaapCpeAuthenticationConfiguration() { + dmaapCpeAuthenticationConsumerConfiguration = new ImmutableDmaapConsumerConfiguration.Builder() + .dmaapHostName(dmaapCpeAuthenticationConsumerProperties.getDmaapHostName()) + .dmaapPortNumber(dmaapCpeAuthenticationConsumerProperties.getDmaapPortNumber()) + .dmaapProtocol(dmaapCpeAuthenticationConsumerProperties.getDmaapProtocol()) + .dmaapTopicName(dmaapCpeAuthenticationConsumerProperties.getDmaapTopicName()) + .dmaapUserName( + dmaapCpeAuthenticationConsumerProperties.getDmaapUserName() == null ? "" : + dmaapCpeAuthenticationConsumerProperties.getDmaapUserName()) + .dmaapUserPassword( + dmaapCpeAuthenticationConsumerProperties.getDmaapUserPassword() == null ? "" : + dmaapCpeAuthenticationConsumerProperties.getDmaapUserPassword()) + .dmaapContentType(dmaapCpeAuthenticationConsumerProperties.getDmaapContentType()) + .consumerId(dmaapCpeAuthenticationConsumerProperties.getConsumerId()) + .consumerGroup(dmaapCpeAuthenticationConsumerProperties.getConsumerGroup()) + .timeoutMs(dmaapCpeAuthenticationConsumerProperties.getTimeoutMs()) + .messageLimit(dmaapCpeAuthenticationConsumerProperties.getMessageLimit()) + .enableDmaapCertAuth(securityProperties.isEnableDmaapCertAuth()) + .keyStorePath(securityProperties.getKeyStorePath()) + .keyStorePasswordPath(securityProperties.getKeyStorePasswordPath()) + .trustStorePath(securityProperties.getTrustStorePath()) + .trustStorePasswordPath(securityProperties.getTrustStorePasswordPath()) + .build(); + } + + private void constructDmaapProducerConfiguration() { + dmaapPublisherConfiguration = new ImmutableDmaapPublisherConfiguration.Builder() + .dmaapHostName(dmaapProducerProperties.getDmaapHostName()) + .dmaapPortNumber(dmaapProducerProperties.getDmaapPortNumber()) + .dmaapProtocol(dmaapProducerProperties.getDmaapProtocol()) + .dmaapTopicName(dmaapProducerProperties.getDmaapTopicName()) + .dmaapUserName( + dmaapProducerProperties.getDmaapUserName() == null ? "" : + dmaapProducerProperties.getDmaapUserName()) + .dmaapUserPassword( + dmaapProducerProperties.getDmaapUserPassword() == null ? "" : + dmaapProducerProperties.getDmaapUserPassword()) + .dmaapContentType(dmaapProducerProperties.getDmaapContentType()) + .enableDmaapCertAuth(securityProperties.isEnableDmaapCertAuth()) + .keyStorePath(securityProperties.getKeyStorePath()) + .keyStorePasswordPath(securityProperties.getKeyStorePasswordPath()) + .trustStorePath(securityProperties.getTrustStorePath()) + .trustStorePasswordPath(securityProperties.getTrustStorePasswordPath()) + .build(); + } + + private void constructAaiConfiguration() { + aaiClientConfiguration = new ImmutableAaiClientConfiguration.Builder() + .aaiHost(aaiClientProperties.getAaiHost()) + .aaiPort(aaiClientProperties.getAaiPort()) + .aaiProtocol(aaiClientProperties.getAaiProtocol()) + .aaiUserName(aaiClientProperties.getAaiUserName()) + .aaiUserPassword(aaiClientProperties.getAaiUserPassword()) + .aaiHeaders(aaiClientProperties.getAaiHeaders()) + .aaiIgnoreSslCertificateErrors(aaiClientProperties.isAaiIgnoreSslCertificateErrors()) + .enableAaiCertAuth(securityProperties.isEnableAaiCertAuth()) + .keyStorePath(securityProperties.getKeyStorePath()) + .keyStorePasswordPath(securityProperties.getKeyStorePasswordPath()) + .trustStorePath(securityProperties.getTrustStorePath()) + .trustStorePasswordPath(securityProperties.getTrustStorePasswordPath()) + .build(); + } + + private TopicUrlInfo parseTopicUrl(String topicUrl) { + String[] urlTokens = topicUrl.split(":"); + if (urlTokens.length != 3) { + throw new ConfigurationParsingException("Wrong topic URL format"); + } + TopicUrlInfo topicUrlInfo = new TopicUrlInfo(); + topicUrlInfo.setHost(urlTokens[1].replace("/", "")); + + String[] tokensAfterHost = urlTokens[2].split("/events/"); + if (tokensAfterHost.length != 2) { + throw new ConfigurationParsingException("Wrong topic name structure"); + } + topicUrlInfo.setPort(Integer.valueOf(tokensAfterHost[0])); + topicUrlInfo.setTopicName("/events/" + tokensAfterHost[1]); + + return topicUrlInfo; + } + + private static class TopicUrlInfo { + private String host; + private int port; + private String topicName; + + String getHost() { + return host; + } + + void setHost(String host) { + this.host = host; + } + + int getPort() { + return port; + } + + void setPort(int port) { + this.port = port; + } + + String getTopicName() { + return topicName; + } + + void setTopicName(String topicName) { + this.topicName = topicName; + } + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConstants.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConstants.java new file mode 100644 index 00000000..5718432e --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ApplicationConstants.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +public class ApplicationConstants { + + public static final String CONSUME_REREGISTRATION_TASK_NAME = "Consume Re-registration DMaaP message"; + public static final String CONSUME_CPE_AUTHENTICATION_TASK_NAME = "Consume CPE Authentication DMaaP message"; + public static final String RETRIEVE_PNF_TASK_NAME = "PNF Retrieval"; + public static final String RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME = "HSI CFS Service Instance Retrieval"; + + public static final String STREAMS_TYPE = "message_router"; + + public static final String IN_SERVICE_NAME_IN_ONAP = "inService"; + public static final String OUT_OF_SERVICE_NAME_IN_ONAP = "outOfService"; + + private ApplicationConstants() {} +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObservable.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObservable.java new file mode 100644 index 00000000..1a395892 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObservable.java @@ -0,0 +1,41 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +public interface ConfigurationChangeObservable { + + /** + * Register a new configuration changes observer. + * @param observer New Observer + */ + void register(ConfigurationChangeObserver observer); + + /** + * Un-register an existing configuration changes observer. + * @param observer Existing Observer + */ + void unRegister(ConfigurationChangeObserver observer); + + /** + * Notifies all observers about a new application configuration. + */ + void notifyObservers(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObserver.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObserver.java new file mode 100644 index 00000000..d007c982 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConfigurationChangeObserver.java @@ -0,0 +1,30 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +public interface ConfigurationChangeObserver { + + /** + * Take actions upon new application configuration. + * @param configuration new application configuration (complete configuration) + */ + void updateConfiguration(ApplicationConfiguration configuration); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConsulConfigurationGateway.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConsulConfigurationGateway.java new file mode 100644 index 00000000..315fc793 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/ConsulConfigurationGateway.java @@ -0,0 +1,252 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.time.Duration; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +import org.onap.bbs.event.processor.exceptions.ApplicationEnvironmentException; +import org.onap.bbs.event.processor.model.GeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableDmaapInfo; +import org.onap.bbs.event.processor.model.ImmutableGeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableStreamsObject; +import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.CbsClientFactory; +import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties; +import org.onap.dcaegen2.services.sdk.rest.services.model.logging.RequestDiagnosticContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import reactor.core.Disposable; + +@Component +public class ConsulConfigurationGateway { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulConfigurationGateway.class); + + private static final String CONSUL_HOST = "CONSUL_HOST"; + private static final String CONFIG_BINDING_SERVICE = "CONFIG_BINDING_SERVICE"; + private static final String HOSTNAME = "HOSTNAME"; + + private final ApplicationConfiguration configuration; + private Gson gson; + private Disposable cbsFetchPipeline; + + @Autowired + ConsulConfigurationGateway(ApplicationConfiguration configuration) { + this.configuration = configuration; + gson = new GsonBuilder().setPrettyPrinting().create(); + } + + /** + * Periodically fetch application configuration via CBS service of DCAE. + * @param initialDelay initial delay before initiation of polling + * @param period polling interval + */ + public void periodicallyFetchConfigFromCbs(Duration initialDelay, Duration period) { + if (environmentNotReady()) { + throw new ApplicationEnvironmentException( + String.format("Application Environment missing critical parameters: %s", + getMissingEnvironmentVariables())); + } + + RequestDiagnosticContext diagnosticContext = RequestDiagnosticContext.create(); + + // Necessary properties from the environment (Consul host:port, service-name (hostname), CBS name) + EnvProperties env = EnvProperties.fromEnvironment(); + + // Create the client and use it to get the configuration + cbsFetchPipeline = CbsClientFactory.createCbsClient(env) + .doOnError(e -> LOGGER.warn("CBS Configuration fetch failed with error: {}", e)) + .retry(e -> true) + .flatMapMany(cbsClient -> cbsClient.updates(diagnosticContext, initialDelay, period)) + .subscribe(this::parseConsulRetrievedConfiguration, this::handleErrors); + } + + boolean environmentNotReady() { + String consulHost = System.getenv().get(CONSUL_HOST); + String cbs = System.getenv().get(CONFIG_BINDING_SERVICE); + String hostname = System.getenv().get(HOSTNAME); + return consulHost == null || cbs == null || hostname == null; + } + + /** + * Reschedule application configuration periodic retrieval via CBS service of DCAE. + * @param initialDelay initial delay before rescheduling + * @param period new polling interval + */ + public void rescheduleCbsConfigurationRetrieval(Duration initialDelay, Duration period) { + if (cbsFetchPipeline != null && !cbsFetchPipeline.isDisposed()) { + LOGGER.info("Disposing old CBS Config fetch job"); + cbsFetchPipeline.dispose(); + } + periodicallyFetchConfigFromCbs(initialDelay, period); + } + + private void parseConsulRetrievedConfiguration(JsonObject jsonObject) { + + GeneratedAppConfigObject generatedAppConfigObject = generateAppConfigObject(jsonObject); + LOGGER.trace("Consul-Retrieved Application Generated Object:\n{}", generatedAppConfigObject); + configuration.updateCurrentConfiguration(generatedAppConfigObject); + } + + private void handleErrors(Throwable throwable) { + LOGGER.error("Periodic CBS configuration polling was terminated with error: {}", throwable); + } + + @NotNull + GeneratedAppConfigObject generateAppConfigObject(JsonObject configObject) { + + if (LOGGER.isInfoEnabled()) { + String configAsString = gson.toJson(configObject); + LOGGER.info("Received App Config object\n{}", configAsString); + } + + final String dmaapProtocol = configObject.get("dmaap.protocol").getAsString(); + final String dmaapContentType = configObject.get("dmaap.contentType").getAsString(); + final String dmaapConsumerId = configObject.get("dmaap.consumer.consumerId").getAsString(); + final String dmaapConsumerGroup = configObject.get("dmaap.consumer.consumerGroup").getAsString(); + final int dmaapMessageLimit = configObject.get("dmaap.messageLimit").getAsInt(); + final int dmaapTimeoutMs = configObject.get("dmaap.timeoutMs").getAsInt(); + + final String aaiHost = configObject.get("aai.host").getAsString(); + final int aaiPort = configObject.get("aai.port").getAsInt(); + final String aaiProtocol = configObject.get("aai.protocol").getAsString(); + final String aaiUsername = configObject.get("aai.username").getAsString(); + final String aaiPassword = configObject.get("aai.password").getAsString(); + final boolean aaiIgnoreSslCertificateErrors = + configObject.get("aai.aaiIgnoreSslCertificateErrors").getAsBoolean(); + + final int pipelinesPollingIntervalSec = configObject.get("application.pipelinesPollingIntervalSec").getAsInt(); + final int pipelinesTimeoutSec = configObject.get("application.pipelinesTimeoutSec").getAsInt(); + final int cbsPollingIntervalSec = configObject.get("application.cbsPollingIntervalSec").getAsInt(); + final String reRegPolicyScope = configObject.get("application.reregistration.policyScope").getAsString(); + final String reRegClControlName = configObject.get("application.reregistration.clControlName").getAsString(); + final String cpeAuthPolicyScope = configObject.get("application.cpe.authentication.policyScope").getAsString(); + final String cpeAuthClControlName = + configObject.get("application.cpe.authentication.clControlName").getAsString(); + final String reRegConfigKey = configObject.get("application.reregistration.configKey").getAsString(); + final String cpeAuthConfigKey = configObject.get("application.cpeAuth.configKey").getAsString(); + final String closeLoopConfigKey = configObject.get("application.closeLoop.configKey").getAsString(); + + final JsonObject streamsPublishes = configObject.getAsJsonObject("streams_publishes"); + final JsonObject streamsSubscribes = configObject.getAsJsonObject("streams_subscribes"); + + return ImmutableGeneratedAppConfigObject.builder() + .dmaapProtocol(dmaapProtocol) + .dmaapContentType(dmaapContentType) + .dmaapConsumerConsumerId(dmaapConsumerId) + .dmaapConsumerConsumerGroup(dmaapConsumerGroup) + .dmaapMessageLimit(dmaapMessageLimit) + .dmaapTimeoutMs(dmaapTimeoutMs) + .aaiHost(aaiHost) + .aaiPort(aaiPort) + .aaiProtocol(aaiProtocol) + .aaiUsername(aaiUsername) + .aaiPassword(aaiPassword) + .aaiIgnoreSslCertificateErrors(aaiIgnoreSslCertificateErrors) + .pipelinesPollingIntervalSec(pipelinesPollingIntervalSec) + .pipelinesTimeoutSec(pipelinesTimeoutSec) + .cbsPollingIntervalSec(cbsPollingIntervalSec) + .reRegistrationPolicyScope(reRegPolicyScope) + .reRegistrationClControlName(reRegClControlName) + .cpeAuthPolicyScope(cpeAuthPolicyScope) + .cpeAuthClControlName(cpeAuthClControlName) + .reRegConfigKey(reRegConfigKey) + .cpeAuthConfigKey(cpeAuthConfigKey) + .closeLoopConfigKey(closeLoopConfigKey) + .streamSubscribesMap(parseStreamsObjects(streamsSubscribes)) + .streamPublishesMap(parseStreamsObjects(streamsPublishes)) + .build(); + } + + private Set<String> getMissingEnvironmentVariables() { + Set<String> missingVars = new HashSet<>(); + if (System.getenv().get(CONSUL_HOST) == null) { + missingVars.add(CONSUL_HOST); + } + if (System.getenv().get(CONFIG_BINDING_SERVICE) == null) { + missingVars.add(CONFIG_BINDING_SERVICE); + } + if (System.getenv().get(HOSTNAME) == null) { + missingVars.add(HOSTNAME); + } + return missingVars; + } + + private Map<String, GeneratedAppConfigObject.StreamsObject> parseStreamsObjects( + JsonObject jsonObject) { + Map<String, GeneratedAppConfigObject.StreamsObject> streams = new HashMap<>(); + + jsonObject.entrySet().stream() + .map(this::parseStreamsSingleObject) + .forEach(e -> streams.put(e.getKey(), e.getValue())); + + return streams; + } + + private Map.Entry<String, GeneratedAppConfigObject.StreamsObject> parseStreamsSingleObject( + Map.Entry<String, JsonElement> jsonEntry) { + + JsonObject closeLoopOutput = (JsonObject) jsonEntry.getValue(); + + String type = closeLoopOutput.get("type").getAsString(); + String aafUsername = closeLoopOutput.get("aaf_username") != null + ? closeLoopOutput.get("aaf_username").getAsString() : ""; + String aafPassword = closeLoopOutput.get("aaf_password") != null + ? closeLoopOutput.get("aaf_password").getAsString() : ""; + + JsonObject dmaapInfo = closeLoopOutput.getAsJsonObject("dmaap_info"); + String clientId = dmaapInfo.get("client_id") != null + ? dmaapInfo.get("client_id").getAsString() : ""; + String clientRole = dmaapInfo.get("client_role") != null + ? dmaapInfo.get("client_role").getAsString() : ""; + String location = dmaapInfo.get("location") != null + ? dmaapInfo.get("location").getAsString() : ""; + String topicUrl = dmaapInfo.get("topic_url").getAsString(); + + GeneratedAppConfigObject.DmaapInfo dmaapInfoObject = ImmutableDmaapInfo.builder() + .clientId(clientId) + .clientRole(clientRole) + .location(location) + .topicUrl(topicUrl) + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject = ImmutableStreamsObject.builder() + .type(type) + .aafUsername(aafUsername) + .aafPassword(aafPassword) + .dmaapInfo(dmaapInfoObject) + .build(); + + return new AbstractMap.SimpleEntry<>(jsonEntry.getKey(), streamsObject); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerProperties.java new file mode 100644 index 00000000..ecc8d6b1 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerProperties.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.dmaap.consumer.cpe-authentication") +@Getter +@Setter +@Validated +public class DmaapCpeAuthenticationConsumerProperties { + + @NotBlank + private String dmaapHostName; + + @Min(1025) + @Max(65536) + private int dmaapPortNumber; + + @NotBlank + private String dmaapTopicName; + + @NotBlank + @Pattern(regexp = "(http|https)") + private String dmaapProtocol; + + private String dmaapUserName; + + private String dmaapUserPassword; + + @NotBlank + private String dmaapContentType; + + @NotBlank + private String consumerId; + + @NotBlank + private String consumerGroup; + + private int timeoutMs; + private int messageLimit; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapProducerProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapProducerProperties.java new file mode 100644 index 00000000..919b4065 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapProducerProperties.java @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.dmaap.producer") +@Getter +@Setter +@Validated +public class DmaapProducerProperties { + + @NotBlank + private String dmaapHostName; + + @Min(1025) + @Max(65536) + private int dmaapPortNumber; + + @NotBlank + private String dmaapTopicName; + + @NotBlank + @Pattern(regexp = "(http|https)") + private String dmaapProtocol; + + private String dmaapUserName; + + private String dmaapUserPassword; + + @NotBlank + private String dmaapContentType; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerProperties.java new file mode 100644 index 00000000..d3076393 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerProperties.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.dmaap.consumer.re-registration") +@Getter +@Setter +@Validated +public class DmaapReRegistrationConsumerProperties { + + @NotBlank + private String dmaapHostName; + + @Min(1025) + @Max(65536) + private int dmaapPortNumber; + + @NotBlank + private String dmaapTopicName; + + @NotBlank + @Pattern(regexp = "(http|https)") + private String dmaapProtocol; + + private String dmaapUserName; + + private String dmaapUserPassword; + + @NotBlank + private String dmaapContentType; + + @NotBlank + private String consumerId; + + @NotBlank + private String consumerGroup; + + private int timeoutMs; + private int messageLimit; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/GenericProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/GenericProperties.java new file mode 100644 index 00000000..bc8020a4 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/GenericProperties.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import javax.validation.constraints.NotBlank; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.application") +@Getter +@Setter +@Validated +public class GenericProperties { + + private int pipelinesPollingIntervalSec; + + private int pipelinesTimeoutSec; + + private ReRegistrationGenericProperties reRegistration; + + private CpeAuthenticationGenericProperties cpeAuthentication; + + @Getter + @Setter + @Validated + static class ReRegistrationGenericProperties { + + @NotBlank + private String policyScope; + + @NotBlank + private String clControlName; + } + + @Getter + @Setter + @Validated + static class CpeAuthenticationGenericProperties { + @NotBlank + private String policyScope; + + @NotBlank + private String clControlName; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SecurityProperties.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SecurityProperties.java new file mode 100644 index 00000000..188cd658 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SecurityProperties.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import javax.validation.constraints.NotBlank; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Configuration +@ConfigurationProperties("configs.security") +@Getter +@Setter +@Validated +public class SecurityProperties { + + @NotBlank + private String trustStorePath; + + @NotBlank + private String trustStorePasswordPath; + + @NotBlank + private String keyStorePath; + + @NotBlank + private String keyStorePasswordPath; + + private boolean enableAaiCertAuth; + private boolean enableDmaapCertAuth; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SwaggerConfiguration.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SwaggerConfiguration.java new file mode 100644 index 00000000..c3c87da2 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/config/SwaggerConfiguration.java @@ -0,0 +1,83 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +@Profile("production") +public class SwaggerConfiguration extends WebMvcConfigurationSupport { + + private static final String PACKAGE_PATH = "org.onap.bbs.event.processor"; + private static final String API_TITLE = "BBS Event Processor"; + private static final String DESCRIPTION = "This page lists bbs-event-processor REST API details"; + private static final String VERSION = "1.0"; + private static final String RESOURCES_PATH = "classpath:/META-INF/resources/"; + private static final String WEBJARS_PATH = RESOURCES_PATH + "webjars/"; + private static final String SWAGGER_UI = "swagger-ui.html"; + private static final String WEBJARS = "/webjars/**"; + + /** + * Swagger configuration function for hosting it next to spring http website. + * + * @return Docket + */ + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage(PACKAGE_PATH)) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title(API_TITLE) + .description(DESCRIPTION) + .version(VERSION) + .build(); + } + + + @Override + protected void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler(SWAGGER_UI) + .addResourceLocations(RESOURCES_PATH); + + registry.addResourceHandler(WEBJARS) + .addResourceLocations(WEBJARS_PATH); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorController.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorController.java new file mode 100644 index 00000000..09691c16 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorController.java @@ -0,0 +1,174 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.controllers; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +import java.util.concurrent.Executors; + +import org.onap.bbs.event.processor.pipelines.CpeAuthenticationPipeline; +import org.onap.bbs.event.processor.pipelines.ReRegistrationPipeline; +import org.onap.bbs.event.processor.pipelines.Scheduler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import reactor.core.publisher.Mono; + +@RestController +@Api(value = "BbsEventProcessorController", description = "Manage bbs-event-processor microService") +public class BbsEventProcessorController { + + private ReRegistrationPipeline reRegistrationPipeline; + private CpeAuthenticationPipeline cpeAuthenticationPipeline; + private Scheduler scheduler; + + /** + * Constructs BBE event processor REST controller. + * @param reRegistrationPipeline processing pipeline for polling DMaaP for PNF re-registration events + * @param cpeAuthenticationPipeline processing pipeline for polling DMaaP for CPE authentication events + * @param scheduler application scheduler + */ + @Autowired + public BbsEventProcessorController(ReRegistrationPipeline reRegistrationPipeline, + CpeAuthenticationPipeline cpeAuthenticationPipeline, + Scheduler scheduler) { + this.reRegistrationPipeline = reRegistrationPipeline; + this.cpeAuthenticationPipeline = cpeAuthenticationPipeline; + this.scheduler = scheduler; + } + + private static final Logger LOGGER = LoggerFactory.getLogger(BbsEventProcessorController.class); + + /** + * Responds to health-check heartbeats. + * @return Proper HTTP response based on application health + */ + @GetMapping("heartbeat") + @ApiOperation(value = "Returns liveness of bbs-event-processor microService") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "bbs-event-processor microService is alive"), + @ApiResponse(code = 401, message = "Not authorized to view the resource"), + @ApiResponse(code = 403, message = "Resource access is forbidden"), + @ApiResponse(code = 404, message = "Resource is not found")}) + public Mono<ResponseEntity<String>> handleHeartBeat() { + LOGGER.debug("bbs-event-processor has received a heartbeat request"); + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("bbs-event-processor is alive\n", HttpStatus.OK)) + ); + } + + /** + * Polls DMaaP for PNF re-registration events just once. + * @return Proper HTTP response based on request submission result + */ + @PostMapping("poll-reregistration-events") + @ApiOperation(value = "Returns result of request submission. PNF re-registration polling will occur asynchronously") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Polling Re-registration events task submitted successfully"), + @ApiResponse(code = 401, message = "Not authorized to view the resource"), + @ApiResponse(code = 403, message = "Resource access is forbidden"), + @ApiResponse(code = 404, message = "Resource is not found")}) + public Mono<ResponseEntity<String>> handleReRegistrationRestCall() { + LOGGER.debug("bbs-event-processor has received a re-registration handling request"); + Executors.newSingleThreadExecutor().submit(() -> reRegistrationPipeline.processPnfReRegistrationEvents()); + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Request submitted\n", HttpStatus.OK)) + ); + } + + /** + * Polls DMaaP for CPE authentication events just once. + * @return Proper HTTP response based on request submission result + */ + @PostMapping("poll-cpe-authentication-events") + @ApiOperation(value = "Returns result of request submission. CPE authentication polling will occur asynchronously") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "CPE authentication task submitted successfully"), + @ApiResponse(code = 401, message = "Not authorized to view the resource"), + @ApiResponse(code = 403, message = "Resource access is forbidden"), + @ApiResponse(code = 404, message = "Resource is not found")}) + public Mono<ResponseEntity<String>> handleCpeAuthenticationRestCall() { + LOGGER.debug("bbs-event-processor has received a cpe-authentication handling request"); + Executors.newSingleThreadExecutor().submit(() -> cpeAuthenticationPipeline.processPnfCpeAuthenticationEvents()); + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Request submitted\n", HttpStatus.OK)) + ); + } + + /** + * Reschedules DMaaP polling tasks. + * @return Proper HTTP response based on rescheduling result + */ + @PostMapping("start-tasks") + @ApiOperation(value = "Returns result of request to start microservice tasks") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Tasks were successfully started"), + @ApiResponse(code = 401, message = "Not authorized to view the resource"), + @ApiResponse(code = 403, message = "Resource access is forbidden"), + @ApiResponse(code = 404, message = "Resource is not found"), + @ApiResponse(code = 406, message = "Task initiation failed. Check logs")}) + public Mono<ResponseEntity<String>> reScheduleTasks() { + LOGGER.trace("bbs-event-processor has received a request to reschedule all running tasks"); + if (scheduler.reScheduleProcessingTasks()) { + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Initiation of tasks was successful\n", HttpStatus.OK)) + ); + } else { + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Initiation of tasks failed\n", HttpStatus.NOT_ACCEPTABLE)) + ); + } + } + + /** + * Cancels DMaaP polling tasks. + * @return Proper HTTP response based on cancellation result + */ + @PostMapping("cancel-tasks") + @ApiOperation(value = "Returns result of request to cancel running microservice tasks") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Tasks were successfully cancelled"), + @ApiResponse(code = 401, message = "Not authorized to view the resource"), + @ApiResponse(code = 403, message = "Resource access is forbidden"), + @ApiResponse(code = 404, message = "Resource is not found"), + @ApiResponse(code = 406, message = "Cancellation failed. Check logs")}) + public Mono<ResponseEntity<String>> cancelTasks() { + LOGGER.debug("bbs-event-processor has received a request to cancel all running tasks"); + if (scheduler.cancelScheduledProcessingTasks()) { + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Cancellation was successful\n", HttpStatus.OK)) + ); + } else { + return Mono.defer(() -> + Mono.just(new ResponseEntity<>("Cancellation failed\n", HttpStatus.NOT_ACCEPTABLE)) + ); + } + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/AaiTaskException.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/AaiTaskException.java new file mode 100644 index 00000000..91493573 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/AaiTaskException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.exceptions; + +public class AaiTaskException extends RuntimeException { + + public AaiTaskException(String message) { + super(message); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ApplicationEnvironmentException.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ApplicationEnvironmentException.java new file mode 100644 index 00000000..2103589c --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ApplicationEnvironmentException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.exceptions; + +public class ApplicationEnvironmentException extends RuntimeException { + + public ApplicationEnvironmentException(String message) { + super(message); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ConfigurationParsingException.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ConfigurationParsingException.java new file mode 100644 index 00000000..55f27111 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/ConfigurationParsingException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.exceptions; + +public class ConfigurationParsingException extends RuntimeException { + + public ConfigurationParsingException(String message) { + super(message); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/DmaapException.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/DmaapException.java new file mode 100644 index 00000000..d9a02014 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/DmaapException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.exceptions; + +public class DmaapException extends RuntimeException { + + public DmaapException(String message) { + super(message); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/EmptyDmaapResponseException.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/EmptyDmaapResponseException.java new file mode 100644 index 00000000..1be4f43a --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/exceptions/EmptyDmaapResponseException.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.exceptions; + +public class EmptyDmaapResponseException extends RuntimeException { + + public EmptyDmaapResponseException() { + super(); + } + + public EmptyDmaapResponseException(String message) { + super(message); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/AuthenticationState.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/AuthenticationState.java new file mode 100644 index 00000000..cef24b5f --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/AuthenticationState.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import static org.onap.bbs.event.processor.config.ApplicationConstants.IN_SERVICE_NAME_IN_ONAP; +import static org.onap.bbs.event.processor.config.ApplicationConstants.OUT_OF_SERVICE_NAME_IN_ONAP; + +public enum AuthenticationState { + + IN_SERVICE(IN_SERVICE_NAME_IN_ONAP), + OUT_OF_SERVICE(OUT_OF_SERVICE_NAME_IN_ONAP); + + AuthenticationState(String nameInOnap) { + this.nameInOnap = nameInOnap; + } + + private String nameInOnap; + + public String getNameInOnap() { + return nameInOnap; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ControlLoopPublisherDmaapModel.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ControlLoopPublisherDmaapModel.java new file mode 100644 index 00000000..8fa73e42 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ControlLoopPublisherDmaapModel.java @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Map; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.onap.dcaegen2.services.sdk.rest.services.model.DmaapModel; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true) +public interface ControlLoopPublisherDmaapModel extends DmaapModel { + + @SerializedName(value = "closedLoopEventClient", alternate = "closedLoopEventClient") + String getClosedLoopEventClient(); + + @SerializedName(value = "policyVersion", alternate = "policyVersion") + String getPolicyVersion(); + + @SerializedName(value = "policyName", alternate = "policyName") + String getPolicyName(); + + @SerializedName(value = "policyScope", alternate = "policyScope") + String getPolicyScope(); + + @SerializedName(value = "target_type", alternate = "target_type") + String getTargetType(); + + // It will handle all pieces of information that the microservice needs to send + // towards Policy + @SerializedName(value = "AAI", alternate = "AAI") + Map<String, String> getAaiEnrichmentData(); + + @SerializedName(value = "closedLoopAlarmStart", alternate = "closedLoopAlarmStart") + long getClosedLoopAlarmStart(); + + @SerializedName(value = "closedLoopEventStatus", alternate = "closedLoopEventStatus") + String getClosedLoopEventStatus(); + + @SerializedName(value = "closedLoopControlName", alternate = "closedLoopControlName") + String getClosedLoopControlName(); + + @SerializedName(value = "version", alternate = "version") + String getVersion(); + + @SerializedName(value = "target", alternate = "target") + String getTarget(); + + @SerializedName(value = "requestID", alternate = "requestID") + String getRequestId(); + + @SerializedName(value = "from", alternate = "from") + String getOriginator(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/CpeAuthenticationConsumerDmaapModel.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/CpeAuthenticationConsumerDmaapModel.java new file mode 100644 index 00000000..42c9896f --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/CpeAuthenticationConsumerDmaapModel.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Optional; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.onap.dcaegen2.services.sdk.rest.services.model.AaiModel; +import org.onap.dcaegen2.services.sdk.rest.services.model.DmaapModel; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true) +public interface CpeAuthenticationConsumerDmaapModel extends AaiModel, DmaapModel { + + @SerializedName(value = "correlationId", alternate = "correlationId") + String getCorrelationId(); + + @SerializedName(value = "old-authentication-state", alternate = "old-authentication-state") + String getOldAuthenticationState(); + + @SerializedName(value = "new-authentication-state", alternate = "new-authentication-state") + String getNewAuthenticationState(); + + @SerializedName(value = "state-interface", alternate = "state-interface") + Optional<String> getStateInterface(); + + @SerializedName(value = "rgw-mac-address", alternate = "rgw-mac-address") + Optional<String> getRgwMacAddress(); + + @SerializedName(value = "sw-version", alternate = "sw-version") + Optional<String> getSwVersion(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/GeneratedAppConfigObject.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/GeneratedAppConfigObject.java new file mode 100644 index 00000000..c48ea6ef --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/GeneratedAppConfigObject.java @@ -0,0 +1,145 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Map; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true, emptyAsNulls = true) +public interface GeneratedAppConfigObject { + + @SerializedName(value = "dmaap.protocol", alternate = "dmaap.protocol") + String dmaapProtocol(); + + @SerializedName(value = "dmaap.contentType", alternate = "dmaap.contentType") + String dmaapContentType(); + + @SerializedName(value = "dmaap.consumer.consumerId", alternate = "dmaap.consumer.consumerId") + String dmaapConsumerConsumerId(); + + @SerializedName(value = "dmaap.consumer.consumerGroup", alternate = "dmaap.consumer.consumerGroup") + String dmaapConsumerConsumerGroup(); + + @SerializedName(value = "dmaap.messageLimit", alternate = "dmaap.messageLimit") + int dmaapMessageLimit(); + + @SerializedName(value = "dmaap.timeoutMs", alternate = "dmaap.timeoutMs") + int dmaapTimeoutMs(); + + @SerializedName(value = "aai.host", alternate = "aai.host") + String aaiHost(); + + @SerializedName(value = "aai.port", alternate = "aai.port") + int aaiPort(); + + @SerializedName(value = "aai.protocol", alternate = "aai.protocol") + String aaiProtocol(); + + @SerializedName(value = "aai.username", alternate = "aai.username") + String aaiUsername(); + + @SerializedName(value = "aai.password", alternate = "aai.password") + String aaiPassword(); + + @SerializedName(value = "aai.aaiIgnoreSslCertificateErrors", alternate = "aai.aaiIgnoreSslCertificateErrors") + boolean aaiIgnoreSslCertificateErrors(); + + @SerializedName(value = "application.pipelinesPollingIntervalSec", + alternate = "application.pipelinesPollingIntervalSec") + int pipelinesPollingIntervalSec(); + + @SerializedName(value = "application.pipelinesTimeoutSec", alternate = "application.pipelinesTimeoutSec") + int pipelinesTimeoutSec(); + + @SerializedName(value = "application.cbsPollingIntervalSec", + alternate = "application.cbsPollingIntervalSec") + int cbsPollingIntervalSec(); + + @SerializedName(value = "application.reregistration.policyScope", + alternate = "application.reregistration.policyScope") + String reRegistrationPolicyScope(); + + @SerializedName(value = "application.reregistration.clControlName", + alternate = "application.reregistration.clControlName") + String reRegistrationClControlName(); + + @SerializedName(value = "application.cpe.authentication.policyScope", + alternate = "application.reregistration.policyScope") + String cpeAuthPolicyScope(); + + @SerializedName(value = "application.cpe.authentication.clControlName", + alternate = "application.reregistration.clControlName") + String cpeAuthClControlName(); + + @SerializedName(value = "application.reregistration.configKey", alternate = "application.reregistration.configKey") + String reRegConfigKey(); + + @SerializedName(value = "application.cpeAuth.configKey", alternate = "application.cpeAuth.configKey") + String cpeAuthConfigKey(); + + @SerializedName(value = "application.closeLoop.configKey", alternate = "application.closeLoop.configKey") + String closeLoopConfigKey(); + + @SerializedName(value = "streams_subscribes", alternate = "streams_subscribes") + Map<String, StreamsObject> streamSubscribesMap(); + + @SerializedName(value = "streams_publishes", alternate = "streams_publishes") + Map<String, StreamsObject> streamPublishesMap(); + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface StreamsObject { + + @SerializedName(value = "type", alternate = "type") + String type(); + + @SerializedName(value = "aaf_username", alternate = "aaf_username") + String aafUsername(); + + @SerializedName(value = "aaf_password", alternate = "aaf_password") + String aafPassword(); + + @SerializedName(value = "dmaap_info", alternate = "dmaap_info") + DmaapInfo dmaapInfo(); + } + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface DmaapInfo { + + @SerializedName(value = "client_id", alternate = "client_id") + String clientId(); + + @SerializedName(value = "client_role", alternate = "client_role") + String clientRole(); + + @SerializedName(value = "location", alternate = "location") + String location(); + + @SerializedName(value = "topic_url", alternate = "topic_url") + String topicUrl(); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/MetadataListAaiObject.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/MetadataListAaiObject.java new file mode 100644 index 00000000..221fade5 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/MetadataListAaiObject.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true, emptyAsNulls = true) +public interface MetadataListAaiObject { + + @SerializedName(value = "metadatum", alternate = "metadatum") + List<MetadataEntryAaiObject> getMetadataEntries(); + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface MetadataEntryAaiObject { + + @SerializedName(value = "metaname", alternate = "metaname") + String getMetaname(); + + @SerializedName(value = "metaval", alternate = "metaval") + String getMetavalue(); + + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/PnfAaiObject.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/PnfAaiObject.java new file mode 100644 index 00000000..682c0641 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/PnfAaiObject.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Optional; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.onap.dcaegen2.services.sdk.rest.services.model.ClientModel; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true, emptyAsNulls = true) +public interface PnfAaiObject extends ClientModel { + + @SerializedName(value = "pnf-name", alternate = "pnf-name") + String getPnfName(); + + @SerializedName(value = "in-maint", alternate = "in-maint") + boolean isInMaintenance(); + + @SerializedName(value = "sw-version", alternate = "sw-version") + Optional<String> getSwVersion(); + + @SerializedName(value = "relationship-list", alternate = "relationship-list") + RelationshipListAaiObject getRelationshipListAaiObject(); + +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ReRegistrationConsumerDmaapModel.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ReRegistrationConsumerDmaapModel.java new file mode 100644 index 00000000..07fb75aa --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ReRegistrationConsumerDmaapModel.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.onap.dcaegen2.services.sdk.rest.services.model.AaiModel; +import org.onap.dcaegen2.services.sdk.rest.services.model.DmaapModel; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true) +public interface ReRegistrationConsumerDmaapModel extends AaiModel, DmaapModel { + + @SerializedName(value = "correlationId", alternate = "correlationId") + String getCorrelationId(); + + @SerializedName(value = "attachment-point", alternate = "attachment-point") + String getAttachmentPoint(); + + @SerializedName(value = "remote-id", alternate = "remote-id") + String getRemoteId(); + + @SerializedName(value = "cvlan", alternate = "cvlan") + String getCVlan(); + + @SerializedName(value = "svlan", alternate = "svlan") + String getSVlan(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/RelationshipListAaiObject.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/RelationshipListAaiObject.java new file mode 100644 index 00000000..76aab92e --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/RelationshipListAaiObject.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; +import java.util.Optional; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true, emptyAsNulls = true) +public interface RelationshipListAaiObject { + + @SerializedName(value = "relationship", alternate = "relationship") + List<RelationshipEntryAaiObject> getRelationshipEntries(); + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface RelationshipEntryAaiObject { + + @SerializedName(value = "related-to", alternate = "related-to") + String getRelatedTo(); + + @SerializedName(value = "relationship-label", alternate = "relationship-label") + Optional<String> getRelationshipLabel(); + + @SerializedName(value = "related-link", alternate = "related-link") + String getRelatedLink(); + + @SerializedName(value = "relationship-data", alternate = "relationship-data") + List<RelationshipDataEntryAaiObject> getRelationshipData(); + + @SerializedName(value = "related-to-property", alternate = "related-to-property") + Optional<List<PropertyAaiObject>> getRelatedToProperties(); + + } + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface RelationshipDataEntryAaiObject { + + @SerializedName(value = "relationship-key", alternate = "relationship-key") + String getRelationshipKey(); + + @SerializedName(value = "relationship-value", alternate = "relationship-value") + String getRelationshipValue(); + + } + + @Value.Immutable + @Gson.TypeAdapters(fieldNamingStrategy = true) + interface PropertyAaiObject { + + @SerializedName(value = "property-key", alternate = "property-key") + String getPropertyKey(); + + @SerializedName(value = "property-value", alternate = "property-value") + Optional<String> getPropertyValue(); + + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ServiceInstanceAaiObject.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ServiceInstanceAaiObject.java new file mode 100644 index 00000000..9b2d8ef7 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/model/ServiceInstanceAaiObject.java @@ -0,0 +1,45 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Optional; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters(fieldNamingStrategy = true, emptyAsNulls = true) +public interface ServiceInstanceAaiObject { + + @SerializedName(value = "service-instance-id", alternate = "service-instance-id") + String getServiceInstanceId(); + + @SerializedName(value = "orchestration-status", alternate = "orchestration-status") + Optional<String> getOrchestrationStatus(); + + @SerializedName(value = "relationship-list", alternate = "relationship-list") + RelationshipListAaiObject getRelationshipListAaiObject(); + + @SerializedName(value = "metadata", alternate = "metadata") + Optional<MetadataListAaiObject> getMetadataListAaiObject(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipeline.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipeline.java new file mode 100644 index 00000000..a8d08576 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipeline.java @@ -0,0 +1,338 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import static org.onap.bbs.event.processor.config.ApplicationConstants.CONSUME_CPE_AUTHENTICATION_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_PNF_TASK_NAME; +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.INSTANCE_UUID; +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.RESPONSE_CODE; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeoutException; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.MetadataListAaiObject; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.tasks.AaiClientTask; +import org.onap.bbs.event.processor.tasks.DmaapCpeAuthenticationConsumerTask; +import org.onap.bbs.event.processor.tasks.DmaapPublisherTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +public class CpeAuthenticationPipeline { + + private static final Logger LOGGER = LoggerFactory.getLogger(CpeAuthenticationPipeline.class); + + private static final String DCAE_BBS_EVENT_PROCESSOR_MS_INSTANCE = "DCAE.BBS_event_processor_mSInstance"; + private static final String POLICY_VERSION = "1.0.0.5"; + private static final String POLICY_NAME = "CPE_Authentication"; + private static final String CLOSE_LOOP_TARGET_TYPE = "VM"; + private static final String CLOSED_LOOP_EVENT_STATUS = "ONSET"; + private static final String CLOSE_LOOP_VERSION = "1.0.2"; + private static final String CLOSE_LOOP_TARGET = "vserver.vserver-name"; + private static final String FROM = "DCAE"; + + private DmaapCpeAuthenticationConsumerTask consumerTask; + private DmaapPublisherTask publisherTask; + private AaiClientTask aaiClientTask; + + private ApplicationConfiguration configuration; + + private Map<String, String> mdcContextMap; + + @Autowired + CpeAuthenticationPipeline(ApplicationConfiguration configuration, + DmaapCpeAuthenticationConsumerTask consumerTask, + DmaapPublisherTask publisherTask, + AaiClientTask aaiClientTask, + Map<String, String> mdcContextMap) { + this.configuration = configuration; + this.consumerTask = consumerTask; + this.publisherTask = publisherTask; + this.aaiClientTask = aaiClientTask; + this.mdcContextMap = mdcContextMap; + } + + /** + * PNF CPE Authentication processing pipeline for BBS uS. + */ + public void processPnfCpeAuthenticationEvents() { + MDC.setContextMap(mdcContextMap); + LOGGER.info("Process next CPE Authentication events"); + executePipeline() + .subscribe(this::onSuccess, this::onError, this::onComplete); + LOGGER.trace("Reactive CPE Authentication pipeline subscribed - Execution started"); + } + + Flux<ResponseEntity<String>> executePipeline() { + return + // Consume CPE Authentication from DMaaP + consumeCpeAuthenticationFromDmaap() + // Fetch PNF from A&AI + .flatMap(this::fetchPnfFromAai) + // Fetch related HSI CFS instance from A&AI + .flatMap(this::fetchHsiCfsServiceInstanceFromAai) + // Trigger Policy for relocation + .flatMap(this::triggerPolicy); + } + + private void onSuccess(ResponseEntity<String> responseCode) { + MDC.put(RESPONSE_CODE, responseCode.getStatusCode().toString()); + LOGGER.info("CPE Authentication event successfully handled. " + + "Publishing to DMaaP for Policy returned a status code of ({} {})", + responseCode.getStatusCode().value(), responseCode.getStatusCode().getReasonPhrase()); + MDC.remove(RESPONSE_CODE); + } + + private void onError(Throwable throwable) { + LOGGER.error("Aborted CPE Authentication events processing. Error: {}", throwable.getMessage()); + } + + private void onComplete() { + LOGGER.info("CPE Authentication processing pipeline has been completed"); + } + + private Flux<PipelineState> consumeCpeAuthenticationFromDmaap() { + return Flux.defer(() -> { + MDC.put(INSTANCE_UUID, UUID.randomUUID().toString()); + try { + return consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(e -> { + if (e instanceof TimeoutException) { + LOGGER.warn("Timed out waiting for DMaaP response"); + } else if (e instanceof EmptyDmaapResponseException) { + LOGGER.warn("Nothing to consume from DMaaP"); + } + }) + .onErrorResume( + e -> (e instanceof EmptyDmaapResponseException || e instanceof TimeoutException), + e -> Mono.empty()) + .map(event -> { + // For each message, we have to keep separate state. This state will be enhanced + // in each step and handed off to the next processing step + PipelineState state = new PipelineState(); + state.setCpeAuthenticationEvent(event); + return state; + }); + } catch (SSLException e) { + return Flux.error(e); + } + }); + } + + private Mono<PipelineState> fetchPnfFromAai(PipelineState state) { + + CpeAuthenticationConsumerDmaapModel vesEvent = state.getCpeAuthenticationEvent(); + String pnfName = vesEvent.getCorrelationId(); + String url = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName); + LOGGER.debug("Processing Step: Retrieve PNF. Url: ({})", url); + + return aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, url) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for A&AI response") + ) + .doOnError(e -> LOGGER.error("Error while retrieving PNF: {}", + e.getMessage()) + ) + .onErrorResume( + e -> e instanceof AaiTaskException || e instanceof TimeoutException, + e -> Mono.empty()) + .map(p -> { + state.setPnfAaiObject(p); + return state; + }); + } + + private Mono<PipelineState> fetchHsiCfsServiceInstanceFromAai(PipelineState state) { + + if (state == null || state.getPnfAaiObject() == null) { + return Mono.empty(); + } + + PnfAaiObject pnf = state.getPnfAaiObject(); + // Assuming that the PNF will only have a single service-instance relationship pointing + // towards the HSI CFS service + String serviceInstanceId = pnf.getRelationshipListAaiObject().getRelationshipEntries() + .stream() + .filter(e -> e.getRelatedTo().equals("service-instance")) + .flatMap(e -> e.getRelationshipData().stream()) + .filter(d -> d.getRelationshipKey().equals("service-instance.service-instance-id")) + .map(RelationshipListAaiObject.RelationshipDataEntryAaiObject::getRelationshipValue) + .findFirst().orElse(""); + + if (StringUtils.isEmpty(serviceInstanceId)) { + LOGGER.error("Unable to retrieve HSI CFS service instance from PNF {}", + state.getPnfAaiObject().getPnfName()); + return Mono.empty(); + } + + String url = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + serviceInstanceId); + LOGGER.debug("Processing Step: Retrieve HSI CFS Service. Url: ({})", url); + return aaiClientTask.executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, url) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for A&AI response") + ) + .doOnError(e -> LOGGER.error("Error while retrieving HSI CFS Service instance: {}", + e.getMessage()) + ) + .onErrorResume( + e -> e instanceof AaiTaskException || e instanceof TimeoutException, + e -> Mono.empty()) + .map(s -> { + state.setHsiCfsServiceInstance(s); + return state; + }); + } + + private Mono<ResponseEntity<String>> triggerPolicy(PipelineState state) { + + if (state == null || state.getHsiCfsServiceInstance() == null) { + return Mono.empty(); + } + + // At this point, we must check if the PNF RGW MAC address matches the value extracted from VES event + if (!isCorrectMacAddress(state)) { + LOGGER.warn("Processing stopped. RGW MAC address taken from event ({}) " + + "does not match with A&AI metadata corresponding value", + state.getCpeAuthenticationEvent().getRgwMacAddress()); + return Mono.empty(); + } + + ControlLoopPublisherDmaapModel event = buildTriggeringPolicyEvent(state); + return publisherTask.execute(event) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for DMaaP publish confirmation") + ) + .doOnError(e -> LOGGER.error("Error while triggering Policy: {}", e.getMessage())) + .onErrorResume( + e -> e instanceof DmaapException || e instanceof TimeoutException, + e -> Mono.empty()); + } + + + private boolean isCorrectMacAddress(PipelineState state) { + // We need to check if the RGW MAC address received in VES event matches the one found in + // HSIA CFS service (in its metadata section) + Optional<MetadataListAaiObject> optionalMetadata = state.getHsiCfsServiceInstance() + .getMetadataListAaiObject(); + String eventRgwMacAddress = state.getCpeAuthenticationEvent().getRgwMacAddress().orElse(""); + return optionalMetadata + .map(list -> list.getMetadataEntries() + .stream() + .anyMatch(m -> m.getMetaname().equals("rgw-mac-address") + && m.getMetavalue().equals(eventRgwMacAddress))) + .orElse(false); + } + + private ControlLoopPublisherDmaapModel buildTriggeringPolicyEvent(PipelineState state) { + + String cfsServiceInstanceId = state.getHsiCfsServiceInstance().getServiceInstanceId(); + + Map<String, String> enrichmentData = new HashMap<>(); + enrichmentData.put("service-information.hsia-cfs-service-instance-id", cfsServiceInstanceId); + enrichmentData.put("cpe.old-authentication-state", state.cpeAuthenticationEvent.getOldAuthenticationState()); + enrichmentData.put("cpe.new-authentication-state", state.cpeAuthenticationEvent.getNewAuthenticationState()); + String swVersion = state.getCpeAuthenticationEvent().getSwVersion().orElse(""); + if (!StringUtils.isEmpty(swVersion)) { + enrichmentData.put("cpe.swVersion", swVersion); + } + + ControlLoopPublisherDmaapModel triggerEvent = ImmutableControlLoopPublisherDmaapModel.builder() + .closedLoopEventClient(DCAE_BBS_EVENT_PROCESSOR_MS_INSTANCE) + .policyVersion(POLICY_VERSION) + .policyName(POLICY_NAME) + .policyScope(configuration.getCpeAuthenticationCloseLoopPolicyScope()) + .targetType(CLOSE_LOOP_TARGET_TYPE) + .aaiEnrichmentData(enrichmentData) + .closedLoopAlarmStart(Instant.now().getEpochSecond()) + .closedLoopEventStatus(CLOSED_LOOP_EVENT_STATUS) + .closedLoopControlName(configuration.getCpeAuthenticationCloseLoopControlName()) + .version(CLOSE_LOOP_VERSION) + .target(CLOSE_LOOP_TARGET) + .requestId(UUID.randomUUID().toString()) + .originator(FROM) + .build(); + LOGGER.debug("Processing Step: Publish for Policy"); + LOGGER.trace("Trigger Policy event: ({})",triggerEvent); + return triggerEvent; + } + + private static class PipelineState { + + private CpeAuthenticationConsumerDmaapModel cpeAuthenticationEvent; + private PnfAaiObject pnfAaiObject; + private ServiceInstanceAaiObject hsiCfsServiceInstance; + + CpeAuthenticationConsumerDmaapModel getCpeAuthenticationEvent() { + return cpeAuthenticationEvent; + } + + void setCpeAuthenticationEvent(CpeAuthenticationConsumerDmaapModel cpeAuthenticationEvent) { + this.cpeAuthenticationEvent = cpeAuthenticationEvent; + } + + PnfAaiObject getPnfAaiObject() { + return pnfAaiObject; + } + + void setPnfAaiObject(PnfAaiObject pnfAaiObject) { + this.pnfAaiObject = pnfAaiObject; + } + + ServiceInstanceAaiObject getHsiCfsServiceInstance() { + return hsiCfsServiceInstance; + } + + void setHsiCfsServiceInstance(ServiceInstanceAaiObject hsiCfsServiceInstance) { + this.hsiCfsServiceInstance = hsiCfsServiceInstance; + } + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipeline.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipeline.java new file mode 100644 index 00000000..7f96cdd5 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipeline.java @@ -0,0 +1,352 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import static org.onap.bbs.event.processor.config.ApplicationConstants.CONSUME_REREGISTRATION_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_PNF_TASK_NAME; +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.INSTANCE_UUID; +import static org.onap.dcaegen2.services.sdk.rest.services.model.logging.MdcVariables.RESPONSE_CODE; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeoutException; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.tasks.AaiClientTask; +import org.onap.bbs.event.processor.tasks.DmaapPublisherTask; +import org.onap.bbs.event.processor.tasks.DmaapReRegistrationConsumerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +public class ReRegistrationPipeline { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReRegistrationPipeline.class); + + private static final String DCAE_BBS_EVENT_PROCESSOR_MS_INSTANCE = "DCAE.BBS_event_processor_mSInstance"; + private static final String POLICY_VERSION = "1.0.0.5"; + private static final String POLICY_NAME = "Nomadic_ONT"; + private static final String CLOSE_LOOP_TARGET_TYPE = "VM"; + private static final String CLOSED_LOOP_EVENT_STATUS = "ONSET"; + private static final String CLOSE_LOOP_VERSION = "1.0.2"; + private static final String CLOSE_LOOP_TARGET = "vserver.vserver-name"; + private static final String FROM = "DCAE"; + + private DmaapReRegistrationConsumerTask consumerTask; + private DmaapPublisherTask publisherTask; + private AaiClientTask aaiClientTask; + + private ApplicationConfiguration configuration; + + private Map<String, String> mdcContextMap; + + @Autowired + ReRegistrationPipeline(ApplicationConfiguration configuration, + DmaapReRegistrationConsumerTask consumerTask, + DmaapPublisherTask publisherTask, + AaiClientTask aaiClientTask, + Map<String, String> mdcContextMap) { + this.configuration = configuration; + this.consumerTask = consumerTask; + this.publisherTask = publisherTask; + this.aaiClientTask = aaiClientTask; + this.mdcContextMap = mdcContextMap; + } + + /** + * PNF re-registration processing pipeline for BBS uS. + */ + public void processPnfReRegistrationEvents() { + MDC.setContextMap(mdcContextMap); + LOGGER.info("Process next Re-Registration events"); + executePipeline() + .subscribe(this::onSuccess, this::onError, this::onComplete); + LOGGER.trace("Reactive PNF Re-registration pipeline subscribed - Execution started"); + } + + Flux<ResponseEntity<String>> executePipeline() { + return + // Consume Re-Registration from DMaaP + consumeReRegistrationsFromDmaap() + // Fetch PNF from A&AI + .flatMap(this::fetchPnfFromAai) + // Fetch related HSI CFS instance from A&AI + .flatMap(this::fetchHsiCfsServiceInstanceFromAai) + // Trigger Policy for relocation + .flatMap(this::triggerPolicy); + } + + private void onSuccess(ResponseEntity<String> responseCode) { + MDC.put(RESPONSE_CODE, responseCode.getStatusCode().toString()); + LOGGER.info("PNF Re-Registration event successfully handled. " + + "Publishing to DMaaP for Policy returned a status code of ({} {})", + responseCode.getStatusCode().value(), responseCode.getStatusCode().getReasonPhrase()); + MDC.remove(RESPONSE_CODE); + } + + private void onError(Throwable throwable) { + LOGGER.error("Aborted PNF Re-Registration events processing. Error: {}", throwable.getMessage()); + } + + private void onComplete() { + LOGGER.info("PNF Re-Registration processing pipeline has been completed"); + } + + private Flux<PipelineState> consumeReRegistrationsFromDmaap() { + return Flux.defer(() -> { + MDC.put(INSTANCE_UUID, UUID.randomUUID().toString()); + try { + return consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(e -> { + if (e instanceof TimeoutException) { + LOGGER.warn("Timed out waiting for DMaaP response"); + } else if (e instanceof EmptyDmaapResponseException) { + LOGGER.warn("Nothing to consume from DMaaP"); + } + }) + .onErrorResume( + e -> (e instanceof EmptyDmaapResponseException || e instanceof TimeoutException), + e -> Mono.empty()) + .map(event -> { + // For each message, we have to keep separate state. This state will be enhanced + // in each step and handed off to the next processing step + PipelineState state = new PipelineState(); + state.setReRegistrationEvent(event); + return state; + }); + } catch (SSLException e) { + return Flux.error(e); + } + }); + } + + private Mono<PipelineState> fetchPnfFromAai(PipelineState state) { + + ReRegistrationConsumerDmaapModel vesEvent = state.getReRegistrationEvent(); + String pnfName = vesEvent.getCorrelationId(); + String url = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName); + LOGGER.debug("Processing Step: Retrieve PNF. Url: ({})", url); + + return aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, url) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for A&AI response") + ) + .doOnError(e -> LOGGER.error("Error while retrieving PNF: {}", + e.getMessage()) + ) + .onErrorResume( + e -> e instanceof AaiTaskException || e instanceof TimeoutException, + e -> Mono.empty()) + .map(p -> { + state.setPnfAaiObject(p); + return state; + }); + } + + private Mono<PipelineState> fetchHsiCfsServiceInstanceFromAai(PipelineState state) { + + if (state == null || state.getPnfAaiObject() == null) { + return Mono.empty(); + } + + // At this point, we have both the VES-event of the re-registration and the PNF object retrieved from A&AI + // We can check if this processing needs to continue in case of a true relocation + if (isNotReallyAnOntRelocation(state)) { + return Mono.empty(); + } + + PnfAaiObject pnf = state.getPnfAaiObject(); + // Assuming that the PNF will only have a single service-instance relationship pointing + // towards the HSI CFS service + String serviceInstanceId = pnf.getRelationshipListAaiObject().getRelationshipEntries() + .stream() + .filter(e -> e.getRelatedTo().equals("service-instance")) + .flatMap(e -> e.getRelationshipData().stream()) + .filter(d -> d.getRelationshipKey().equals("service-instance.service-instance-id")) + .map(RelationshipListAaiObject.RelationshipDataEntryAaiObject::getRelationshipValue) + .findFirst().orElse(""); + + if (StringUtils.isEmpty(serviceInstanceId)) { + LOGGER.error("Unable to retrieve HSI CFS service instance from PNF {}", + state.getPnfAaiObject().getPnfName()); + return Mono.empty(); + } + + String url = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + serviceInstanceId); + LOGGER.debug("Processing Step: Retrieve HSI CFS Service. Url: ({})", url); + return aaiClientTask.executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, url) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for A&AI response") + ) + .doOnError(e -> LOGGER.error("Error while retrieving HSI CFS Service instance: {}", + e.getMessage()) + ) + .onErrorResume( + e -> e instanceof AaiTaskException || e instanceof TimeoutException, + e -> Mono.empty()) + .map(s -> { + state.setHsiCfsServiceInstance(s); + return state; + }); + } + + private boolean isNotReallyAnOntRelocation(PipelineState state) { + List<RelationshipListAaiObject.RelationshipEntryAaiObject> relationshipEntries = + state.getPnfAaiObject().getRelationshipListAaiObject().getRelationshipEntries(); + + // If no logical-link, fail further processing + if (relationshipEntries.stream().noneMatch(e -> e.getRelatedTo().equals("logical-link"))) { + LOGGER.warn("PNF {} does not have any logical-links bridged. Stop further processing", + state.getPnfAaiObject().getPnfName()); + return true; + } + + // Assuming PNF will only have one logical-link per BBS use case design + boolean isNotRelocation = relationshipEntries + .stream() + .filter(e -> e.getRelatedTo().equals("logical-link")) + .flatMap(e -> e.getRelationshipData().stream()) + .anyMatch(d -> d.getRelationshipValue() + .equals(state.getReRegistrationEvent().getAttachmentPoint())); + + + if (isNotRelocation) { + LOGGER.warn("Not a Relocation for PNF {} with attachment point {}", + state.getPnfAaiObject().getPnfName(), + state.getReRegistrationEvent().getAttachmentPoint()); + } + return isNotRelocation; + } + + private Mono<ResponseEntity<String>> triggerPolicy(PipelineState state) { + + if (state == null || state.getHsiCfsServiceInstance() == null) { + return Mono.empty(); + } + + ControlLoopPublisherDmaapModel event = buildTriggeringPolicyEvent(state); + return publisherTask.execute(event) + .timeout(Duration.ofSeconds(configuration.getPipelinesTimeoutInSeconds())) + .doOnError(TimeoutException.class, + e -> LOGGER.warn("Timed out waiting for DMaaP confirmation") + ) + .doOnError(e -> LOGGER.error("Error while triggering Policy: {}", e.getMessage())) + .onErrorResume( + e -> e instanceof DmaapException || e instanceof TimeoutException, + e -> Mono.empty()); + } + + private ControlLoopPublisherDmaapModel buildTriggeringPolicyEvent(PipelineState state) { + + String cfsServiceInstanceId = state.getHsiCfsServiceInstance().getServiceInstanceId(); + + String attachmentPoint = state.getReRegistrationEvent().getAttachmentPoint(); + String remoteId = state.getReRegistrationEvent().getRemoteId(); + String cvlan = state.getReRegistrationEvent().getCVlan(); + String svlan = state.getReRegistrationEvent().getSVlan(); + + Map<String, String> enrichmentData = new HashMap<>(); + enrichmentData.put("service-information.hsia-cfs-service-instance-id", cfsServiceInstanceId); + + enrichmentData.put("attachmentPoint", attachmentPoint); + enrichmentData.put("remoteId", remoteId); + enrichmentData.put("cvlan", cvlan); + enrichmentData.put("svlan", svlan); + + ControlLoopPublisherDmaapModel triggerEvent = ImmutableControlLoopPublisherDmaapModel.builder() + .closedLoopEventClient(DCAE_BBS_EVENT_PROCESSOR_MS_INSTANCE) + .policyVersion(POLICY_VERSION) + .policyName(POLICY_NAME) + .policyScope(configuration.getReRegistrationCloseLoopPolicyScope()) + .targetType(CLOSE_LOOP_TARGET_TYPE) + .aaiEnrichmentData(enrichmentData) + .closedLoopAlarmStart(Instant.now().getEpochSecond()) + .closedLoopEventStatus(CLOSED_LOOP_EVENT_STATUS) + .closedLoopControlName(configuration.getReRegistrationCloseLoopControlName()) + .version(CLOSE_LOOP_VERSION) + .target(CLOSE_LOOP_TARGET) + .requestId(UUID.randomUUID().toString()) + .originator(FROM) + .build(); + LOGGER.debug("Processing Step: Publish for Policy"); + LOGGER.trace("Trigger Policy event: ({})",triggerEvent); + return triggerEvent; + } + + private static class PipelineState { + + private ReRegistrationConsumerDmaapModel reRegistrationEvent; + private PnfAaiObject pnfAaiObject; + private ServiceInstanceAaiObject hsiCfsServiceInstance; + + ReRegistrationConsumerDmaapModel getReRegistrationEvent() { + return reRegistrationEvent; + } + + void setReRegistrationEvent(ReRegistrationConsumerDmaapModel reRegistrationEvent) { + this.reRegistrationEvent = reRegistrationEvent; + } + + PnfAaiObject getPnfAaiObject() { + return pnfAaiObject; + } + + void setPnfAaiObject(PnfAaiObject pnfAaiObject) { + this.pnfAaiObject = pnfAaiObject; + } + + ServiceInstanceAaiObject getHsiCfsServiceInstance() { + return hsiCfsServiceInstance; + } + + void setHsiCfsServiceInstance(ServiceInstanceAaiObject hsiCfsServiceInstance) { + this.hsiCfsServiceInstance = hsiCfsServiceInstance; + } + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/Scheduler.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/Scheduler.java new file mode 100644 index 00000000..64d212ad --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/pipelines/Scheduler.java @@ -0,0 +1,249 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.config.ConfigurationChangeObserver; +import org.onap.bbs.event.processor.config.ConsulConfigurationGateway; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class Scheduler implements ConfigurationChangeObserver { + + private static final Logger LOGGER = LoggerFactory.getLogger(Scheduler.class); + + private static final int PIPELINES_INITIAL_DELAY_IN_SECONDS = 10; + private static final int DEFAULT_PIPELINES_POLLING_INTERVAL = 15; + private static final Duration CBS_INITIAL_DELAY = Duration.ofSeconds(1); + private static final int DEFAULT_CBS_POLLING_INTERVAL = 30; + + private final ConsulConfigurationGateway configurationGateway; + private final TaskScheduler taskScheduler; + private final ReRegistrationPipeline reRegistrationPipeline; + private final CpeAuthenticationPipeline cpeAuthenticationPipeline; + private ApplicationConfiguration configuration; + private Map<String, ScheduledFuture> processingScheduledTasks; + private ScheduledFuture cbsScheduledTask; + private int currentPipelinesPollingInterval; + private int currentCbsPollingInterval; + + @Autowired + Scheduler(ApplicationConfiguration configuration, + ConsulConfigurationGateway configurationGateway, + TaskScheduler taskScheduler, + ReRegistrationPipeline reRegistrationPipeline, + CpeAuthenticationPipeline cpeAuthenticationPipeline) { + this.configuration = configuration; + this.configurationGateway = configurationGateway; + this.taskScheduler = taskScheduler; + this.reRegistrationPipeline = reRegistrationPipeline; + this.cpeAuthenticationPipeline = cpeAuthenticationPipeline; + processingScheduledTasks = new ConcurrentHashMap<>(); + } + + /** + * Sets up Scheduler. + * + * <p>Initiates CBS configuration fetch periodic task and DMaaP PNF re-registration and CPE + * authentication event polling tasks.</p> + * + * <p>It also registers for application configuration changes notifications.</p> + */ + @PostConstruct + public void setupScheduler() { + + // Initiate periodic configuration fetching from CBS + currentCbsPollingInterval = verifyCbsPollingInterval(); + cbsScheduledTask = + taskScheduler.schedule(() -> configurationGateway.periodicallyFetchConfigFromCbs(CBS_INITIAL_DELAY, + Duration.ofSeconds(currentCbsPollingInterval)), Instant.now()); + + // Initiate Processing tasks + currentPipelinesPollingInterval = validatePipelinesPollingInterval(); + LOGGER.info("BBS event processing pipelines will start in {} seconds " + + "and will run periodically every {} seconds", PIPELINES_INITIAL_DELAY_IN_SECONDS, + currentPipelinesPollingInterval); + Instant desiredStartTime = Instant.now().plusSeconds(PIPELINES_INITIAL_DELAY_IN_SECONDS); + scheduleProcessingTasks(desiredStartTime, currentPipelinesPollingInterval); + + // Register for configuration changes + configuration.register(this); + } + + /** + * Un-registers from getting application configuration changes notifications. + */ + @PreDestroy + public void unRegisterAsConfigChangeObserver() { + configuration.unRegister(this); + } + + @Override + public void updateConfiguration(ApplicationConfiguration newConfiguration) { + if (newConfiguration.getPipelinesPollingIntervalInSeconds() != currentPipelinesPollingInterval + || newConfiguration.getCbsPollingInterval() != currentCbsPollingInterval) { + configuration = newConfiguration; + } + if (newConfiguration.getPipelinesPollingIntervalInSeconds() != currentPipelinesPollingInterval) { + LOGGER.info("Pipelines Polling interval has changed. Re-scheduling processing pipelines"); + cancelScheduledProcessingTasks(); + reScheduleProcessingTasks(); + } + int newCbsPollingInterval = newConfiguration.getCbsPollingInterval(); + if (newCbsPollingInterval != currentCbsPollingInterval) { + if (newCbsPollingInterval < DEFAULT_CBS_POLLING_INTERVAL) { + LOGGER.warn("CBS Polling interval is too small ({}). Will not re-schedule CBS job", + newCbsPollingInterval); + } else { + rescheduleCbsScheduledTask(newCbsPollingInterval); + } + } + } + + private void rescheduleCbsScheduledTask(int newCbsPollingInterval) { + LOGGER.info("CBS Polling interval has changed. Re-scheduling CBS job"); + currentCbsPollingInterval = newCbsPollingInterval; + if (!cbsScheduledTask.isDone()) { + if (cbsScheduledTask.cancel(true)) { + LOGGER.debug("CBS task has been cancelled"); + } else { + LOGGER.error("Error while cancelling CBS task. Task status (isDone/isCanceled) is ({}/{})", + cbsScheduledTask.isDone(), cbsScheduledTask.isCancelled()); + } + } + cbsScheduledTask = taskScheduler.schedule(() -> + configurationGateway.rescheduleCbsConfigurationRetrieval(CBS_INITIAL_DELAY, + Duration.ofSeconds(currentCbsPollingInterval)), Instant.now()); + } + + /** + * Cancels DMaaP polling tasks (PNF re-registration & CPE authentication). + * @return Tasks cancellation result + */ + public boolean cancelScheduledProcessingTasks() { + + if (processingScheduledTasks.isEmpty()) { + LOGGER.debug("No tasks found to cancel"); + return true; + } + + processingScheduledTasks.forEach((key, value) -> { + if (value.cancel(false)) { + LOGGER.debug("Task {} has been cancelled", key); + } else { + LOGGER.error("Error while cancelling task {}. Task status (isDone/isCanceled) is ({}/{})", + key, value.isDone(), value.isCancelled()); + } + }); + processingScheduledTasks.entrySet().removeIf(entry -> entry.getValue().isCancelled()); + LOGGER.info("All cancelled tasks have been removed"); + return processingScheduledTasks.isEmpty(); + } + + /** + * Reschedules DMaaP polling tasks (PNF re-registration & CPE authentication). + * @return Tasks rescheduling result + */ + public boolean reScheduleProcessingTasks() { + + if (processingScheduledTasks.size() != 0) { + // If every task is cancelled, we can remove and re-schedule + if (processingScheduledTasks.entrySet().stream() + .allMatch(e -> e.getValue().isCancelled())) { + processingScheduledTasks.clear(); + LOGGER.debug("Old cancelled tasks have been removed"); + } else { + LOGGER.error("Cannot reschedule. There are {} active tasks that must be first cancelled", + processingScheduledTasks.entrySet().stream() + .filter(e -> !e.getValue().isCancelled()) + .count() + ); + return false; + } + } + currentPipelinesPollingInterval = validatePipelinesPollingInterval(); + LOGGER.info("Reschedule tasks"); + scheduleProcessingTasks(Instant.now(), currentPipelinesPollingInterval); + return true; + } + + int numberOfTotalTasks() { + return processingScheduledTasks.size(); + } + + long numberOfActiveTasks() { + return processingScheduledTasks.entrySet().stream() + .filter(e -> (!e.getValue().isCancelled())) + .count(); + } + + long numberOfCancelledTasks() { + return processingScheduledTasks.entrySet().stream() + .filter(e -> (e.getValue().isCancelled())) + .count(); + } + + private void scheduleProcessingTasks(Instant desiredStartTime, int pollingInterval) { + processingScheduledTasks.put("Re-registration", + taskScheduler.scheduleAtFixedRate(reRegistrationPipeline::processPnfReRegistrationEvents, + desiredStartTime, Duration.ofSeconds(pollingInterval))); + processingScheduledTasks.put("CPE Authentication", + taskScheduler.scheduleAtFixedRate(cpeAuthenticationPipeline::processPnfCpeAuthenticationEvents, + desiredStartTime, Duration.ofSeconds(pollingInterval))); + } + + private int validatePipelinesPollingInterval() { + int pipelinesPollingInterval = configuration.getPipelinesPollingIntervalInSeconds(); + boolean isSmallInterval = pipelinesPollingInterval < DEFAULT_PIPELINES_POLLING_INTERVAL; + int verifiedInterval = isSmallInterval ? DEFAULT_PIPELINES_POLLING_INTERVAL : pipelinesPollingInterval; + if (isSmallInterval) { + LOGGER.warn("Pipelines Polling interval is too small ({}). Defaulting to {}", pipelinesPollingInterval, + DEFAULT_PIPELINES_POLLING_INTERVAL); + } + return verifiedInterval; + } + + private int verifyCbsPollingInterval() { + int cbsPollingInterval = configuration.getCbsPollingInterval(); + boolean isSmallInterval = cbsPollingInterval < DEFAULT_CBS_POLLING_INTERVAL; + int verifiedInterval = isSmallInterval ? DEFAULT_CBS_POLLING_INTERVAL : cbsPollingInterval; + if (isSmallInterval) { + LOGGER.warn("CBS Polling interval is too small ({}). Defaulting to {}", cbsPollingInterval, + DEFAULT_CBS_POLLING_INTERVAL); + } + return verifiedInterval; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTask.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTask.java new file mode 100644 index 00000000..239ccd6c --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTask.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.utilities.AaiReactiveClient; + +import reactor.core.publisher.Mono; + +public interface AaiClientTask { + + Mono<PnfAaiObject> executePnfRetrieval(String taskName, String url); + + Mono<ServiceInstanceAaiObject> executeServiceInstanceRetrieval(String taskName, String url); + + AaiReactiveClient resolveClient(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImpl.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImpl.java new file mode 100644 index 00000000..1dc43557 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImpl.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.utilities.AaiReactiveClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import reactor.core.publisher.Mono; + +@Component +public class AaiClientTaskImpl implements AaiClientTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(AaiClientTaskImpl.class); + private final AaiReactiveClient reactiveClient; + + @Autowired + public AaiClientTaskImpl(AaiReactiveClient reactiveClient) { + this.reactiveClient = reactiveClient; + } + + @Override + public Mono<PnfAaiObject> executePnfRetrieval(String taskName, String url) { + if (StringUtils.isEmpty(url)) { + throw new AaiTaskException("Cannot invoke an A&AI client task with an invalid URL"); + } + LOGGER.info("Executing task ({}) for retrieving PNF object", taskName); + return resolveClient().getPnfObjectDataFor(url); + } + + @Override + public Mono<ServiceInstanceAaiObject> executeServiceInstanceRetrieval(String taskName, String url) { + if (StringUtils.isEmpty(url)) { + throw new AaiTaskException("Cannot invoke an A&AI client task with an invalid URL"); + } + LOGGER.info("Executing task ({}) for retrieving Service Instance object", taskName); + return resolveClient().getServiceInstanceObjectDataFor(url); + } + + @Override + public AaiReactiveClient resolveClient() { + return reactiveClient; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTask.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTask.java new file mode 100644 index 00000000..2e8a9ee2 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTask.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; + +import reactor.core.publisher.Flux; + +public interface DmaapCpeAuthenticationConsumerTask { + + Flux<CpeAuthenticationConsumerDmaapModel> execute(String object) throws SSLException; + + DMaaPConsumerReactiveHttpClient resolveClient() throws SSLException; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImpl.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImpl.java new file mode 100644 index 00000000..e9546638 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImpl.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.utilities.CpeAuthenticationDmaapConsumerJsonParser; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.ConsumerReactiveHttpClientFactory; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPReactiveWebClientFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +public class DmaapCpeAuthenticationConsumerTaskImpl implements DmaapCpeAuthenticationConsumerTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(DmaapCpeAuthenticationConsumerTaskImpl.class); + private final ApplicationConfiguration configuration; + private final CpeAuthenticationDmaapConsumerJsonParser cpeAuthenticationDmaapConsumerJsonParser; + private final ConsumerReactiveHttpClientFactory httpClientFactory; + + @Autowired + public DmaapCpeAuthenticationConsumerTaskImpl(ApplicationConfiguration configuration) { + this(configuration, new CpeAuthenticationDmaapConsumerJsonParser(), + new ConsumerReactiveHttpClientFactory(new DMaaPReactiveWebClientFactory())); + } + + DmaapCpeAuthenticationConsumerTaskImpl(ApplicationConfiguration configuration, + CpeAuthenticationDmaapConsumerJsonParser + cpeAuthenticationDmaapConsumerJsonParser, + ConsumerReactiveHttpClientFactory httpClientFactory) { + this.configuration = configuration; + this.cpeAuthenticationDmaapConsumerJsonParser = cpeAuthenticationDmaapConsumerJsonParser; + this.httpClientFactory = httpClientFactory; + } + + @Override + public Flux<CpeAuthenticationConsumerDmaapModel> execute(String taskName) throws SSLException { + LOGGER.debug("Executing task for CPE-Authentication with name \"{}\"", taskName); + DMaaPConsumerReactiveHttpClient dmaaPConsumerReactiveHttpClient = resolveClient(); + Mono<String> response = dmaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse(); + return cpeAuthenticationDmaapConsumerJsonParser.extractModelFromDmaap(response) + .switchIfEmpty(Flux.error( + new EmptyDmaapResponseException("CPE Authentication: Got an empty response from DMaaP"))) + .doOnError(e -> { + if (!(e instanceof EmptyDmaapResponseException)) { + LOGGER.error("DMaaP Consumption Exception: {}", e.getMessage()); + } + }); + } + + @Override + public DMaaPConsumerReactiveHttpClient resolveClient() throws SSLException { + return httpClientFactory.create(configuration.getDmaapCpeAuthenticationConsumerConfiguration()); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTask.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTask.java new file mode 100644 index 00000000..bc18064b --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTask.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.DMaaPPublisherReactiveHttpClient; +import org.springframework.http.ResponseEntity; + +import reactor.core.publisher.Mono; + +public interface DmaapPublisherTask { + + Mono<ResponseEntity<String>> execute(ControlLoopPublisherDmaapModel controlLoopPublisherDmaapModel); + + DMaaPPublisherReactiveHttpClient resolveClient(); +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImpl.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImpl.java new file mode 100644 index 00000000..1dd39bec --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImpl.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.utilities.ControlLoopJsonBodyBuilder; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.DMaaPPublisherReactiveHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.DmaaPRestTemplateFactory; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.PublisherReactiveHttpClientFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import reactor.core.publisher.Mono; + +@Component +public class DmaapPublisherTaskImpl implements DmaapPublisherTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(DmaapPublisherTaskImpl.class); + private final ApplicationConfiguration configuration; + private final PublisherReactiveHttpClientFactory httpClientFactory; + + @Autowired + DmaapPublisherTaskImpl(ApplicationConfiguration configuration) { + this(configuration, new PublisherReactiveHttpClientFactory(new DmaaPRestTemplateFactory(), + new ControlLoopJsonBodyBuilder())); + } + + DmaapPublisherTaskImpl(ApplicationConfiguration configuration, + PublisherReactiveHttpClientFactory httpClientFactory) { + this.configuration = configuration; + this.httpClientFactory = httpClientFactory; + } + + @Override + public Mono<ResponseEntity<String>> execute(ControlLoopPublisherDmaapModel controlLoopPublisherDmaapModel) { + if (controlLoopPublisherDmaapModel == null) { + throw new DmaapException("Cannot invoke a DMaaP Publish task with a null message"); + } + LOGGER.info("Executing task for publishing control loop message \n{}", controlLoopPublisherDmaapModel); + DMaaPPublisherReactiveHttpClient dmaapPublisherReactiveHttpClient = resolveClient(); + return dmaapPublisherReactiveHttpClient.getDMaaPProducerResponse(controlLoopPublisherDmaapModel); + } + + @Override + public DMaaPPublisherReactiveHttpClient resolveClient() { + return httpClientFactory.create(configuration.getDmaapPublisherConfiguration()); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTask.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTask.java new file mode 100644 index 00000000..ea459d00 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTask.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; + +import reactor.core.publisher.Flux; + +public interface DmaapReRegistrationConsumerTask { + + Flux<ReRegistrationConsumerDmaapModel> execute(String taskName) throws SSLException; + + DMaaPConsumerReactiveHttpClient resolveClient() throws SSLException; +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImpl.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImpl.java new file mode 100644 index 00000000..d8610215 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImpl.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.utilities.ReRegistrationDmaapConsumerJsonParser; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.ConsumerReactiveHttpClientFactory; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPReactiveWebClientFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +public class DmaapReRegistrationConsumerTaskImpl implements DmaapReRegistrationConsumerTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(DmaapReRegistrationConsumerTaskImpl.class); + private final ApplicationConfiguration configuration; + private final ReRegistrationDmaapConsumerJsonParser reRegistrationDmaapConsumerJsonParser; + private final ConsumerReactiveHttpClientFactory httpClientFactory; + + @Autowired + public DmaapReRegistrationConsumerTaskImpl(ApplicationConfiguration configuration) { + this(configuration, new ReRegistrationDmaapConsumerJsonParser(), + new ConsumerReactiveHttpClientFactory(new DMaaPReactiveWebClientFactory())); + } + + DmaapReRegistrationConsumerTaskImpl(ApplicationConfiguration configuration, + ReRegistrationDmaapConsumerJsonParser reRegDmaapConsumerJsonParser, + ConsumerReactiveHttpClientFactory httpClientFactory) { + this.configuration = configuration; + this.reRegistrationDmaapConsumerJsonParser = reRegDmaapConsumerJsonParser; + this.httpClientFactory = httpClientFactory; + } + + @Override + public Flux<ReRegistrationConsumerDmaapModel> execute(String taskName) throws SSLException { + LOGGER.debug("Executing task for Re-Registration with name \"{}\"", taskName); + DMaaPConsumerReactiveHttpClient dmaaPConsumerReactiveHttpClient = resolveClient(); + Mono<String> response = dmaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse(); + return reRegistrationDmaapConsumerJsonParser.extractModelFromDmaap(response) + .switchIfEmpty(Flux.error( + new EmptyDmaapResponseException("Re-Registration: Got an empty response from DMaaP"))) + .doOnError(e -> { + if (!(e instanceof EmptyDmaapResponseException)) { + LOGGER.error("DMaaP Consumption Exception: {}", e.getMessage()); + } + }); + } + + @Override + public DMaaPConsumerReactiveHttpClient resolveClient() throws SSLException { + return httpClientFactory.create(configuration.getDmaapReRegistrationConsumerConfiguration()); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/AaiReactiveClient.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/AaiReactiveClient.java new file mode 100644 index 00000000..131551e5 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/AaiReactiveClient.java @@ -0,0 +1,189 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +import io.netty.handler.ssl.SslContext; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.net.ssl.SSLException; + +import org.onap.bbs.event.processor.config.AaiClientConfiguration; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.config.ConfigurationChangeObserver; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.dcaegen2.services.sdk.rest.services.ssl.SslFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; +import reactor.netty.http.client.HttpClient; + +@Component +public class AaiReactiveClient implements ConfigurationChangeObserver { + + private static final Logger LOGGER = LoggerFactory.getLogger(AaiReactiveClient.class); + + private final Gson gson; + private WebClient webClient; + private SslFactory sslFactory; + private final ApplicationConfiguration configuration; + private AaiClientConfiguration aaiClientConfiguration; + + @Autowired + AaiReactiveClient(ApplicationConfiguration configuration, Gson gson) throws SSLException { + this.configuration = configuration; + this.gson = gson; + this.sslFactory = new SslFactory(); + + aaiClientConfiguration = configuration.getAaiClientConfiguration(); + setupWebClient(); + } + + @PostConstruct + public void registerForConfigChanges() { + configuration.register(this); + } + + @PreDestroy + public void unRegisterForConfigChanges() { + configuration.unRegister(this); + } + + @Override + public void updateConfiguration(ApplicationConfiguration configuration) { + AaiClientConfiguration newConfiguration = configuration.getAaiClientConfiguration(); + if (aaiClientConfiguration.equals(newConfiguration)) { + LOGGER.debug("No Configuration changes necessary for AAI Reactive client"); + } else { + LOGGER.debug("AAI Reactive client must be re-configured"); + aaiClientConfiguration = newConfiguration; + try { + setupWebClient(); + } catch (SSLException e) { + LOGGER.error("AAI Reactive client error while re-configuring WebClient"); + } + } + } + + private synchronized void setupWebClient() throws SSLException { + SslContext sslContext = createSslContext(); + + ClientHttpConnector reactorClientHttpConnector = new ReactorClientHttpConnector( + HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext))); + + this.webClient = WebClient.builder() + .baseUrl(aaiClientConfiguration.aaiProtocol() + "://" + aaiClientConfiguration.aaiHost() + + ":" + aaiClientConfiguration.aaiPort()) + .clientConnector(reactorClientHttpConnector) + .defaultHeaders(httpHeaders -> httpHeaders.setAll(aaiClientConfiguration.aaiHeaders())) + .filter(basicAuthentication(aaiClientConfiguration.aaiUserName(), + aaiClientConfiguration.aaiUserPassword())) + .filter(logRequest()) + .filter(logResponse()) + .build(); + } + + public Mono<PnfAaiObject> getPnfObjectDataFor(String url) { + + return performReactiveHttpGet(url, PnfAaiObject.class); + } + + public Mono<ServiceInstanceAaiObject> getServiceInstanceObjectDataFor(String url) { + + return performReactiveHttpGet(url, ServiceInstanceAaiObject.class); + } + + private synchronized <T> Mono<T> performReactiveHttpGet(String url, Class<T> responseType) { + LOGGER.debug("Will issue Reactive GET request to URL ({}) for object ({})", url, responseType.getName()); + return webClient + .get() + .uri(url) + .retrieve() + .onStatus(HttpStatus::is4xxClientError, + response -> Mono.error(createExceptionObject(url, response))) + .onStatus(HttpStatus::is5xxServerError, + response -> Mono.error(createExceptionObject(url, response))) + .bodyToMono(String.class) + .flatMap(body -> extractMono(body, responseType)); + } + + private AaiTaskException createExceptionObject(String url, ClientResponse response) { + return new AaiTaskException(String.format("A&AI Request for (%s) failed with HTTP status code %d", url, + response.statusCode().value())); + } + + private <T> Mono<T> extractMono(String body, Class<T> responseType) { + LOGGER.debug("Response body \n{}", body); + try { + return Mono.just(parseFromJsonReply(body, responseType)); + } catch (JsonSyntaxException | IllegalStateException e) { + return Mono.error(e); + } + } + + private <T> T parseFromJsonReply(String body, Class<T> responseType) { + return gson.fromJson(body, responseType); + } + + private static ExchangeFilterFunction logRequest() { + return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { + LOGGER.debug("Request: {} {}", clientRequest.method(), clientRequest.url()); + clientRequest.headers() + .forEach((name, values) -> values.forEach(value -> LOGGER.debug("{}={}", name, value))); + return Mono.just(clientRequest); + }); + } + + private static ExchangeFilterFunction logResponse() { + return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> { + LOGGER.debug("Response status {}", clientResponse.statusCode()); + return Mono.just(clientResponse); + }); + } + + private SslContext createSslContext() throws SSLException { + if (aaiClientConfiguration.enableAaiCertAuth()) { + return sslFactory.createSecureContext( + aaiClientConfiguration.keyStorePath(), + aaiClientConfiguration.keyStorePasswordPath(), + aaiClientConfiguration.trustStorePath(), + aaiClientConfiguration.trustStorePasswordPath() + ); + } + return sslFactory.createInsecureContext(); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CommonEventFields.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CommonEventFields.java new file mode 100644 index 00000000..c2b67348 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CommonEventFields.java @@ -0,0 +1,33 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +public class CommonEventFields { + + static final String COMMON_FORMAT = "\": \"%s\""; + static final String EVENT = "event"; + static final String COMMON_EVENT_HEADER = "commonEventHeader"; + static final String SOURCE_NAME = "sourceName"; + static final String CORRELATION_ID = "correlationId"; + + // Non-instantiable class + private CommonEventFields() {} +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ControlLoopJsonBodyBuilder.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ControlLoopJsonBodyBuilder.java new file mode 100644 index 00000000..03ea0936 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ControlLoopJsonBodyBuilder.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.ServiceLoader; + +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableControlLoopPublisherDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.model.JsonBodyBuilder; + +public class ControlLoopJsonBodyBuilder implements JsonBodyBuilder<ControlLoopPublisherDmaapModel> { + + /** + * Serialize the Control Loop DMaaP model with GSON. + * @param publisherDmaapModel object to be serialized + * @return String output of serialization + */ + @Override + public String createJsonBody(ControlLoopPublisherDmaapModel publisherDmaapModel) { + GsonBuilder gsonBuilder = new GsonBuilder().disableHtmlEscaping(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + return gsonBuilder.create().toJson(ImmutableControlLoopPublisherDmaapModel.builder() + .closedLoopEventClient(publisherDmaapModel.getClosedLoopEventClient()) + .policyVersion(publisherDmaapModel.getPolicyVersion()) + .policyName(publisherDmaapModel.getPolicyName()) + .policyScope(publisherDmaapModel.getPolicyScope()) + .targetType(publisherDmaapModel.getTargetType()) + .aaiEnrichmentData(publisherDmaapModel.getAaiEnrichmentData()) + .closedLoopAlarmStart(publisherDmaapModel.getClosedLoopAlarmStart()) + .closedLoopEventStatus(publisherDmaapModel.getClosedLoopEventStatus()) + .closedLoopControlName(publisherDmaapModel.getClosedLoopControlName()) + .version(publisherDmaapModel.getVersion()) + .target(publisherDmaapModel.getTarget()) + .requestId(publisherDmaapModel.getRequestId()) + .originator(publisherDmaapModel.getOriginator()) + .build()); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParser.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParser.java new file mode 100644 index 00000000..62ab02d5 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParser.java @@ -0,0 +1,183 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static org.onap.bbs.event.processor.utilities.CommonEventFields.COMMON_EVENT_HEADER; +import static org.onap.bbs.event.processor.utilities.CommonEventFields.COMMON_FORMAT; +import static org.onap.bbs.event.processor.utilities.CommonEventFields.CORRELATION_ID; +import static org.onap.bbs.event.processor.utilities.CommonEventFields.EVENT; +import static org.onap.bbs.event.processor.utilities.CommonEventFields.SOURCE_NAME; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.ADDITIONAL_FIELDS; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.NEW_AUTHENTICATION_STATE; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.OLD_AUTHENTICATION_STATE; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.RGW_MAC_ADDRESS; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.STATE_CHANGE_FIELDS; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.STATE_INTERFACE; +import static org.onap.bbs.event.processor.utilities.CpeAuthenticationEventFields.SW_VERSION; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import java.util.Optional; +import java.util.stream.StreamSupport; + +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableCpeAuthenticationConsumerDmaapModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class CpeAuthenticationDmaapConsumerJsonParser { + + private static final Logger LOGGER = LoggerFactory.getLogger(CpeAuthenticationDmaapConsumerJsonParser.class); + + private static final String CPE_AUTHENTICATION_DUMPING_TEMPLATE = "%n{" + + "\"" + CORRELATION_ID + COMMON_FORMAT + "," + + "\"" + OLD_AUTHENTICATION_STATE + COMMON_FORMAT + "," + + "\"" + NEW_AUTHENTICATION_STATE + COMMON_FORMAT + "," + + "\"" + STATE_INTERFACE + COMMON_FORMAT + "," + + "\"" + RGW_MAC_ADDRESS + COMMON_FORMAT + "," + + "\"" + SW_VERSION + COMMON_FORMAT + + "}"; + + private String pnfSourceName; + + private String oldAuthenticationStatus; + private String newAuthenticationStatus; + private String stateInterface; + private String rgwMacAddress; + private String swVersion; + + /** + * Translates a response from DMaaP to a reactive {@link CpeAuthenticationConsumerDmaapModel} model. + * @param dmaapResponse Response from DMaaP + * @return CPE Authentication Consumer DMaaP reactive model + */ + public Flux<CpeAuthenticationConsumerDmaapModel> extractModelFromDmaap(Mono<String> dmaapResponse) { + return dmaapResponse + .flatMapMany(this::parseToMono) + .flatMap(this::createTargetFlux); + } + + private Mono<JsonElement> parseToMono(String message) { + if (StringUtils.isEmpty(message)) { + LOGGER.warn("DMaaP response is empty"); + return Mono.empty(); + } + return Mono.fromCallable(() -> new JsonParser().parse(message)) + .doOnError(e -> e instanceof JsonSyntaxException, e -> LOGGER.error("Invalid JSON. Ignoring")) + .onErrorResume(e -> e instanceof JsonSyntaxException, e -> Mono.empty()); + } + + private Flux<CpeAuthenticationConsumerDmaapModel> createTargetFlux(JsonElement jsonElement) { + if (jsonElement.isJsonObject()) { + return doCreateTargetFlux(Flux.defer(() -> Flux.just(jsonElement.getAsJsonObject()))); + } + return doCreateTargetFlux( + Flux.defer(() -> Flux.fromStream(StreamSupport.stream(jsonElement.getAsJsonArray().spliterator(), false) + .map(jsonElementFromArray -> getJsonObjectFromAnArray(jsonElementFromArray) + .orElseGet(JsonObject::new))))); + } + + private Flux<CpeAuthenticationConsumerDmaapModel> doCreateTargetFlux(Flux<JsonObject> jsonObject) { + return jsonObject + .flatMap(this::transform) + .onErrorResume(exception -> exception instanceof DmaapException, e -> Mono.empty()); + } + + private Mono<CpeAuthenticationConsumerDmaapModel> transform(JsonObject dmaapResponseJsonObject) { + + if (!containsProperHeaders(dmaapResponseJsonObject)) { + LOGGER.warn("Incorrect CPE Authentication JSON event - missing headers"); + return Mono.empty(); + } + + JsonObject commonEventHeader = dmaapResponseJsonObject.getAsJsonObject(EVENT) + .getAsJsonObject(COMMON_EVENT_HEADER); + JsonObject stateChangeFields = dmaapResponseJsonObject.getAsJsonObject(EVENT) + .getAsJsonObject(STATE_CHANGE_FIELDS); + + pnfSourceName = getValueFromJson(commonEventHeader, SOURCE_NAME); + + oldAuthenticationStatus = getValueFromJson(stateChangeFields, OLD_AUTHENTICATION_STATE); + newAuthenticationStatus = getValueFromJson(stateChangeFields, NEW_AUTHENTICATION_STATE); + stateInterface = getValueFromJson(stateChangeFields, STATE_INTERFACE); + + if (stateChangeFields.has(ADDITIONAL_FIELDS)) { + JsonObject additionalFields = stateChangeFields.getAsJsonObject(ADDITIONAL_FIELDS); + rgwMacAddress = getValueFromJson(additionalFields, RGW_MAC_ADDRESS); + swVersion = getValueFromJson(additionalFields, SW_VERSION); + } + + if (StringUtils.isEmpty(pnfSourceName) + || authenticationStatusMissing(oldAuthenticationStatus) + || authenticationStatusMissing(newAuthenticationStatus)) { + String incorrectEvent = dumpJsonData(); + LOGGER.warn("Incorrect CPE Authentication JSON event: {}", incorrectEvent); + return Mono.empty(); + } + + return Mono.just(ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfSourceName) + .oldAuthenticationState(oldAuthenticationStatus) + .newAuthenticationState(newAuthenticationStatus) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build()); + } + + private boolean authenticationStatusMissing(String authenticationStatus) { + return StringUtils.isEmpty(authenticationStatus); + } + + private boolean containsProperHeaders(JsonObject jsonObject) { + return jsonObject.has(EVENT) && jsonObject.getAsJsonObject(EVENT).has(COMMON_EVENT_HEADER) + && jsonObject.getAsJsonObject(EVENT).has(STATE_CHANGE_FIELDS); + } + + private String dumpJsonData() { + return String.format(CPE_AUTHENTICATION_DUMPING_TEMPLATE, + pnfSourceName, + oldAuthenticationStatus, + newAuthenticationStatus, + stateInterface, + rgwMacAddress, + swVersion + ); + } + + Optional<JsonObject> getJsonObjectFromAnArray(JsonElement element) { + JsonParser jsonParser = new JsonParser(); + return element.isJsonPrimitive() ? Optional.of(jsonParser.parse(element.getAsString()).getAsJsonObject()) + : Optional.of(jsonParser.parse(element.toString()).getAsJsonObject()); + } + + private String getValueFromJson(JsonObject jsonObject, String jsonKey) { + return jsonObject.has(jsonKey) ? jsonObject.get(jsonKey).getAsString() : ""; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationEventFields.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationEventFields.java new file mode 100644 index 00000000..00a3f5e0 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationEventFields.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +class CpeAuthenticationEventFields { + + static final String STATE_CHANGE_FIELDS = "stateChangeFields"; + static final String NEW_AUTHENTICATION_STATE = "newState"; + static final String OLD_AUTHENTICATION_STATE = "oldState"; + static final String STATE_INTERFACE = "stateInterface"; + static final String ADDITIONAL_FIELDS = "additionalFields"; + static final String RGW_MAC_ADDRESS = "macAddress"; + static final String SW_VERSION = "swVersion"; + + // Non-instantiable class + private CpeAuthenticationEventFields(){} +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationJsonBodyBuilder.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationJsonBodyBuilder.java new file mode 100644 index 00000000..09aa7303 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationJsonBodyBuilder.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.ServiceLoader; + +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableCpeAuthenticationConsumerDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.model.JsonBodyBuilder; + +public class CpeAuthenticationJsonBodyBuilder implements JsonBodyBuilder<CpeAuthenticationConsumerDmaapModel> { + + /** + * Serialize the CPE authentication DMaaP model with GSON. + * @param cpeAuthenticationConsumerDmaapModel object to be serialized + * @return String output of serialization + */ + @Override + public String createJsonBody(CpeAuthenticationConsumerDmaapModel cpeAuthenticationConsumerDmaapModel) { + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + return gsonBuilder.create().toJson(ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(cpeAuthenticationConsumerDmaapModel.getCorrelationId()) + .oldAuthenticationState(cpeAuthenticationConsumerDmaapModel.getOldAuthenticationState()) + .newAuthenticationState(cpeAuthenticationConsumerDmaapModel.getNewAuthenticationState()) + .stateInterface(cpeAuthenticationConsumerDmaapModel.getStateInterface().orElse("")) + .rgwMacAddress(cpeAuthenticationConsumerDmaapModel.getRgwMacAddress().orElse("")) + .swVersion(cpeAuthenticationConsumerDmaapModel.getSwVersion().orElse("")) + .build()); + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParser.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParser.java new file mode 100644 index 00000000..7dd8a3d2 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParser.java @@ -0,0 +1,167 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static org.onap.bbs.event.processor.utilities.CommonEventFields.COMMON_FORMAT; +import static org.onap.bbs.event.processor.utilities.CommonEventFields.CORRELATION_ID; +import static org.onap.bbs.event.processor.utilities.ReRegistrationEventFields.ADDITIONAL_FIELDS; +import static org.onap.bbs.event.processor.utilities.ReRegistrationEventFields.ATTACHMENT_POINT; +import static org.onap.bbs.event.processor.utilities.ReRegistrationEventFields.CVLAN; +import static org.onap.bbs.event.processor.utilities.ReRegistrationEventFields.REMOTE_ID; +import static org.onap.bbs.event.processor.utilities.ReRegistrationEventFields.SVLAN; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import java.util.Optional; +import java.util.stream.StreamSupport; + +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.model.ImmutableReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class ReRegistrationDmaapConsumerJsonParser { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReRegistrationDmaapConsumerJsonParser.class); + + private static final String RE_REGISTRATION_DUMPING_TEMPLATE = "%n{" + + "\"" + CORRELATION_ID + COMMON_FORMAT + "," + + "\"" + ATTACHMENT_POINT + COMMON_FORMAT + "," + + "\"" + REMOTE_ID + COMMON_FORMAT + "," + + "\"" + CVLAN + COMMON_FORMAT + "," + + "\"" + SVLAN + COMMON_FORMAT + + "}"; + + private String pnfCorrelationId; + + private String attachmentPoint; + private String remoteId; + private String cvlan; + private String svlan; + + /** + * Translates a response from DMaaP to a reactive {@link ReRegistrationConsumerDmaapModel} model. + * @param dmaapResponse Response from DMaaP + * @return Re-Registration Consumer DMaaP reactive model + */ + public Flux<ReRegistrationConsumerDmaapModel> extractModelFromDmaap(Mono<String> dmaapResponse) { + return dmaapResponse + .flatMapMany(this::parseToMono) + .flatMap(this::createTargetFlux); + } + + private Mono<JsonElement> parseToMono(String message) { + if (StringUtils.isEmpty(message)) { + LOGGER.warn("DMaaP response is empty"); + return Mono.empty(); + } + return Mono.fromCallable(() -> new JsonParser().parse(message)) + .doOnError(e -> e instanceof JsonSyntaxException, e -> LOGGER.error("Invalid JSON. Ignoring")) + .onErrorResume(e -> e instanceof JsonSyntaxException, e -> Mono.empty()); + } + + private Flux<ReRegistrationConsumerDmaapModel> createTargetFlux(JsonElement jsonElement) { + if (jsonElement.isJsonObject()) { + return doCreateTargetFlux(Flux.defer(() -> Flux.just(jsonElement.getAsJsonObject()))); + } + return doCreateTargetFlux( + Flux.defer(() -> Flux.fromStream(StreamSupport.stream(jsonElement.getAsJsonArray().spliterator(), false) + .map(jsonElementFromArray -> getJsonObjectFromAnArray(jsonElementFromArray) + .orElseGet(JsonObject::new))))); + } + + private Flux<ReRegistrationConsumerDmaapModel> doCreateTargetFlux(Flux<JsonObject> jsonObject) { + return jsonObject + .flatMap(this::transform) + .onErrorResume(exception -> exception instanceof DmaapException, e -> Mono.empty()); + } + + private Mono<ReRegistrationConsumerDmaapModel> transform(JsonObject dmaapResponseJsonObject) { + + if (!containsProperHeaders(dmaapResponseJsonObject)) { + LOGGER.warn("Incorrect JsonObject - missing headers"); + return Mono.empty(); + } + + JsonObject pnfReRegistrationFields = + dmaapResponseJsonObject.getAsJsonObject(ADDITIONAL_FIELDS); + + pnfCorrelationId = getValueFromJson(dmaapResponseJsonObject, CORRELATION_ID); + + attachmentPoint = getValueFromJson(pnfReRegistrationFields, ATTACHMENT_POINT); + remoteId = getValueFromJson(pnfReRegistrationFields, REMOTE_ID); + cvlan = getValueFromJson(pnfReRegistrationFields, CVLAN); + svlan = getValueFromJson(pnfReRegistrationFields, SVLAN); + + if (StringUtils.isEmpty(pnfCorrelationId) || anyImportantPropertyMissing()) { + String incorrectEvent = dumpJsonData(); + LOGGER.warn("Incorrect Re-Registration JSON event: {}", incorrectEvent); + return Mono.empty(); + } + + return Mono.just(ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfCorrelationId) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build()); + } + + private boolean anyImportantPropertyMissing() { + return StringUtils.isEmpty(attachmentPoint) + || StringUtils.isEmpty(remoteId) + || StringUtils.isEmpty(cvlan) + || StringUtils.isEmpty(svlan); + } + + private boolean containsProperHeaders(JsonObject jsonObject) { + return jsonObject.has(ADDITIONAL_FIELDS); + } + + private String dumpJsonData() { + return String.format(RE_REGISTRATION_DUMPING_TEMPLATE, + pnfCorrelationId, + attachmentPoint, + remoteId, + cvlan, + svlan + ); + } + + Optional<JsonObject> getJsonObjectFromAnArray(JsonElement element) { + JsonParser jsonParser = new JsonParser(); + return element.isJsonPrimitive() ? Optional.of(jsonParser.parse(element.getAsString()).getAsJsonObject()) + : Optional.of(jsonParser.parse(element.toString()).getAsJsonObject()); + } + + private String getValueFromJson(JsonObject jsonObject, String jsonKey) { + return jsonObject.has(jsonKey) ? jsonObject.get(jsonKey).getAsString() : ""; + } +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationEventFields.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationEventFields.java new file mode 100644 index 00000000..35e78b01 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationEventFields.java @@ -0,0 +1,33 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +class ReRegistrationEventFields { + + static final String ADDITIONAL_FIELDS = "additionalFields"; + static final String ATTACHMENT_POINT = "attachment-point"; + static final String REMOTE_ID = "remote-id"; + static final String CVLAN = "cvlan"; + static final String SVLAN = "svlan"; + + // Non-instantiable class + private ReRegistrationEventFields(){} +} diff --git a/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationJsonBodyBuilder.java b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationJsonBodyBuilder.java new file mode 100644 index 00000000..867cfda7 --- /dev/null +++ b/components/bbs-event-processor/src/main/java/org/onap/bbs/event/processor/utilities/ReRegistrationJsonBodyBuilder.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.ServiceLoader; + +import org.onap.bbs.event.processor.model.ImmutableReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.model.JsonBodyBuilder; + +public class ReRegistrationJsonBodyBuilder implements JsonBodyBuilder<ReRegistrationConsumerDmaapModel> { + + /** + * Serialize the Re-Registration DMaaP model with GSON. + * @param reRegistrationConsumerDmaapModel object to be serialized + * @return String output of serialization + */ + @Override + public String createJsonBody(ReRegistrationConsumerDmaapModel reRegistrationConsumerDmaapModel) { + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + return gsonBuilder.create().toJson(ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(reRegistrationConsumerDmaapModel.getCorrelationId()) + .attachmentPoint(reRegistrationConsumerDmaapModel.getAttachmentPoint()) + .remoteId(reRegistrationConsumerDmaapModel.getRemoteId()) + .cVlan(reRegistrationConsumerDmaapModel.getCVlan()) + .sVlan(reRegistrationConsumerDmaapModel.getSVlan()) + .build()); + } +} diff --git a/components/bbs-event-processor/src/main/resources/application.yml b/components/bbs-event-processor/src/main/resources/application.yml new file mode 100644 index 00000000..c9820ebf --- /dev/null +++ b/components/bbs-event-processor/src/main/resources/application.yml @@ -0,0 +1,73 @@ +spring: + profiles: + active: production +server: + port: 8100 +configs: + dmaap: + consumer: + re-registration: + dmaapHostName: localhost + dmaapPortNumber: 2222 + dmaapTopicName: /events/unauthenticated.PNF_Update + dmaapProtocol: http + dmaapContentType: application/json + consumerId: c12 + consumerGroup: OpenDcae-c12 + timeoutMs: -1 + messageLimit: 1 + cpe-authentication: + dmaapHostName: localhost + dmaapPortNumber: 2222 + dmaapTopicName: /events/unauthenticated.CPE_Authentication + dmaapProtocol: http + dmaapContentType: application/json + consumerId: c12 + consumerGroup: OpenDcae-c12 + timeoutMs: -1 + messageLimit: 1 + producer: + dmaapHostName: localhost + dmaapPortNumber: 2223 + dmaapTopicName: /events/unauthenticated.DCAE_CL_OUTPUT + dmaapProtocol: http + dmaapContentType: application/json + aai: + client: + aaiHost: localhost + aaiPort: 8080 + aaiProtocol: https + aaiUserName: AAI + aaiUserPassword: AAI + aaiIgnoreSslCertificateErrors: true + aaiHeaders: + X-FromAppId: bbs + X-TransactionId: 9999 + Accept: application/json + Real-Time: true + Content-Type: application/json + security: + trustStorePath: change it + trustStorePasswordPath: change it + keyStorePath: change it + keyStorePasswordPath: change it + enableAaiCertAuth: false + enableDmaapCertAuth: false + application: + pipelinesPollingIntervalSec: 30 + pipelinesTimeoutSec: 15 + re-registration: + policyScope: policyScope + clControlName: controlName + cpe-authentication: + policyScope: policyScope + clControlName: controlName +logging: + level: + ROOT: ERROR + org.onap.bbs: INFO + org.onap.dcaegen2: WARN + reactor.ipc.netty.http.client: WARN + org.springframework: ERROR + org.springframework.data: ERROR + org.springframework.web.reactive: WARN
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/AaiClientPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/AaiClientPropertiesTest.java new file mode 100644 index 00000000..449be724 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/AaiClientPropertiesTest.java @@ -0,0 +1,70 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = AaiClientProperties.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.aai.client.aaiHost=test localhost", + "configs.aai.client.aaiPort=1234", + "configs.aai.client.aaiProtocol=https", + "configs.aai.client.aaiUserName=AAI", + "configs.aai.client.aaiUserPassword=AAI", + "configs.aai.client.aaiIgnoreSslCertificateErrors=true", + "configs.aai.client.aaiHeaders.X-FromAppId=bbs", + "configs.aai.client.aaiHeaders.X-TransactionId=9999", + "configs.aai.client.aaiHeaders.Accept=application/json", + "configs.aai.client.aaiHeaders.Real-Time=true", + "configs.aai.client.aaiHeaders.Content-Type=application/merge-patch+json"}) +class AaiClientPropertiesTest { + + private AaiClientProperties properties; + + @Autowired + public AaiClientPropertiesTest( + AaiClientProperties properties) { + this.properties = properties; + } + + @Test + void dmaapReRegistrationProperties_SuccessFullyLoaded() { + assertEquals("test localhost", properties.getAaiHost()); + assertEquals(1234, properties.getAaiPort()); + assertEquals("https", properties.getAaiProtocol()); + assertEquals("AAI", properties.getAaiUserName()); + assertEquals("AAI", properties.getAaiUserPassword()); + assertTrue(properties.isAaiIgnoreSslCertificateErrors()); + assertEquals("bbs", properties.getAaiHeaders().get("X-FromAppId")); + assertEquals("9999", properties.getAaiHeaders().get("X-TransactionId")); + assertEquals("application/json", properties.getAaiHeaders().get("Accept")); + assertEquals("true", properties.getAaiHeaders().get("Real-Time")); + assertEquals("application/merge-patch+json", properties.getAaiHeaders().get("Content-Type")); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ApplicationConfigurationTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ApplicationConfigurationTest.java new file mode 100644 index 00000000..59feacaa --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ApplicationConfigurationTest.java @@ -0,0 +1,350 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.FixMethodOrder; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.runners.MethodSorters; +import org.onap.bbs.event.processor.model.GeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableDmaapInfo; +import org.onap.bbs.event.processor.model.ImmutableGeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableStreamsObject; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapPublisherConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = { + AaiClientProperties.class, + DmaapReRegistrationConsumerProperties.class, + DmaapCpeAuthenticationConsumerProperties.class, + DmaapProducerProperties.class, + SecurityProperties.class, + GenericProperties.class}) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.aai.client.aaiHost=test localhost", + "configs.aai.client.aaiPort=1234", + "configs.aai.client.aaiProtocol=https", + "configs.aai.client.aaiUserName=AAI", + "configs.aai.client.aaiUserPassword=AAI", + "configs.aai.client.aaiIgnoreSslCertificateErrors=true", + "configs.aai.client.aaiHeaders.X-FromAppId=bbs", + "configs.aai.client.aaiHeaders.X-TransactionId=9999", + "configs.aai.client.aaiHeaders.Accept=application/json", + "configs.aai.client.aaiHeaders.Real-Time=true", + "configs.aai.client.aaiHeaders.Content-Type=application/merge-patch+json", + "configs.dmaap.consumer.re-registration.dmaapHostName=test localhost", + "configs.dmaap.consumer.re-registration.dmaapPortNumber=1234", + "configs.dmaap.consumer.re-registration.dmaapTopicName=/events/unauthenticated.PNF_REREGISTRATION", + "configs.dmaap.consumer.re-registration.dmaapProtocol=http", + "configs.dmaap.consumer.re-registration.dmaapContentType=application/json", + "configs.dmaap.consumer.re-registration.consumerId=c12", + "configs.dmaap.consumer.re-registration.consumerGroup=OpenDcae-c12", + "configs.dmaap.consumer.re-registration.timeoutMs=-1", + "configs.dmaap.consumer.re-registration.messageLimit=1", + "configs.dmaap.consumer.cpe-authentication.dmaapHostName=test localhost", + "configs.dmaap.consumer.cpe-authentication.dmaapPortNumber=1234", + "configs.dmaap.consumer.cpe-authentication.dmaapTopicName=/events/unauthenticated.CPE_AUTHENTICATION", + "configs.dmaap.consumer.cpe-authentication.dmaapProtocol=http", + "configs.dmaap.consumer.cpe-authentication.dmaapContentType=application/json", + "configs.dmaap.consumer.cpe-authentication.consumerId=c12", + "configs.dmaap.consumer.cpe-authentication.consumerGroup=OpenDcae-c12", + "configs.dmaap.consumer.cpe-authentication.timeoutMs=-1", + "configs.dmaap.consumer.cpe-authentication.messageLimit=1", + "configs.dmaap.producer.dmaapHostName=test localhost", + "configs.dmaap.producer.dmaapPortNumber=1234", + "configs.dmaap.producer.dmaapTopicName=/events/unauthenticated.DCAE_CL_OUTPUT", + "configs.dmaap.producer.dmaapProtocol=http", + "configs.dmaap.producer.dmaapContentType=application/json", + "configs.security.trustStorePath=test trust store path", + "configs.security.trustStorePasswordPath=test trust store password path", + "configs.security.keyStorePath=test key store path", + "configs.security.keyStorePasswordPath=test key store password path", + "configs.security.enableDmaapCertAuth=true", + "configs.security.enableAaiCertAuth=true", + "configs.application.pipelinesPollingIntervalSec=30", + "configs.application.pipelinesTimeoutSec=15", + "configs.application.re-registration.policyScope=reRegPolicyScope", + "configs.application.re-registration.clControlName=reRegControlName", + "configs.application.cpe-authentication.policyScope=cpeAuthPolicyScope", + "configs.application.cpe-authentication.clControlName=cpeAuthControlName"}) +@DisplayName("Application Configuration Unit-Tests") +// Ordering tests because we need a first configuration population from @TestPropertySource +// and then update of the config parameters based on a new Consul-retrieved Configuration object +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class ApplicationConfigurationTest { + + private ApplicationConfiguration configuration; + + @Autowired + public ApplicationConfigurationTest(AaiClientProperties aaiClientProperties, + DmaapReRegistrationConsumerProperties dmaapReRegistrationConsumerProperties, + DmaapCpeAuthenticationConsumerProperties + dmaapCpeAuthenticationConsumerProperties, + DmaapProducerProperties dmaapProducerProperties, + SecurityProperties securityProperties, + GenericProperties genericProperties) { + this.configuration = new ApplicationConfiguration(aaiClientProperties, + dmaapReRegistrationConsumerProperties, + dmaapCpeAuthenticationConsumerProperties, + dmaapProducerProperties, + securityProperties, + genericProperties); + } + + @Test + void testA_configurationObjectSuccessfullyPopulated() { + + AaiClientConfiguration aaiClientConfiguration = configuration.getAaiClientConfiguration(); + assertAll("AAI Client Configuration Properties", + () -> assertEquals("test localhost", aaiClientConfiguration.aaiHost()), + () -> assertEquals(Integer.valueOf(1234), aaiClientConfiguration.aaiPort()), + () -> assertEquals("https", aaiClientConfiguration.aaiProtocol()), + () -> assertEquals("AAI", aaiClientConfiguration.aaiUserName()), + () -> assertEquals("AAI", aaiClientConfiguration.aaiUserPassword()), + () -> assertTrue(aaiClientConfiguration.aaiIgnoreSslCertificateErrors()), + () -> assertEquals("bbs", aaiClientConfiguration.aaiHeaders().get("X-FromAppId")), + () -> assertEquals("9999", aaiClientConfiguration.aaiHeaders().get("X-TransactionId")), + () -> assertEquals("application/json", aaiClientConfiguration.aaiHeaders().get("Accept")), + () -> assertEquals("true", aaiClientConfiguration.aaiHeaders().get("Real-Time")), + () -> assertEquals("application/merge-patch+json", + aaiClientConfiguration.aaiHeaders().get("Content-Type")) + ); + + DmaapConsumerConfiguration dmaapConsumerReRegistrationConfig = + configuration.getDmaapReRegistrationConsumerConfiguration(); + assertAll("DMaaP Consumer Re-Registration Configuration Properties", + () -> assertEquals("test localhost", dmaapConsumerReRegistrationConfig.dmaapHostName()), + () -> assertEquals(Integer.valueOf(1234), dmaapConsumerReRegistrationConfig.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.PNF_REREGISTRATION", + dmaapConsumerReRegistrationConfig.dmaapTopicName()), + () -> assertEquals("http", dmaapConsumerReRegistrationConfig.dmaapProtocol()), + () -> assertEquals("", dmaapConsumerReRegistrationConfig.dmaapUserName()), + () -> assertEquals("", dmaapConsumerReRegistrationConfig.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapConsumerReRegistrationConfig.dmaapContentType()), + () -> assertEquals("c12", dmaapConsumerReRegistrationConfig.consumerId()), + () -> assertEquals("OpenDcae-c12", dmaapConsumerReRegistrationConfig.consumerGroup()), + () -> assertEquals(Integer.valueOf(-1), dmaapConsumerReRegistrationConfig.timeoutMs()), + () -> assertEquals(Integer.valueOf(1), dmaapConsumerReRegistrationConfig.messageLimit()) + ); + + DmaapConsumerConfiguration dmaapConsumerCpeAuthenticationConfig = + configuration.getDmaapCpeAuthenticationConsumerConfiguration(); + assertAll("DMaaP Consumer CPE Authentication Configuration Properties", + () -> assertEquals("test localhost", dmaapConsumerCpeAuthenticationConfig.dmaapHostName()), + () -> assertEquals(Integer.valueOf(1234), dmaapConsumerCpeAuthenticationConfig.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.CPE_AUTHENTICATION", + dmaapConsumerCpeAuthenticationConfig.dmaapTopicName()), + () -> assertEquals("http", dmaapConsumerCpeAuthenticationConfig.dmaapProtocol()), + () -> assertEquals("", dmaapConsumerCpeAuthenticationConfig.dmaapUserName()), + () -> assertEquals("", dmaapConsumerCpeAuthenticationConfig.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapConsumerCpeAuthenticationConfig.dmaapContentType()), + () -> assertEquals("c12", dmaapConsumerCpeAuthenticationConfig.consumerId()), + () -> assertEquals("OpenDcae-c12", dmaapConsumerCpeAuthenticationConfig.consumerGroup()), + () -> assertEquals(Integer.valueOf(-1), dmaapConsumerCpeAuthenticationConfig.timeoutMs()), + () -> assertEquals(Integer.valueOf(1), dmaapConsumerCpeAuthenticationConfig.messageLimit()) + ); + + DmaapPublisherConfiguration dmaapPublisherConfiguration = configuration.getDmaapPublisherConfiguration(); + assertAll("DMaaP Publisher Configuration Properties", + () -> assertEquals("test localhost", dmaapPublisherConfiguration.dmaapHostName()), + () -> assertEquals(Integer.valueOf(1234), dmaapPublisherConfiguration.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.DCAE_CL_OUTPUT", + dmaapPublisherConfiguration.dmaapTopicName()), + () -> assertEquals("http", dmaapPublisherConfiguration.dmaapProtocol()), + () -> assertEquals("", dmaapPublisherConfiguration.dmaapUserName()), + () -> assertEquals("", dmaapPublisherConfiguration.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapPublisherConfiguration.dmaapContentType()) + ); + + assertAll("Generic Application Properties", + () -> assertEquals(30, configuration.getPipelinesPollingIntervalInSeconds()), + () -> assertEquals(15, configuration.getPipelinesTimeoutInSeconds()), + () -> assertEquals("reRegPolicyScope", configuration.getReRegistrationCloseLoopPolicyScope()), + () -> assertEquals("cpeAuthPolicyScope", configuration.getCpeAuthenticationCloseLoopPolicyScope()), + () -> assertEquals("reRegControlName", configuration.getReRegistrationCloseLoopControlName()), + () -> assertEquals("cpeAuthControlName", configuration.getCpeAuthenticationCloseLoopControlName()) + ); + } + + @Test + void testB_passingNewConfiguration_UpdateSucceeds() { + Map<String, GeneratedAppConfigObject.StreamsObject> subscribes = new HashMap<>(); + + GeneratedAppConfigObject.DmaapInfo dmaapInfo1 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router1.us:3901/events/unauthenticated.PNF_UPDATE") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject1 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo1) + .build(); + GeneratedAppConfigObject.DmaapInfo dmaapInfo2 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router2.us:3902/events/unauthenticated.CPE_AUTHENTICATION") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject2 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo2) + .build(); + + subscribes.put("config_key_1", streamsObject1); + subscribes.put("config_key_2", streamsObject2); + + // Create Publishes Objects + GeneratedAppConfigObject.DmaapInfo dmaapInfo3 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router3.us:3903/events/unauthenticated.DCAE_CL_OUTPUT") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject3 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo3) + .build(); + + // Final config object + GeneratedAppConfigObject updatedConfiguration = ImmutableGeneratedAppConfigObject.builder() + .dmaapProtocol("https") + .dmaapContentType("application/json") + .dmaapConsumerConsumerId("c13") + .dmaapConsumerConsumerGroup("OpenDcae-c13") + .dmaapMessageLimit(10) + .dmaapTimeoutMs(5) + .aaiHost("aai.onap.svc.cluster.local") + .aaiPort(8443) + .aaiProtocol("http") + .aaiUsername("AAI-update") + .aaiPassword("AAI-update") + .aaiIgnoreSslCertificateErrors(false) + .pipelinesPollingIntervalSec(20) + .pipelinesTimeoutSec(20) + .cbsPollingIntervalSec(180) + .reRegistrationPolicyScope("policyScope-update") + .reRegistrationClControlName("controlName-update") + .cpeAuthPolicyScope("policyScope-update") + .cpeAuthClControlName("controlName-update") + .reRegConfigKey("config_key_1") + .cpeAuthConfigKey("config_key_2") + .closeLoopConfigKey("config_key_3") + .streamSubscribesMap(subscribes) + .streamPublishesMap(Collections.singletonMap("config_key_3", streamsObject3)) + .build(); + + // Update the configuration + configuration.updateCurrentConfiguration(updatedConfiguration); + + AaiClientConfiguration aaiClientConfiguration = configuration.getAaiClientConfiguration(); + assertAll("AAI Client Configuration Properties", + () -> assertEquals("aai.onap.svc.cluster.local", aaiClientConfiguration.aaiHost()), + () -> assertEquals(Integer.valueOf(8443), aaiClientConfiguration.aaiPort()), + () -> assertEquals("http", aaiClientConfiguration.aaiProtocol()), + () -> assertEquals("AAI-update", aaiClientConfiguration.aaiUserName()), + () -> assertEquals("AAI-update", aaiClientConfiguration.aaiUserPassword()), + () -> assertFalse(aaiClientConfiguration.aaiIgnoreSslCertificateErrors()), + () -> assertEquals("bbs", aaiClientConfiguration.aaiHeaders().get("X-FromAppId")), + () -> assertEquals("9999", aaiClientConfiguration.aaiHeaders().get("X-TransactionId")), + () -> assertEquals("application/json", aaiClientConfiguration.aaiHeaders().get("Accept")), + () -> assertEquals("true", aaiClientConfiguration.aaiHeaders().get("Real-Time")), + () -> assertEquals("application/merge-patch+json", + aaiClientConfiguration.aaiHeaders().get("Content-Type")) + ); + + DmaapConsumerConfiguration dmaapConsumerReRegistrationConfig = + configuration.getDmaapReRegistrationConsumerConfiguration(); + assertAll("DMaaP Consumer Re-Registration Configuration Properties", + () -> assertEquals("we-are-message-router1.us", dmaapConsumerReRegistrationConfig.dmaapHostName()), + () -> assertEquals(Integer.valueOf(3901), dmaapConsumerReRegistrationConfig.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.PNF_UPDATE", + dmaapConsumerReRegistrationConfig.dmaapTopicName()), + () -> assertEquals("https", dmaapConsumerReRegistrationConfig.dmaapProtocol()), + () -> assertEquals("", dmaapConsumerReRegistrationConfig.dmaapUserName()), + () -> assertEquals("", dmaapConsumerReRegistrationConfig.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapConsumerReRegistrationConfig.dmaapContentType()), + () -> assertEquals("c13", dmaapConsumerReRegistrationConfig.consumerId()), + () -> assertEquals("OpenDcae-c13", dmaapConsumerReRegistrationConfig.consumerGroup()), + () -> assertEquals(Integer.valueOf(5), dmaapConsumerReRegistrationConfig.timeoutMs()), + () -> assertEquals(Integer.valueOf(10), dmaapConsumerReRegistrationConfig.messageLimit()) + ); + + DmaapConsumerConfiguration dmaapConsumerCpeAuthenticationConfig = + configuration.getDmaapCpeAuthenticationConsumerConfiguration(); + assertAll("DMaaP Consumer CPE Authentication Configuration Properties", + () -> assertEquals("we-are-message-router2.us", dmaapConsumerCpeAuthenticationConfig.dmaapHostName()), + () -> assertEquals(Integer.valueOf(3902), dmaapConsumerCpeAuthenticationConfig.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.CPE_AUTHENTICATION", + dmaapConsumerCpeAuthenticationConfig.dmaapTopicName()), + () -> assertEquals("https", dmaapConsumerCpeAuthenticationConfig.dmaapProtocol()), + () -> assertEquals("", dmaapConsumerCpeAuthenticationConfig.dmaapUserName()), + () -> assertEquals("", dmaapConsumerCpeAuthenticationConfig.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapConsumerCpeAuthenticationConfig.dmaapContentType()), + () -> assertEquals("c13", dmaapConsumerCpeAuthenticationConfig.consumerId()), + () -> assertEquals("OpenDcae-c13", dmaapConsumerCpeAuthenticationConfig.consumerGroup()), + () -> assertEquals(Integer.valueOf(5), dmaapConsumerCpeAuthenticationConfig.timeoutMs()), + () -> assertEquals(Integer.valueOf(10), dmaapConsumerCpeAuthenticationConfig.messageLimit()) + ); + + DmaapPublisherConfiguration dmaapPublisherConfiguration = configuration.getDmaapPublisherConfiguration(); + assertAll("DMaaP Publisher Configuration Properties", + () -> assertEquals("we-are-message-router3.us", dmaapPublisherConfiguration.dmaapHostName()), + () -> assertEquals(Integer.valueOf(3903), dmaapPublisherConfiguration.dmaapPortNumber()), + () -> assertEquals("/events/unauthenticated.DCAE_CL_OUTPUT", + dmaapPublisherConfiguration.dmaapTopicName()), + () -> assertEquals("https", dmaapPublisherConfiguration.dmaapProtocol()), + () -> assertEquals("", dmaapPublisherConfiguration.dmaapUserName()), + () -> assertEquals("", dmaapPublisherConfiguration.dmaapUserPassword()), + () -> assertEquals("application/json", dmaapPublisherConfiguration.dmaapContentType()) + ); + + assertAll("Generic Application Properties", + () -> assertEquals(20, configuration.getPipelinesPollingIntervalInSeconds()), + () -> assertEquals(20, configuration.getPipelinesTimeoutInSeconds()), + () -> assertEquals(180, configuration.getCbsPollingInterval()), + () -> assertEquals("policyScope-update", configuration.getReRegistrationCloseLoopPolicyScope()), + () -> assertEquals("policyScope-update", configuration.getCpeAuthenticationCloseLoopPolicyScope()), + () -> assertEquals("controlName-update", configuration.getReRegistrationCloseLoopControlName()), + () -> assertEquals("controlName-update", configuration.getCpeAuthenticationCloseLoopControlName()) + ); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ConsulConfigurationGatewayTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ConsulConfigurationGatewayTest.java new file mode 100644 index 00000000..ee75926b --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/ConsulConfigurationGatewayTest.java @@ -0,0 +1,201 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; + +import com.google.gson.JsonParser; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.model.GeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableDmaapInfo; +import org.onap.bbs.event.processor.model.ImmutableGeneratedAppConfigObject; +import org.onap.bbs.event.processor.model.ImmutableStreamsObject; + +class ConsulConfigurationGatewayTest { + + private ConsulConfigurationGateway configurationGateway; + private static JsonParser jsonParser; + + @BeforeAll + static void setup() { + jsonParser = new JsonParser(); + } + + ConsulConfigurationGatewayTest() { + ApplicationConfiguration configuration = Mockito.mock(ApplicationConfiguration.class); + this.configurationGateway = new ConsulConfigurationGateway(configuration); + } + + @Test + void passingValidJson_constructsGeneratedAppConfigObject() { + final String validJson = "{" + + "\"dmaap.protocol\": \"http\"," + + "\"dmaap.contentType\": \"application/json\"," + + "\"dmaap.consumer.consumerId\": \"c12\"," + + "\"dmaap.consumer.consumerGroup\": \"OpenDcae-c12\"," + + "\"dmaap.messageLimit\": 1," + + "\"dmaap.timeoutMs\": -1," + + "\"aai.host\": \"aai.onap.svc.cluster.local\"," + + "\"aai.port\": \"8443\"," + + "\"aai.protocol\": \"https\"," + + "\"aai.username\": \"AAI\"," + + "\"aai.password\": \"AAI\"," + + "\"aai.aaiIgnoreSslCertificateErrors\": true," + + "\"application.pipelinesPollingIntervalSec\": 30," + + "\"application.pipelinesTimeoutSec\": 15," + + "\"application.cbsPollingIntervalSec\": 180," + + "\"application.reregistration.policyScope\": \"policyScope\"," + + "\"application.reregistration.clControlName\": \"controlName\"," + + "\"application.cpe.authentication.policyScope\": \"policyScope\"," + + "\"application.cpe.authentication.clControlName\": \"controlName\"," + + "\"application.reregistration.configKey\": \"config_key_2\"," + + "\"application.cpeAuth.configKey\": \"config_key_1\"," + + "\"application.closeLoop.configKey\": \"config_key_3\"," + + "\"streams_subscribes\": {" + + "\"config_key_1\": {" + + "\"type\": \"message_router\"," + + "\"aaf_username\": \"some-user\"," + + "\"aaf_password\": \"some-password\"," + + "\"dmaap_info\": {" + + "\"client_id\": \"1500462518108\"," + + "\"client_role\": \"com.dcae.member\"," + + "\"location\": \"mtc00\"," + + "\"topic_url\": \"https://we-are-message-router.us:3905/events/unauthenticated.CPE_AUTHENTICATION\"" + + "}" + + "}," + + "\"config_key_2\": {" + + "\"type\": \"message_router\"," + + "\"aaf_username\": \"some-user\"," + + "\"aaf_password\": \"some-password\"," + + "\"dmaap_info\": {" + + "\"client_id\": \"1500462518108\"," + + "\"client_role\": \"com.dcae.member\"," + + "\"location\": \"mtc00\"," + + "\"topic_url\": \"https://we-are-message-router.us:3905/events/unauthenticated.PNF_UPDATE\"" + + "}" + + "}" + + "}," + + "\"streams_publishes\": {" + + "\"config_key_3\": {" + + "\"type\": \"message_router\"," + + "\"aaf_username\": \"some-user\"," + + "\"aaf_password\": \"some-password\"," + + "\"dmaap_info\": {" + + "\"client_id\": \"1500462518108\"," + + "\"client_role\": \"com.dcae.member\"," + + "\"location\": \"mtc00\"," + + "\"topic_url\": \"https://we-are-message-router.us:3905/events/unauthenticated.DCAE_CL_OUTPUT\"" + + "}" + + "}" + + "}," + + "\"services_calls\": {" + + "\"aai-interaction\": []" + + "}" + + "}"; + + // Create expected configuration + // Create Subscribes Objects + Map<String, GeneratedAppConfigObject.StreamsObject> subscribes = new HashMap<>(); + + GeneratedAppConfigObject.DmaapInfo dmaapInfo1 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router.us:3905/events/unauthenticated.CPE_AUTHENTICATION") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject1 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo1) + .build(); + GeneratedAppConfigObject.DmaapInfo dmaapInfo2 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router.us:3905/events/unauthenticated.PNF_UPDATE") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject2 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo2) + .build(); + + subscribes.put("config_key_1", streamsObject1); + subscribes.put("config_key_2", streamsObject2); + + // Create Publishes Objects + GeneratedAppConfigObject.DmaapInfo dmaapInfo3 = ImmutableDmaapInfo.builder() + .clientId("1500462518108") + .clientRole("com.dcae.member") + .location("mtc00") + .topicUrl("https://we-are-message-router.us:3905/events/unauthenticated.DCAE_CL_OUTPUT") + .build(); + GeneratedAppConfigObject.StreamsObject streamsObject3 = ImmutableStreamsObject.builder() + .type("message_router") + .aafUsername("some-user") + .aafPassword("some-password") + .dmaapInfo(dmaapInfo3) + .build(); + + // Expected final config object + GeneratedAppConfigObject expectedConfiguration = ImmutableGeneratedAppConfigObject.builder() + .dmaapProtocol("http") + .dmaapContentType("application/json") + .dmaapConsumerConsumerId("c12") + .dmaapConsumerConsumerGroup("OpenDcae-c12") + .dmaapMessageLimit(1) + .dmaapTimeoutMs(-1) + .aaiHost("aai.onap.svc.cluster.local") + .aaiPort(8443) + .aaiProtocol("https") + .aaiUsername("AAI") + .aaiPassword("AAI") + .aaiIgnoreSslCertificateErrors(true) + .pipelinesPollingIntervalSec(30) + .pipelinesTimeoutSec(15) + .cbsPollingIntervalSec(180) + .reRegistrationPolicyScope("policyScope") + .reRegistrationClControlName("controlName") + .cpeAuthPolicyScope("policyScope") + .cpeAuthClControlName("controlName") + .reRegConfigKey("config_key_2") + .cpeAuthConfigKey("config_key_1") + .closeLoopConfigKey("config_key_3") + .streamSubscribesMap(subscribes) + .streamPublishesMap(Collections.singletonMap("config_key_3", streamsObject3)) + .build(); + + ConsulConfigurationGateway spiedGateway = Mockito.spy(configurationGateway); + doReturn(false).when(spiedGateway).environmentNotReady(); + assertEquals(expectedConfiguration, + spiedGateway.generateAppConfigObject(jsonParser.parse(validJson).getAsJsonObject())); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerPropertiesTest.java new file mode 100644 index 00000000..103335ce --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapCpeAuthenticationConsumerPropertiesTest.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = DmaapCpeAuthenticationConsumerProperties.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.dmaap.consumer.cpe-authentication.dmaapHostName=test localhost", + "configs.dmaap.consumer.cpe-authentication.dmaapPortNumber=1234", + "configs.dmaap.consumer.cpe-authentication.dmaapTopicName=/events/unauthenticated.PNF_CPE_AUTHENTICATION", + "configs.dmaap.consumer.cpe-authentication.dmaapProtocol=http", + "configs.dmaap.consumer.cpe-authentication.dmaapContentType=application/json", + "configs.dmaap.consumer.cpe-authentication.consumerId=c12", + "configs.dmaap.consumer.cpe-authentication.consumerGroup=OpenDcae-c12", + "configs.dmaap.consumer.cpe-authentication.timeoutMs=-1", + "configs.dmaap.consumer.cpe-authentication.messageLimit=1"}) +class DmaapCpeAuthenticationConsumerPropertiesTest { + + private DmaapCpeAuthenticationConsumerProperties properties; + + @Autowired + public DmaapCpeAuthenticationConsumerPropertiesTest( + DmaapCpeAuthenticationConsumerProperties properties) { + this.properties = properties; + } + + @Test + void dmaapCpeAuthenticationProperties_SuccessFullyLoaded() { + assertEquals("test localhost", properties.getDmaapHostName()); + assertEquals(1234, properties.getDmaapPortNumber()); + assertEquals("/events/unauthenticated.PNF_CPE_AUTHENTICATION", properties.getDmaapTopicName()); + assertEquals("http", properties.getDmaapProtocol()); + assertNull(properties.getDmaapUserName()); + assertNull(properties.getDmaapUserPassword()); + assertEquals("application/json", properties.getDmaapContentType()); + assertEquals("c12", properties.getConsumerId()); + assertEquals("OpenDcae-c12", properties.getConsumerGroup()); + assertEquals(-1, properties.getTimeoutMs()); + assertEquals(1, properties.getMessageLimit()); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapProducerPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapProducerPropertiesTest.java new file mode 100644 index 00000000..7ba38f9e --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapProducerPropertiesTest.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = DmaapProducerProperties.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.dmaap.producer.dmaapHostName=test localhost", + "configs.dmaap.producer.dmaapPortNumber=1234", + "configs.dmaap.producer.dmaapTopicName=/events/unauthenticated.DCAE_CL_OUTPUT", + "configs.dmaap.producer.dmaapProtocol=http", + "configs.dmaap.producer.dmaapContentType=application/json"}) +class DmaapProducerPropertiesTest { + + private DmaapProducerProperties properties; + + @Autowired + public DmaapProducerPropertiesTest( + DmaapProducerProperties properties) { + this.properties = properties; + } + + @Test + void dmaapReRegistrationProperties_SuccessFullyLoaded() { + assertEquals("test localhost", properties.getDmaapHostName()); + assertEquals(1234, properties.getDmaapPortNumber()); + assertEquals("/events/unauthenticated.DCAE_CL_OUTPUT", properties.getDmaapTopicName()); + assertEquals("http", properties.getDmaapProtocol()); + assertNull(properties.getDmaapUserName()); + assertNull(properties.getDmaapUserPassword()); + assertEquals("application/json", properties.getDmaapContentType()); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerPropertiesTest.java new file mode 100644 index 00000000..682d2f31 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/DmaapReRegistrationConsumerPropertiesTest.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = DmaapReRegistrationConsumerProperties.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.dmaap.consumer.re-registration.dmaapHostName=test localhost", + "configs.dmaap.consumer.re-registration.dmaapPortNumber=1234", + "configs.dmaap.consumer.re-registration.dmaapTopicName=/events/unauthenticated.PNF_REREGISTRATION", + "configs.dmaap.consumer.re-registration.dmaapProtocol=http", + "configs.dmaap.consumer.re-registration.dmaapContentType=application/json", + "configs.dmaap.consumer.re-registration.consumerId=c12", + "configs.dmaap.consumer.re-registration.consumerGroup=OpenDcae-c12", + "configs.dmaap.consumer.re-registration.timeoutMs=-1", + "configs.dmaap.consumer.re-registration.messageLimit=1"}) +class DmaapReRegistrationConsumerPropertiesTest { + + private DmaapReRegistrationConsumerProperties properties; + + @Autowired + public DmaapReRegistrationConsumerPropertiesTest( + DmaapReRegistrationConsumerProperties properties) { + this.properties = properties; + } + + @Test + void dmaapReRegistrationProperties_SuccessFullyLoaded() { + assertEquals("test localhost", properties.getDmaapHostName()); + assertEquals(1234, properties.getDmaapPortNumber()); + assertEquals("/events/unauthenticated.PNF_REREGISTRATION", properties.getDmaapTopicName()); + assertEquals("http", properties.getDmaapProtocol()); + assertNull(properties.getDmaapUserName()); + assertNull(properties.getDmaapUserPassword()); + assertEquals("application/json", properties.getDmaapContentType()); + assertEquals("c12", properties.getConsumerId()); + assertEquals("OpenDcae-c12", properties.getConsumerGroup()); + assertEquals(-1, properties.getTimeoutMs()); + assertEquals(1, properties.getMessageLimit()); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/GenericPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/GenericPropertiesTest.java new file mode 100644 index 00000000..12e393a1 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/GenericPropertiesTest.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = {GenericProperties.class, + GenericProperties.ReRegistrationGenericProperties.class, + GenericProperties.CpeAuthenticationGenericProperties.class}) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.application.pipelinesPollingIntervalSec=30", + "configs.application.pipelinesTimeoutSec=15", + "configs.application.re-registration.policyScope=reRegPolicyScope", + "configs.application.re-registration.clControlName=reRegControlName", + "configs.application.cpe-authentication.policyScope=cpeAuthPolicyScope", + "configs.application.cpe-authentication.clControlName=cpeAuthControlName"}) +class GenericPropertiesTest { + + private GenericProperties genericProperties; + + @Autowired + public GenericPropertiesTest(GenericProperties genericProperties) { + this.genericProperties = genericProperties; + } + + @Test + void genericProperties_SuccessFullyLoaded() { + assertAll("Generic Application Properties", + () -> assertEquals(30, genericProperties.getPipelinesPollingIntervalSec()), + () -> assertEquals(15, genericProperties.getPipelinesTimeoutSec()), + () -> assertEquals("reRegPolicyScope", genericProperties.getReRegistration().getPolicyScope()), + () -> assertEquals("cpeAuthPolicyScope", + genericProperties.getCpeAuthentication().getPolicyScope()), + () -> assertEquals("reRegControlName", genericProperties.getReRegistration().getClControlName()), + () -> assertEquals("cpeAuthControlName", + genericProperties.getCpeAuthentication().getClControlName()) + ); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/SecurityPropertiesTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/SecurityPropertiesTest.java new file mode 100644 index 00000000..0dd6d75d --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/config/SecurityPropertiesTest.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = SecurityProperties.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "configs.security.trustStorePath=test trust store path", + "configs.security.trustStorePasswordPath=test trust store password path", + "configs.security.keyStorePath=test key store path", + "configs.security.keyStorePasswordPath=test key store password path", + "configs.security.enableDmaapCertAuth=true", + "configs.security.enableAaiCertAuth=true"}) +class SecurityPropertiesTest { + + private SecurityProperties securityProperties; + + @Autowired + public SecurityPropertiesTest(SecurityProperties securityProperties) { + this.securityProperties = securityProperties; + } + + @Test + void securityProperties_SuccessFullyLoaded() { + assertEquals("test key store path", + securityProperties.getKeyStorePath()); + assertEquals("test key store password path", + securityProperties.getKeyStorePasswordPath()); + assertEquals("test trust store path", + securityProperties.getTrustStorePath()); + assertEquals("test trust store password path", + securityProperties.getTrustStorePasswordPath()); + assertTrue(securityProperties.isEnableDmaapCertAuth()); + assertTrue(securityProperties.isEnableAaiCertAuth()); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorControllerTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorControllerTest.java new file mode 100644 index 00000000..bacb6c3e --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/controllers/BbsEventProcessorControllerTest.java @@ -0,0 +1,163 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.controllers; + +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.pipelines.CpeAuthenticationPipeline; +import org.onap.bbs.event.processor.pipelines.ReRegistrationPipeline; +import org.onap.bbs.event.processor.pipelines.Scheduler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +@WebMvcTest(BbsEventProcessorController.class) +@DisplayName("BBS Event Processor Controllers MVC Unit-Tests") +class BbsEventProcessorControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ReRegistrationPipeline reRegistrationPipeline; + @Autowired + private CpeAuthenticationPipeline cpeAuthenticationPipeline; + @Autowired + private Scheduler scheduler; + @Autowired + private ApplicationConfiguration configuration; + + @BeforeEach + void resetInteractions() { + Mockito.reset(scheduler); + } + + @Test + void sendingHeartBeatRestCall_RespondsWithAlive() throws Exception { + MvcResult heartBeatResult = mockMvc.perform(get("/heartbeat")).andReturn(); + + mockMvc.perform(asyncDispatch(heartBeatResult)) + .andExpect(status().isOk()) + .andExpect(content().string("bbs-event-processor is alive\n")); + } + + @Test + void sendingReRegistrationSubmissionRestCall_RespondsWithOk() throws Exception { + MvcResult reregistrationSubmissionResult = mockMvc.perform(post("/poll-reregistration-events")).andReturn(); + + mockMvc.perform(asyncDispatch(reregistrationSubmissionResult)) + .andExpect(status().isOk()) + .andExpect(content().string("Request submitted\n")); + verify(reRegistrationPipeline, timeout(500)).processPnfReRegistrationEvents(); + } + + @Test + void sendingCpeAuthenticationSubmissionRestCall_RespondsWithOk() throws Exception { + MvcResult reregistrationSubmissionResult = mockMvc.perform(post("/poll-cpe-authentication-events")).andReturn(); + + mockMvc.perform(asyncDispatch(reregistrationSubmissionResult)) + .andExpect(status().isOk()) + .andExpect(content().string("Request submitted\n")); + verify(cpeAuthenticationPipeline, timeout(500)).processPnfCpeAuthenticationEvents(); + } + + @Test + void sendingStartTasksRestCall_ifItSucceeds_RespondsWithOk() throws Exception { + when(scheduler.reScheduleProcessingTasks()).thenReturn(true); + MvcResult startTasksResult = mockMvc.perform(post("/start-tasks")).andReturn(); + + mockMvc.perform(asyncDispatch(startTasksResult)) + .andExpect(status().isOk()) + .andExpect(content().string("Initiation of tasks was successful\n")); + verify(scheduler).reScheduleProcessingTasks(); + } + + @Test + void sendingStartTasksRestCall_ifItFails_RespondsWithNotAcceptable() throws Exception { + when(scheduler.reScheduleProcessingTasks()).thenReturn(false); + MvcResult startTasksResult = mockMvc.perform(post("/start-tasks")).andReturn(); + + mockMvc.perform(asyncDispatch(startTasksResult)) + .andExpect(status().isNotAcceptable()) + .andExpect(content().string("Initiation of tasks failed\n")); + verify(scheduler).reScheduleProcessingTasks(); + } + + @Test + void sendingCancelTasksRestCall_ifItSucceeds_RespondsWithOk() throws Exception { + when(scheduler.cancelScheduledProcessingTasks()).thenReturn(true); + MvcResult cancellationResult = mockMvc.perform(post("/cancel-tasks")).andReturn(); + + mockMvc.perform(asyncDispatch(cancellationResult)) + .andExpect(status().isOk()) + .andExpect(content().string("Cancellation was successful\n")); + verify(scheduler).cancelScheduledProcessingTasks(); + } + + @Test + void sendingCancelTasksRestCall_ifItFails_RespondsWithNotAcceptable() throws Exception { + when(scheduler.cancelScheduledProcessingTasks()).thenReturn(false); + MvcResult cancellationResult = mockMvc.perform(post("/cancel-tasks")).andReturn(); + + mockMvc.perform(asyncDispatch(cancellationResult)) + .andExpect(status().isNotAcceptable()) + .andExpect(content().string("Cancellation failed\n")); + verify(scheduler).cancelScheduledProcessingTasks(); + } + + @TestConfiguration + static class ControllerTestConfiguration { + @Bean + ReRegistrationPipeline reRegistrationPipeline() { + return Mockito.mock(ReRegistrationPipeline.class); + } + + @Bean + CpeAuthenticationPipeline cpeAuthenticationPipeline() { + return Mockito.mock(CpeAuthenticationPipeline.class); + } + + @Bean + Scheduler scheduler() { + return Mockito.mock(Scheduler.class); + } + + @Bean + ApplicationConfiguration configuration() { + return Mockito.mock(ApplicationConfiguration.class); + } + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/model/GsonSerializationsTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/model/GsonSerializationsTest.java new file mode 100644 index 00000000..fd43b8be --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/model/GsonSerializationsTest.java @@ -0,0 +1,379 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.ServiceLoader; + +import org.junit.jupiter.api.Test; +import org.onap.bbs.event.processor.utilities.ControlLoopJsonBodyBuilder; +import org.onap.bbs.event.processor.utilities.CpeAuthenticationJsonBodyBuilder; +import org.onap.bbs.event.processor.utilities.ReRegistrationJsonBodyBuilder; + +class GsonSerializationsTest { + + @Test + void creatingReRegistrationJsonBody_returnsJsonInString() { + + String correlationId = "NokiaCorrelationId"; + String attachmentPoint = "olt2/1/1"; + String remoteId = "RemoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String template = "{" + + "\"correlationId\":\"%s\"," + + "\"attachment-point\":\"%s\"," + + "\"remote-id\":\"%s\"," + + "\"cvlan\":\"%s\"," + + "\"svlan\":\"%s\"" + + "}"; + + ReRegistrationConsumerDmaapModel model = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(correlationId) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + + String expectedResult = String.format(template, correlationId, attachmentPoint, remoteId, cvlan, svlan); + + assertEquals(expectedResult, new ReRegistrationJsonBodyBuilder().createJsonBody(model)); + } + + @Test + void creatingCpeAuthenticationJsonBody_returnsJsonInString() { + + String correlationId = "NokiaCorrelationID"; + AuthenticationState oldAuthenticationState = AuthenticationState.IN_SERVICE; + AuthenticationState newAuthenticationState = AuthenticationState.OUT_OF_SERVICE; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String template = "{" + + "\"correlationId\":\"%s\"," + + "\"old-authentication-state\":\"%s\"," + + "\"new-authentication-state\":\"%s\"," + + "\"state-interface\":\"%s\"," + + "\"rgw-mac-address\":\"%s\"," + + "\"sw-version\":\"%s\"" + + "}"; + + CpeAuthenticationConsumerDmaapModel model = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(correlationId) + .oldAuthenticationState(oldAuthenticationState.getNameInOnap()) + .newAuthenticationState(newAuthenticationState.getNameInOnap()) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + + String expectedResult = String.format(template, correlationId, oldAuthenticationState.getNameInOnap(), + newAuthenticationState.getNameInOnap(), stateInterface, rgwMacAddress, swVersion); + + assertEquals(expectedResult, new CpeAuthenticationJsonBodyBuilder().createJsonBody(model)); + } + + @Test + void creatingDcaeControlLoopJsonBody_returnsJsonInString() { + + String closedLoopEventClient = "DCAE.BBS_mSInstance"; + String policyVersion = "1.0.0.5"; + String policyName = "CPE_Authentication"; + String policyScope = + "service=HSIAService,type=SampleType," + + "closedLoopControlName=CL-CPE_A-d925ed73-8231-4d02-9545-db4e101f88f8"; + String targetType = "VM"; + long closedLoopAlarmStart = 1484677482204798L; + String closedLoopEventStatus = "ONSET"; + String closedLoopControlName = "ControlLoop-CPE_A-2179b738-fd36-4843-a71a-a8c24c70c88b"; + String version = "1.0.2"; + String target = "vserver.vserver-name"; + String requestId = "97964e10-686e-4790-8c45-bdfa61df770f"; + String from = "DCAE"; + + Map<String, String> aaiEnrichmentData = new LinkedHashMap<>(); + aaiEnrichmentData.put("service-information.service-instance-id", "service-instance-id-example"); + aaiEnrichmentData.put("cvlan-id", "example cvlan-id"); + aaiEnrichmentData.put("svlan-id", "example svlan-id"); + + String template = "{" + + "\"closedLoopEventClient\":\"%s\"," + + "\"policyVersion\":\"%s\"," + + "\"policyName\":\"%s\"," + + "\"policyScope\":\"%s\"," + + "\"target_type\":\"%s\"," + + "\"AAI\":{" + + "\"service-information.service-instance-id\":\"service-instance-id-example\"," + + "\"cvlan-id\":\"example cvlan-id\"," + + "\"svlan-id\":\"example svlan-id\"" + + "}," + + "\"closedLoopAlarmStart\":%s," + + "\"closedLoopEventStatus\":\"%s\"," + + "\"closedLoopControlName\":\"%s\"," + + "\"version\":\"%s\"," + + "\"target\":\"%s\"," + + "\"requestID\":\"%s\"," + + "\"from\":\"%s\"" + + "}"; + + + ControlLoopPublisherDmaapModel model = ImmutableControlLoopPublisherDmaapModel.builder() + .closedLoopEventClient(closedLoopEventClient) + .policyVersion(policyVersion) + .policyName(policyName) + .policyScope(policyScope) + .targetType(targetType) + .aaiEnrichmentData(aaiEnrichmentData) + .closedLoopAlarmStart(closedLoopAlarmStart) + .closedLoopEventStatus(closedLoopEventStatus) + .closedLoopControlName(closedLoopControlName) + .version(version) + .target(target) + .requestId(requestId) + .originator(from) + .build(); + + String expectedResult = String.format(template, + closedLoopEventClient, + policyVersion, + policyName, + policyScope, + targetType, + closedLoopAlarmStart, + closedLoopEventStatus, + closedLoopControlName, + version, + target, + requestId, + from); + + assertEquals(expectedResult, new ControlLoopJsonBodyBuilder().createJsonBody(model)); + } + + @Test + void pnfAaiObject_IsSerializedSuccessfully() { + + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + Gson gson = gsonBuilder.create(); + + String pnfName = "NokiaCorrelationID"; + String swVersion = "1.2"; + + String template = "{" + + "\"pnf-name\":\"%s\"," + + "\"in-maint\":true," + + "\"sw-version\":\"%s\"," + + "\"relationship-list\":{" + + "\"relationship\":[" + + "{" + + "\"related-to\":\"service-instance\"," + + "\"relationship-label\":\"org.onap.relationships.inventory.ComposedOf\"," + + "\"related-link\":\"/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS/service-instances/service-instance/84003b26-6b76-4c75-b805-7b14ab4ffaef\"," + + "\"relationship-data\":[" + + "{" + + "\"relationship-key\":\"customer.global-customer-id\"," + + "\"relationship-value\":\"Demonstration\"" + + "}," + + "{" + + "\"relationship-key\":\"service-subscription.service-type\"," + + "\"relationship-value\":\"BBS\"" + + "}," + + "{" + + "\"relationship-key\":\"service-instance.service-instance-id\"," + + "\"relationship-value\":\"84003b26-6b76-4c75-b805-7b14ab4ffaef\"" + + "}" + + "]," + + "\"related-to-property\":[" + + "{" + + "\"property-key\":\"service-instance.service-instance-name\"," + + "\"property-value\":\"bbs-instance\"" + + "}" + + "]" + + "}," + + "{" + + "\"related-to\":\"platform\"," + + "\"relationship-label\":\"org.onap.relationships.inventory.Uses\"," + + "\"related-link\":\"/aai/v14/business/platforms/platform/bbs-platform\"," + + "\"relationship-data\":[" + + "{" + + "\"relationship-key\":\"platform.platform-name\"," + + "\"relationship-value\":\"bbs-platform\"" + + "}" + + "]" + + "}" + + "]" + + "}" + + "}"; + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject firstRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS/service-instances" + + "/service-instance/84003b26-6b76-4c75-b805-7b14ab4ffaef") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("84003b26-6b76-4c75-b805-7b14ab4ffaef").build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject.RelationshipEntryAaiObject secondRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("platform") + .relatedLink("/aai/v14/business/platforms/platform/bbs-platform") + .relationshipLabel("org.onap.relationships.inventory.Uses") + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("platform.platform-name") + .relationshipValue("bbs-platform").build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Arrays.asList(firstRelationshipEntry, secondRelationshipEntry)) + .build(); + + // Finally construct PNF object data + PnfAaiObject pnfAaiObject = ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .swVersion(swVersion) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + + + String jsonPnfObject = String.format(template, pnfName, swVersion); + + assertEquals(jsonPnfObject, gson.toJson(pnfAaiObject)); + assertEquals(pnfAaiObject, gson.fromJson(jsonPnfObject, ImmutablePnfAaiObject.class)); + } + + @Test + void serviceInstanceAaiObject_IsSerializedSuccessfully() { + + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + Gson gson = gsonBuilder.create(); + + String serviceInstanceId = "84003b26-6b76-4c75-b805-7b14ab4ffaef"; + String orchestrationStatus = "active"; + + String template = "{" + + "\"service-instance-id\":\"%s\"," + + "\"orchestration-status\":\"%s\"," + + "\"relationship-list\":{" + + "\"relationship\":[" + + "{" + + "\"related-to\":\"service-instance\"," + + "\"relationship-label\":\"org.onap.relationships.inventory.ComposedOf\"," + + "\"related-link\":\"/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS" + + "/service-instances/service-instance/bb374844-44e4-488f-8381-fb5a0e3e6989\"," + + "\"relationship-data\":[" + + "{" + + "\"relationship-key\":\"service-instance.service-instance-id\"," + + "\"relationship-value\":\"bb374844-44e4-488f-8381-fb5a0e3e6989\"" + + "}" + + "]" + + "}" + + "]" + + "}," + + "\"metadata\":{" + + "\"metadatum\":[" + + "{" + + "\"metaname\":\"cvlan\"," + + "\"metaval\":\"1005\"" + + "}" + + "]" + + "}" + + "}"; + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/bb374844-44e4-488f-8381-fb5a0e3e6989") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("bb374844-44e4-488f-8381-fb5a0e3e6989").build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + MetadataListAaiObject.MetadataEntryAaiObject metadataEntry = + ImmutableMetadataEntryAaiObject.builder() + .metaname("cvlan") + .metavalue("1005") + .build(); + + MetadataListAaiObject metadataListAaiObject = ImmutableMetadataListAaiObject.builder() + .metadataEntries(Collections.singletonList(metadataEntry)) + .build(); + + // Finally construct Service Instance object data + ServiceInstanceAaiObject serviceInstanceAaiObject = ImmutableServiceInstanceAaiObject.builder() + .serviceInstanceId(serviceInstanceId) + .orchestrationStatus(orchestrationStatus) + .relationshipListAaiObject(relationshipListAaiObject) + .metadataListAaiObject(metadataListAaiObject) + .build(); + + + String jsonServiceInstanceObject = String.format(template, serviceInstanceId, orchestrationStatus); + + assertEquals(jsonServiceInstanceObject, gson.toJson(serviceInstanceAaiObject)); + assertEquals(serviceInstanceAaiObject, gson.fromJson(jsonServiceInstanceObject, + ImmutableServiceInstanceAaiObject.class)); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipelineTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipelineTest.java new file mode 100644 index 00000000..dbac5bf2 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/CpeAuthenticationPipelineTest.java @@ -0,0 +1,656 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.onap.bbs.event.processor.config.ApplicationConstants.CONSUME_CPE_AUTHENTICATION_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_PNF_TASK_NAME; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.UUID; + +import javax.net.ssl.SSLException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableCpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableMetadataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableMetadataListAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePnfAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePropertyAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipDataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ImmutableServiceInstanceAaiObject; +import org.onap.bbs.event.processor.model.MetadataListAaiObject; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.tasks.AaiClientTask; +import org.onap.bbs.event.processor.tasks.DmaapCpeAuthenticationConsumerTask; +import org.onap.bbs.event.processor.tasks.DmaapPublisherTask; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +// We can safely suppress unchecked assignment warnings for the ResponseEntity mock +@SuppressWarnings("unchecked") +@DisplayName("CPE Authentication Pipeline Unit-Tests") +class CpeAuthenticationPipelineTest { + + private CpeAuthenticationPipeline pipeline; + private ApplicationConfiguration configuration; + private DmaapCpeAuthenticationConsumerTask consumerTask; + private DmaapPublisherTask publisherTask; + private AaiClientTask aaiClientTask; + + private ResponseEntity<String> responseEntity; + + @BeforeEach + void setup() { + + responseEntity = Mockito.mock(ResponseEntity.class); + + configuration = Mockito.mock(ApplicationConfiguration.class); + consumerTask = Mockito.mock(DmaapCpeAuthenticationConsumerTask.class); + publisherTask = Mockito.mock(DmaapPublisherTask.class); + aaiClientTask = Mockito.mock(AaiClientTask.class); + + when(configuration.getCpeAuthenticationCloseLoopControlName()) + .thenReturn("controlName"); + when(configuration.getCpeAuthenticationCloseLoopPolicyScope()) + .thenReturn("policyScope"); + + pipeline = new CpeAuthenticationPipeline(configuration, consumerTask, + publisherTask, aaiClientTask, new HashMap<>()); + } + + @Test + void handleEmptyResponseFromDmaap() throws SSLException { + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(anyString())) + .thenReturn(Flux.error(new EmptyDmaapResponseException("Mock empty"))); + + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseFromDmaap_PipelineTimesOut() throws SSLException { + + // Prepare mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)) + .thenReturn(Flux.never()); + + // Execute pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseFromAai_PipelineTimesOut() throws SSLException { + + String pnfName = "olt1"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel event = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + // Prepare mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)).thenReturn(Flux.just(event)); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())).thenReturn(Mono.never()); + + // Execute pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseWhilePublishing_PipelineTimesOut() throws SSLException { + + String pnfName = "olt1"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel event = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName, hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName, rgwMacAddress); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)).thenReturn(Flux.just(event)); + + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.never()); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void singleCorrectEvent_handleSuccessfully() throws SSLException { + + String pnfName = "olt1"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel event = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName, hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName, rgwMacAddress); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)).thenReturn(Flux.just(event)); + + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoCorrectEvents_handleSuccessfully() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress1 = "00:0a:95:8d:78:16"; + final String rgwMacAddress2 = "00:0a:95:8d:78:17"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId1 = UUID.randomUUID().toString(); + String hsiCfsServiceInstanceId2 = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel firstEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress1) + .swVersion(swVersion) + .build(); + CpeAuthenticationConsumerDmaapModel secondEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress2) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject1 = constructPnfObject(pnfName1, hsiCfsServiceInstanceId1); + PnfAaiObject pnfAaiObject2 = constructPnfObject(pnfName2, hsiCfsServiceInstanceId2); + ServiceInstanceAaiObject hsiCfsServiceInstance1 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId1, pnfName1, rgwMacAddress1); + ServiceInstanceAaiObject hsiCfsServiceInstance2 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId2, pnfName2, rgwMacAddress2); + + // Prepare Mocks + String pnfUrl1 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName1); + String pnfUrl2 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName2); + String cfsUrl1 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance1.getServiceInstanceId()); + String cfsUrl2 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance2.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl1)).thenReturn(Mono.just(pnfAaiObject1)); + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl2)).thenReturn(Mono.just(pnfAaiObject2)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl1)) + .thenReturn(Mono.just(hsiCfsServiceInstance1)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl2)) + .thenReturn(Mono.just(hsiCfsServiceInstance2)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask, times(2)).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void singleEvent_withPnfErrorReply_handleGracefully() throws SSLException { + + String pnfName = "olt1"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel event = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + // Prepare Mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)).thenReturn(Flux.just(event)); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verify(aaiClientTask).executePnfRetrieval(anyString(), anyString()); + verifyNoMoreInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void twoEvents_FirstOk_SecondUnmatchedMac_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress1 = "00:0a:95:8d:78:16"; + final String rgwMacAddress2 = "00:0a:95:8d:78:17"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId1 = UUID.randomUUID().toString(); + String hsiCfsServiceInstanceId2 = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel firstEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress1) + .swVersion(swVersion) + .build(); + CpeAuthenticationConsumerDmaapModel secondEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress2) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject1 = constructPnfObject(pnfName1, hsiCfsServiceInstanceId1); + PnfAaiObject pnfAaiObject2 = constructPnfObject(pnfName2, hsiCfsServiceInstanceId2); + ServiceInstanceAaiObject hsiCfsServiceInstance1 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId1, pnfName1, rgwMacAddress1); + ServiceInstanceAaiObject hsiCfsServiceInstance2 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId2, pnfName2, + "Having unmatched RGW MAC address"); + + // Prepare Mocks + String pnfUrl1 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName1); + String pnfUrl2 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName2); + String cfsUrl1 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance1.getServiceInstanceId()); + String cfsUrl2 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance2.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl1)).thenReturn(Mono.just(pnfAaiObject1)); + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl2)).thenReturn(Mono.just(pnfAaiObject2)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl1)) + .thenReturn(Mono.just(hsiCfsServiceInstance1)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl2)) + .thenReturn(Mono.just(hsiCfsServiceInstance2)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoEvents_firstOk_secondWithPnfErrorReply_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel firstEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + CpeAuthenticationConsumerDmaapModel secondEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName1, hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName1, rgwMacAddress); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(aaiClientTask, times(2)).executePnfRetrieval(anyString(), anyString()); + verify(aaiClientTask).executeServiceInstanceRetrieval(anyString(), anyString()); + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoEvents_firstWithPnfErrorReply_secondOk_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + CpeAuthenticationConsumerDmaapModel firstEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + CpeAuthenticationConsumerDmaapModel secondEvent = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName2, hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName2, rgwMacAddress); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_CPE_AUTHENTICATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))) + .thenReturn(Mono.just(pnfAaiObject)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(aaiClientTask, times(2)) + .executePnfRetrieval(anyString(), anyString()); + verify(aaiClientTask).executeServiceInstanceRetrieval(anyString(), anyString()); + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + private PnfAaiObject constructPnfObject(String pnfName, String hsiCfsServiceInstanceId) { + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/" + hsiCfsServiceInstanceId) + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS-CFS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue(hsiCfsServiceInstanceId).build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + // Finally construct PNF object data + return ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + } + + private ServiceInstanceAaiObject constructHsiCfsServiceInstanceObject(String hsiCfsServiceInstanceId, + String pnfName, + String rgwMacAddress) { + String orchestrationStatus = "active"; + + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("pnf") + .relatedLink("/pnfs/pnf/" + pnfName) + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("pnf.pnf-name") + .relationshipValue(pnfName).build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + MetadataListAaiObject.MetadataEntryAaiObject metadataEntry = + ImmutableMetadataEntryAaiObject.builder() + .metaname("rgw-mac-address") + .metavalue(rgwMacAddress) + .build(); + + MetadataListAaiObject metadataListAaiObject = ImmutableMetadataListAaiObject.builder() + .metadataEntries(Collections.singletonList(metadataEntry)) + .build(); + + // Finally construct Service Instance object data + return ImmutableServiceInstanceAaiObject.builder() + .serviceInstanceId(hsiCfsServiceInstanceId) + .orchestrationStatus(orchestrationStatus) + .relationshipListAaiObject(relationshipListAaiObject) + .metadataListAaiObject(metadataListAaiObject) + .build(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipelineTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipelineTest.java new file mode 100644 index 00000000..dbd1aab1 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/ReRegistrationPipelineTest.java @@ -0,0 +1,745 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.onap.bbs.event.processor.config.ApplicationConstants.CONSUME_REREGISTRATION_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME; +import static org.onap.bbs.event.processor.config.ApplicationConstants.RETRIEVE_PNF_TASK_NAME; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.UUID; + +import javax.net.ssl.SSLException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableMetadataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableMetadataListAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePnfAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePropertyAaiObject; +import org.onap.bbs.event.processor.model.ImmutableReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableRelationshipDataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ImmutableServiceInstanceAaiObject; +import org.onap.bbs.event.processor.model.MetadataListAaiObject; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.tasks.AaiClientTask; +import org.onap.bbs.event.processor.tasks.DmaapPublisherTask; +import org.onap.bbs.event.processor.tasks.DmaapReRegistrationConsumerTask; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +// We can safely suppress unchecked assignment warnings for the ResponseEntity mock +@SuppressWarnings("unchecked") +@DisplayName("PNF Re-registration Pipeline Unit-Tests") +class ReRegistrationPipelineTest { + + private ReRegistrationPipeline pipeline; + private ApplicationConfiguration configuration; + private DmaapReRegistrationConsumerTask consumerTask; + private DmaapPublisherTask publisherTask; + private AaiClientTask aaiClientTask; + + private ResponseEntity<String> responseEntity; + + @BeforeEach + void setup() { + + responseEntity = Mockito.mock(ResponseEntity.class); + + configuration = Mockito.mock(ApplicationConfiguration.class); + consumerTask = Mockito.mock(DmaapReRegistrationConsumerTask.class); + publisherTask = Mockito.mock(DmaapPublisherTask.class); + aaiClientTask = Mockito.mock(AaiClientTask.class); + + when(configuration.getReRegistrationCloseLoopControlName()) + .thenReturn("controlName"); + when(configuration.getReRegistrationCloseLoopPolicyScope()) + .thenReturn("policyScope"); + + pipeline = new ReRegistrationPipeline(configuration, consumerTask, + publisherTask, aaiClientTask, new HashMap<>()); + } + + @Test + void handleEmptyResponseFromDmaap() throws SSLException { + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(anyString())) + .thenReturn(Flux.error(new EmptyDmaapResponseException("Mock empty"))); + + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseFromDmaap_PipelineTimesOut() throws SSLException { + + // Prepare mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)) + .thenReturn(Flux.never()); + + // Execute pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseFromAai_PipelineTimesOut() throws SSLException { + + String pnfName = "olt1"; + String attachmentPoint = "olt2-2-2"; + String remoteId = "newRemoteId"; + String cvlan = "1005"; + String svlan = "100"; + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel event = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + // Prepare mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)).thenReturn(Flux.just(event)); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())).thenReturn(Mono.never()); + + // Execute pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verifyZeroInteractions(publisherTask); + } + + @Test + void noResponseWhilePublishing_PipelineTimesOut() throws SSLException { + + String pnfName = "olt1"; + String attachmentPoint = "olt2-2-2"; + String remoteId = "newRemoteId"; + String cvlan = "1005"; + String svlan = "100"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel event = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName, "olt1-1-1", hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName, cvlan); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(1); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)).thenReturn(Flux.just(event)); + + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.never()); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void singleCorrectEvent_PnfHavingNoLogicalLink_handleGracefully() throws SSLException { + + String pnfName = "olt1"; + String attachmentPoint = "olt2-2-2"; + String remoteId = "newRemoteId"; + String cvlan = "1005"; + String svlan = "100"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel event = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObjectWithoutLogicalLink(pnfName, hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName, cvlan); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)).thenReturn(Flux.just(event)); + + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verify(aaiClientTask).executePnfRetrieval(anyString(), anyString()); + verifyNoMoreInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void singleCorrectEvent_handleSuccessfully() throws SSLException { + + String pnfName = "olt1"; + String attachmentPoint = "olt2-2-2"; + String remoteId = "newRemoteId"; + String cvlan = "1005"; + String svlan = "100"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel event = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName, "old-attachment-point", hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName, cvlan); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)).thenReturn(Flux.just(event)); + + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoCorrectEvents_handleSuccessfully() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + String attachmentPoint1 = "olt1-1-1"; + String attachmentPoint2 = "olt2-2-2"; + String remoteId1 = "newRemoteId1"; + String remoteId2 = "newRemoteId2"; + String cvlan1 = "1005"; + String cvlan2 = "1006"; + String svlan = "100"; + String hsiCfsServiceInstanceId1 = UUID.randomUUID().toString(); + String hsiCfsServiceInstanceId2 = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel firstEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .attachmentPoint(attachmentPoint1) + .remoteId(remoteId1) + .cVlan(cvlan1) + .sVlan(svlan) + .build(); + ReRegistrationConsumerDmaapModel secondEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .attachmentPoint(attachmentPoint2) + .remoteId(remoteId2) + .cVlan(cvlan2) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject1 = constructPnfObject(pnfName1, "olt1-1-0", hsiCfsServiceInstanceId1); + PnfAaiObject pnfAaiObject2 = constructPnfObject(pnfName2, "olt2-2-0", hsiCfsServiceInstanceId2); + ServiceInstanceAaiObject hsiCfsServiceInstance1 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId1, pnfName1, cvlan1); + ServiceInstanceAaiObject hsiCfsServiceInstance2 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId2, pnfName2, cvlan2); + + // Prepare Mocks + String pnfUrl1 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName1); + String pnfUrl2 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName2); + String cfsUrl1 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance1.getServiceInstanceId()); + String cfsUrl2 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance2.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl1)).thenReturn(Mono.just(pnfAaiObject1)); + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl2)).thenReturn(Mono.just(pnfAaiObject2)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl1)) + .thenReturn(Mono.just(hsiCfsServiceInstance1)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl2)) + .thenReturn(Mono.just(hsiCfsServiceInstance2)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask, times(2)).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void singleEvent_withPnfErrorReply_handleGracefully() throws SSLException { + + String pnfName = "olt1"; + String attachmentPoint = "olt2-2-2"; + String remoteId = "newRemoteId"; + String cvlan = "1005"; + String svlan = "100"; + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel event = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + // Prepare Mocks + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)).thenReturn(Flux.just(event)); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .verifyComplete(); + + verify(aaiClientTask).executePnfRetrieval(anyString(), anyString()); + verifyNoMoreInteractions(aaiClientTask); + verifyZeroInteractions(publisherTask); + } + + @Test + void twoEvents_FirstOk_SecondNotRelocation_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + String attachmentPoint1 = "olt1-1-1"; + String attachmentPoint2 = "olt2-2-2"; + String remoteId1 = "newRemoteId1"; + String remoteId2 = "newRemoteId2"; + String cvlan1 = "1005"; + String cvlan2 = "1006"; + String svlan = "100"; + String hsiCfsServiceInstanceId1 = UUID.randomUUID().toString(); + String hsiCfsServiceInstanceId2 = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel firstEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .attachmentPoint(attachmentPoint1) + .remoteId(remoteId1) + .cVlan(cvlan1) + .sVlan(svlan) + .build(); + ReRegistrationConsumerDmaapModel secondEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .attachmentPoint(attachmentPoint2) + .remoteId(remoteId2) + .cVlan(cvlan2) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject1 = constructPnfObject(pnfName1, "olt1-1-0", hsiCfsServiceInstanceId1); + PnfAaiObject pnfAaiObject2 = constructPnfObject(pnfName2, attachmentPoint2, hsiCfsServiceInstanceId2); + ServiceInstanceAaiObject hsiCfsServiceInstance1 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId1, pnfName1, cvlan1); + ServiceInstanceAaiObject hsiCfsServiceInstance2 = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId2, pnfName2, cvlan2); + + // Prepare Mocks + String pnfUrl1 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName1); + String pnfUrl2 = String.format("/aai/v14/network/pnfs/pnf/%s?depth=all", pnfName2); + String cfsUrl1 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance1.getServiceInstanceId()); + String cfsUrl2 = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance2.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl1)).thenReturn(Mono.just(pnfAaiObject1)); + when(aaiClientTask.executePnfRetrieval(RETRIEVE_PNF_TASK_NAME, pnfUrl2)).thenReturn(Mono.just(pnfAaiObject2)); + + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl1)) + .thenReturn(Mono.just(hsiCfsServiceInstance1)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl2)) + .thenReturn(Mono.just(hsiCfsServiceInstance2)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoEvents_firstOk_secondWithPnfErrorReply_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + String attachmentPoint1 = "olt1-1-1"; + String attachmentPoint2 = "olt2-2-2"; + String remoteId1 = "newRemoteId1"; + String remoteId2 = "newRemoteId2"; + String cvlan1 = "1005"; + String cvlan2 = "1006"; + String svlan = "100"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel firstEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .attachmentPoint(attachmentPoint1) + .remoteId(remoteId1) + .cVlan(cvlan1) + .sVlan(svlan) + .build(); + ReRegistrationConsumerDmaapModel secondEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .attachmentPoint(attachmentPoint2) + .remoteId(remoteId2) + .cVlan(cvlan2) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName1, "old-attachment-point", hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName1, cvlan1); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.just(pnfAaiObject)) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(aaiClientTask, times(2)).executePnfRetrieval(anyString(), anyString()); + verify(aaiClientTask).executeServiceInstanceRetrieval(anyString(), anyString()); + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + @Test + void twoEvents_firstWithPnfErrorReply_secondOk_handleCorrectOnly() throws SSLException { + + String pnfName1 = "olt1"; + String pnfName2 = "olt2"; + String attachmentPoint1 = "olt1-1-1"; + String attachmentPoint2 = "olt2-2-2"; + String remoteId1 = "newRemoteId1"; + String remoteId2 = "newRemoteId2"; + String cvlan1 = "1005"; + String cvlan2 = "1006"; + String svlan = "100"; + String hsiCfsServiceInstanceId = UUID.randomUUID().toString(); + + // Prepare stubbed replies + ReRegistrationConsumerDmaapModel firstEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName1) + .attachmentPoint(attachmentPoint1) + .remoteId(remoteId1) + .cVlan(cvlan1) + .sVlan(svlan) + .build(); + ReRegistrationConsumerDmaapModel secondEvent = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(pnfName2) + .attachmentPoint(attachmentPoint2) + .remoteId(remoteId2) + .cVlan(cvlan2) + .sVlan(svlan) + .build(); + + PnfAaiObject pnfAaiObject = constructPnfObject(pnfName2, "old-attachment-point", hsiCfsServiceInstanceId); + ServiceInstanceAaiObject hsiCfsServiceInstance = + constructHsiCfsServiceInstanceObject(hsiCfsServiceInstanceId, pnfName2, cvlan2); + + // Prepare Mocks + String cfsUrl = String.format("/aai/v14/nodes/service-instances/service-instance/%s?depth=all", + hsiCfsServiceInstance.getServiceInstanceId()); + + when(configuration.getPipelinesTimeoutInSeconds()).thenReturn(10); + when(consumerTask.execute(CONSUME_REREGISTRATION_TASK_NAME)) + .thenReturn(Flux.fromIterable(Arrays.asList(firstEvent, secondEvent))); + when(aaiClientTask.executePnfRetrieval(anyString(), anyString())) + .thenReturn(Mono.error(new AaiTaskException("Mock A&AI exception"))) + .thenReturn(Mono.just(pnfAaiObject)); + when(aaiClientTask + .executeServiceInstanceRetrieval(RETRIEVE_HSI_CFS_SERVICE_INSTANCE_TASK_NAME, cfsUrl)) + .thenReturn(Mono.just(hsiCfsServiceInstance)); + + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(HttpStatus.OK.value())); + when(publisherTask.execute(any(ControlLoopPublisherDmaapModel.class))).thenReturn(Mono.just(responseEntity)); + + // Execute the pipeline + StepVerifier.create(pipeline.executePipeline()) + .expectSubscription() + .assertNext(r -> assertEquals(HttpStatus.OK, r.getStatusCode())) + .verifyComplete(); + + verify(aaiClientTask, times(2)) + .executePnfRetrieval(anyString(), anyString()); + verify(aaiClientTask).executeServiceInstanceRetrieval(anyString(), anyString()); + verify(publisherTask).execute(any(ControlLoopPublisherDmaapModel.class)); + } + + private PnfAaiObject constructPnfObject(String pnfName, String attachmentPoint, + String hsiCfsServiceInstanceId) { + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject firstRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/" + hsiCfsServiceInstanceId) + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS-CFS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue(hsiCfsServiceInstanceId).build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject.RelationshipEntryAaiObject secondRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("logical-link") + .relatedLink("/network/logical-links/logical-link/" + attachmentPoint) + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("logical-link.link-name") + .relationshipValue(attachmentPoint).build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Arrays.asList(firstRelationshipEntry, secondRelationshipEntry)) + .build(); + + // Finally construct PNF object data + return ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + } + + private PnfAaiObject constructPnfObjectWithoutLogicalLink(String pnfName, String hsiCfsServiceInstanceId) { + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/" + hsiCfsServiceInstanceId) + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS-CFS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue(hsiCfsServiceInstanceId).build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + // Finally construct PNF object data + return ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + } + + private ServiceInstanceAaiObject constructHsiCfsServiceInstanceObject(String hsiCfsServiceInstanceId, + String pnfName, + String cvlan) { + String orchestrationStatus = "active"; + + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("pnf") + .relatedLink("/pnfs/pnf/" + pnfName) + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("pnf.pnf-name") + .relationshipValue(pnfName).build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + MetadataListAaiObject.MetadataEntryAaiObject metadataEntry = + ImmutableMetadataEntryAaiObject.builder() + .metaname("cvlan") + .metavalue(cvlan) + .build(); + + MetadataListAaiObject metadataListAaiObject = ImmutableMetadataListAaiObject.builder() + .metadataEntries(Collections.singletonList(metadataEntry)) + .build(); + + // Finally construct Service Instance object data + return ImmutableServiceInstanceAaiObject.builder() + .serviceInstanceId(hsiCfsServiceInstanceId) + .orchestrationStatus(orchestrationStatus) + .relationshipListAaiObject(relationshipListAaiObject) + .metadataListAaiObject(metadataListAaiObject) + .build(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/SchedulerTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/SchedulerTest.java new file mode 100644 index 00000000..f721ca7e --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/pipelines/SchedulerTest.java @@ -0,0 +1,189 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.pipelines; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.ScheduledFuture; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.config.ConsulConfigurationGateway; +import org.springframework.scheduling.TaskScheduler; + +// We can safely suppress unchecked assignment warnings for the ScheduledFuture mock +@SuppressWarnings("unchecked") +@DisplayName("Application Task Scheduler Unit-Tests") +class SchedulerTest { + + private Scheduler applicationScheduler; + private ApplicationConfiguration configuration; + private TaskScheduler taskScheduler; + + SchedulerTest() { + configuration = Mockito.mock(ApplicationConfiguration.class); + taskScheduler = Mockito.mock(TaskScheduler.class); + ReRegistrationPipeline reRegistrationPipeline = Mockito.mock(ReRegistrationPipeline.class); + CpeAuthenticationPipeline cpeAuthenticationPipeline = Mockito.mock(CpeAuthenticationPipeline.class); + ConsulConfigurationGateway configurationGateway = Mockito.mock(ConsulConfigurationGateway.class); + this.applicationScheduler = new Scheduler(configuration, configurationGateway, taskScheduler, + reRegistrationPipeline, cpeAuthenticationPipeline); + } + + @Test + void scheduleTasksWithValidSchedulingPeriod_Succeeds() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + ScheduledFuture scheduledFuture = Mockito.mock(ScheduledFuture.class); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture); + + applicationScheduler.setupScheduler(); + assertAll("Scheduler with valid Scheduling period", + () -> assertEquals(2, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(2, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } + + @Test + void cancellingRunningTasksSucceeds_tasksAreDeleted() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + ScheduledFuture scheduledFuture1 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture2 = Mockito.mock(ScheduledFuture.class); + when(scheduledFuture1.cancel(false)).thenReturn(true); + when(scheduledFuture2.cancel(false)).thenReturn(true); + when(scheduledFuture1.isCancelled()).thenReturn(true); + when(scheduledFuture2.isCancelled()).thenReturn(true); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture1).thenReturn(scheduledFuture2); + + applicationScheduler.setupScheduler(); + boolean result = applicationScheduler.cancelScheduledProcessingTasks(); + assertAll("Successfully cancelling tasks", + () -> assertTrue(result, "Result of cancellation task"), + () -> assertEquals(0, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(0, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } + + @Test + void cancellingRunningTasksPartiallyFailing_tasksAreNotDeleted() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + ScheduledFuture scheduledFuture1 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture2 = Mockito.mock(ScheduledFuture.class); + when(scheduledFuture1.cancel(false)).thenReturn(true); + when(scheduledFuture2.cancel(false)).thenReturn(false); + when(scheduledFuture1.isCancelled()).thenReturn(true); + when(scheduledFuture2.isCancelled()).thenReturn(false); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture1).thenReturn(scheduledFuture2); + + applicationScheduler.setupScheduler(); + boolean result = applicationScheduler.cancelScheduledProcessingTasks(); + assertAll("Partially cancelling tasks", + () -> assertFalse(result, "Result of cancellation task"), + () -> assertEquals(1, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(1, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } + + @Test + void cancellingRunningTasksFailingForAllOfThem_noTasksAreDeleted() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + ScheduledFuture scheduledFuture1 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture2 = Mockito.mock(ScheduledFuture.class); + when(scheduledFuture1.cancel(false)).thenReturn(false); + when(scheduledFuture2.cancel(false)).thenReturn(false); + when(scheduledFuture1.isCancelled()).thenReturn(false); + when(scheduledFuture2.isCancelled()).thenReturn(false); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture1).thenReturn(scheduledFuture2); + + applicationScheduler.setupScheduler(); + boolean result = applicationScheduler.cancelScheduledProcessingTasks(); + assertAll("Failing in cancelling tasks", + () -> assertFalse(result, "Result of cancellation task"), + () -> assertEquals(2, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(2, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } + + @Test + void reSchedulingWithExistingActiveTasks_Fails() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + ScheduledFuture scheduledFuture1 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture2 = Mockito.mock(ScheduledFuture.class); + when(scheduledFuture1.isCancelled()).thenReturn(false); + when(scheduledFuture2.isCancelled()).thenReturn(false); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture1).thenReturn(scheduledFuture2); + + applicationScheduler.setupScheduler(); + boolean result = applicationScheduler.reScheduleProcessingTasks(); + assertAll("Rescheduling with active tasks", + () -> assertFalse(result, "Result of re-scheduling"), + () -> assertEquals(2, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(2, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } + + @Test + void reSchedulingWithExistingCancelledTasks_Succeeds() { + when(configuration.getPipelinesPollingIntervalInSeconds()).thenReturn(20); + // Initial tasks + ScheduledFuture scheduledFuture1 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture2 = Mockito.mock(ScheduledFuture.class); + // Re-scheduled tasks + ScheduledFuture scheduledFuture3 = Mockito.mock(ScheduledFuture.class); + ScheduledFuture scheduledFuture4 = Mockito.mock(ScheduledFuture.class); + when(scheduledFuture1.isCancelled()).thenReturn(true); + when(scheduledFuture2.isCancelled()).thenReturn(true); + when(scheduledFuture3.isCancelled()).thenReturn(false); + when(scheduledFuture4.isCancelled()).thenReturn(false); + when(taskScheduler.scheduleAtFixedRate(any(Runnable.class), any(Instant.class), any(Duration.class))) + .thenReturn(scheduledFuture1) + .thenReturn(scheduledFuture2) + .thenReturn(scheduledFuture3) + .thenReturn(scheduledFuture4); + + applicationScheduler.setupScheduler(); + boolean result = applicationScheduler.reScheduleProcessingTasks(); + assertAll("Rescheduling with cancelled tasks", + () -> assertTrue(result, "Result of re-scheduling"), + () -> assertEquals(2, applicationScheduler.numberOfTotalTasks(), "Total tasks"), + () -> assertEquals(2, applicationScheduler.numberOfActiveTasks(), "Active tasks"), + () -> assertEquals(0, applicationScheduler.numberOfCancelledTasks(), "Cancelled tasks") + ); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImplTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImplTest.java new file mode 100644 index 00000000..db5f7cb1 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/AaiClientTaskImplTest.java @@ -0,0 +1,239 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Collections; +import java.util.ServiceLoader; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.exceptions.AaiTaskException; +import org.onap.bbs.event.processor.model.ImmutableMetadataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableMetadataListAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePnfAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePropertyAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipDataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ImmutableServiceInstanceAaiObject; +import org.onap.bbs.event.processor.model.MetadataListAaiObject; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.onap.bbs.event.processor.utilities.AaiReactiveClient; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class AaiClientTaskImplTest { + + private AaiReactiveClient reactiveClient; + + private AaiClientTask task; + + @BeforeEach + void init() { + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + reactiveClient = Mockito.mock(AaiReactiveClient.class); + task = new AaiClientTaskImpl(reactiveClient); + } + + @Test + void passingEmptyPnfObject_NothingHappens() throws AaiTaskException { + when(reactiveClient.getPnfObjectDataFor(any(String.class))).thenReturn(Mono.empty()); + Mono<PnfAaiObject> pnf = task.executePnfRetrieval("Empty PNF task", "some-url"); + + verify(reactiveClient).getPnfObjectDataFor("some-url"); + assertNull(pnf.block(Duration.ofSeconds(5))); + } + + @Test + void passingEmptyServiceInstanceObject_NothingHappens() throws AaiTaskException { + when(reactiveClient.getServiceInstanceObjectDataFor(any(String.class))).thenReturn(Mono.empty()); + Mono<ServiceInstanceAaiObject> serviceInstance = + task.executeServiceInstanceRetrieval("Empty Service Instance task", "some-url"); + + verify(reactiveClient).getServiceInstanceObjectDataFor("some-url"); + assertNull(serviceInstance.block(Duration.ofSeconds(5))); + } + + @Test + void passingPnfObject_taskSucceeds() throws AaiTaskException { + + String pnfName = "pnf-1"; + String attachmentPoint = "olt1-1-1"; + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject firstRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS/service-instances" + + "/service-instance/84003b26-6b76-4c75-b805-7b14ab4ffaef") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("84003b26-6b76-4c75-b805-7b14ab4ffaef").build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject.RelationshipEntryAaiObject secondRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("logical-link") + .relatedLink("/network/logical-links/logical-link/" + attachmentPoint) + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("logical-link.link-name") + .relationshipValue(attachmentPoint).build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Arrays.asList(firstRelationshipEntry, secondRelationshipEntry)) + .build(); + + // Finally construct PNF object data + PnfAaiObject pnfAaiObject = ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + + when(reactiveClient.getPnfObjectDataFor(any(String.class))).thenReturn(Mono.just(pnfAaiObject)); + Mono<PnfAaiObject> pnf = task.executePnfRetrieval("Normal PNF retrieval task", "some-url"); + + verify(reactiveClient).getPnfObjectDataFor("some-url"); + assertNotNull(pnf.block(Duration.ofSeconds(5))); + + StepVerifier.create(pnf) + .expectSubscription() + .consumeNextWith(aPnf -> { + Assertions.assertEquals(pnfName, aPnf.getPnfName(), "PNF Name in response does not match"); + String extractedAttachmentPoint = aPnf.getRelationshipListAaiObject().getRelationshipEntries() + .stream() + .filter(e -> e.getRelatedTo().equals("logical-link")) + .flatMap(e -> e.getRelationshipData().stream()) + .filter(d -> d.getRelationshipKey().equals("logical-link.link-name")) + .map(RelationshipListAaiObject.RelationshipDataEntryAaiObject::getRelationshipValue) + .findFirst().orElseThrow(AaiClientTaskTestException::new); + Assertions.assertEquals(attachmentPoint, extractedAttachmentPoint, + "Attachment point in response does not match"); + }) + .verifyComplete(); + } + + @Test + void passingServiceInstanceObject_taskSucceeds() throws AaiTaskException { + + String serviceInstanceId = "84003b26-6b76-4c75-b805-7b14ab4ffaef"; + String orchestrationStatus = "active"; + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/bb374844-44e4-488f-8381-fb5a0e3e6989") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("bb374844-44e4-488f-8381-fb5a0e3e6989").build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + MetadataListAaiObject.MetadataEntryAaiObject metadataEntry = + ImmutableMetadataEntryAaiObject.builder() + .metaname("cvlan") + .metavalue("1005") + .build(); + + MetadataListAaiObject metadataListAaiObject = ImmutableMetadataListAaiObject.builder() + .metadataEntries(Collections.singletonList(metadataEntry)) + .build(); + + // Finally construct Service Instance object data + ServiceInstanceAaiObject serviceInstanceAaiObject = ImmutableServiceInstanceAaiObject.builder() + .serviceInstanceId(serviceInstanceId) + .orchestrationStatus(orchestrationStatus) + .relationshipListAaiObject(relationshipListAaiObject) + .metadataListAaiObject(metadataListAaiObject) + .build(); + + when(reactiveClient.getServiceInstanceObjectDataFor(any(String.class))) + .thenReturn(Mono.just(serviceInstanceAaiObject)); + Mono<ServiceInstanceAaiObject> serviceInstance = + task.executeServiceInstanceRetrieval("Normal Service Instance retrieval task", + "some-url"); + + verify(reactiveClient).getServiceInstanceObjectDataFor("some-url"); + assertNotNull(serviceInstance.block(Duration.ofSeconds(5))); + + StepVerifier.create(serviceInstance) + .expectSubscription() + .consumeNextWith(instance -> { + Assertions.assertEquals(serviceInstanceId, instance.getServiceInstanceId(), + "Service Instance ID in response does not match"); + + MetadataListAaiObject extractedMetadataListObject = + instance.getMetadataListAaiObject().orElseThrow(AaiClientTaskTestException::new); + + MetadataListAaiObject.MetadataEntryAaiObject extractedMetadataEntry = + extractedMetadataListObject.getMetadataEntries() + .stream() + .filter(m -> m.getMetaname().equals("cvlan")) + .findFirst().orElseThrow(AaiClientTaskTestException::new); + + Assertions.assertEquals("1005", extractedMetadataEntry.getMetavalue(), + "CVLAN in response does not match"); + }) + .verifyComplete(); + } + + private static class AaiClientTaskTestException extends RuntimeException {} +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImplTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImplTest.java new file mode 100644 index 00000000..538ff1de --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapCpeAuthenticationConsumerTaskImplTest.java @@ -0,0 +1,149 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.net.ssl.SSLException; + +import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableCpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.utilities.CpeAuthenticationDmaapConsumerJsonParser; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.ConsumerReactiveHttpClientFactory; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class DmaapCpeAuthenticationConsumerTaskImplTest { + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"%s\"}," + + "\"stateChangeFields\": {" + + " \"oldState\": \"%s\"," + + " \"newState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + private static DmaapCpeAuthenticationConsumerTask dmaapConsumerTask; + private static CpeAuthenticationConsumerDmaapModel cpeAuthenticationConsumerDmaapModel; + private static DMaaPConsumerReactiveHttpClient dMaaPConsumerReactiveHttpClient; + private static String eventsArray; + + @BeforeAll + static void setUp() throws SSLException { + + final String sourceName = "PNF-CorrelationId"; + final String oldAuthenticationState = "outOfService"; + final String newAuthenticationState = "inService"; + final String stateInterface = "stateInterface"; + final String rgwMacAddress = "00:0a:95:8d:78:16"; + final String swVersion = "1.2"; + + // Mock Re-registration configuration + DmaapConsumerConfiguration dmaapConsumerConfiguration = testVersionOfDmaapConsumerConfiguration(); + ApplicationConfiguration configuration = mock(ApplicationConfiguration.class); + when(configuration.getDmaapCpeAuthenticationConsumerConfiguration()).thenReturn(dmaapConsumerConfiguration); + + // Mock reactive DMaaP client + ConsumerReactiveHttpClientFactory httpClientFactory = mock(ConsumerReactiveHttpClientFactory.class); + dMaaPConsumerReactiveHttpClient = mock(DMaaPConsumerReactiveHttpClient.class); + doReturn(dMaaPConsumerReactiveHttpClient).when(httpClientFactory).create(dmaapConsumerConfiguration); + + dmaapConsumerTask = new DmaapCpeAuthenticationConsumerTaskImpl(configuration, + new CpeAuthenticationDmaapConsumerJsonParser(), httpClientFactory); + + cpeAuthenticationConsumerDmaapModel = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(sourceName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE, sourceName, oldAuthenticationState, + newAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + eventsArray = "[" + event + "]"; + } + + @AfterEach + void resetMock() { + reset(dMaaPConsumerReactiveHttpClient); + } + + @Test + void passingEmptyMessage_NothingHappens() throws Exception { + when(dMaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse()).thenReturn(Mono.just("")); + + StepVerifier.create(dmaapConsumerTask.execute("Sample input")) + .expectSubscription() + .expectError(EmptyDmaapResponseException.class); + verify(dMaaPConsumerReactiveHttpClient).getDMaaPConsumerResponse(); + } + + @Test + void passingNormalMessage_ResponseSucceeds() throws Exception { + when(dMaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse()).thenReturn(Mono.just(eventsArray)); + + StepVerifier.create(dmaapConsumerTask.execute("Sample input")) + .expectSubscription() + .consumeNextWith(e -> Assert.assertEquals(e, cpeAuthenticationConsumerDmaapModel)); + verify(dMaaPConsumerReactiveHttpClient).getDMaaPConsumerResponse(); + } + + private static DmaapConsumerConfiguration testVersionOfDmaapConsumerConfiguration() { + return new ImmutableDmaapConsumerConfiguration.Builder() + .consumerGroup("consumer-group") + .consumerId("consumer-id") + .dmaapContentType("application/json") + .dmaapHostName("message-router.onap.svc.cluster.local") + .dmaapPortNumber(3904) + .dmaapProtocol("http") + .dmaapUserName("admin") + .dmaapUserPassword("admin") + .trustStorePath("change it") + .trustStorePasswordPath("change_it") + .keyStorePath("change it") + .keyStorePasswordPath("change_it") + .enableDmaapCertAuth(false) + .dmaapTopicName("/events/unauthenticated.CPE_AUTHENTICATION") + .timeoutMs(-1) + .messageLimit(-1) + .build(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImplTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImplTest.java new file mode 100644 index 00000000..199a43ec --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapPublisherTaskImplTest.java @@ -0,0 +1,173 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.DmaapException; +import org.onap.bbs.event.processor.model.ControlLoopPublisherDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableControlLoopPublisherDmaapModel; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapPublisherConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapPublisherConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.DMaaPPublisherReactiveHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.producer.PublisherReactiveHttpClientFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class DmaapPublisherTaskImplTest { + + private static ControlLoopPublisherDmaapModel controlLoopPublisherDmaapModel; + private static DmaapPublisherTaskImpl task; + private static DMaaPPublisherReactiveHttpClient reactiveHttpClient; + private static ApplicationConfiguration configuration; + private static DmaapPublisherConfiguration dmaapPublisherConfiguration; + + @BeforeAll + static void setUp() { + dmaapPublisherConfiguration = testVersionOfDmaapPublisherConfiguration(); + configuration = mock(ApplicationConfiguration.class); + + final String closedLoopEventClient = "DCAE.BBS_mSInstance"; + final String policyVersion = "1.0.0.5"; + final String policyName = "CPE_Authentication"; + final String policyScope = + "service=HSIAService,type=SampleType," + + "closedLoopControlName=CL-CPE_A-d925ed73-8231-4d02-9545-db4e101f88f8"; + final String targetType = "VM"; + final long closedLoopAlarmStart = 1484677482204798L; + final String closedLoopEventStatus = "ONSET"; + final String closedLoopControlName = "ControlLoop-CPE_A-2179b738-fd36-4843-a71a-a8c24c70c88b"; + final String version = "1.0.2"; + final String target = "vserver.vserver-name"; + final String requestId = "97964e10-686e-4790-8c45-bdfa61df770f"; + final String from = "DCAE"; + + final Map<String, String> aaiEnrichmentData = new LinkedHashMap<>(); + aaiEnrichmentData.put("service-information.service-instance-id", "service-instance-id-example"); + aaiEnrichmentData.put("cvlan-id", "example cvlan-id"); + aaiEnrichmentData.put("svlan-id", "example svlan-id"); + + controlLoopPublisherDmaapModel = ImmutableControlLoopPublisherDmaapModel.builder() + .closedLoopEventClient(closedLoopEventClient) + .policyVersion(policyVersion) + .policyName(policyName) + .policyScope(policyScope) + .targetType(targetType) + .aaiEnrichmentData(aaiEnrichmentData) + .closedLoopAlarmStart(closedLoopAlarmStart) + .closedLoopEventStatus(closedLoopEventStatus) + .closedLoopControlName(closedLoopControlName) + .version(version) + .target(target) + .requestId(requestId) + .originator(from) + .build(); + + when(configuration.getDmaapPublisherConfiguration()).thenReturn(dmaapPublisherConfiguration); + } + + @Test + void passingNullMessage_ExceptionIsRaised() { + + task = new DmaapPublisherTaskImpl(configuration); + + Executable executableFunction = () -> task.execute(null); + + Assertions.assertThrows(DmaapException.class, executableFunction, "Input message is invalid"); + } + + @Test + void passingNormalMessage_ReactiveClientProcessesIt() throws DmaapException { + ResponseEntity<String> responseEntity = setupMocks(HttpStatus.OK.value()); + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.OK); + StepVerifier.create(task.execute(controlLoopPublisherDmaapModel)).expectSubscription() + .expectNext(responseEntity).verifyComplete(); + + verify(reactiveHttpClient, times(1)) + .getDMaaPProducerResponse(controlLoopPublisherDmaapModel); + verifyNoMoreInteractions(reactiveHttpClient); + } + + @Test + void passingNormalMessage_IncorrectResponseIsHandled() throws DmaapException { + ResponseEntity<String> responseEntity = setupMocks(HttpStatus.UNAUTHORIZED.value()); + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.UNAUTHORIZED); + StepVerifier.create(task.execute(controlLoopPublisherDmaapModel)).expectSubscription() + .expectNext(responseEntity).verifyComplete(); + + verify(reactiveHttpClient, times(1)) + .getDMaaPProducerResponse(controlLoopPublisherDmaapModel); + verifyNoMoreInteractions(reactiveHttpClient); + } + + // We can safely suppress unchecked assignment warning here since it is a mock class + @SuppressWarnings("unchecked") + private ResponseEntity<String> setupMocks(Integer httpResponseCode) { + + ResponseEntity<String> responseEntity = mock(ResponseEntity.class); + when(responseEntity.getStatusCode()).thenReturn(HttpStatus.valueOf(httpResponseCode)); + + reactiveHttpClient = mock(DMaaPPublisherReactiveHttpClient.class); + when(reactiveHttpClient.getDMaaPProducerResponse(any())) + .thenReturn(Mono.just(responseEntity)); + + PublisherReactiveHttpClientFactory httpClientFactory = mock(PublisherReactiveHttpClientFactory.class); + doReturn(reactiveHttpClient).when(httpClientFactory).create(dmaapPublisherConfiguration); + + task = new DmaapPublisherTaskImpl(configuration, httpClientFactory); + + return responseEntity; + } + + private static DmaapPublisherConfiguration testVersionOfDmaapPublisherConfiguration() { + return new ImmutableDmaapPublisherConfiguration.Builder() + .dmaapContentType("application/json") + .dmaapHostName("message-router.onap.svc.cluster.local") + .dmaapPortNumber(3904) + .dmaapProtocol("http") + .dmaapUserName("admin") + .dmaapUserPassword("admin") + .trustStorePath("/opt/app/bbs/local/org.onap.bbs.trust.jks") + .trustStorePasswordPath("change_it") + .keyStorePath("/opt/app/bbs/local/org.onap.bbs.p12") + .keyStorePasswordPath("change_it") + .enableDmaapCertAuth(false) + .dmaapTopicName("/events/unauthenticated.DCAE_CL_OUTPUT") + .build(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImplTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImplTest.java new file mode 100644 index 00000000..c9a461d8 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/tasks/DmaapReRegistrationConsumerTaskImplTest.java @@ -0,0 +1,147 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.tasks; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.net.ssl.SSLException; + +import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.exceptions.EmptyDmaapResponseException; +import org.onap.bbs.event.processor.model.ImmutableReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.utilities.ReRegistrationDmaapConsumerJsonParser; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapConsumerConfiguration; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.ConsumerReactiveHttpClientFactory; +import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.service.consumer.DMaaPConsumerReactiveHttpClient; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class DmaapReRegistrationConsumerTaskImplTest { + + private static final String RE_REGISTRATION_EVENT_TEMPLATE = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"%s\"}," + + "\"additionalFields\": {" + + " \"attachment-point\": \"%s\"," + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}}"; + + private static DmaapReRegistrationConsumerTaskImpl dmaapConsumerTask; + private static ReRegistrationConsumerDmaapModel reRegistrationConsumerDmaapModel; + private static DMaaPConsumerReactiveHttpClient dMaaPConsumerReactiveHttpClient; + private static String message; + + @BeforeAll + static void setUp() throws SSLException { + + final String sourceName = "PNF-CorrelationId"; + final String attachmentPoint = "olt2/2/2"; + final String remoteId = "remoteId"; + final String cvlan = "1005"; + final String svlan = "100"; + + // Mock Re-registration configuration + DmaapConsumerConfiguration dmaapConsumerConfiguration = testVersionOfDmaapConsumerConfiguration(); + ApplicationConfiguration configuration = mock(ApplicationConfiguration.class); + when(configuration.getDmaapReRegistrationConsumerConfiguration()).thenReturn(dmaapConsumerConfiguration); + + // Mock reactive DMaaP client + ConsumerReactiveHttpClientFactory httpClientFactory = mock(ConsumerReactiveHttpClientFactory.class); + dMaaPConsumerReactiveHttpClient = mock(DMaaPConsumerReactiveHttpClient.class); + doReturn(dMaaPConsumerReactiveHttpClient).when(httpClientFactory).create(dmaapConsumerConfiguration); + + dmaapConsumerTask = new DmaapReRegistrationConsumerTaskImpl(configuration, + new ReRegistrationDmaapConsumerJsonParser(), httpClientFactory); + + reRegistrationConsumerDmaapModel = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(sourceName) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + message = String.format("[" + RE_REGISTRATION_EVENT_TEMPLATE + "]", + sourceName, + attachmentPoint, + remoteId, + cvlan, + svlan); + } + + @AfterEach + void resetMock() { + reset(dMaaPConsumerReactiveHttpClient); + } + + @Test + void passingEmptyMessage_NothingHappens() throws Exception { + when(dMaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse()).thenReturn(Mono.just("")); + + StepVerifier.create(dmaapConsumerTask.execute("Sample input")) + .expectSubscription() + .expectError(EmptyDmaapResponseException.class); + verify(dMaaPConsumerReactiveHttpClient).getDMaaPConsumerResponse(); + } + + @Test + void passingNormalMessage_ResponseSucceeds() throws Exception { + when(dMaaPConsumerReactiveHttpClient.getDMaaPConsumerResponse()).thenReturn(Mono.just(message)); + + StepVerifier.create(dmaapConsumerTask.execute("Sample input")) + .expectSubscription() + .consumeNextWith(e -> Assert.assertEquals(e, reRegistrationConsumerDmaapModel)); + verify(dMaaPConsumerReactiveHttpClient).getDMaaPConsumerResponse(); + } + + private static DmaapConsumerConfiguration testVersionOfDmaapConsumerConfiguration() { + return new ImmutableDmaapConsumerConfiguration.Builder() + .consumerGroup("OpenDCAE-c12") + .consumerId("c12") + .dmaapContentType("application/json") + .dmaapHostName("message-router.onap.svc.cluster.local") + .dmaapPortNumber(3904) + .dmaapProtocol("http") + .dmaapUserName("admin") + .dmaapUserPassword("admin") + .trustStorePath("/opt/app/bbs/local/org.onap.bbs.trust.jks") + .trustStorePasswordPath("change_it") + .keyStorePath("/opt/app/bbs/local/org.onap.bbs.p12") + .keyStorePasswordPath("change_it") + .enableDmaapCertAuth(false) + .dmaapTopicName("/events/unauthenticated.PNF_REREGISTRATION") + .timeoutMs(-1) + .messageLimit(-1) + .build(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/AaiReactiveClientTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/AaiReactiveClientTest.java new file mode 100644 index 00000000..8e3c46ba --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/AaiReactiveClientTest.java @@ -0,0 +1,257 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.givenThat; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.mockito.Mockito.when; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapterFactory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.ServiceLoader; + +import javax.net.ssl.SSLException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.config.AaiClientConfiguration; +import org.onap.bbs.event.processor.config.ApplicationConfiguration; +import org.onap.bbs.event.processor.model.ImmutableMetadataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableMetadataListAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePnfAaiObject; +import org.onap.bbs.event.processor.model.ImmutablePropertyAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipDataEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipEntryAaiObject; +import org.onap.bbs.event.processor.model.ImmutableRelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ImmutableServiceInstanceAaiObject; +import org.onap.bbs.event.processor.model.MetadataListAaiObject; +import org.onap.bbs.event.processor.model.PnfAaiObject; +import org.onap.bbs.event.processor.model.RelationshipListAaiObject; +import org.onap.bbs.event.processor.model.ServiceInstanceAaiObject; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import reactor.test.StepVerifier; + +@ExtendWith(SpringExtension.class) +class AaiReactiveClientTest { + + private static final int PORT = 9999; + + private static AaiReactiveClient reactiveClient; + private static Gson gson; + private static WireMockServer wireMockServer; + + @BeforeAll + static void init() throws SSLException { + GsonBuilder gsonBuilder = new GsonBuilder(); + ServiceLoader.load(TypeAdapterFactory.class).forEach(gsonBuilder::registerTypeAdapterFactory); + gson = gsonBuilder.create(); + + ApplicationConfiguration configuration = Mockito.mock(ApplicationConfiguration.class); + AaiClientConfiguration aaiClientConfiguration = Mockito.mock(AaiClientConfiguration.class); + when(configuration.getAaiClientConfiguration()).thenReturn(aaiClientConfiguration); + when(aaiClientConfiguration.aaiUserName()).thenReturn("AAI"); + when(aaiClientConfiguration.aaiUserPassword()).thenReturn("AAI"); + when(aaiClientConfiguration.aaiHeaders()).thenReturn(new HashMap<>()); + when(aaiClientConfiguration.enableAaiCertAuth()).thenReturn(false); + + reactiveClient = new AaiReactiveClient(configuration, gson); + + wireMockServer = new WireMockServer(PORT); + WireMock.configureFor("localhost", PORT); + } + + @BeforeEach + void wireMockSetup() { + wireMockServer.start(); + } + + @AfterEach + void wireMockTearDown() { + wireMockServer.start(); + } + + @Test + void sendingReactiveRequestForPnf_Succeeds() { + + String pnfName = "pnf-1"; + String attachmentPoint = "olt1-1-1"; + + String pnfUrl = String.format("/aai/v14/network/pnfs/pnf/%s?depth=1", pnfName); + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject firstRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS/service-instances" + + "/service-instance/84003b26-6b76-4c75-b805-7b14ab4ffaef") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Arrays.asList( + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("customer.global-customer-id") + .relationshipValue("Demonstration").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-subscription.service-type") + .relationshipValue("BBS").build(), + ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("84003b26-6b76-4c75-b805-7b14ab4ffaef").build()) + ) + .relatedToProperties(Collections.singletonList( + ImmutablePropertyAaiObject.builder() + .propertyKey("service-instance.service-instance-name") + .propertyValue("bbs-instance").build()) + ) + .build(); + + RelationshipListAaiObject.RelationshipEntryAaiObject secondRelationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("logical-link") + .relatedLink("/network/logical-links/logical-link/" + attachmentPoint) + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("logical-link.link-name") + .relationshipValue(attachmentPoint).build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Arrays.asList(firstRelationshipEntry, secondRelationshipEntry)) + .build(); + + // Finally construct PNF object data + PnfAaiObject pnfAaiObject = ImmutablePnfAaiObject.builder() + .pnfName(pnfName) + .isInMaintenance(true) + .relationshipListAaiObject(relationshipListAaiObject) + .build(); + + givenThat(get(urlEqualTo(pnfUrl)) + .willReturn(aResponse().withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(gson.toJson(pnfAaiObject, ImmutablePnfAaiObject.class)))); + + StepVerifier.create(reactiveClient.getPnfObjectDataFor("http://127.0.0.1:" + PORT + pnfUrl)) + .expectSubscription() + .consumeNextWith(pnf -> { + Assertions.assertEquals(pnfName, pnf.getPnfName(), "PNF Name in response does not match"); + String extractedAttachmentPoint = pnf.getRelationshipListAaiObject().getRelationshipEntries() + .stream() + .filter(e -> e.getRelatedTo().equals("logical-link")) + .flatMap(e -> e.getRelationshipData().stream()) + .filter(d -> d.getRelationshipKey().equals("logical-link.link-name")) + .map(RelationshipListAaiObject.RelationshipDataEntryAaiObject::getRelationshipValue) + .findFirst().orElseThrow(AaiReactiveClientTestException::new); + Assertions.assertEquals(attachmentPoint, extractedAttachmentPoint, + "Attachment point in response does not match"); + }) + .verifyComplete(); + } + + @Test + void sendingReactiveRequestForServiceInstance_Succeeds() { + + String serviceInstanceId = "84003b26-6b76-4c75-b805-7b14ab4ffaef"; + String orchestrationStatus = "active"; + + String serviceInstanceUrl = + String.format("/aai/v14/nodes/service-instances/service-instance/%s?format=resource_and_url", + serviceInstanceId); + + // Build Relationship Data + RelationshipListAaiObject.RelationshipEntryAaiObject relationshipEntry = + ImmutableRelationshipEntryAaiObject.builder() + .relatedTo("service-instance") + .relatedLink("/aai/v14/business/customers/customer/Demonstration/service-subscriptions" + + "/service-subscription/BBS-CFS/service-instances" + + "/service-instance/bb374844-44e4-488f-8381-fb5a0e3e6989") + .relationshipLabel("org.onap.relationships.inventory.ComposedOf") + .relationshipData(Collections.singletonList(ImmutableRelationshipDataEntryAaiObject.builder() + .relationshipKey("service-instance.service-instance-id") + .relationshipValue("bb374844-44e4-488f-8381-fb5a0e3e6989").build())) + .build(); + + RelationshipListAaiObject relationshipListAaiObject = ImmutableRelationshipListAaiObject.builder() + .relationshipEntries(Collections.singletonList(relationshipEntry)) + .build(); + + MetadataListAaiObject.MetadataEntryAaiObject metadataEntry = + ImmutableMetadataEntryAaiObject.builder() + .metaname("cvlan") + .metavalue("1005") + .build(); + + MetadataListAaiObject metadataListAaiObject = ImmutableMetadataListAaiObject.builder() + .metadataEntries(Collections.singletonList(metadataEntry)) + .build(); + + // Finally construct Service Instance object data + ServiceInstanceAaiObject serviceInstanceAaiObject = ImmutableServiceInstanceAaiObject.builder() + .serviceInstanceId(serviceInstanceId) + .orchestrationStatus(orchestrationStatus) + .relationshipListAaiObject(relationshipListAaiObject) + .metadataListAaiObject(metadataListAaiObject) + .build(); + + givenThat(get(urlEqualTo(serviceInstanceUrl)) + .willReturn(aResponse().withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(gson.toJson(serviceInstanceAaiObject, ImmutableServiceInstanceAaiObject.class)))); + + StepVerifier.create( + reactiveClient.getServiceInstanceObjectDataFor("http://127.0.0.1:" + PORT + serviceInstanceUrl) + ) + .expectSubscription() + .consumeNextWith(serviceInstance -> { + Assertions.assertEquals(serviceInstanceId, serviceInstance.getServiceInstanceId(), + "Service Instance ID in response does not match"); + + MetadataListAaiObject extractedMetadataListObject = + serviceInstance.getMetadataListAaiObject().orElseThrow(AaiReactiveClientTestException::new); + + MetadataListAaiObject.MetadataEntryAaiObject extractedMetadataEntry = + extractedMetadataListObject.getMetadataEntries() + .stream() + .filter(m -> m.getMetaname().equals("cvlan")) + .findFirst().orElseThrow(AaiReactiveClientTestException::new); + + Assertions.assertEquals("1005", extractedMetadataEntry.getMetavalue(), + "CVLAN in response does not match"); + }) + .verifyComplete(); + } + + private static class AaiReactiveClientTestException extends RuntimeException {} + +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParserTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParserTest.java new file mode 100644 index 00000000..4ca61f5e --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/CpeAuthenticationDmaapConsumerJsonParserTest.java @@ -0,0 +1,311 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static org.mockito.Mockito.spy; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.model.CpeAuthenticationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ImmutableCpeAuthenticationConsumerDmaapModel; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class CpeAuthenticationDmaapConsumerJsonParserTest { + + private static JsonParser jsonParser; + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"%s\"}," + + "\"stateChangeFields\": {" + + " \"oldState\": \"%s\"," + + " \"newState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_AUTHENTICATION_STATE = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"%s\"}," + + "\"stateChangeFields\": {" + + " \"oldState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_SOURCE_NAME = "{\"event\": {" + + "\"commonEventHeader\": { }," + + "\"stateChangeFields\": {" + + " \"oldState\": \"%s\"," + + " \"newState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_SOURCE_NAME_VALUE = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"\"}," + + "\"stateChangeFields\": {" + + " \"oldState\": \"%s\"," + + " \"newState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + private static final String CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_STATE_CHANGE_FIELDS = "{\"event\": {" + + "\"commonEventHeader\": { \"sourceName\":\"\"}," + + "\"somethingElse\": {" + + " \"oldState\": \"%s\"," + + " \"newState\": \"%s\"," + + " \"stateInterface\": \"%s\"," + + " \"additionalFields\": {" + + " \"macAddress\": \"%s\"," + + " \"swVersion\": \"%s\"" + + "}}}}"; + + @BeforeAll + static void init() { + jsonParser = new JsonParser(); + } + + @Test + void passingNonJson_EmptyFluxIsReturned() { + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + new CpeAuthenticationDmaapConsumerJsonParser(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just("not JSON"))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingNoEvents_EmptyFluxIsReturned() { + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + new CpeAuthenticationDmaapConsumerJsonParser(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just("[]"))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingOneCorrectEvent_validationSucceeds() { + + String sourceName = "PNF-CorrelationId"; + String oldAuthenticationState = "outOfService"; + String newAuthenticationState = "inService"; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE, sourceName, oldAuthenticationState, + newAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + CpeAuthenticationConsumerDmaapModel expectedEventObject = ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(sourceName) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress) + .swVersion(swVersion) + .build(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .expectNext(expectedEventObject); + } + + @Test + void passingTwoCorrectEvents_validationSucceeds() { + + String sourceName1 = "PNF-CorrelationId"; + String sourceName2 = "PNF-CorrelationId"; + String oldAuthenticationState = "outOfService"; + String newAuthenticationState = "inService"; + String stateInterface = "stateInterface"; + String rgwMacAddress1 = "00:0a:95:8d:78:16"; + String rgwMacAddress2 = "00:0a:95:8d:78:17"; + String swVersion = "1.2"; + + String firstEvent = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE, sourceName1, oldAuthenticationState, + newAuthenticationState, stateInterface, rgwMacAddress1, swVersion); + String secondEvent = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE, sourceName2, oldAuthenticationState, + newAuthenticationState, stateInterface, rgwMacAddress2, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement1 = jsonParser.parse(firstEvent); + Mockito.doReturn(Optional.of(jsonElement1.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement1); + JsonElement jsonElement2 = jsonParser.parse(secondEvent); + Mockito.doReturn(Optional.of(jsonElement2.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement2); + + String eventsArray = "[" + firstEvent + secondEvent + "]"; + + CpeAuthenticationConsumerDmaapModel expectedFirstEventObject = + ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(sourceName1) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress1) + .swVersion(swVersion) + .build(); + CpeAuthenticationConsumerDmaapModel expectedSecondEventObject = + ImmutableCpeAuthenticationConsumerDmaapModel.builder() + .correlationId(sourceName2) + .oldAuthenticationState(oldAuthenticationState) + .newAuthenticationState(newAuthenticationState) + .stateInterface(stateInterface) + .rgwMacAddress(rgwMacAddress2) + .swVersion(swVersion) + .build(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .expectNext(expectedFirstEventObject) + .expectNext(expectedSecondEventObject); + } + + @Test + void passingJsonWithMissingAuthenticationState_validationFails() { + + String sourceName = "PNF-CorrelationId"; + String oldAuthenticationState = "outOfService"; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_AUTHENTICATION_STATE, sourceName, + oldAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingSourceName_validationFails() { + + String oldAuthenticationState = "outOfService"; + String newAuthenticationState = "inService"; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_SOURCE_NAME, + oldAuthenticationState, newAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingSourceNameValue_validationFails() { + + String oldAuthenticationState = "outOfService"; + String newAuthenticationState = "inService"; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_SOURCE_NAME_VALUE, + oldAuthenticationState, newAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingStateChangeFieldsHeader_validationFails() { + + String oldAuthenticationState = "outOfService"; + String newAuthenticationState = "inService"; + String stateInterface = "stateInterface"; + String rgwMacAddress = "00:0a:95:8d:78:16"; + String swVersion = "1.2"; + + String event = String.format(CPE_AUTHENTICATION_EVENT_TEMPLATE_WITH_MISSING_STATE_CHANGE_FIELDS, + oldAuthenticationState, newAuthenticationState, stateInterface, rgwMacAddress, swVersion); + + CpeAuthenticationDmaapConsumerJsonParser consumerJsonParser = + spy(new CpeAuthenticationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParserTest.java b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParserTest.java new file mode 100644 index 00000000..ca448dd0 --- /dev/null +++ b/components/bbs-event-processor/src/test/java/org/onap/bbs/event/processor/utilities/ReRegistrationDmaapConsumerJsonParserTest.java @@ -0,0 +1,297 @@ +/* + * ============LICENSE_START======================================================= + * BBS-RELOCATION-CPE-AUTHENTICATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. 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.bbs.event.processor.utilities; + +import static org.mockito.Mockito.spy; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.bbs.event.processor.model.ImmutableReRegistrationConsumerDmaapModel; +import org.onap.bbs.event.processor.model.ReRegistrationConsumerDmaapModel; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class ReRegistrationDmaapConsumerJsonParserTest { + + private static JsonParser jsonParser; + + private static final String RE_REGISTRATION_EVENT_TEMPLATE = "{" + + "\"correlationId\":\"%s\"," + + "\"additionalFields\": {" + + " \"attachment-point\": \"%s\"," + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}"; + + private static final String RE_REGISTRATION_EVENT_TEMPLATE_MISSING_ATTACHMENT_POINT = "{" + + "\"correlationId\":\"%s\"," + + "\"additionalFields\": {" + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}"; + + private static final String RE_REGISTRATION_EVENT_TEMPLATE_MISSING_CORRELATION_ID = "{" + + "\"additionalFields\": {" + + " \"attachment-point\": \"%s\"," + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}"; + + private static final String RE_REGISTRATION_EVENT_TEMPLATE_MISSING_CORRELATION_ID_VALUE = "{" + + "\"correlationId\":\"\"," + + "\"additionalFields\": {" + + " \"attachment-point\": \"%s\"," + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}"; + + private static final String RE_REGISTRATION_EVENT_TEMPLATE_MISSING_ADDITIONAL_FIELDS = "{" + + "\"correlationId\":\"%s\"," + + "\"somethingElse\": {" + + " \"attachment-point\": \"%s\"," + + " \"remote-id\": \"%s\"," + + " \"cvlan\": \"%s\"," + + " \"svlan\": \"%s\"" + + "}}"; + + @BeforeAll + static void init() { + jsonParser = new JsonParser(); + } + + @Test + void passingNonJson_EmptyFluxIsReturned() { + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = new ReRegistrationDmaapConsumerJsonParser(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just("not JSON"))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingNoEvents_EmptyFluxIsReturned() { + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = new ReRegistrationDmaapConsumerJsonParser(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just("[]"))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingOneCorrectEvent_validationSucceeds() { + + String correlationId = "PNF-CorrelationId"; + String attachmentPoint = "olt1/1/1"; + String remoteId = "remoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String event = String.format(RE_REGISTRATION_EVENT_TEMPLATE, correlationId, attachmentPoint, + remoteId, cvlan, svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + ReRegistrationConsumerDmaapModel expectedEventObject = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(correlationId) + .attachmentPoint(attachmentPoint) + .remoteId(remoteId) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .expectNext(expectedEventObject); + } + + @Test + void passingTwoCorrectEvents_validationSucceeds() { + + String correlationId1 = "PNF-CorrelationId1"; + String correlationId2 = "PNF-CorrelationId2"; + String attachmentPoint1 = "olt1/1/1"; + String attachmentPoint2 = "olt2/2/2"; + String remoteId1 = "remoteId1"; + String remoteId2 = "remoteId2"; + String cvlan = "1005"; + String svlan = "100"; + + String firstEvent = String.format(RE_REGISTRATION_EVENT_TEMPLATE, correlationId1, attachmentPoint1, + remoteId1, cvlan, svlan); + String secondEvent = String.format(RE_REGISTRATION_EVENT_TEMPLATE, correlationId1, attachmentPoint1, + remoteId1, cvlan, svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement1 = jsonParser.parse(firstEvent); + Mockito.doReturn(Optional.of(jsonElement1.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement1); + JsonElement jsonElement2 = jsonParser.parse(secondEvent); + Mockito.doReturn(Optional.of(jsonElement2.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement2); + + String eventsArray = "[" + firstEvent + secondEvent + "]"; + + ReRegistrationConsumerDmaapModel expectedFirstEventObject = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(correlationId1) + .attachmentPoint(attachmentPoint1) + .remoteId(remoteId1) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + ReRegistrationConsumerDmaapModel expectedSecondEventObject = ImmutableReRegistrationConsumerDmaapModel.builder() + .correlationId(correlationId2) + .attachmentPoint(attachmentPoint2) + .remoteId(remoteId2) + .cVlan(cvlan) + .sVlan(svlan) + .build(); + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .expectNext(expectedFirstEventObject) + .expectNext(expectedSecondEventObject); + } + + @Test + void passingJsonWithMissingAttachmentPoint_validationFails() { + + String correlationId = "PNF-CorrelationId"; + String remoteId = "remoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String event = String.format(RE_REGISTRATION_EVENT_TEMPLATE_MISSING_ATTACHMENT_POINT, + correlationId, + remoteId, + cvlan, + svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingCorrelationId_validationFails() { + + String attachmentPoint = "olt1/1/1"; + String remoteId = "remoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String event = String.format(RE_REGISTRATION_EVENT_TEMPLATE_MISSING_CORRELATION_ID, + attachmentPoint, + remoteId, + cvlan, + svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingCorrelationIdValue_validationFails() { + + String attachmentPoint = "olt1/1/1"; + String remoteId = "remoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String event = String.format(RE_REGISTRATION_EVENT_TEMPLATE_MISSING_CORRELATION_ID_VALUE, + attachmentPoint, + remoteId, + cvlan, + svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + + @Test + void passingJsonWithMissingAdditionalFields_validationFails() { + + String correlationId = "PNF-CorrelationId"; + String attachmentPoint = "olt1/1/1"; + String remoteId = "remoteId"; + String cvlan = "1005"; + String svlan = "100"; + + String event = String.format(RE_REGISTRATION_EVENT_TEMPLATE_MISSING_ADDITIONAL_FIELDS, + correlationId, + attachmentPoint, + remoteId, + cvlan, + svlan); + + ReRegistrationDmaapConsumerJsonParser consumerJsonParser = spy(new ReRegistrationDmaapConsumerJsonParser()); + JsonElement jsonElement = jsonParser.parse(event); + Mockito.doReturn(Optional.of(jsonElement.getAsJsonObject())) + .when(consumerJsonParser).getJsonObjectFromAnArray(jsonElement); + + String eventsArray = "[" + event + "]"; + + StepVerifier.create(consumerJsonParser.extractModelFromDmaap(Mono.just(eventsArray))) + .expectSubscription() + .verifyComplete(); + } + +}
\ No newline at end of file diff --git a/components/bbs-event-processor/src/test/resources/logback-test.xml b/components/bbs-event-processor/src/test/resources/logback-test.xml new file mode 100644 index 00000000..0b93a431 --- /dev/null +++ b/components/bbs-event-processor/src/test/resources/logback-test.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ===============================LICENSE_START====================================== + ~ Copyright © 2017 AT&T Intellectual Property. 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=========================================== + --> +<configuration> + <include resource="org/springframework/boot/logging/logback/base.xml" /> + <root level="ERROR"/> + <logger name="org.springframework" level="ERROR"/> + <logger name="org.onap" level="WARN"/> +</configuration>
\ No newline at end of file |