aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.input.json (renamed from models-examples/src/main/resources/policies/vCPE.policy.operational.input.json)0
-rw-r--r--models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.output.json (renamed from models-examples/src/main/resources/policies/vCPE.policy.operational.output.json)0
-rw-r--r--models-examples/src/main/resources/policies/vCPE.policy.operational.output.tosca.yaml2
-rw-r--r--models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.input.json (renamed from models-examples/src/main/resources/policies/vDNS.policy.operational.input.json)0
-rw-r--r--models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.output.json (renamed from models-examples/src/main/resources/policies/vDNS.policy.operational.output.json)0
-rw-r--r--models-examples/src/main/resources/policies/vFirewall.policy.operational.input.tosca.json39
-rw-r--r--models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.input.json (renamed from models-examples/src/main/resources/policies/vFirewall.policy.operational.input.json)0
-rw-r--r--models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.output.json (renamed from models-examples/src/main/resources/policies/vFirewall.policy.operational.output.json)0
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.controlloop.Operational.yaml2
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.Common.yaml37
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Apex.yaml1
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Drools.yaml13
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app.yaml3
-rw-r--r--models-examples/src/main/resources/policytypes/onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server.yaml4
-rw-r--r--models-interactions/model-actors/actor.aai/pom.xml89
-rw-r--r--models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProvider.java47
-rw-r--r--models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java127
-rw-r--r--models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java133
-rw-r--r--models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiUtil.java50
-rw-r--r--models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor1
-rw-r--r--models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java48
-rw-r--r--models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java189
-rw-r--r--models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java131
-rw-r--r--models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java36
-rw-r--r--models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java54
-rw-r--r--models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java15
-rw-r--r--models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicHttpOperationTest.java25
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java6
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairActor.java112
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperation.java316
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperator.java156
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParams.java93
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParams.java (renamed from models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParams.java)22
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java141
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java57
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java104
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPair.java122
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairManager.java37
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java4
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/MyExec.java65
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java35
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperationTest.java503
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperatorTest.java140
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParamsTest.java132
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParamsTest.java (renamed from models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParamsTest.java)17
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/ForwarderTest.java201
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java93
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImplTest.java154
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairTest.java158
-rw-r--r--models-interactions/model-actors/actorServiceProvider/src/test/resources/logback-test.xml7
-rw-r--r--models-interactions/model-actors/pom.xml1
-rw-r--r--models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyLegacyOperationalPersistenceTest.java17
-rw-r--r--models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyToscaPersistenceTest.java58
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProvider.java1
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider.java9
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicy.java5
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicyType.java5
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/simple/provider/SimpleToscaProvider.java39
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtils.java4
-rw-r--r--models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaUtils.java4
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyFilterTest.java23
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyTypeFilterTest.java6
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProviderPolicyTypeTest.java30
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/mapping/LegacyOperationalPolicyMapperTest.java4
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider4LegacyOperationalTest.java6
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/simple/serialization/MonitoringPolicyTypeSerializationTest.java10
-rw-r--r--models-tosca/src/test/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtilsTest.java14
-rw-r--r--models-tosca/src/test/resources/onap.policies.NoVersion.yaml1
68 files changed, 3753 insertions, 205 deletions
diff --git a/models-examples/src/main/resources/policies/vCPE.policy.operational.input.json b/models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.input.json
index 7d26e8e67..7d26e8e67 100644
--- a/models-examples/src/main/resources/policies/vCPE.policy.operational.input.json
+++ b/models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.input.json
diff --git a/models-examples/src/main/resources/policies/vCPE.policy.operational.output.json b/models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.output.json
index 7d26e8e67..7d26e8e67 100644
--- a/models-examples/src/main/resources/policies/vCPE.policy.operational.output.json
+++ b/models-examples/src/main/resources/policies/vCPE.policy.operational.legacy.output.json
diff --git a/models-examples/src/main/resources/policies/vCPE.policy.operational.output.tosca.yaml b/models-examples/src/main/resources/policies/vCPE.policy.operational.output.tosca.yaml
index e4a06947f..2c7981a29 100644
--- a/models-examples/src/main/resources/policies/vCPE.policy.operational.output.tosca.yaml
+++ b/models-examples/src/main/resources/policies/vCPE.policy.operational.output.tosca.yaml
@@ -23,7 +23,7 @@ topology_template:
actor: APPC
recipe: Restart
target:
- type: VM
+ targetType: VM
retry: 3
timeout: 1200
success: final_success
diff --git a/models-examples/src/main/resources/policies/vDNS.policy.operational.input.json b/models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.input.json
index 5ce44e0ba..5ce44e0ba 100644
--- a/models-examples/src/main/resources/policies/vDNS.policy.operational.input.json
+++ b/models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.input.json
diff --git a/models-examples/src/main/resources/policies/vDNS.policy.operational.output.json b/models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.output.json
index 5ce44e0ba..5ce44e0ba 100644
--- a/models-examples/src/main/resources/policies/vDNS.policy.operational.output.json
+++ b/models-examples/src/main/resources/policies/vDNS.policy.operational.legacy.output.json
diff --git a/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.tosca.json b/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.tosca.json
index 63c0d8b85..f6f15fe50 100644
--- a/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.tosca.json
+++ b/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.tosca.json
@@ -4,32 +4,32 @@
"policies": [
{
"operational.modifyconfig": {
- "type": "onap.policies.controlloop.Operational",
- "version": "1.0.0",
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
"metadata": {
"policy-id": "operational.modifyconfig"
},
"properties": {
- "controlLoop": {
- "version": "2.0.0",
- "controlLoopName": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
- "trigger_policy": "unique-policy-id-1-modifyConfig",
- "timeout": 1200,
- "abatement": false
- },
- "policies": [
+ "id": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
+ "timeout": 1200,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-modifyConfig",
+ "operations": [
{
"id": "unique-policy-id-1-modifyConfig",
- "name": "modify packet gen config",
- "description": null,
- "actor": "APPC",
- "recipe": "ModifyConfig",
- "target": {
- "resourceID": "Eace933104d443b496b8.nodes.heat.vpg",
- "type": "VNF"
+ "description": "Modify the packet generator",
+ "operation": {
+ "actor": "APPC",
+ "operation": "ModifyConfig",
+ "target": {
+ "targetType": "VNF",
+ "entityId": {
+ "resourceID": "bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38"
+ }
+ }
},
- "retry": 0,
"timeout": 300,
+ "retries": 0,
"success": "final_success",
"failure": "final_failure",
"failure_timeout": "final_failure_timeout",
@@ -37,7 +37,8 @@
"failure_exception": "final_failure_exception",
"failure_guard": "final_failure_guard"
}
- ]
+ ],
+ "controllerName": "usecases"
}
}
}
diff --git a/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.json b/models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.input.json
index bb8b907f8..bb8b907f8 100644
--- a/models-examples/src/main/resources/policies/vFirewall.policy.operational.input.json
+++ b/models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.input.json
diff --git a/models-examples/src/main/resources/policies/vFirewall.policy.operational.output.json b/models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.output.json
index bb8b907f8..bb8b907f8 100644
--- a/models-examples/src/main/resources/policies/vFirewall.policy.operational.output.json
+++ b/models-examples/src/main/resources/policies/vFirewall.policy.operational.legacy.output.json
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.Operational.yaml b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.Operational.yaml
index f21fd5afb..773e0c90b 100644
--- a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.Operational.yaml
+++ b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.Operational.yaml
@@ -3,4 +3,4 @@ policy_types:
onap.policies.controlloop.Operational:
derived_from: tosca.policies.Root
version: 1.0.0
- description: Operational Policy for Control Loops \ No newline at end of file
+ description: Operational Policy for Control Loops Supporting Legacy YAML Policy Definition. \ No newline at end of file
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.Common.yaml b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.Common.yaml
index 0dbe7e41a..4a918bef1 100644
--- a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.Common.yaml
+++ b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.Common.yaml
@@ -3,7 +3,9 @@ policy_types:
onap.policies.controlloop.operational.Common:
derived_from: tosca.policies.Root
version: 1.0.0
- description: Operational Policy for Control Loop execution
+ description: |
+ Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant
+ Policy Types. This does NOT support the legacy Policy YAML policy type.
properties:
id:
type: string
@@ -31,36 +33,7 @@ policy_types:
entry_schema:
type: onap.datatype.controlloop.Operation
- onap.policies.controlloop.operational.common.Drools:
- derived_from: onap.policies.controlloop.operational.Common
- type_version: 1.0.0
- version: 1.0.0
- description: Operational policies for Drools PDP
- properties:
- controllerName:
- type: string
- description: Drools controller properties
- required: false
-
data_types:
- # TBD if this is needed
- onap.datatype.controlloop.operation.Failure:
- derived_from: tosca.datatypes.Root
- description: Captures information of an operational failure performed for control loop
- properties:
- messages:
- type: string
- description: error message
- required: true
- category:
- type: string
- description: |
- The category the error occurred in. Whether this is a general error from the actor, or the operation
- timed out, retries were exhausted in trying to execute the operation, a guard policy prevented the
- operation from occuring, or an exception in the system caused the failure.
- constraints:
- - valid_values: [error, timeout, retries, guard, exception]
-
onap.datatype.controlloop.Target:
derived_from: tosca.datatypes.Root
description: Definition for a entity in A&AI to perform a control loop operation on
@@ -77,6 +50,8 @@ data_types:
Map of values that identify the resource. If none are provided, it is assumed that the
entity that generated the ONSET event will be the target.
required: false
+ entry_schema:
+ type: string
onap.datatype.controlloop.Actor:
derived_from: tosca.datatypes.Root
@@ -91,7 +66,7 @@ data_types:
description: The operation the actor is performing.
required: true
target:
- type: string
+ type: onap.datatype.controlloop.Target
description: The resource the operation should be performed on.
required: true
metadata:
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Apex.yaml b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Apex.yaml
index e1555e8ed..9c6c6120d 100644
--- a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Apex.yaml
+++ b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Apex.yaml
@@ -2,6 +2,7 @@ tosca_definitions_version: tosca_simple_yaml_1_0_0
policy_types:
onap.policies.controlloop.operational.common.Apex:
derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
version: 1.0.0
description: Operational policies for Apex PDP
properties:
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Drools.yaml b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Drools.yaml
new file mode 100644
index 000000000..2d793cc4b
--- /dev/null
+++ b/models-examples/src/main/resources/policytypes/onap.policies.controlloop.operational.common.Drools.yaml
@@ -0,0 +1,13 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.controlloop.operational.common.Drools:
+ derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Operational policies for Drools PDP
+ properties:
+ controllerName:
+ type: string
+ description: Drools controller properties
+ required: false
+
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app.yaml b/models-examples/src/main/resources/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app.yaml
index 2f5abdde3..5fa4308db 100644
--- a/models-examples/src/main/resources/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app.yaml
+++ b/models-examples/src/main/resources/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app.yaml
@@ -2,7 +2,8 @@ tosca_definitions_version: tosca_simple_yaml_1_0_0
policy_types:
onap.policies.Monitoring:
derived_from: tosca.policies.Root
- description: a base policy type for all policies that governs monitoring provisioning
+ version: 1.0.0
+ description: a base policy type for all policies that govern monitoring provisioning
onap.policies.monitoring.cdap.tca.hi.lo.app:
derived_from: onap.policies.Monitoring
version: 1.0.0
diff --git a/models-examples/src/main/resources/policytypes/onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server.yaml b/models-examples/src/main/resources/policytypes/onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server.yaml
index cf70e9bb2..8419b096f 100644
--- a/models-examples/src/main/resources/policytypes/onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server.yaml
+++ b/models-examples/src/main/resources/policytypes/onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server.yaml
@@ -2,10 +2,10 @@ tosca_definitions_version: tosca_simple_yaml_1_0_0
policy_types:
onap.policies.Monitoring:
derived_from: tosca.policies.Root
- description: a base policy type for all policies that govern monitoring provision
+ description: a base policy type for all policies that govern monitoring provisioning
version: 1.0.0
onap.policies.monitoring.dcaegen2.collectors.datafile.datafile-app-server:
- derived_from: policy.nodes.Root
+ derived_from: onap.policies.Monitoring
version: 1.0.0
properties:
buscontroller_feed_publishing_endpoint:
diff --git a/models-interactions/model-actors/actor.aai/pom.xml b/models-interactions/model-actors/actor.aai/pom.xml
new file mode 100644
index 000000000..deb0181be
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/pom.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+ ============LICENSE_START=======================================================
+ Copyright (C) 2018 Huawei Intellectual Property. All rights reserved.
+ Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ Copyright (C) 2020 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=========================================================
+ -->
+
+<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.policy.models.policy-models-interactions.model-actors</groupId>
+ <artifactId>model-actors</artifactId>
+ <version>2.2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>actor.aai</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId>
+ <artifactId>actorServiceProvider</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+ <artifactId>aai</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+ <artifactId>events</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+ <artifactId>aai</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>policy-endpoints</artifactId>
+ <version>${policy.common.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId>
+ <artifactId>actor.test</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.models.policy-models-interactions</groupId>
+ <artifactId>simulators</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProvider.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProvider.java
new file mode 100644
index 000000000..df427c32c
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProvider.java
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpActor;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator;
+
+/**
+ * A&AI Actor.
+ */
+public class AaiActorServiceProvider extends HttpActor {
+ public static final String NAME = AaiConstants.ACTOR_NAME;
+
+ /**
+ * Constructs the object.
+ */
+ public AaiActorServiceProvider() {
+ super(NAME);
+
+ addOperator(HttpOperator.makeOperator(NAME, AaiCustomQueryOperation.NAME,
+ AaiCustomQueryOperation::new));
+
+ // add all "get" operators
+ for (String operation : AaiGetOperation.OPERATIONS) {
+ addOperator(HttpOperator.makeOperator(NAME, operation, AaiGetOperation::new));
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java
new file mode 100644
index 000000000..5f432704c
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.aai.AaiCqResponse;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A&AI Custom Query. Stores the {@link AaiCqResponse} in the context. In addition, if the
+ * context does not contain the "tenant" data for the vserver, then it will request that,
+ * as well.
+ */
+public class AaiCustomQueryOperation extends HttpOperation<String> {
+ private static final Logger logger = LoggerFactory.getLogger(AaiCustomQueryOperation.class);
+
+ public static final String NAME = "CustomQuery";
+
+ public static final String RESOURCE_LINK = "resource-link";
+ public static final String RESULT_DATA = "result-data";
+
+ private static final String PREFIX = "/aai/v16";
+
+ /**
+ * Constructs the object.
+ *
+ * @param params operation parameters
+ * @param operator operator that created this operation
+ */
+ public AaiCustomQueryOperation(ControlLoopOperationParams params, HttpOperator operator) {
+ super(params, operator, String.class);
+ }
+
+ /**
+ * Queries the vserver, if necessary.
+ */
+ @Override
+ protected CompletableFuture<OperationOutcome> startPreprocessorAsync() {
+ String vserver = params.getTargetEntity();
+
+ ControlLoopOperationParams tenantParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME)
+ .operation(AaiGetOperation.TENANT).payload(null).retry(null).timeoutSec(null).build();
+
+ return params.getContext().obtain(AaiGetOperation.getTenantKey(vserver), tenantParams);
+ }
+
+ @Override
+ protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
+
+ Map<String, String> request = makeRequest();
+
+ Entity<Map<String, String>> entity = Entity.entity(request, MediaType.APPLICATION_JSON);
+
+ Map<String, Object> headers = makeHeaders();
+
+ headers.put("Accept", MediaType.APPLICATION_JSON);
+ String url = makeUrl();
+
+ logRestRequest(url, request);
+
+ // @formatter:off
+ return handleResponse(outcome, url,
+ callback -> operator.getClient().put(callback, makePath(), entity, headers));
+ // @formatter:on
+ }
+
+ /**
+ * Constructs the custom query using the previously retrieved tenant data.
+ */
+ private Map<String, String> makeRequest() {
+ String vserver = params.getTargetEntity();
+ StandardCoderObject tenant = params.getContext().getProperty(AaiGetOperation.getTenantKey(vserver));
+
+ String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
+ if (resourceLink == null) {
+ throw new IllegalArgumentException("cannot perform custom query - no resource-link");
+ }
+
+ resourceLink = resourceLink.replace(PREFIX, "");
+
+ return Map.of("start", resourceLink, "query", "query/closed-loop");
+ }
+
+ @Override
+ protected Map<String, Object> makeHeaders() {
+ return AaiUtil.makeHeaders(params);
+ }
+
+ /**
+ * Injects the response into the context.
+ */
+ @Override
+ protected void postProcessResponse(OperationOutcome outcome, String url, Response rawResponse, String response) {
+
+ logger.info("{}: caching response for {}", getFullName(), params.getRequestId());
+ params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, new AaiCqResponse(response));
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java
new file mode 100644
index 000000000..3bc359af2
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java
@@ -0,0 +1,133 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Superclass of A&AI operators that use "get" to perform their request and store their
+ * response within the context as a {@link StandardCoderObject}. The property name under
+ * which they are stored is ${actor}.${operation}.${targetEntity}.
+ */
+public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
+ private static final Logger logger = LoggerFactory.getLogger(AaiGetOperation.class);
+
+ public static final int DEFAULT_RETRY = 3;
+
+ // operation names
+ public static final String TENANT = "Tenant";
+
+ // property prefixes
+ private static final String TENANT_KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + TENANT + ".";
+
+ /**
+ * Operation names supported by this operator.
+ */
+ public static final Set<String> OPERATIONS = Set.of(TENANT);
+
+
+ /**
+ * Responses that are retrieved from A&AI are placed in the operation context under
+ * the name "${propertyPrefix}.${targetEntity}".
+ */
+ private final String propertyPrefix;
+
+ /**
+ * Constructs the object.
+ *
+ * @param params operation parameters
+ * @param operator operator that created this operation
+ */
+ public AaiGetOperation(ControlLoopOperationParams params, HttpOperator operator) {
+ super(params, operator, StandardCoderObject.class);
+ this.propertyPrefix = operator.getFullName() + ".";
+ }
+
+ /**
+ * Gets the "context key" for the tenant query response associated with the given
+ * target entity.
+ *
+ * @param targetEntity target entity
+ * @return the "context key" for the response associated with the given target
+ */
+ public static String getTenantKey(String targetEntity) {
+ return (TENANT_KEY_PREFIX + targetEntity);
+ }
+
+ @Override
+ protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
+
+ Map<String, Object> headers = makeHeaders();
+
+ headers.put("Accept", MediaType.APPLICATION_JSON);
+ String url = makeUrl();
+
+ logRestRequest(url, null);
+
+ // @formatter:off
+ return handleResponse(outcome, url,
+ callback -> operator.getClient().get(callback, makePath(), headers));
+ // @formatter:on
+ }
+
+ @Override
+ protected Map<String, Object> makeHeaders() {
+ return AaiUtil.makeHeaders(params);
+ }
+
+ @Override
+ public String makePath() {
+ return (operator.getPath() + "/" + params.getTargetEntity());
+ }
+
+ /**
+ * Injects the response into the context.
+ */
+ @Override
+ protected void postProcessResponse(OperationOutcome outcome, String url, Response rawResponse,
+ StandardCoderObject response) {
+ String entity = params.getTargetEntity();
+
+ logger.info("{}: caching response of {} for {}", getFullName(), entity, params.getRequestId());
+
+ params.getContext().setProperty(propertyPrefix + entity, response);
+ }
+
+ /**
+ * Provides a default retry value, if none specified.
+ */
+ @Override
+ protected int getRetry(Integer retry) {
+ return (retry == null ? DEFAULT_RETRY : retry);
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiUtil.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiUtil.java
new file mode 100644
index 000000000..14edc3aa1
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiUtil.java
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+
+/**
+ * Utilities used by A&AI classes.
+ */
+public class AaiUtil {
+
+ private AaiUtil() {
+ // do nothing
+ }
+
+ /**
+ * Makes standard request headers for A&AI requests.
+ *
+ * @param params operation parameters
+ * @return new request headers
+ */
+ public static Map<String, Object> makeHeaders(ControlLoopOperationParams params) {
+ Map<String, Object> headers = new HashMap<>();
+
+ headers.put("X-FromAppId", "POLICY");
+ headers.put("X-TransactionId", params.getRequestId().toString());
+
+ return headers;
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor
new file mode 100644
index 000000000..6a52e3f17
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor
@@ -0,0 +1 @@
+org.onap.policy.controlloop.actor.aai.AaiActorServiceProvider
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java
new file mode 100644
index 000000000..513f339fb
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+public class AaiActorServiceProviderTest {
+
+ @Test
+ public void testAaiActorServiceProvider() {
+ final AaiActorServiceProvider prov = new AaiActorServiceProvider();
+
+ // verify that it has the operators we expect
+ List<String> expected = new LinkedList<>();
+ expected.add(AaiCustomQueryOperation.NAME);
+ expected.addAll(AaiGetOperation.OPERATIONS);
+
+ Collections.sort(expected);
+
+ var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList());
+
+ assertEquals(expected.toString(), actual.toString());
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java
new file mode 100644
index 000000000..eca5062f1
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java
@@ -0,0 +1,189 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.aai.AaiCqResponse;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactory;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
+import org.onap.policy.controlloop.policy.PolicyResult;
+
+public class AaiCustomQueryOperationTest extends BasicAaiOperator<Map<String, String>> {
+ private static final StandardCoder coder = new StandardCoder();
+
+ private static final String MY_LINK = "my-link";
+
+ @Mock
+ private Actor tenantActor;
+
+ private AaiCustomQueryOperation oper;
+
+ public AaiCustomQueryOperationTest() {
+ super(AaiConstants.ACTOR_NAME, AaiCustomQueryOperation.NAME);
+ }
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ MyTenantOperator tenantOperator = new MyTenantOperator();
+
+ when(service.getActor(AaiConstants.ACTOR_NAME)).thenReturn(tenantActor);
+ when(tenantActor.getOperator(AaiGetOperation.TENANT)).thenReturn(tenantOperator);
+
+ oper = new AaiCustomQueryOperation(params, operator);
+ }
+
+ @Test
+ public void testAaiCustomQueryOperation() {
+ assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
+ assertEquals(AaiCustomQueryOperation.NAME, oper.getName());
+ }
+
+ @Test
+ public void testStartOperationAsync_testStartPreprocessorAsync_testMakeRequest_testPostProcess() throws Exception {
+ // need two responses
+ when(rawResponse.readEntity(String.class)).thenReturn(makeTenantReply()).thenReturn(makeCqReply());
+ when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+ when(client.put(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+
+ CompletableFuture<OperationOutcome> future2 = oper.start();
+
+ assertEquals(PolicyResult.SUCCESS, future2.get(5, TimeUnit.SECONDS).getResult());
+
+ // tenant response should have been cached within the context
+ assertNotNull(context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY)));
+
+ // custom query response should have been cached within the context
+ AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY);
+ assertNotNull(cqData);
+ }
+
+ /**
+ * Tests when preprocessor step is not needed.
+ */
+ @Test
+ public void testStartOperationAsync_testStartPreprocessorAsyncNotNeeded() throws Exception {
+ // pre-load the tenant data
+ final StandardCoderObject data = preloadTenantData();
+
+ // only need one response
+ when(rawResponse.readEntity(String.class)).thenReturn(makeCqReply());
+ when(client.put(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+
+ CompletableFuture<OperationOutcome> future2 = oper.start();
+
+ assertEquals(PolicyResult.SUCCESS, future2.get(5, TimeUnit.SECONDS).getResult());
+
+ // should not have replaced tenant response
+ assertSame(data, context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY)));
+
+ // custom query response should have been cached within the context
+ AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY);
+ assertNotNull(cqData);
+ }
+
+ @Test
+ public void testMakeHeaders() {
+ verifyHeaders(oper.makeHeaders());
+ }
+
+ @Test
+ public void testMakeRequestNoResourceLink() throws Exception {
+ // pre-load EMPTY tenant data
+ preloadTenantData(new StandardCoderObject());
+
+ when(rawResponse.readEntity(String.class)).thenReturn(makeCqReply());
+ when(client.put(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+
+ CompletableFuture<OperationOutcome> future2 = oper.start();
+
+ assertEquals(PolicyResult.FAILURE_EXCEPTION, future2.get(5, TimeUnit.SECONDS).getResult());
+ }
+
+ private String makeTenantReply() throws Exception {
+ Map<String, String> links = Map.of(AaiCustomQueryOperation.RESOURCE_LINK, MY_LINK);
+ List<Map<String, String>> data = Arrays.asList(links);
+
+ Map<String, Object> reply = Map.of(AaiCustomQueryOperation.RESULT_DATA, data);
+ return coder.encode(reply);
+ }
+
+ private String makeCqReply() {
+ return "{}";
+ }
+
+ private StandardCoderObject preloadTenantData() throws Exception {
+ StandardCoderObject data = coder.decode(makeTenantReply(), StandardCoderObject.class);
+ preloadTenantData(data);
+ return data;
+ }
+
+ private void preloadTenantData(StandardCoderObject data) {
+ context.setProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY), data);
+ }
+
+ protected class MyTenantOperator extends HttpOperator {
+ public MyTenantOperator() {
+ super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT);
+
+ HttpParams http = HttpParams.builder().clientName(MY_CLIENT).path(PATH).build();
+
+ configure(Util.translateToMap(AaiGetOperation.TENANT, http));
+ start();
+ }
+
+ @Override
+ public Operation buildOperation(ControlLoopOperationParams params) {
+ return new AaiGetOperation(params, this);
+ }
+
+ @Override
+ protected HttpClientFactory getClientFactory() {
+ return factory;
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java
new file mode 100644
index 000000000..ca90ce476
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.policy.PolicyResult;
+
+public class AaiGetOperatorTest extends BasicAaiOperator<Void> {
+
+ private static final String INPUT_FIELD = "input";
+ private static final String TEXT = "my-text";
+
+ private AaiGetOperation oper;
+
+ public AaiGetOperatorTest() {
+ super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT);
+ }
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ oper = new AaiGetOperation(params, operator);
+ }
+
+ @Test
+ public void testGetRetry() {
+ // use default if null retry
+ assertEquals(AaiGetOperation.DEFAULT_RETRY, oper.getRetry(null));
+
+ // otherwise, use specified value
+ assertEquals(0, oper.getRetry(0));
+ assertEquals(10, oper.getRetry(10));
+ }
+
+ @Test
+ public void testStartOperationAsync_testStartQueryAsync_testPostProcessResponse() throws Exception {
+
+ // return a map in the reply
+ Map<String, String> reply = Map.of(INPUT_FIELD, TEXT);
+ when(rawResponse.readEntity(String.class)).thenReturn(new StandardCoder().encode(reply));
+
+ when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+
+ CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+ assertFalse(future2.isDone());
+
+ assertEquals(PolicyResult.SUCCESS, future2.get(5, TimeUnit.SECONDS).getResult());
+
+ // data should have been cached within the context
+ StandardCoderObject data = context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY));
+ assertNotNull(data);
+ assertEquals(TEXT, data.getString(INPUT_FIELD));
+ }
+
+ /**
+ * Tests startOperationAsync() when there's a failure.
+ */
+ @Test
+ public void testStartOperationAsyncFailure() throws Exception {
+
+ when(rawResponse.getStatus()).thenReturn(500);
+ when(rawResponse.readEntity(String.class)).thenReturn("");
+
+ when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
+
+ CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+ assertFalse(future2.isDone());
+
+ assertEquals(PolicyResult.FAILURE, future2.get(5, TimeUnit.SECONDS).getResult());
+
+ // data should NOT have been cached within the context
+ assertNull(context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY)));
+ }
+
+ @Test
+ public void testMakeHeaders() {
+ verifyHeaders(oper.makeHeaders());
+ }
+
+ @Test
+ public void testMakePath() {
+ assertEquals(PATH + "/" + TARGET_ENTITY, oper.makePath());
+ }
+
+ @Test
+ public void testAaiGetOperator() {
+ assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
+ assertEquals(AaiGetOperation.TENANT, oper.getName());
+ }
+
+ @Test
+ public void testGetTenantKey() {
+ assertEquals("AAI.Tenant." + TARGET_ENTITY, AaiGetOperation.getTenantKey(TARGET_ENTITY));
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java
new file mode 100644
index 000000000..39ed6fe88
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.util.Map;
+import org.junit.Test;
+
+public class AaiUtilTest extends BasicAaiOperator<Void> {
+
+ @Test
+ public void testMakeHeaders() {
+ makeContext();
+
+ Map<String, Object> headers = AaiUtil.makeHeaders(params);
+
+ verifyHeaders(headers);
+ }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java
new file mode 100644
index 000000000..50b562afb
--- /dev/null
+++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+import org.onap.policy.controlloop.actor.test.BasicHttpOperation;
+
+/**
+ * Superclass for various operator tests.
+ */
+public abstract class BasicAaiOperator<Q> extends BasicHttpOperation<Q> {
+
+ /**
+ * Constructs the object using a default actor and operation name.
+ */
+ public BasicAaiOperator() {
+ super();
+ }
+
+ /**
+ * Constructs the object.
+ *
+ * @param actor actor name
+ * @param operation operation name
+ */
+ public BasicAaiOperator(String actor, String operation) {
+ super(actor, operation);
+ }
+
+ protected void verifyHeaders(Map<String, Object> headers) {
+ assertEquals("POLICY", headers.get("X-FromAppId").toString());
+ assertEquals(params.getRequestId().toString(), headers.get("X-TransactionId"));
+ }
+}
diff --git a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java
index 15e4848c6..cd9681c8e 100644
--- a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java
+++ b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java
@@ -33,6 +33,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import org.onap.policy.common.endpoints.http.client.HttpClient;
import org.onap.policy.common.endpoints.http.client.HttpClientFactory;
import org.onap.policy.controlloop.VirtualControlLoopEvent;
@@ -166,4 +167,18 @@ public class BasicHttpOperation<Q> {
protected Map<String, String> makeEnrichment() {
return new TreeMap<>();
}
+
+ /**
+ * Provides a response to an asynchronous HttpClient call.
+ *
+ * @param response response to be provided to the call
+ * @return a function that provides the response to the call
+ */
+ protected Answer<CompletableFuture<Response>> provideResponse(Response response) {
+ return args -> {
+ InvocationCallback<Response> cb = args.getArgument(0);
+ cb.completed(response);
+ return CompletableFuture.completedFuture(response);
+ };
+ }
}
diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicHttpOperationTest.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicHttpOperationTest.java
index c33483d26..1de2f923d 100644
--- a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicHttpOperationTest.java
+++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicHttpOperationTest.java
@@ -24,7 +24,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import javax.ws.rs.client.InvocationCallback;
+import javax.ws.rs.core.Response;
import org.junit.Before;
import org.junit.Test;
@@ -55,7 +59,7 @@ public class BasicHttpOperationTest {
}
@Test
- public void testSetUp() {
+ public void testSetUp() throws Exception {
assertNotNull(oper.client);
assertSame(oper.client, oper.factory.get(BasicHttpOperation.MY_CLIENT));
assertEquals(200, oper.rawResponse.getStatus());
@@ -101,4 +105,23 @@ public class BasicHttpOperationTest {
assertTrue(oper.makeEnrichment().isEmpty());
}
+ @Test
+ public void testProvideResponse() throws Exception {
+ InvocationCallback<Response> cb = new InvocationCallback<>() {
+ @Override
+ public void completed(Response response) {
+ // do nothing
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ // do nothing
+ }
+ };
+
+
+ when(oper.client.get(any(), any(), any())).thenAnswer(oper.provideResponse(oper.rawResponse));
+
+ assertSame(oper.rawResponse, oper.client.get(cb, null, null).get());
+ }
}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java
index c4bf5f484..ba75f0be6 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java
@@ -181,9 +181,9 @@ public abstract class HttpOperation<T> extends OperationPartial {
try {
response = makeCoder().decode(strResponse, responseClass);
} catch (CoderException e) {
- logger.warn("{}.{} cannot decode response with http error code {} for {}", params.getActor(),
- params.getOperation(), rawResponse.getStatus(), params.getRequestId(), e);
- return setOutcome(outcome, PolicyResult.FAILURE_EXCEPTION);
+ logger.warn("{}.{} cannot decode response for {}", params.getActor(), params.getOperation(),
+ params.getRequestId(), e);
+ throw new IllegalArgumentException("cannot decode response");
}
}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairActor.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairActor.java
new file mode 100644
index 000000000..c3e1e5c4d
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairActor.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairActorParams;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPair;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPairManager;
+
+/**
+ * Actor that uses a topic pair. The actor's parameters must be a
+ * {@link TopicPairActorParams}.
+ */
+public class TopicPairActor extends ActorImpl implements TopicPairManager {
+
+ /**
+ * Maps a topic source and target name to its topic pair.
+ */
+ private final Map<Pair<String, String>, TopicPair> params2topic = new ConcurrentHashMap<>();
+
+
+ /**
+ * Constructs the object.
+ *
+ * @param name actor's name
+ */
+ public TopicPairActor(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void doStart() {
+ params2topic.values().forEach(TopicPair::start);
+ super.doStart();
+ }
+
+ @Override
+ protected void doStop() {
+ params2topic.values().forEach(TopicPair::stop);
+ super.doStop();
+ }
+
+ @Override
+ protected void doShutdown() {
+ params2topic.values().forEach(TopicPair::shutdown);
+ params2topic.clear();
+ super.doShutdown();
+ }
+
+ @Override
+ public TopicPair getTopicPair(String source, String target) {
+ Pair<String, String> key = Pair.of(source, target);
+ return params2topic.computeIfAbsent(key, pair -> new TopicPair(source, target));
+ }
+
+ /**
+ * Translates the parameters to a {@link TopicPairActorParams} and then creates a
+ * function that will extract operator-specific parameters.
+ */
+ @Override
+ protected Function<String, Map<String, Object>> makeOperatorParameters(Map<String, Object> actorParameters) {
+ String actorName = getName();
+
+ TopicPairActorParams params = Util.translate(actorName, actorParameters, TopicPairActorParams.class);
+ ValidationResult result = params.validate(getName());
+ if (!result.isValid()) {
+ throw new ParameterValidationRuntimeException("invalid parameters", result);
+ }
+
+ // create a map of the default parameters
+ Map<String, Object> defaultParams = Util.translateToMap(getName(), params.getDefaults());
+ Map<String, Map<String, Object>> operations = params.getOperation();
+
+ return operationName -> {
+ Map<String, Object> specificParams = operations.get(operationName);
+ if (specificParams == null) {
+ return null;
+ }
+
+ // start with a copy of defaults and overlay with specific
+ Map<String, Object> subparams = new TreeMap<>(defaultParams);
+ subparams.putAll(specificParams);
+
+ return Util.translateToMap(getName() + "." + operationName, subparams);
+ };
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperation.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperation.java
new file mode 100644
index 000000000..6b584d7c6
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperation.java
@@ -0,0 +1,316 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import lombok.Getter;
+import org.apache.commons.lang3.tuple.Triple;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil;
+import org.onap.policy.common.endpoints.utils.PropertyUtils.TriConsumer;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairParams;
+import org.onap.policy.controlloop.actorserviceprovider.pipeline.PipelineControllerFuture;
+import org.onap.policy.controlloop.actorserviceprovider.topic.Forwarder;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPair;
+import org.onap.policy.controlloop.policy.PolicyResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Operation that uses a Topic pair.
+ *
+ * @param <S> response type
+ */
+@Getter
+public abstract class TopicPairOperation<Q, S> extends OperationPartial {
+ private static final Logger logger = LoggerFactory.getLogger(TopicPairOperation.class);
+ private static final Coder coder = new StandardCoder();
+
+ // fields extracted from the operator
+
+ private final TopicPair topicPair;
+ private final Forwarder forwarder;
+ private final TopicPairParams pairParams;
+ private final long timeoutMs;
+
+ /**
+ * Response class.
+ */
+ private final Class<S> responseClass;
+
+
+ /**
+ * Constructs the object.
+ *
+ * @param params operation parameters
+ * @param operator operator that created this operation
+ * @param clazz response class
+ */
+ public TopicPairOperation(ControlLoopOperationParams params, TopicPairOperator operator, Class<S> clazz) {
+ super(params, operator);
+ this.topicPair = operator.getTopicPair();
+ this.forwarder = operator.getForwarder();
+ this.pairParams = operator.getParams();
+ this.responseClass = clazz;
+ this.timeoutMs = TimeUnit.MILLISECONDS.convert(pairParams.getTimeoutSec(), TimeUnit.SECONDS);
+ }
+
+ /**
+ * If no timeout is specified, then it returns the default timeout.
+ */
+ @Override
+ protected long getTimeoutMs(Integer timeoutSec) {
+ // TODO move this method to the superclass
+ return (timeoutSec == null || timeoutSec == 0 ? this.timeoutMs : super.getTimeoutMs(timeoutSec));
+ }
+
+ /**
+ * Publishes the request and arranges to receive the response.
+ */
+ @Override
+ protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
+
+ final Q request = makeRequest(attempt);
+ final List<String> expectedKeyValues = getExpectedKeyValues(attempt, request);
+
+ final PipelineControllerFuture<OperationOutcome> controller = new PipelineControllerFuture<>();
+ final CompletableFuture<Triple<CommInfrastructure, String, StandardCoderObject>> future =
+ new CompletableFuture<>();
+ final Executor executor = params.getExecutor();
+
+ // register a listener BEFORE publishing
+
+ // @formatter:off
+ TriConsumer<CommInfrastructure, String, StandardCoderObject> listener =
+ (infra, rawResponse, scoResponse) -> future.complete(Triple.of(infra, rawResponse, scoResponse));
+ // @formatter:on
+
+ // TODO this currently only allows a single matching response
+
+ forwarder.register(expectedKeyValues, listener);
+
+ // ensure listener is unregistered if the controller is canceled
+ controller.add(() -> forwarder.unregister(expectedKeyValues, listener));
+
+ // publish the request
+ try {
+ publishRequest(request);
+ } catch (RuntimeException e) {
+ logger.warn("{}: failed to publish request for {}", getFullName(), params.getRequestId());
+ forwarder.unregister(expectedKeyValues, listener);
+ throw e;
+ }
+
+
+ // once "future" completes, process the response, and then complete the controller
+
+ // @formatter:off
+ future.thenApplyAsync(
+ triple -> processResponse(triple.getLeft(), outcome, triple.getMiddle(), triple.getRight()),
+ executor)
+ .whenCompleteAsync(controller.delayedComplete(), executor);
+ // @formatter:on
+
+ return controller;
+ }
+
+ /**
+ * Makes the request.
+ *
+ * @param attempt operation attempt
+ * @return a new request
+ */
+ protected abstract Q makeRequest(int attempt);
+
+ /**
+ * Gets values, expected in the response, that should match the selector keys.
+ *
+ * @param attempt operation attempt
+ * @param request request to be published
+ * @return a list of the values to be matched by the selector keys
+ */
+ protected abstract List<String> getExpectedKeyValues(int attempt, Q request);
+
+ /**
+ * Publishes the request. Encodes the request, if it is not already a String.
+ *
+ * @param request request to be published
+ */
+ protected void publishRequest(Q request) {
+ String json;
+ try {
+ if (request instanceof String) {
+ json = request.toString();
+ } else {
+ json = makeCoder().encode(request);
+ }
+ } catch (CoderException e) {
+ throw new IllegalArgumentException("cannot encode request", e);
+ }
+
+ List<CommInfrastructure> list = topicPair.publish(json);
+ if (list.isEmpty()) {
+ throw new IllegalStateException("nothing published");
+ }
+
+ logTopicRequest(list, request);
+ }
+
+ /**
+ * Processes a response.
+ *
+ * @param infra communication infrastructure on which the response was received
+ * @param outcome outcome to be populated
+ * @param response raw response to process
+ * @param scoResponse response, as a {@link StandardCoderObject}
+ * @return the outcome
+ */
+ protected OperationOutcome processResponse(CommInfrastructure infra, OperationOutcome outcome, String rawResponse,
+ StandardCoderObject scoResponse) {
+
+ logger.info("{}.{}: response received for {}", params.getActor(), params.getOperation(), params.getRequestId());
+
+ logTopicResponse(infra, rawResponse);
+
+ S response;
+ if (responseClass == String.class) {
+ response = responseClass.cast(rawResponse);
+
+ } else if (responseClass == StandardCoderObject.class) {
+ response = responseClass.cast(scoResponse);
+
+ } else {
+ try {
+ response = makeCoder().decode(rawResponse, responseClass);
+ } catch (CoderException e) {
+ logger.warn("{}.{} cannot decode response for {}", params.getActor(), params.getOperation(),
+ params.getRequestId());
+ throw new IllegalArgumentException("cannot decode response", e);
+ }
+ }
+
+ if (!isSuccess(rawResponse, response)) {
+ logger.info("{}.{} request failed for {}", params.getActor(), params.getOperation(),
+ params.getRequestId());
+ return setOutcome(outcome, PolicyResult.FAILURE);
+ }
+
+ logger.info("{}.{} request succeeded for {}", params.getActor(), params.getOperation(), params.getRequestId());
+ setOutcome(outcome, PolicyResult.SUCCESS);
+ postProcessResponse(outcome, rawResponse, response);
+
+ return outcome;
+ }
+
+ /**
+ * Processes a successful response.
+ *
+ * @param outcome outcome to be populated
+ * @param rawResponse raw response
+ * @param response decoded response
+ */
+ protected void postProcessResponse(OperationOutcome outcome, String rawResponse, S response) {
+ // do nothing
+ }
+
+ /**
+ * Determines if the response indicates success.
+ *
+ * @param rawResponse raw response
+ * @param response decoded response
+ * @return {@code true} if the response indicates success, {@code false} otherwise
+ */
+ protected abstract boolean isSuccess(String rawResponse, S response);
+
+ /**
+ * Logs a TOPIC request. If the request is not of type, String, then it attempts to
+ * pretty-print it into JSON before logging.
+ *
+ * @param infrastructures list of communication infrastructures on which it was
+ * published
+ * @param request request to be logged
+ */
+ protected void logTopicRequest(List<CommInfrastructure> infrastructures, Q request) {
+ if (infrastructures.isEmpty()) {
+ return;
+ }
+
+ String json;
+ try {
+ if (request == null) {
+ json = null;
+ } else if (request instanceof String) {
+ json = request.toString();
+ } else {
+ json = makeCoder().encode(request, true);
+ }
+
+ } catch (CoderException e) {
+ logger.warn("cannot pretty-print request", e);
+ json = request.toString();
+ }
+
+ for (CommInfrastructure infra : infrastructures) {
+ logger.info("[OUT|{}|{}|]{}{}", infra, pairParams.getTarget(), NetLoggerUtil.SYSTEM_LS, json);
+ }
+ }
+
+ /**
+ * Logs a TOPIC response. If the response is not of type, String, then it attempts to
+ * pretty-print it into JSON before logging.
+ *
+ * @param infra communication infrastructure on which the response was received
+ * @param response response to be logged
+ */
+ protected <T> void logTopicResponse(CommInfrastructure infra, T response) {
+ String json;
+ try {
+ if (response == null) {
+ json = null;
+ } else if (response instanceof String) {
+ json = response.toString();
+ } else {
+ json = makeCoder().encode(response, true);
+ }
+
+ } catch (CoderException e) {
+ logger.warn("cannot pretty-print response", e);
+ json = response.toString();
+ }
+
+ logger.info("[IN|{}|{}|]{}{}", infra, pairParams.getSource(), NetLoggerUtil.SYSTEM_LS, json);
+ }
+
+ // these may be overridden by junit tests
+
+ protected Coder makeCoder() {
+ return coder;
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperator.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperator.java
new file mode 100644
index 000000000..8ce013388
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperator.java
@@ -0,0 +1,156 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import lombok.Getter;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairParams;
+import org.onap.policy.controlloop.actorserviceprovider.topic.Forwarder;
+import org.onap.policy.controlloop.actorserviceprovider.topic.SelectorKey;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPair;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPairManager;
+
+/**
+ * Operator that uses a pair of topics, one for publishing the request, and another for
+ * receiving the response. Topic operators may share a {@link TopicPair}.
+ */
+public abstract class TopicPairOperator extends OperatorPartial {
+
+ /**
+ * Manager from which to get the topic pair.
+ */
+ private final TopicPairManager pairManager;
+
+ /**
+ * Keys used to extract the fields used to select responses for this operator.
+ */
+ private final List<SelectorKey> selectorKeys;
+
+ /*
+ * The remaining fields are initialized when configure() is invoked, thus they may
+ * change.
+ */
+
+ /**
+ * Current parameters. While {@link params} may change, the values contained within it
+ * will not, thus operations may copy it.
+ */
+ @Getter
+ private TopicPairParams params;
+
+ /**
+ * Topic pair associated with the parameters.
+ */
+ @Getter
+ private TopicPair topicPair;
+
+ /**
+ * Forwarder associated with the parameters.
+ */
+ @Getter
+ private Forwarder forwarder;
+
+
+ /**
+ * Constructs the object.
+ *
+ * @param actorName name of the actor with which this operator is associated
+ * @param name operation name
+ * @param pairManager manager from which to get the topic pair
+ * @param selectorKeys keys used to extract the fields used to select responses for
+ * this operator
+ */
+ public TopicPairOperator(String actorName, String name, TopicPairManager pairManager,
+ List<SelectorKey> selectorKeys) {
+ super(actorName, name);
+ this.pairManager = pairManager;
+ this.selectorKeys = selectorKeys;
+ }
+
+ @Override
+ protected void doConfigure(Map<String, Object> parameters) {
+ params = Util.translate(getFullName(), parameters, TopicPairParams.class);
+ ValidationResult result = params.validate(getFullName());
+ if (!result.isValid()) {
+ throw new ParameterValidationRuntimeException("invalid parameters", result);
+ }
+
+ topicPair = pairManager.getTopicPair(params.getSource(), params.getTarget());
+ forwarder = topicPair.addForwarder(selectorKeys);
+ }
+
+ /**
+ * Makes an operator that will construct operations.
+ *
+ * @param <Q> request type
+ * @param <S> response type
+ * @param actorName actor name
+ * @param operation operation name
+ * @param pairManager manager from which to get the topic pair
+ * @param operationMaker function to make an operation
+ * @param keys keys used to extract the fields used to select responses for this
+ * operator
+ * @return a new operator
+ */
+ // @formatter:off
+ public static <Q,S> TopicPairOperator makeOperator(String actorName, String operation, TopicPairManager pairManager,
+ BiFunction<ControlLoopOperationParams, TopicPairOperator, TopicPairOperation<Q,S>> operationMaker,
+ SelectorKey... keys) {
+ // @formatter:off
+
+ return makeOperator(actorName, operation, pairManager, Arrays.asList(keys), operationMaker);
+ }
+
+ /**
+ * Makes an operator that will construct operations.
+ *
+ * @param <Q> request type
+ * @param <S> response type
+ * @param actorName actor name
+ * @param operation operation name
+ * @param pairManager manager from which to get the topic pair
+ * @param keys keys used to extract the fields used to select responses for
+ * this operator
+ * @param operationMaker function to make an operation
+ * @return a new operator
+ */
+ // @formatter:off
+ public static <Q,S> TopicPairOperator makeOperator(String actorName, String operation, TopicPairManager pairManager,
+ List<SelectorKey> keys,
+ BiFunction<ControlLoopOperationParams, TopicPairOperator, TopicPairOperation<Q,S>> operationMaker) {
+ // @formatter:on
+
+ return new TopicPairOperator(actorName, operation, pairManager, keys) {
+ @Override
+ public synchronized Operation buildOperation(ControlLoopOperationParams params) {
+ return operationMaker.apply(params, this);
+ }
+ };
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParams.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParams.java
new file mode 100644
index 000000000..42a44ee9c
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParams.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.parameters;
+
+import java.util.Map;
+import lombok.Builder;
+import lombok.Data;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.parameters.BeanValidator;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+
+/**
+ * Parameters used by Actors whose Operators use a pair of Topics, one to publish requests
+ * and the other to receive responses.
+ */
+@NotNull
+@NotBlank
+@Data
+@Builder
+public class TopicPairActorParams {
+
+ /**
+ * This contains the default parameters that are used when an operation doesn't
+ * specify them. Note: each operation to be used must still have an entry in
+ * {@link #operation}, even if it's empty. Otherwise, the given operation will not be
+ * started.
+ */
+ private TopicPairParams defaults;
+
+ /**
+ * Maps an operation name to its individual parameters.
+ */
+ private Map<String, Map<String, Object>> operation;
+
+
+ /**
+ * Validates the parameters.
+ *
+ * @param name name of the object containing these parameters
+ * @return "this"
+ * @throws IllegalArgumentException if the parameters are invalid
+ */
+ public TopicPairActorParams doValidation(String name) {
+ ValidationResult result = validate(name);
+ if (!result.isValid()) {
+ throw new ParameterValidationRuntimeException("invalid parameters", result);
+ }
+
+ return this;
+ }
+
+ /**
+ * Validates the parameters.
+ *
+ * @param resultName name of the result
+ *
+ * @return the validation result
+ */
+ public ValidationResult validate(String resultName) {
+ BeanValidationResult result = new BeanValidator().validateTop(resultName, this);
+
+ if (defaults != null) {
+ result.addResult(defaults.validate("defaults"));
+ }
+
+ // @formatter:off
+ result.validateMap("operation", operation,
+ (result2, entry) -> result2.validateNotNull(entry.getKey(), entry.getValue()));
+ // @formatter:on
+
+ return result;
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParams.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParams.java
index 9e6d8a15e..33fcf3052 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParams.java
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParams.java
@@ -29,34 +29,34 @@ import org.onap.policy.common.parameters.annotations.NotBlank;
import org.onap.policy.common.parameters.annotations.NotNull;
/**
- * Parameters used by Operators that connect to a server via DMaaP.
+ * Parameters used by Operators that use a pair of Topics, one to publish requests and the
+ * other to receive responses.
*/
@NotNull
@NotBlank
@Data
@Builder(toBuilder = true)
-public class TopicParams {
+public class TopicPairParams {
/**
- * Name of the target topic end point to which requests should be published.
+ * Source topic end point, from which to read responses.
*/
- private String target;
+ private String source;
/**
- * Source topic end point, from which to read responses.
+ * Name of the target topic end point to which requests should be published.
*/
- private String source;
+ private String target;
/**
- * Amount of time, in seconds to wait for the response, where zero indicates that it
- * should wait forever. The default is zero.
+ * Amount of time, in seconds to wait for the response. The default is five minutes.
*/
- @Min(0)
+ @Min(1)
@Builder.Default
- private long timeoutSec = 0;
+ private int timeoutSec = 300;
/**
- * Validates both the publisher and the subscriber parameters.
+ * Validates the parameters.
*
* @param resultName name of the result
*
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java
new file mode 100644
index 000000000..8e9109c9e
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.PropertyUtils.TriConsumer;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Forwarder that selectively forwards message to listeners based on the content of the
+ * message. Each forwarder is associated with a single set of selector keys. Listeners are
+ * then registered with that forwarder for a particular set of values for the given keys.
+ */
+public class Forwarder {
+ private static final Logger logger = LoggerFactory.getLogger(Forwarder.class);
+
+ /**
+ * Maps a set of field values to one or more listeners.
+ */
+ // @formatter:off
+ private final Map<List<String>, Map<TriConsumer<CommInfrastructure, String, StandardCoderObject>, String>>
+ values2listeners = new ConcurrentHashMap<>();
+ // @formatter:on
+
+ /**
+ * Keys used to extract the field values from the {@link StandardCoderObject}.
+ */
+ private final List<SelectorKey> keys;
+
+ /**
+ * Constructs the object.
+ *
+ * @param keys keys used to extract the field's value from the
+ * {@link StandardCoderObject}
+ */
+ public Forwarder(List<SelectorKey> keys) {
+ this.keys = keys;
+ }
+
+ /**
+ * Registers a listener for messages containing the given field values.
+ *
+ * @param values field values of interest, in one-to-one correspondence with the keys
+ * @param listener listener to register
+ */
+ public void register(List<String> values, TriConsumer<CommInfrastructure, String, StandardCoderObject> listener) {
+ if (keys.size() != values.size()) {
+ throw new IllegalArgumentException("key/value mismatch");
+ }
+
+ values2listeners.compute(values, (key, listeners) -> {
+ Map<TriConsumer<CommInfrastructure, String, StandardCoderObject>, String> map = listeners;
+ if (map == null) {
+ map = new ConcurrentHashMap<>();
+ }
+
+ map.put(listener, "");
+ return map;
+ });
+ }
+
+ /**
+ * Unregisters a listener for messages containing the given field values.
+ *
+ * @param values field values of interest, in one-to-one correspondence with the keys
+ * @param listener listener to unregister
+ */
+ public void unregister(List<String> values, TriConsumer<CommInfrastructure, String, StandardCoderObject> listener) {
+ values2listeners.computeIfPresent(values, (key, listeners) -> {
+ listeners.remove(listener);
+ return (listeners.isEmpty() ? null : listeners);
+ });
+ }
+
+ /**
+ * Processes a message, forwarding it to the appropriate listeners, if any.
+ *
+ * @param infra communication infrastructure on which the response was received
+ * @param textMessage original text message that was received
+ * @param scoMessage decoded text message
+ */
+ public void onMessage(CommInfrastructure infra, String textMessage, StandardCoderObject scoMessage) {
+ // extract the key values from the message
+ List<String> values = new ArrayList<>(keys.size());
+ for (SelectorKey key : keys) {
+ String value = key.extractField(scoMessage);
+ if (value == null) {
+ /*
+ * No value for this field, so this message is not relevant to this
+ * forwarder.
+ */
+ return;
+ }
+
+ values.add(value);
+ }
+
+ // get the listeners for this set of values
+ Map<TriConsumer<CommInfrastructure, String, StandardCoderObject>, String> listeners =
+ values2listeners.get(values);
+ if (listeners == null) {
+ // no listeners for this particular list of values
+ return;
+ }
+
+
+ // forward the message to each listener
+ for (TriConsumer<CommInfrastructure, String, StandardCoderObject> listener : listeners.keySet()) {
+ try {
+ listener.accept(infra, textMessage, scoMessage);
+ } catch (RuntimeException e) {
+ logger.warn("exception thrown by listener {}", Util.ident(listener), e);
+ }
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java
new file mode 100644
index 000000000..fc5727395
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import lombok.EqualsAndHashCode;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+
+/**
+ * Selector key, which contains a hierarchical list of Strings and Integers that are used
+ * to extract the content of a field, typically from a {@link StandardCoderObject}.
+ */
+@EqualsAndHashCode
+public class SelectorKey {
+
+ /**
+ * Names and indices used to extract the field's value.
+ */
+ private final Object[] fieldIdentifiers;
+
+ /**
+ * Constructs the object.
+ *
+ * @param fieldIdentifiers names and indices used to extract the field's value
+ */
+ public SelectorKey(Object... fieldIdentifiers) {
+ this.fieldIdentifiers = fieldIdentifiers;
+ }
+
+ /**
+ * Extracts the given field from an object.
+ *
+ * @param object object from which to extract the field
+ * @return the extracted value, or {@code null} if the object does not contain the
+ * field
+ */
+ public String extractField(StandardCoderObject object) {
+ return object.getString(fieldIdentifiers);
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java
new file mode 100644
index 000000000..eb805ca5d
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicListener;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A topic listener. When a message arrives on a topic, it is forwarded to listeners based
+ * on the content of fields found within the message. However, depending on the message
+ * type, the relevant fields might be found in different places within the message's
+ * object hierarchy. For each different list of keys, this class maintains a
+ * {@link Forwarder}, which is used to forward the message to all relevant listeners.
+ * <p/>
+ * Once a selector has been added, it is not removed until {@link #shutdown()} is invoked.
+ * As selectors are typically only added by Operators, and not by individual Operations,
+ * this should not pose a problem.
+ */
+public class TopicListenerImpl implements TopicListener {
+ private static final Logger logger = LoggerFactory.getLogger(TopicListenerImpl.class);
+ private static StandardCoder coder = new StandardCoder();
+
+ /**
+ * Maps selector to a forwarder.
+ */
+ private final Map<List<SelectorKey>, Forwarder> selector2forwarder = new ConcurrentHashMap<>();
+
+
+ /**
+ * Removes all forwarders.
+ */
+ public void shutdown() {
+ selector2forwarder.clear();
+ }
+
+ /**
+ * Adds a forwarder, if it doesn't already exist.
+ *
+ * @param keys the selector keys
+ * @return the forwarder associated with the given selector keys
+ */
+ public Forwarder addForwarder(SelectorKey... keys) {
+ return addForwarder(Arrays.asList(keys));
+ }
+
+ /**
+ * Adds a forwarder, if it doesn't already exist.
+ *
+ * @param keys the selector keys
+ * @return the forwarder associated with the given selector keys
+ */
+ public Forwarder addForwarder(List<SelectorKey> keys) {
+ return selector2forwarder.computeIfAbsent(keys, key -> new Forwarder(keys));
+ }
+
+ /**
+ * Decodes the message and then forwards it to each forwarder for processing.
+ */
+ @Override
+ public void onTopicEvent(CommInfrastructure infra, String topic, String message) {
+ StandardCoderObject object;
+ try {
+ object = coder.decode(message, StandardCoderObject.class);
+ } catch (CoderException e) {
+ logger.warn("cannot decode message", e);
+ return;
+ }
+
+ /*
+ * We don't know which selector is appropriate for the message, so we just let
+ * them all take a crack at it.
+ */
+ for (Forwarder forwarder : selector2forwarder.values()) {
+ forwarder.onMessage(infra, message, object);
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPair.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPair.java
new file mode 100644
index 000000000..c0cfe2571
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPair.java
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A pair of topics, one of which is used to publish requests and the other to receive
+ * responses.
+ */
+public class TopicPair extends TopicListenerImpl {
+ private static final Logger logger = LoggerFactory.getLogger(TopicPair.class);
+
+ @Getter
+ private final String source;
+
+ @Getter
+ private final String target;
+
+ private final List<TopicSink> publishers;
+ private final List<TopicSource> subscribers;
+
+ /**
+ * Constructs the object.
+ *
+ * @param source source topic name
+ * @param target target topic name
+ */
+ public TopicPair(String source, String target) {
+ this.source = source;
+ this.target = target;
+
+ publishers = getTopicEndpointManager().getTopicSinks(target);
+ if (publishers.isEmpty()) {
+ throw new IllegalArgumentException("no sinks for topic: " + target);
+ }
+
+ subscribers = getTopicEndpointManager().getTopicSources(Arrays.asList(source));
+ if (subscribers.isEmpty()) {
+ throw new IllegalArgumentException("no sources for topic: " + source);
+ }
+ }
+
+ /**
+ * Starts listening on the source topic(s).
+ */
+ public void start() {
+ subscribers.forEach(topic -> topic.register(this));
+ }
+
+ /**
+ * Stops listening on the source topic(s).
+ */
+ public void stop() {
+ subscribers.forEach(topic -> topic.unregister(this));
+ }
+
+ /**
+ * Stops listening on the source topic(s) and clears all of the forwarders.
+ */
+ @Override
+ public void shutdown() {
+ stop();
+ super.shutdown();
+ }
+
+ /**
+ * Publishes a message to the target topic.
+ *
+ * @param message message to be published
+ * @return a list of the infrastructures on which it was published
+ */
+ public List<CommInfrastructure> publish(String message) {
+ List<CommInfrastructure> infrastructures = new ArrayList<>(publishers.size());
+
+ for (TopicSink topic : publishers) {
+ try {
+ topic.send(message);
+ infrastructures.add(topic.getTopicCommInfrastructure());
+
+ } catch (RuntimeException e) {
+ logger.warn("cannot publish to {}:{}", topic.getTopicCommInfrastructure(), target, e);
+ }
+ }
+
+ return infrastructures;
+ }
+
+ // these may be overridden by junit tests
+
+ protected TopicEndpoint getTopicEndpointManager() {
+ return TopicEndpointManager.getManager();
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairManager.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairManager.java
new file mode 100644
index 000000000..c351f95f6
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairManager.java
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+/**
+ * Manages topic pairs.
+ */
+@FunctionalInterface
+public interface TopicPairManager {
+
+ /**
+ * Gets the topic pair for the given parameters, creating one if it does not exist.
+ *
+ * @param source source topic name
+ * @param target target topic name
+ * @return the topic pair associated with the given source and target topics
+ */
+ TopicPair getTopicPair(String source, String target);
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java
index 19f781d61..39d6fd431 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java
@@ -22,6 +22,7 @@ package org.onap.policy.controlloop.actorserviceprovider.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -359,8 +360,7 @@ public class HttpOperationTest {
public void testProcessResponseDecodeExcept() throws CoderException {
MyGetOperation<Integer> oper2 = new MyGetOperation<>(Integer.class);
- assertSame(outcome, oper2.processResponse(outcome, PATH, response));
- assertEquals(PolicyResult.FAILURE_EXCEPTION, outcome.getResult());
+ assertThatIllegalArgumentException().isThrownBy(() -> oper2.processResponse(outcome, PATH, response));
}
@Test
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/MyExec.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/MyExec.java
new file mode 100644
index 000000000..6515eb37c
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/MyExec.java
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+/**
+ * Executor that will run tasks until the queue is empty or a maximum number of tasks have
+ * been executed. Doesn't actually run anything until {@link #runAll()} is invoked.
+ */
+public class MyExec implements Executor {
+
+ // TODO move this to policy-common/utils-test
+
+ private final int maxTasks;
+ private final Queue<Runnable> commands = new LinkedList<>();
+
+ public MyExec(int maxTasks) {
+ this.maxTasks = maxTasks;
+ }
+
+ public int getQueueLength() {
+ return commands.size();
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ commands.add(command);
+ }
+
+ /**
+ * Runs all tasks until the queue is empty or the maximum number of tasks have been
+ * reached.
+ *
+ * @return {@code true} if the queue is empty, {@code false} if the maximum number of
+ * tasks have been reached before the queue was completed
+ */
+ public boolean runAll() {
+ for (int count = 0; count < maxTasks && !commands.isEmpty(); ++count) {
+ commands.remove().run();
+ }
+
+ return commands.isEmpty();
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java
index 0d5cb2444..f28c1f6c6 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java
@@ -36,7 +36,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@@ -105,7 +104,7 @@ public class OperationPartialTest {
event.setRequestId(REQ_ID);
context = new ControlLoopEventContext(event);
- executor = new MyExec();
+ executor = new MyExec(100 * MAX_PARALLEL_REQUESTS);
params = ControlLoopOperationParams.builder().completeCallback(this::completer).context(context)
.executor(executor).actor(ACTOR).operation(OPERATION).timeoutSec(TIMEOUT)
@@ -1267,36 +1266,4 @@ public class OperationPartialTest {
return 0L;
}
}
-
- /**
- * Executor that will run tasks until the queue is empty or a maximum number of tasks
- * have been executed. Doesn't actually run anything until {@link #runAll()} is
- * invoked.
- */
- private static class MyExec implements Executor {
- private static final int MAX_TASKS = MAX_PARALLEL_REQUESTS * 100;
-
- private Queue<Runnable> commands = new LinkedList<>();
-
- public MyExec() {
- // do nothing
- }
-
- public int getQueueLength() {
- return commands.size();
- }
-
- @Override
- public void execute(Runnable command) {
- commands.add(command);
- }
-
- public boolean runAll() {
- for (int count = 0; count < MAX_TASKS && !commands.isEmpty(); ++count) {
- commands.remove().run();
- }
-
- return commands.isEmpty();
- }
- }
}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperationTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperationTest.java
new file mode 100644
index 000000000..4e45b1abe
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperationTest.java
@@ -0,0 +1,503 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.Logger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import lombok.Getter;
+import lombok.Setter;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.PropertyUtils.TriConsumer;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.common.utils.test.log.logback.ExtractAppender;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairParams;
+import org.onap.policy.controlloop.actorserviceprovider.topic.Forwarder;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPair;
+import org.onap.policy.controlloop.policy.PolicyResult;
+import org.slf4j.LoggerFactory;
+
+public class TopicPairOperationTest {
+ private static final List<CommInfrastructure> INFRA_LIST =
+ Arrays.asList(CommInfrastructure.NOOP, CommInfrastructure.UEB);
+ private static final IllegalStateException EXPECTED_EXCEPTION = new IllegalStateException("expected exception");
+ private static final String ACTOR = "my-actor";
+ private static final String OPERATION = "my-operation";
+ private static final String REQ_ID = "my-request-id";
+ private static final String MY_SOURCE = "my-source";
+ private static final String MY_TARGET = "my-target";
+ private static final String TEXT = "some text";
+ private static final int TIMEOUT_SEC = 10;
+ private static final long TIMEOUT_MS = 1000 * TIMEOUT_SEC;
+
+ private static final StandardCoder coder = new StandardCoder();
+
+ /**
+ * Used to attach an appender to the class' logger.
+ */
+ private static final Logger logger = (Logger) LoggerFactory.getLogger(TopicPairOperation.class);
+ private static final ExtractAppender appender = new ExtractAppender();
+
+ @Mock
+ private TopicPairOperator operator;
+ @Mock
+ private TopicPair pair;
+ @Mock
+ private Forwarder forwarder;
+
+ @Captor
+ private ArgumentCaptor<TriConsumer<CommInfrastructure, String, StandardCoderObject>> listenerCaptor;
+
+ private ControlLoopOperationParams params;
+ private TopicPairParams topicParams;
+ private OperationOutcome outcome;
+ private StandardCoderObject stdResponse;
+ private String responseText;
+ private MyExec executor;
+ private TopicPairOperation<MyRequest, MyResponse> oper;
+
+ /**
+ * Attaches the appender to the logger.
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ /**
+ * Attach appender to the logger.
+ */
+ appender.setContext(logger.getLoggerContext());
+ appender.start();
+
+ logger.addAppender(appender);
+ }
+
+ /**
+ * Stops the appender.
+ */
+ @AfterClass
+ public static void tearDownAfterClass() {
+ appender.stop();
+ }
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() throws CoderException {
+ MockitoAnnotations.initMocks(this);
+
+ appender.clearExtractions();
+
+ topicParams = TopicPairParams.builder().source(MY_SOURCE).target(MY_TARGET).timeoutSec(TIMEOUT_SEC).build();
+
+ when(operator.getActorName()).thenReturn(ACTOR);
+ when(operator.getName()).thenReturn(OPERATION);
+ when(operator.getTopicPair()).thenReturn(pair);
+ when(operator.getForwarder()).thenReturn(forwarder);
+ when(operator.getParams()).thenReturn(topicParams);
+ when(operator.isAlive()).thenReturn(true);
+
+ when(pair.publish(any())).thenReturn(INFRA_LIST);
+
+ executor = new MyExec(100);
+
+ params = ControlLoopOperationParams.builder().actor(ACTOR).operation(OPERATION).executor(executor).build();
+ outcome = params.makeOutcome();
+
+ responseText = coder.encode(new MyResponse());
+ stdResponse = coder.decode(responseText, StandardCoderObject.class);
+
+ oper = new MyOperation();
+ }
+
+ @Test
+ public void testTopicPairOperation_testGetTopicPair_testGetForwarder_testGetPairParams() {
+ assertEquals(ACTOR, oper.getActorName());
+ assertEquals(OPERATION, oper.getName());
+ assertSame(pair, oper.getTopicPair());
+ assertSame(forwarder, oper.getForwarder());
+ assertSame(topicParams, oper.getPairParams());
+ assertEquals(TIMEOUT_MS, oper.getTimeoutMs());
+ assertSame(MyResponse.class, oper.getResponseClass());
+ }
+
+ @Test
+ public void testStartOperationAsync() throws Exception {
+ CompletableFuture<OperationOutcome> future = oper.startOperationAsync(1, outcome);
+ assertFalse(future.isDone());
+
+ verify(forwarder).register(eq(Arrays.asList(REQ_ID)), listenerCaptor.capture());
+
+ verify(forwarder, never()).unregister(any(), any());
+
+ verify(pair).publish(any());
+
+ // provide the response
+ listenerCaptor.getValue().accept(CommInfrastructure.NOOP, responseText, stdResponse);
+
+ // run the tasks
+ assertTrue(executor.runAll());
+
+ assertTrue(future.isDone());
+
+ assertSame(outcome, future.get(5, TimeUnit.SECONDS));
+ assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+
+ verify(forwarder).unregister(eq(Arrays.asList(REQ_ID)), eq(listenerCaptor.getValue()));
+ }
+
+ /**
+ * Tests startOperationAsync() when the publisher throws an exception.
+ */
+ @Test
+ public void testStartOperationAsyncException() throws Exception {
+ // indicate that nothing was published
+ when(pair.publish(any())).thenReturn(Arrays.asList());
+
+ assertThatIllegalStateException().isThrownBy(() -> oper.startOperationAsync(1, outcome));
+
+ verify(forwarder).register(eq(Arrays.asList(REQ_ID)), listenerCaptor.capture());
+
+ // must still unregister
+ verify(forwarder).unregister(eq(Arrays.asList(REQ_ID)), eq(listenerCaptor.getValue()));
+ }
+
+ @Test
+ public void testGetTimeoutMsInteger() {
+ // use default
+ assertEquals(TIMEOUT_MS, oper.getTimeoutMs(null));
+ assertEquals(TIMEOUT_MS, oper.getTimeoutMs(0));
+
+ // use provided value
+ assertEquals(5000, oper.getTimeoutMs(5));
+ }
+
+ @Test
+ public void testPublishRequest() {
+ oper.publishRequest(new MyRequest());
+ assertEquals(INFRA_LIST.size(), appender.getExtracted().size());
+ }
+
+ /**
+ * Tests publishRequest() when nothing is published.
+ */
+ @Test
+ public void testPublishRequestUnpublished() {
+ when(pair.publish(any())).thenReturn(Arrays.asList());
+ assertThatIllegalStateException().isThrownBy(() -> oper.publishRequest(new MyRequest()));
+ }
+
+ /**
+ * Tests publishRequest() when the request type is a String.
+ */
+ @Test
+ public void testPublishRequestString() {
+ MyStringOperation oper2 = new MyStringOperation();
+ oper2.publishRequest(TEXT);
+ assertEquals(INFRA_LIST.size(), appender.getExtracted().size());
+ }
+
+ /**
+ * Tests publishRequest() when the coder throws an exception.
+ */
+ @Test
+ public void testPublishRequestException() {
+ setOperCoderException();
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.publishRequest(new MyRequest()));
+ }
+
+ /**
+ * Tests processResponse() when it's a success and the response type is a String.
+ */
+ @Test
+ public void testProcessResponseSuccessString() {
+ MyStringOperation oper2 = new MyStringOperation();
+
+ assertSame(outcome, oper2.processResponse(CommInfrastructure.NOOP, outcome, TEXT, null));
+ assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+ }
+
+ /**
+ * Tests processResponse() when it's a success and the response type is a
+ * StandardCoderObject.
+ */
+ @Test
+ public void testProcessResponseSuccessSco() {
+ MyScoOperation oper2 = new MyScoOperation();
+
+ assertSame(outcome, oper2.processResponse(CommInfrastructure.NOOP, outcome, responseText, stdResponse));
+ assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+ }
+
+ /**
+ * Tests processResponse() when it's a failure.
+ */
+ @Test
+ public void testProcessResponseFailure() throws CoderException {
+ // indicate error in the response
+ MyResponse resp = new MyResponse();
+ resp.setOutput("error");
+
+ responseText = coder.encode(resp);
+ stdResponse = coder.decode(responseText, StandardCoderObject.class);
+
+ assertSame(outcome, oper.processResponse(CommInfrastructure.NOOP, outcome, responseText, stdResponse));
+ assertEquals(PolicyResult.FAILURE, outcome.getResult());
+ }
+
+ /**
+ * Tests processResponse() when the decoder succeeds.
+ */
+ @Test
+ public void testProcessResponseDecodeOk() throws CoderException {
+ assertSame(outcome, oper.processResponse(CommInfrastructure.NOOP, outcome, responseText, stdResponse));
+ assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+ }
+
+ /**
+ * Tests processResponse() when the decoder throws an exception.
+ */
+ @Test
+ public void testProcessResponseDecodeExcept() throws CoderException {
+ // @formatter:off
+ assertThatIllegalArgumentException().isThrownBy(
+ () -> oper.processResponse(CommInfrastructure.NOOP, outcome, "{invalid json", stdResponse));
+ // @formatter:on
+ }
+
+ @Test
+ public void testPostProcessResponse() {
+ assertThatCode(() -> oper.postProcessResponse(outcome, null, null)).doesNotThrowAnyException();
+ }
+
+ @Test
+ public void testLogTopicRequest() {
+ // nothing to log
+ appender.clearExtractions();
+ oper.logTopicRequest(Arrays.asList(), new MyRequest());
+ assertEquals(0, appender.getExtracted().size());
+
+ // log structured data
+ appender.clearExtractions();
+ oper.logTopicRequest(INFRA_LIST, new MyRequest());
+ List<String> output = appender.getExtracted();
+ assertEquals(2, output.size());
+
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString())
+ .contains("{\n \"theRequestId\": \"my-request-id\"\n}");
+
+ assertThat(output.get(1)).contains(CommInfrastructure.UEB.toString())
+ .contains("{\n \"theRequestId\": \"my-request-id\"\n}");
+
+ // log a plain string
+ appender.clearExtractions();
+ new MyStringOperation().logTopicRequest(Arrays.asList(CommInfrastructure.NOOP), TEXT);
+ output = appender.getExtracted();
+ assertEquals(1, output.size());
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString()).contains(TEXT);
+
+ // log a null request
+ appender.clearExtractions();
+ oper.logTopicRequest(Arrays.asList(CommInfrastructure.NOOP), null);
+ output = appender.getExtracted();
+ assertEquals(1, output.size());
+
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString()).contains("null");
+
+ // exception from coder
+ setOperCoderException();
+
+ appender.clearExtractions();
+ oper.logTopicRequest(Arrays.asList(CommInfrastructure.NOOP), new MyRequest());
+ output = appender.getExtracted();
+ assertEquals(2, output.size());
+ assertThat(output.get(0)).contains("cannot pretty-print request");
+ assertThat(output.get(1)).contains(CommInfrastructure.NOOP.toString());
+ }
+
+ @Test
+ public void testLogTopicResponse() {
+ // log structured data
+ appender.clearExtractions();
+ oper.logTopicResponse(CommInfrastructure.NOOP, new MyResponse());
+ List<String> output = appender.getExtracted();
+ assertEquals(1, output.size());
+
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString())
+ .contains("{\n \"requestId\": \"my-request-id\"\n}");
+
+ // log a plain string
+ appender.clearExtractions();
+ new MyStringOperation().logTopicResponse(CommInfrastructure.NOOP, TEXT);
+ output = appender.getExtracted();
+ assertEquals(1, output.size());
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString()).contains(TEXT);
+
+ // log a null response
+ appender.clearExtractions();
+ oper.logTopicResponse(CommInfrastructure.NOOP, null);
+ output = appender.getExtracted();
+ assertEquals(1, output.size());
+
+ assertThat(output.get(0)).contains(CommInfrastructure.NOOP.toString()).contains("null");
+
+ // exception from coder
+ setOperCoderException();
+
+ appender.clearExtractions();
+ oper.logTopicResponse(CommInfrastructure.NOOP, new MyResponse());
+ output = appender.getExtracted();
+ assertEquals(2, output.size());
+ assertThat(output.get(0)).contains("cannot pretty-print response");
+ assertThat(output.get(1)).contains(CommInfrastructure.NOOP.toString());
+ }
+
+ @Test
+ public void testMakeCoder() {
+ assertNotNull(oper.makeCoder());
+ }
+
+ /**
+ * Creates a new {@link #oper} whose coder will throw an exception.
+ */
+ private void setOperCoderException() {
+ oper = new MyOperation() {
+ @Override
+ protected Coder makeCoder() {
+ return new StandardCoder() {
+ @Override
+ public String encode(Object object, boolean pretty) throws CoderException {
+ throw new CoderException(EXPECTED_EXCEPTION);
+ }
+ };
+ }
+ };
+ }
+
+ @Getter
+ @Setter
+ public static class MyRequest {
+ private String theRequestId = REQ_ID;
+ private String input;
+ }
+
+ @Getter
+ @Setter
+ public static class MyResponse {
+ private String requestId = REQ_ID;
+ private String output;
+ }
+
+
+ private class MyStringOperation extends TopicPairOperation<String, String> {
+ public MyStringOperation() {
+ super(TopicPairOperationTest.this.params, operator, String.class);
+ }
+
+ @Override
+ protected String makeRequest(int attempt) {
+ return TEXT;
+ }
+
+ @Override
+ protected List<String> getExpectedKeyValues(int attempt, String request) {
+ return Arrays.asList(REQ_ID);
+ }
+
+ @Override
+ protected boolean isSuccess(String rawResponse, String response) {
+ return (response != null);
+ }
+ }
+
+
+ private class MyScoOperation extends TopicPairOperation<MyRequest, StandardCoderObject> {
+ public MyScoOperation() {
+ super(TopicPairOperationTest.this.params, operator, StandardCoderObject.class);
+ }
+
+ @Override
+ protected MyRequest makeRequest(int attempt) {
+ return new MyRequest();
+ }
+
+ @Override
+ protected List<String> getExpectedKeyValues(int attempt, MyRequest request) {
+ return Arrays.asList(REQ_ID);
+ }
+
+ @Override
+ protected boolean isSuccess(String rawResponse, StandardCoderObject response) {
+ return (response.getString("output") == null);
+ }
+ }
+
+
+ private class MyOperation extends TopicPairOperation<MyRequest, MyResponse> {
+ public MyOperation() {
+ super(TopicPairOperationTest.this.params, operator, MyResponse.class);
+ }
+
+ @Override
+ protected MyRequest makeRequest(int attempt) {
+ return new MyRequest();
+ }
+
+ @Override
+ protected List<String> getExpectedKeyValues(int attempt, MyRequest request) {
+ return Arrays.asList(REQ_ID);
+ }
+
+ @Override
+ protected boolean isSuccess(String rawResponse, MyResponse response) {
+ return (response.getOutput() == null);
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperatorTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperatorTest.java
new file mode 100644
index 000000000..dd25902d6
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/TopicPairOperatorTest.java
@@ -0,0 +1,140 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.impl;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiFunction;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairParams;
+import org.onap.policy.controlloop.actorserviceprovider.topic.Forwarder;
+import org.onap.policy.controlloop.actorserviceprovider.topic.SelectorKey;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPair;
+import org.onap.policy.controlloop.actorserviceprovider.topic.TopicPairManager;
+
+public class TopicPairOperatorTest {
+ private static final String ACTOR = "my-actor";
+ private static final String OPERATION = "my-operation";
+ private static final String MY_SOURCE = "my-source";
+ private static final String MY_TARGET = "my-target";
+ private static final int TIMEOUT_SEC = 10;
+
+ @Mock
+ private TopicPairManager mgr;
+ @Mock
+ private TopicPair pair;
+ @Mock
+ private Forwarder forwarder;
+ @Mock
+ private TopicPairOperation<String, Integer> operation;
+
+ private List<SelectorKey> keys;
+ private TopicPairParams params;
+ private MyOperator oper;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ keys = List.of(new SelectorKey(""));
+
+ when(mgr.getTopicPair(MY_SOURCE, MY_TARGET)).thenReturn(pair);
+ when(pair.addForwarder(keys)).thenReturn(forwarder);
+
+ oper = new MyOperator(keys);
+
+ params = TopicPairParams.builder().source(MY_SOURCE).target(MY_TARGET).timeoutSec(TIMEOUT_SEC).build();
+ oper.configure(Util.translateToMap(OPERATION, params));
+ oper.start();
+ }
+
+ @Test
+ public void testTopicPairOperator_testGetParams_testGetTopicPair_testGetForwarder() {
+ assertEquals(ACTOR, oper.getActorName());
+ assertEquals(OPERATION, oper.getName());
+ assertEquals(params, oper.getParams());
+ assertSame(pair, oper.getTopicPair());
+ assertSame(forwarder, oper.getForwarder());
+ }
+
+ @Test
+ public void testDoConfigure() {
+ oper.stop();
+
+ // invalid parameters
+ params.setSource(null);
+ assertThatThrownBy(() -> oper.configure(Util.translateToMap(OPERATION, params)))
+ .isInstanceOf(ParameterValidationRuntimeException.class);
+ }
+
+ @Test
+ public void testMakeOperator() {
+ AtomicReference<ControlLoopOperationParams> paramsRef = new AtomicReference<>();
+ AtomicReference<TopicPairOperator> operRef = new AtomicReference<>();
+
+ // @formatter:off
+ BiFunction<ControlLoopOperationParams, TopicPairOperator, TopicPairOperation<String, Integer>> maker =
+ (params, operator) -> {
+ paramsRef.set(params);
+ operRef.set(operator);
+ return operation;
+ };
+ // @formatter:on
+
+ TopicPairOperator oper2 = TopicPairOperator.makeOperator(ACTOR, OPERATION, mgr, maker, new SelectorKey(""));
+
+ assertEquals(ACTOR, oper2.getActorName());
+ assertEquals(OPERATION, oper2.getName());
+
+ ControlLoopOperationParams params2 = ControlLoopOperationParams.builder().build();
+
+ assertSame(operation, oper2.buildOperation(params2));
+ assertSame(params2, paramsRef.get());
+ assertSame(oper2, operRef.get());
+ }
+
+
+ private class MyOperator extends TopicPairOperator {
+ public MyOperator(List<SelectorKey> selectorKeys) {
+ super(ACTOR, OPERATION, mgr, selectorKeys);
+ }
+
+ @Override
+ public Operation buildOperation(ControlLoopOperationParams params) {
+ return null;
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParamsTest.java
new file mode 100644
index 000000000..4322c5f39
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairActorParamsTest.java
@@ -0,0 +1,132 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.parameters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+
+public class TopicPairActorParamsTest {
+ private static final String MY_NAME = "my-name";
+
+ private static final String DFLT_SOURCE = "default-source";
+ private static final String DFLT_TARGET = "default-target";
+ private static final int DFLT_TIMEOUT = 10;
+
+ private static final String OPER1_NAME = "oper A";
+ private static final String OPER1_SOURCE = "source A";
+ private static final String OPER1_TARGET = "target A";
+ private static final int OPER1_TIMEOUT = 20;
+
+ // oper2 uses some default values
+ private static final String OPER2_NAME = "oper B";
+ private static final String OPER2_SOURCE = "source B";
+
+ // oper3 uses default values for everything
+ private static final String OPER3_NAME = "oper C";
+
+ private TopicPairParams defaults;
+ private Map<String, Map<String, Object>> operMap;
+ private TopicPairActorParams params;
+
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ defaults = TopicPairParams.builder().source(DFLT_SOURCE).target(DFLT_TARGET).timeoutSec(DFLT_TIMEOUT).build();
+
+ TopicPairParams oper1 = TopicPairParams.builder().source(OPER1_SOURCE).target(OPER1_TARGET)
+ .timeoutSec(OPER1_TIMEOUT).build();
+
+ Map<String, Object> oper1Map = Util.translateToMap(OPER1_NAME, oper1);
+ Map<String, Object> oper2Map = Map.of("source", OPER2_SOURCE);
+ Map<String, Object> oper3Map = Collections.emptyMap();
+ operMap = Map.of(OPER1_NAME, oper1Map, OPER2_NAME, oper2Map, OPER3_NAME, oper3Map);
+
+ params = TopicPairActorParams.builder().defaults(defaults).operation(operMap).build();
+
+ }
+
+ @Test
+ public void testTopicPairActorParams() {
+ assertSame(defaults, params.getDefaults());
+ assertSame(operMap, params.getOperation());
+ }
+
+ @Test
+ public void testDoValidation() {
+ assertSame(params, params.doValidation(MY_NAME));
+
+ // test with invalid parameters
+ defaults.setTimeoutSec(-1);
+ assertThatThrownBy(() -> params.doValidation(MY_NAME)).isInstanceOf(ParameterValidationRuntimeException.class);
+ }
+
+ @Test
+ public void testValidate() {
+ ValidationResult result;
+
+ // null defaults
+ params.setDefaults(null);
+ result = params.validate(MY_NAME);
+ assertFalse(result.isValid());
+ assertThat(result.getResult()).contains("defaults").contains("null");
+ params.setDefaults(defaults);
+
+ // invalid value in defaults
+ defaults.setTimeoutSec(-1);
+ result = params.validate(MY_NAME);
+ assertFalse(result.isValid());
+ assertThat(result.getResult()).contains("defaults").contains("timeoutSec");
+ defaults.setTimeoutSec(DFLT_TIMEOUT);
+
+ // null map
+ params.setOperation(null);
+ result = params.validate(MY_NAME);
+ assertFalse(result.isValid());
+ assertThat(result.getResult()).contains("operation");
+ params.setOperation(operMap);
+
+ // null entry in the map
+ Map<String, Map<String, Object>> map2 = new TreeMap<>(operMap);
+ map2.put(OPER2_NAME, null);
+ params.setOperation(map2);
+ result = params.validate(MY_NAME);
+ assertFalse(result.isValid());
+ assertThat(result.getResult()).contains("operation").contains("null");
+ params.setOperation(operMap);
+
+ // test success case
+ assertTrue(params.validate(MY_NAME).isValid());
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParamsTest.java
index 4834c98d2..d63c833d1 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicParamsTest.java
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/TopicPairParamsTest.java
@@ -29,20 +29,20 @@ import java.util.function.Function;
import org.junit.Before;
import org.junit.Test;
import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicParams.TopicParamsBuilder;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.TopicPairParams.TopicPairParamsBuilder;
-public class TopicParamsTest {
+public class TopicPairParamsTest {
private static final String CONTAINER = "my-container";
private static final String TARGET = "my-target";
private static final String SOURCE = "my-source";
- private static final long TIMEOUT = 10;
+ private static final int TIMEOUT = 10;
- private TopicParams params;
+ private TopicPairParams params;
@Before
public void setUp() {
- params = TopicParams.builder().target(TARGET).source(SOURCE).timeoutSec(TIMEOUT).build();
+ params = TopicPairParams.builder().target(TARGET).source(SOURCE).timeoutSec(TIMEOUT).build();
}
@Test
@@ -52,8 +52,11 @@ public class TopicParamsTest {
testValidateField("timeoutSec", "minimum", bldr -> bldr.timeoutSec(-1));
// check edge cases
- assertTrue(params.toBuilder().timeoutSec(0).build().validate(CONTAINER).isValid());
+ assertFalse(params.toBuilder().timeoutSec(0).build().validate(CONTAINER).isValid());
assertTrue(params.toBuilder().timeoutSec(1).build().validate(CONTAINER).isValid());
+
+ // some default values should be valid
+ assertTrue(TopicPairParams.builder().target(TARGET).source(SOURCE).build().validate(CONTAINER).isValid());
}
@Test
@@ -66,7 +69,7 @@ public class TopicParamsTest {
}
private void testValidateField(String fieldName, String expected,
- Function<TopicParamsBuilder, TopicParamsBuilder> makeInvalid) {
+ Function<TopicPairParamsBuilder, TopicPairParamsBuilder> makeInvalid) {
// original params should be valid
ValidationResult result = params.validate(CONTAINER);
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/ForwarderTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/ForwarderTest.java
new file mode 100644
index 000000000..24f8b70a8
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/ForwarderTest.java
@@ -0,0 +1,201 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.PropertyUtils.TriConsumer;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+
+public class ForwarderTest {
+ private static final CommInfrastructure INFRA = CommInfrastructure.NOOP;
+ private static final String TEXT = "some text";
+
+ private static final String KEY1 = "requestId";
+ private static final String KEY2 = "container";
+ private static final String SUBKEY = "subRequestId";
+
+ private static final String VALUEA_REQID = "hello";
+ private static final String VALUEA_SUBREQID = "world";
+
+ // request id is shared with value A
+ private static final String VALUEB_REQID = "hello";
+ private static final String VALUEB_SUBREQID = "another world";
+
+ // unique values
+ private static final String VALUEC_REQID = "bye";
+ private static final String VALUEC_SUBREQID = "bye-bye";
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener1;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener1b;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener2;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener3;
+
+ private Forwarder forwarder;
+
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ forwarder = new Forwarder(Arrays.asList(new SelectorKey(KEY1), new SelectorKey(KEY2, SUBKEY)));
+
+ forwarder.register(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1);
+ forwarder.register(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1b);
+ forwarder.register(Arrays.asList(VALUEB_REQID, VALUEB_SUBREQID), listener2);
+ forwarder.register(Arrays.asList(VALUEC_REQID, VALUEC_SUBREQID), listener3);
+ }
+
+ @Test
+ public void testRegister() {
+ // key size mismatches
+ assertThatIllegalArgumentException().isThrownBy(() -> forwarder.register(Arrays.asList(), listener1))
+ .withMessage("key/value mismatch");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> forwarder.register(Arrays.asList(VALUEA_REQID), listener1))
+ .withMessage("key/value mismatch");
+ }
+
+ @Test
+ public void testUnregister() {
+ // remove listener1b
+ forwarder.unregister(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1b);
+
+ StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ verify(listener1).accept(INFRA, TEXT, sco);
+ verify(listener1b, never()).accept(any(), any(), any());
+
+ // remove listener1
+ forwarder.unregister(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1);
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ // route a message to listener2
+ sco = makeMessage(Map.of(KEY1, VALUEB_REQID, KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+ verify(listener2).accept(INFRA, TEXT, sco);
+
+ // no more messages to listener1 or 1b
+ verify(listener1).accept(any(), any(), any());
+ verify(listener1b, never()).accept(any(), any(), any());
+ }
+
+ @Test
+ public void testOnMessage() {
+ StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ verify(listener1).accept(INFRA, TEXT, sco);
+ verify(listener1b).accept(INFRA, TEXT, sco);
+
+ // repeat - counts should increment
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ verify(listener1, times(2)).accept(INFRA, TEXT, sco);
+ verify(listener1b, times(2)).accept(INFRA, TEXT, sco);
+
+ // should not have been invoked
+ verify(listener2, never()).accept(any(), any(), any());
+ verify(listener3, never()).accept(any(), any(), any());
+
+ // try other listeners now
+ sco = makeMessage(Map.of(KEY1, VALUEB_REQID, KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+ verify(listener2).accept(INFRA, TEXT, sco);
+
+ sco = makeMessage(Map.of(KEY1, VALUEC_REQID, KEY2, Map.of(SUBKEY, VALUEC_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+ verify(listener3).accept(INFRA, TEXT, sco);
+
+ // message has no listeners
+ sco = makeMessage(Map.of(KEY1, "xyzzy", KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ // message doesn't have both keys
+ sco = makeMessage(Map.of(KEY1, VALUEA_REQID));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ // counts should not have incremented
+ verify(listener1, times(2)).accept(any(), any(), any());
+ verify(listener1b, times(2)).accept(any(), any(), any());
+ verify(listener2).accept(any(), any(), any());
+ verify(listener3).accept(any(), any(), any());
+
+ // listener throws an exception
+ doThrow(new IllegalStateException("expected exception")).when(listener1).accept(any(), any(), any());
+ }
+
+ /*
+ * Tests onMessage() when listener1 throws an exception.
+ */
+ @Test
+ public void testOnMessageListenerException1() {
+ doThrow(new IllegalStateException("expected exception")).when(listener1).accept(any(), any(), any());
+
+ StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ verify(listener1b).accept(INFRA, TEXT, sco);
+ }
+
+ /*
+ * Tests onMessage() when listener1b throws an exception.
+ */
+ @Test
+ public void testOnMessageListenerException1b() {
+ doThrow(new IllegalStateException("expected exception")).when(listener1b).accept(any(), any(), any());
+
+ StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ forwarder.onMessage(INFRA, TEXT, sco);
+
+ verify(listener1).accept(INFRA, TEXT, sco);
+ }
+
+ /**
+ * Makes a message from a map.
+ */
+ private StandardCoderObject makeMessage(Map<String, Object> map) {
+ return Util.translate("", map, StandardCoderObject.class);
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java
new file mode 100644
index 000000000..19df9c2d8
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Map;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.Util;
+
+public class SelectorKeyTest {
+ private static final String FIELD1 = "map";
+ private static final String FIELD2 = "abc";
+ private static final String FIELDX = "abd";
+
+ private SelectorKey key;
+
+ @Before
+ public void setUp() {
+ key = new SelectorKey(FIELD1, FIELD2);
+ }
+
+ @Test
+ public void testHashCode_testEquals() {
+ SelectorKey key2 = new SelectorKey(FIELD1, FIELD2);
+ assertEquals(key, key2);
+ assertEquals(key.hashCode(), key2.hashCode());
+
+ key2 = new SelectorKey(FIELD1, FIELDX);
+ assertNotEquals(key, key2);
+ assertNotEquals(key.hashCode(), key2.hashCode());
+
+ // test empty key
+ key = new SelectorKey();
+ key2 = new SelectorKey();
+ assertEquals(key, key2);
+ assertEquals(key.hashCode(), key2.hashCode());
+ }
+
+ @Test
+ public void testExtractField() {
+ Map<String, Object> map = Map.of("hello", "world", FIELD1, Map.of("another", "", FIELD2, "value B"));
+ StandardCoderObject sco = Util.translate("", map, StandardCoderObject.class);
+
+ String result = key.extractField(sco);
+ assertNotNull(result);
+ assertEquals("value B", result);
+
+ // shorter key
+ assertEquals("world", new SelectorKey("hello").extractField(sco));
+ assertNull(new SelectorKey("bye").extractField(sco));
+
+ // not found
+ assertNull(new SelectorKey(FIELD1, "not field 2").extractField(sco));
+
+ // test with empty key
+ assertNull(new SelectorKey().extractField(sco));
+ }
+
+ @Getter
+ @Setter
+ @Builder
+ protected static class Data {
+ private String text;
+ private Map<String, String> map;
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImplTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImplTest.java
new file mode 100644
index 000000000..a37085799
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImplTest.java
@@ -0,0 +1,154 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.PropertyUtils.TriConsumer;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+
+public class TopicListenerImplTest {
+ private static final StandardCoder coder = new StandardCoder();
+ private static final CommInfrastructure INFRA = CommInfrastructure.NOOP;
+ private static final String MY_TOPIC = "my-topic";
+ private static final String KEY1 = "requestId";
+ private static final String KEY2 = "container";
+ private static final String SUBKEY = "subRequestId";
+
+ private static final String VALUEA_REQID = "hello";
+ private static final String VALUEA_SUBREQID = "world";
+
+ private static final String VALUEB_REQID = "bye";
+
+ private Forwarder forwarder1;
+ private Forwarder forwarder2;
+ private TopicListenerImpl topic;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener1;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener1b;
+
+ @Mock
+ private TriConsumer<CommInfrastructure, String, StandardCoderObject> listener2;
+
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ topic = new TopicListenerImpl();
+
+ forwarder1 = topic.addForwarder(new SelectorKey(KEY1));
+ forwarder2 = topic.addForwarder(new SelectorKey(KEY1), new SelectorKey(KEY2, SUBKEY));
+
+ assertNotNull(forwarder1);
+ assertNotNull(forwarder2);
+ assertNotSame(forwarder1, forwarder2);
+
+ forwarder1.register(Arrays.asList(VALUEA_REQID), listener1);
+ forwarder1.register(Arrays.asList(VALUEB_REQID), listener1b);
+ forwarder2.register(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener2);
+ }
+
+ @Test
+ public void testShutdown() {
+ // shut it down, which should clear all forwarders
+ topic.shutdown();
+
+ // should get a new forwarder now
+ Forwarder forwarder = topic.addForwarder(new SelectorKey(KEY1));
+ assertNotSame(forwarder1, forwarder);
+ assertNotSame(forwarder2, forwarder);
+
+ // new forwarder should be unchanged
+ assertSame(forwarder, topic.addForwarder(new SelectorKey(KEY1)));
+ }
+
+ @Test
+ public void testAddForwarder() {
+ assertSame(forwarder1, topic.addForwarder(new SelectorKey(KEY1)));
+ assertSame(forwarder2, topic.addForwarder(new SelectorKey(KEY1), new SelectorKey(KEY2, SUBKEY)));
+ }
+
+ @Test
+ public void testOnTopicEvent() {
+ /*
+ * send a message that should go to listener1 on forwarder1 and listener2 on
+ * forwarder2
+ */
+ String msg = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ topic.onTopicEvent(INFRA, MY_TOPIC, msg);
+
+ verify(listener1).accept(eq(INFRA), eq(msg), any());
+ verify(listener2).accept(eq(INFRA), eq(msg), any());
+
+ // not to listener1b
+ verify(listener1b, never()).accept(any(), any(), any());
+
+ /*
+ * now send a message that should only go to listener1b on forwarder1
+ */
+ msg = makeMessage(Map.of(KEY1, VALUEB_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
+ topic.onTopicEvent(INFRA, MY_TOPIC, msg);
+
+ // should route to listener1 on forwarder1 and listener2 on forwarder2
+ verify(listener1b).accept(eq(INFRA), eq(msg), any());
+
+ // try one where the coder throws an exception
+ topic.onTopicEvent(INFRA, MY_TOPIC, "{invalid-json");
+
+ // no extra invocations
+ verify(listener1).accept(any(), any(), any());
+ verify(listener1b).accept(any(), any(), any());
+ verify(listener2).accept(any(), any(), any());
+ }
+
+ /**
+ * Makes a message from a map.
+ */
+ private String makeMessage(Map<String, Object> map) {
+ try {
+ return coder.encode(map);
+ } catch (CoderException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairTest.java
new file mode 100644
index 000000000..c6557d0c9
--- /dev/null
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicPairTest.java
@@ -0,0 +1,158 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 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=========================================================
+ */
+
+package org.onap.policy.controlloop.actorserviceprovider.topic;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+
+public class TopicPairTest {
+ private static final String UNKNOWN = "unknown";
+ private static final String MY_SOURCE = "pair-source";
+ private static final String MY_TARGET = "pair-target";
+ private static final String TEXT = "some text";
+
+ @Mock
+ private TopicSink publisher1;
+
+ @Mock
+ private TopicSink publisher2;
+
+ @Mock
+ private TopicSource subscriber1;
+
+ @Mock
+ private TopicSource subscriber2;
+
+ @Mock
+ private TopicEndpoint mgr;
+
+ private TopicPair pair;
+
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mgr.getTopicSinks(MY_TARGET)).thenReturn(Arrays.asList(publisher1, publisher2));
+ when(mgr.getTopicSources(eq(Arrays.asList(MY_SOURCE)))).thenReturn(Arrays.asList(subscriber1, subscriber2));
+
+ when(publisher1.getTopicCommInfrastructure()).thenReturn(CommInfrastructure.NOOP);
+ when(publisher2.getTopicCommInfrastructure()).thenReturn(CommInfrastructure.UEB);
+
+ pair = new MyTopicPair(MY_SOURCE, MY_TARGET);
+
+ pair.start();
+ }
+
+ @Test
+ public void testTopicPair_testGetSource_testGetTarget() {
+ assertEquals(MY_SOURCE, pair.getSource());
+ assertEquals(MY_TARGET, pair.getTarget());
+
+ verify(mgr).getTopicSinks(anyString());
+ verify(mgr).getTopicSources(any());
+
+ // source not found
+ assertThatIllegalArgumentException().isThrownBy(() -> new MyTopicPair(UNKNOWN, MY_TARGET))
+ .withMessageContaining("sources").withMessageContaining(UNKNOWN);
+
+ // target not found
+ assertThatIllegalArgumentException().isThrownBy(() -> new MyTopicPair(MY_SOURCE, UNKNOWN))
+ .withMessageContaining("sinks").withMessageContaining(UNKNOWN);
+ }
+
+ @Test
+ public void testShutdown() {
+ pair.shutdown();
+ verify(subscriber1).unregister(pair);
+ verify(subscriber2).unregister(pair);
+ }
+
+ @Test
+ public void testStart() {
+ verify(subscriber1).register(pair);
+ verify(subscriber2).register(pair);
+ }
+
+ @Test
+ public void testStop() {
+ pair.stop();
+ verify(subscriber1).unregister(pair);
+ verify(subscriber2).unregister(pair);
+ }
+
+ @Test
+ public void testPublish() {
+ List<CommInfrastructure> infrastructures = pair.publish(TEXT);
+ assertEquals(Arrays.asList(CommInfrastructure.NOOP, CommInfrastructure.UEB), infrastructures);
+
+ verify(publisher1).send(TEXT);
+ verify(publisher2).send(TEXT);
+
+ // first one throws an exception - should have only published to the second
+ when(publisher1.send(any())).thenThrow(new IllegalStateException("expected exception"));
+
+ infrastructures = pair.publish(TEXT);
+ assertEquals(Arrays.asList(CommInfrastructure.UEB), infrastructures);
+
+ verify(publisher2, times(2)).send(TEXT);
+ }
+
+ @Test
+ public void testGetTopicEndpointManager() {
+ // setting "mgr" to null should cause it to use the superclass' method
+ mgr = null;
+ assertNotNull(pair.getTopicEndpointManager());
+ }
+
+
+ private class MyTopicPair extends TopicPair {
+ public MyTopicPair(String source, String target) {
+ super(source, target);
+ }
+
+ @Override
+ protected TopicEndpoint getTopicEndpointManager() {
+ return (mgr != null ? mgr : super.getTopicEndpointManager());
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/resources/logback-test.xml b/models-interactions/model-actors/actorServiceProvider/src/test/resources/logback-test.xml
index 860468821..b11983bed 100644
--- a/models-interactions/model-actors/actorServiceProvider/src/test/resources/logback-test.xml
+++ b/models-interactions/model-actors/actorServiceProvider/src/test/resources/logback-test.xml
@@ -44,4 +44,11 @@
<logger name="org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation" level="info" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
+
+ <!-- this is required for TopicPairOperationTest -->
+ <logger
+ name="org.onap.policy.controlloop.actorserviceprovider.impl.TopicPairOperation"
+ level="info" additivity="false">
+ <appender-ref ref="STDOUT" />
+ </logger>
</configuration>
diff --git a/models-interactions/model-actors/pom.xml b/models-interactions/model-actors/pom.xml
index 029ac7f40..30891142d 100644
--- a/models-interactions/model-actors/pom.xml
+++ b/models-interactions/model-actors/pom.xml
@@ -37,6 +37,7 @@
<modules>
<module>actorServiceProvider</module>
<module>actor.test</module>
+ <module>actor.aai</module>
<module>actor.appc</module>
<module>actor.vfc</module>
<module>actor.sdnc</module>
diff --git a/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyLegacyOperationalPersistenceTest.java b/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyLegacyOperationalPersistenceTest.java
index 0eee4b2b6..30428b099 100644
--- a/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyLegacyOperationalPersistenceTest.java
+++ b/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyLegacyOperationalPersistenceTest.java
@@ -1,6 +1,7 @@
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
+ * Modifications Copyright (C) 2020 AT&T.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,15 +56,15 @@ public class PolicyLegacyOperationalPersistenceTest {
// @formatter:off
private String[] policyInputResourceNames = {
- "policies/vCPE.policy.operational.input.json",
- "policies/vDNS.policy.operational.input.json",
- "policies/vFirewall.policy.operational.input.json"
+ "policies/vCPE.policy.operational.legacy.input.json",
+ "policies/vDNS.policy.operational.legacy.input.json",
+ "policies/vFirewall.policy.operational.legacy.input.json"
};
private String[] policyOutputResourceNames = {
- "policies/vCPE.policy.operational.output.json",
- "policies/vDNS.policy.operational.output.json",
- "policies/vFirewall.policy.operational.output.json"
+ "policies/vCPE.policy.operational.legacy.output.json",
+ "policies/vDNS.policy.operational.legacy.output.json",
+ "policies/vFirewall.policy.operational.legacy.output.json"
};
// @formatter:on
@@ -148,8 +149,8 @@ public class PolicyLegacyOperationalPersistenceTest {
private void createPolicyTypes() throws CoderException, PfModelException, URISyntaxException {
Set<String> policyTypeResources = ResourceUtils.getDirectoryContents("policytypes");
- for (String policyTyoeResource : policyTypeResources) {
- Object yamlObject = new Yaml().load(ResourceUtils.getResourceAsString(policyTyoeResource));
+ for (String policyTypeResource : policyTypeResources) {
+ Object yamlObject = new Yaml().load(ResourceUtils.getResourceAsString(policyTypeResource));
String yamlAsJsonString = new StandardCoder().encode(yamlObject);
ToscaServiceTemplate toscaServiceTemplatePolicyType =
diff --git a/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyToscaPersistenceTest.java b/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyToscaPersistenceTest.java
index 0cdc2ad49..311686831 100644
--- a/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyToscaPersistenceTest.java
+++ b/models-provider/src/test/java/org/onap/policy/models/provider/impl/PolicyToscaPersistenceTest.java
@@ -36,6 +36,7 @@ import org.junit.Before;
import org.junit.Test;
import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
import org.onap.policy.common.utils.resources.ResourceUtils;
import org.onap.policy.models.base.PfModelException;
import org.onap.policy.models.provider.PolicyModelsProvider;
@@ -44,7 +45,8 @@ import org.onap.policy.models.provider.PolicyModelsProviderParameters;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter;
import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
-import org.yaml.snakeyaml.Yaml;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Test persistence of monitoring policies to and from the database.
@@ -52,7 +54,10 @@ import org.yaml.snakeyaml.Yaml;
* @author Liam Fallon (liam.fallon@est.tech)
*/
public class PolicyToscaPersistenceTest {
- private StandardCoder standardCoder;
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolicyToscaPersistenceTest.class);
+
+ private YamlJsonTranslator yamlJsonTranslator = new YamlJsonTranslator();
+ private StandardCoder standardCoder = new StandardCoder();
private PolicyModelsProvider databaseProvider;
@@ -78,14 +83,6 @@ public class PolicyToscaPersistenceTest {
createPolicyTypes();
}
- /**
- * Set up standard coder.
- */
- @Before
- public void setupStandardCoder() {
- standardCoder = new StandardCoder();
- }
-
@After
public void teardown() throws Exception {
databaseProvider.close();
@@ -103,29 +100,44 @@ public class PolicyToscaPersistenceTest {
String policyString = ResourceUtils.getResourceAsString(policyResource);
if (policyResource.endsWith("yaml")) {
- testYamlStringPolicyPersistence(policyString);
+ testPolicyPersistence(yamlJsonTranslator.fromYaml(policyString, ToscaServiceTemplate.class));
} else {
- testJsonStringPolicyPersistence(policyString);
+ testPolicyPersistence(standardCoder.decode(policyString, ToscaServiceTemplate.class));
}
}
}
- private void testYamlStringPolicyPersistence(final String policyString) throws Exception {
- Object yamlObject = new Yaml().load(policyString);
- String yamlAsJsonString = new StandardCoder().encode(yamlObject);
+ @Test
+ public void testNamingPolicyGet() throws PfModelException {
+ String policyYamlString = ResourceUtils.getResourceAsString("policies/sdnc.policy.naming.input.tosca.yaml");
+ ToscaServiceTemplate serviceTemplate =
+ yamlJsonTranslator.fromYaml(policyYamlString, ToscaServiceTemplate.class);
- testJsonStringPolicyPersistence(yamlAsJsonString);
+ long createStartTime = System.currentTimeMillis();
+ databaseProvider.createPolicies(serviceTemplate);
+ LOGGER.trace("Naming policy create time (ms): {}", System.currentTimeMillis() - createStartTime);
+
+ long getStartTime = System.currentTimeMillis();
+ ToscaServiceTemplate namingServiceTemplate =
+ databaseProvider.getPolicies("SDNC_Policy.ONAP_VNF_NAMING_TIMESTAMP", "1.0.0");
+ LOGGER.trace("Naming policy get time (ms): {}", System.currentTimeMillis() - getStartTime);
+
+ assertEquals(1, namingServiceTemplate.getToscaTopologyTemplate().getPoliciesAsMap().size());
+ assertEquals(1, namingServiceTemplate.getPolicyTypesAsMap().size());
+ assertEquals(3, namingServiceTemplate.getDataTypesAsMap().size());
+
+ long deleteStartTime = System.currentTimeMillis();
+ databaseProvider.deletePolicy("SDNC_Policy.ONAP_VNF_NAMING_TIMESTAMP", "1.0.0");
+ LOGGER.trace("Naming policy delete time (ms): {}", System.currentTimeMillis() - deleteStartTime);
}
/**
* Check persistence of a policy.
*
- * @param policyString the policy as a string
+ * @param serviceTemplate the service template containing the policy
* @throws Exception any exception thrown
*/
- public void testJsonStringPolicyPersistence(@NonNull final String policyString) throws Exception {
- ToscaServiceTemplate serviceTemplate = standardCoder.decode(policyString, ToscaServiceTemplate.class);
-
+ public void testPolicyPersistence(@NonNull final ToscaServiceTemplate serviceTemplate) throws Exception {
assertNotNull(serviceTemplate);
databaseProvider.createPolicies(serviceTemplate);
@@ -170,11 +182,9 @@ public class PolicyToscaPersistenceTest {
Set<String> policyTypeResources = ResourceUtils.getDirectoryContents("policytypes");
for (String policyTypeResource : policyTypeResources) {
- Object yamlObject = new Yaml().load(ResourceUtils.getResourceAsString(policyTypeResource));
- String yamlAsJsonString = new StandardCoder().encode(yamlObject);
-
+ String policyTypeYamlString = ResourceUtils.getResourceAsString(policyTypeResource);
ToscaServiceTemplate toscaServiceTemplatePolicyType =
- standardCoder.decode(yamlAsJsonString, ToscaServiceTemplate.class);
+ yamlJsonTranslator.fromYaml(policyTypeYamlString, ToscaServiceTemplate.class);
assertNotNull(toscaServiceTemplatePolicyType);
databaseProvider.createPolicyTypes(toscaServiceTemplatePolicyType);
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProvider.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProvider.java
index 6e60303a0..a65cdbe69 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProvider.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProvider.java
@@ -423,6 +423,7 @@ public class AuthorativeToscaProvider {
*/
private <T extends ToscaEntity> List<T> handlePfModelRuntimeException(final PfModelRuntimeException pfme) {
if (Status.NOT_FOUND.equals(pfme.getErrorResponse().getResponseCode())) {
+ LOGGER.trace("request did not find any results", pfme);
return Collections.emptyList();
} else {
throw pfme;
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider.java
index f5335fe79..09cc6c0ca 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider.java
@@ -93,13 +93,13 @@ public class LegacyProvider {
LOGGER.debug("->createOperationalPolicy: legacyOperationalPolicy={}", legacyOperationalPolicy);
- JpaToscaServiceTemplate incomingServiceTemplate =
+ JpaToscaServiceTemplate legacyOperationalServiceTemplate =
new LegacyOperationalPolicyMapper().toToscaServiceTemplate(legacyOperationalPolicy);
- JpaToscaServiceTemplate outgoingingServiceTemplate =
- new SimpleToscaProvider().createPolicies(dao, incomingServiceTemplate);
+
+ new SimpleToscaProvider().createPolicies(dao, legacyOperationalServiceTemplate);
LegacyOperationalPolicy createdLegacyOperationalPolicy =
- new LegacyOperationalPolicyMapper().fromToscaServiceTemplate(outgoingingServiceTemplate);
+ new LegacyOperationalPolicyMapper().fromToscaServiceTemplate(legacyOperationalServiceTemplate);
LOGGER.debug("<-createOperationalPolicy: createdLegacyOperationalPolicy={}", createdLegacyOperationalPolicy);
return createdLegacyOperationalPolicy;
@@ -223,7 +223,6 @@ public class LegacyProvider {
return updatedLegacyGuardPolicyMap;
}
-
/**
* Delete legacy guard policy.
*
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicy.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicy.java
index 2816df004..b500a8bc9 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicy.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicy.java
@@ -261,6 +261,11 @@ public class JpaToscaPolicy extends JpaToscaEntityType<ToscaPolicy> implements P
public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
PfValidationResult result = super.validate(resultIn);
+ if (PfKey.NULL_KEY_VERSION.equals(getKey().getVersion())) {
+ result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
+ "key version is a null version"));
+ }
+
if (type == null || type.isNullKey()) {
result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
"type is null or a null key"));
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicyType.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicyType.java
index b068beaa0..423620dd7 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicyType.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/concepts/JpaToscaPolicyType.java
@@ -203,6 +203,11 @@ public class JpaToscaPolicyType extends JpaToscaEntityType<ToscaPolicyType> impl
public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
PfValidationResult result = super.validate(resultIn);
+ if (PfKey.NULL_KEY_VERSION.equals(getKey().getVersion())) {
+ result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
+ "key version is a null version"));
+ }
+
if (properties != null) {
result = validateProperties(result);
}
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/provider/SimpleToscaProvider.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/provider/SimpleToscaProvider.java
index 9c7d6d305..c537bbcb5 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/provider/SimpleToscaProvider.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/simple/provider/SimpleToscaProvider.java
@@ -106,7 +106,7 @@ public class SimpleToscaProvider {
PfValidationResult result = serviceTemplateToWrite.validate(new PfValidationResult());
if (!result.isValid()) {
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, result.toString());
+ throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, result.toString());
}
new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplateToWrite);
@@ -264,6 +264,9 @@ public class SimpleToscaProvider {
"policy types for " + name + ":" + version + DO_NOT_EXIST);
}
+ JpaToscaServiceTemplate dataTypeServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
+ dataTypeServiceTemplate.setPolicyTypes(null);
+
for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getConceptMap().values()) {
Collection<PfConceptKey> referencedDataTypeKeys = policyType.getReferencedDataTypes();
@@ -271,11 +274,13 @@ public class SimpleToscaProvider {
JpaToscaServiceTemplate dataTypeEntityTreeServiceTemplate =
getDataTypes(dao, referencedDataTypeKey.getName(), referencedDataTypeKey.getVersion());
- serviceTemplate =
- ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeEntityTreeServiceTemplate);
+ dataTypeServiceTemplate = ToscaServiceTemplateUtils.addFragment(dataTypeServiceTemplate,
+ dataTypeEntityTreeServiceTemplate);
}
}
+ serviceTemplate = ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeServiceTemplate);
+
LOGGER.debug("<-getPolicyTypes: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
return serviceTemplate;
}
@@ -372,7 +377,11 @@ public class SimpleToscaProvider {
throws PfModelException {
LOGGER.debug("->getPolicies: name={}, version={}", name, version);
- JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
+ JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
+
+ JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
+ serviceTemplate.setDataTypes(new JpaToscaDataTypes());
+ serviceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
if (!ToscaUtils.doPoliciesExist(serviceTemplate)) {
throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
@@ -386,18 +395,20 @@ public class SimpleToscaProvider {
"policies for " + name + ":" + version + DO_NOT_EXIST);
}
+ JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
+ returnServiceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
+
for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().values()) {
- if (policy.getDerivedFrom() != null) {
- JpaToscaServiceTemplate referencedEntitiesServiceTemplate =
- getPolicyTypes(dao, policy.getDerivedFrom().getName(), policy.getDerivedFrom().getVersion());
+ JpaToscaServiceTemplate referencedEntitiesServiceTemplate =
+ getPolicyTypes(dao, policy.getType().getName(), policy.getType().getVersion());
- serviceTemplate =
- ToscaServiceTemplateUtils.addFragment(serviceTemplate, referencedEntitiesServiceTemplate);
- }
+ returnServiceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policy.getKey(), policy);
+ returnServiceTemplate =
+ ToscaServiceTemplateUtils.addFragment(returnServiceTemplate, referencedEntitiesServiceTemplate);
}
- LOGGER.debug("<-getPolicies: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
- return serviceTemplate;
+ LOGGER.debug("<-getPolicies: name={}, version={}, serviceTemplate={}", name, version, returnServiceTemplate);
+ return returnServiceTemplate;
}
/**
@@ -497,7 +508,7 @@ public class SimpleToscaProvider {
if (policyType == null) {
String errorMessage =
"policy type " + policyTypeKey.getId() + " for policy " + policy.getId() + " does not exist";
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, errorMessage);
+ throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, errorMessage);
}
}
@@ -526,7 +537,7 @@ public class SimpleToscaProvider {
// We should have one and only one returned entry
if (filterdPolicyTypeList.size() != 1) {
String errorMessage = "search for latest policy type " + policyTypeName + " returned more than one entry";
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, errorMessage);
+ throw new PfModelRuntimeException(Response.Status.CONFLICT, errorMessage);
}
return (JpaToscaPolicyType) filterdPolicyTypeList.get(0);
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtils.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtils.java
index 87b499b4c..6f21c1942 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtils.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtils.java
@@ -74,7 +74,7 @@ public class ToscaServiceTemplateUtils {
compositeTemplate.setPolicyTypes(
addFragmentEntitites(compositeTemplate.getPolicyTypes(), fragmentTemplate.getPolicyTypes(), result));
- if (originalTemplate.getTopologyTemplate() != null) {
+ if (originalTemplate.getTopologyTemplate() != null && fragmentTemplate.getTopologyTemplate() != null) {
if (originalTemplate.getTopologyTemplate()
.compareToWithoutEntities(fragmentTemplate.getTopologyTemplate()) == 0) {
compositeTemplate.getTopologyTemplate()
@@ -95,7 +95,7 @@ public class ToscaServiceTemplateUtils {
if (!result.isValid()) {
String message = result.toString();
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, message);
+ throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, message);
}
return compositeTemplate;
diff --git a/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaUtils.java b/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaUtils.java
index cc0431946..b75273e5e 100644
--- a/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaUtils.java
+++ b/models-tosca/src/main/java/org/onap/policy/models/tosca/utils/ToscaUtils.java
@@ -147,7 +147,7 @@ public final class ToscaUtils {
final Function<JpaToscaServiceTemplate, String> checkerFunction) {
String message = checkerFunction.apply(serviceTemplate);
if (message != null) {
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, message);
+ throw new PfModelRuntimeException(Response.Status.NOT_FOUND, message);
}
}
@@ -263,7 +263,7 @@ public final class ToscaUtils {
}
if (!result.isValid()) {
- throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, result.toString());
+ throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, result.toString());
}
entityTypes.getConceptMap().entrySet()
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyFilterTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyFilterTest.java
index 0bf371022..858ac09fe 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyFilterTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyFilterTest.java
@@ -87,6 +87,7 @@ public class ToscaPolicyFilterTest {
for (String policyResourceName : policyResourceNames) {
String policyString = ResourceUtils.getResourceAsString(policyResourceName);
if (policyResourceName.endsWith("yaml")) {
+ LOGGER.info("loading {}", policyResourceName);
Object yamlObject = new Yaml().load(policyString);
policyString = new GsonBuilder().setPrettyPrinting().create().toJson(yamlObject);
}
@@ -150,7 +151,7 @@ public class ToscaPolicyFilterTest {
assertEquals(VERSION_100, filteredList.get(7).getVersion());
assertEquals(VERSION_100, filteredList.get(12).getVersion());
- assertEquals(24, policyList.size());
+ assertEquals(23, policyList.size());
assertEquals(22, filteredList.size());
policyList.get(10).setVersion("2.0.0");
@@ -172,7 +173,7 @@ public class ToscaPolicyFilterTest {
public void testFilterNameVersion() {
ToscaPolicyFilter filter = ToscaPolicyFilter.builder().name("operational.modifyconfig").build();
List<ToscaPolicy> filteredList = filter.filter(policyList);
- assertEquals(2, filteredList.size());
+ assertEquals(1, filteredList.size());
filter = ToscaPolicyFilter.builder().name("guard.frequency.scaleout").build();
filteredList = filter.filter(policyList);
@@ -184,7 +185,7 @@ public class ToscaPolicyFilterTest {
filter = ToscaPolicyFilter.builder().version(VERSION_100).build();
filteredList = filter.filter(policyList);
- assertEquals(22, filteredList.size());
+ assertEquals(21, filteredList.size());
filter = ToscaPolicyFilter.builder().name("OSDF_CASABLANCA.SubscriberPolicy_v1").version(VERSION_100).build();
filteredList = filter.filter(policyList);
@@ -192,7 +193,7 @@ public class ToscaPolicyFilterTest {
filter = ToscaPolicyFilter.builder().name("operational.modifyconfig").version(VERSION_100).build();
filteredList = filter.filter(policyList);
- assertEquals(1, filteredList.size());
+ assertEquals(0, filteredList.size());
}
@Test
@@ -200,11 +201,11 @@ public class ToscaPolicyFilterTest {
// null pattern
ToscaPolicyFilter filter = ToscaPolicyFilter.builder().versionPrefix(null).build();
List<ToscaPolicy> filteredList = filter.filter(policyList);
- assertEquals(24, filteredList.size());
+ assertEquals(23, filteredList.size());
filter = ToscaPolicyFilter.builder().versionPrefix("1.").build();
filteredList = filter.filter(policyList);
- assertEquals(22, filteredList.size());
+ assertEquals(21, filteredList.size());
filter = ToscaPolicyFilter.builder().versionPrefix("100.").build();
filteredList = filter.filter(policyList);
@@ -215,7 +216,11 @@ public class ToscaPolicyFilterTest {
public void testFilterTypeVersion() {
ToscaPolicyFilter filter = ToscaPolicyFilter.builder().type("onap.policies.controlloop.Operational").build();
List<ToscaPolicy> filteredList = filter.filter(policyList);
- assertEquals(1, filteredList.size());
+ assertEquals(0, filteredList.size());
+
+ filter = ToscaPolicyFilter.builder().type("onap.policies.controlloop.operational.common.Apex").build();
+ filteredList = filter.filter(policyList);
+ assertEquals(0, filteredList.size());
filter = ToscaPolicyFilter.builder().type("onap.policies.controlloop.operational.common.Drools").build();
filteredList = filter.filter(policyList);
@@ -231,7 +236,7 @@ public class ToscaPolicyFilterTest {
filter = ToscaPolicyFilter.builder().typeVersion(VERSION_000).build();
filteredList = filter.filter(policyList);
- assertEquals(4, filteredList.size());
+ assertEquals(3, filteredList.size());
filter = ToscaPolicyFilter.builder().type("onap.policies.optimization.resource.HpaPolicy")
.typeVersion(VERSION_100).build();
@@ -241,6 +246,6 @@ public class ToscaPolicyFilterTest {
filter = ToscaPolicyFilter.builder().type("onap.policies.controlloop.Operational").typeVersion(VERSION_000)
.build();
filteredList = filter.filter(policyList);
- assertEquals(1, filteredList.size());
+ assertEquals(0, filteredList.size());
}
}
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyTypeFilterTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyTypeFilterTest.java
index 30696ce9d..0f038d3cd 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyTypeFilterTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/concepts/ToscaPolicyTypeFilterTest.java
@@ -163,7 +163,7 @@ public class ToscaPolicyTypeFilterTest {
public void testFilterNameVersion() {
ToscaPolicyTypeFilter filter = ToscaPolicyTypeFilter.builder().name("onap.policies.Monitoring").build();
List<ToscaPolicyType> filteredList = filter.filter(typeList);
- assertEquals(2, filteredList.size());
+ assertEquals(1, filteredList.size());
filter = ToscaPolicyTypeFilter.builder().name("onap.policies.monitoring.cdap.tca.hi.lo.app").build();
filteredList = filter.filter(typeList);
@@ -173,9 +173,9 @@ public class ToscaPolicyTypeFilterTest {
filteredList = filter.filter(typeList);
assertEquals(0, filteredList.size());
- filter = ToscaPolicyTypeFilter.builder().version(VERSION_000).build();
+ filter = ToscaPolicyTypeFilter.builder().version(VERSION_100).build();
filteredList = filter.filter(typeList);
- assertEquals(1, filteredList.size());
+ assertEquals(20, filteredList.size());
filter = ToscaPolicyTypeFilter.builder().name("onap.policies.optimization.Vim_fit").version(VERSION_000)
.build();
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProviderPolicyTypeTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProviderPolicyTypeTest.java
index ae350bd90..3f0d9e2a5 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProviderPolicyTypeTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/authorative/provider/AuthorativeToscaProviderPolicyTypeTest.java
@@ -58,11 +58,11 @@ import org.yaml.snakeyaml.Yaml;
*/
public class AuthorativeToscaProviderPolicyTypeTest {
private static final String VERSION = "version";
- private static final String POLICY_NO_VERSION_VERSION0 = "onap.policies.NoVersion:0.0.0";
+ private static final String POLICY_NO_VERSION_VERSION1 = "onap.policies.NoVersion:0.0.1";
private static final String POLICY_NO_VERSION = "onap.policies.NoVersion";
private static final String MISSING_POLICY_TYPES = "no policy types specified on service template";
private static final String DAO_IS_NULL = "^dao is marked .*on.*ull but is null$";
- private static final String VERSION_000 = "0.0.0";
+ private static final String VERSION_001 = "0.0.1";
private static String yamlAsJsonString;
private PfDao pfDao;
private StandardCoder standardCoder;
@@ -135,7 +135,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
ToscaServiceTemplate createdServiceTemplate =
new AuthorativeToscaProvider().createPolicyTypes(pfDao, toscaServiceTemplate);
- PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION0);
+ PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION1);
ToscaPolicyType beforePolicyType = toscaServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
ToscaPolicyType createdPolicyType = createdServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
@@ -150,7 +150,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
assertEquals(0, ObjectUtils.compare(beforePolicyType.getDescription(), createdPolicyType.getDescription()));
List<ToscaPolicyType> gotPolicyTypeList =
- new AuthorativeToscaProvider().getPolicyTypeList(pfDao, POLICY_NO_VERSION, VERSION_000);
+ new AuthorativeToscaProvider().getPolicyTypeList(pfDao, POLICY_NO_VERSION, VERSION_001);
assertEquals(2, gotPolicyTypeList.size());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
@@ -162,14 +162,14 @@ public class AuthorativeToscaProviderPolicyTypeTest {
assertEquals(2, gotPolicyTypeList.size());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
- gotPolicyTypeList = new AuthorativeToscaProvider().getPolicyTypeList(pfDao, null, VERSION_000);
+ gotPolicyTypeList = new AuthorativeToscaProvider().getPolicyTypeList(pfDao, null, VERSION_001);
assertEquals(2, gotPolicyTypeList.size());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
assertThatThrownBy(() -> new AuthorativeToscaProvider().getPolicyTypeList(new DefaultPfDao(), POLICY_NO_VERSION,
- VERSION_000)).hasMessageContaining("Policy Framework DAO has not been initialized");
+ VERSION_001)).hasMessageContaining("Policy Framework DAO has not been initialized");
- assertTrue(new AuthorativeToscaProvider().getPolicyTypeList(pfDao, "i.dont.Exist", VERSION_000).isEmpty());
+ assertTrue(new AuthorativeToscaProvider().getPolicyTypeList(pfDao, "i.dont.Exist", VERSION_001).isEmpty());
}
@Test
@@ -212,7 +212,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
ToscaServiceTemplate createdServiceTemplate =
new AuthorativeToscaProvider().createPolicyTypes(pfDao, toscaServiceTemplate);
- PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION0);
+ PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION1);
ToscaPolicyType beforePolicyType = toscaServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
ToscaPolicyType createdPolicyType = createdServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
@@ -234,14 +234,14 @@ public class AuthorativeToscaProviderPolicyTypeTest {
assertEquals(0, ObjectUtils.compare(beforePolicyType.getDescription(), gotPolicyType.getDescription()));
gotServiceTemplate = new AuthorativeToscaProvider().getFilteredPolicyTypes(pfDao,
- ToscaPolicyTypeFilter.builder().name(policyTypeKey.getName()).version(VERSION_000).build());
+ ToscaPolicyTypeFilter.builder().name(policyTypeKey.getName()).version(VERSION_001).build());
gotPolicyType = gotServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
assertEquals(0, ObjectUtils.compare(beforePolicyType.getDescription(), gotPolicyType.getDescription()));
List<ToscaPolicyType> gotPolicyTypeList =
- new AuthorativeToscaProvider().getPolicyTypeList(pfDao, POLICY_NO_VERSION, VERSION_000);
+ new AuthorativeToscaProvider().getPolicyTypeList(pfDao, POLICY_NO_VERSION, VERSION_001);
assertEquals(2, gotPolicyTypeList.size());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
@@ -256,7 +256,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
gotPolicyTypeList = new AuthorativeToscaProvider().getFilteredPolicyTypeList(pfDao,
- ToscaPolicyTypeFilter.builder().name(policyTypeKey.getName()).version(VERSION_000).build());
+ ToscaPolicyTypeFilter.builder().name(policyTypeKey.getName()).version(VERSION_001).build());
assertEquals(1, gotPolicyTypeList.size());
assertEquals(true, beforePolicyType.getName().equals(gotPolicyType.getName()));
@@ -296,7 +296,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
ToscaServiceTemplate createdServiceTemplate =
new AuthorativeToscaProvider().createPolicyTypes(pfDao, toscaServiceTemplate);
- PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION0);
+ PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION1);
ToscaPolicyType beforePolicyType = toscaServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
ToscaPolicyType createdPolicyType = createdServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
@@ -328,7 +328,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
ToscaServiceTemplate createdServiceTemplate =
new AuthorativeToscaProvider().createPolicyTypes(pfDao, toscaServiceTemplate);
- PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION0);
+ PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION1);
ToscaPolicyType beforePolicyType = toscaServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
ToscaPolicyType createdPolicyType = createdServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
@@ -379,7 +379,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
ToscaServiceTemplate createdServiceTemplate =
new AuthorativeToscaProvider().createPolicyTypes(pfDao, toscaServiceTemplate);
- PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION0);
+ PfConceptKey policyTypeKey = new PfConceptKey(POLICY_NO_VERSION_VERSION1);
ToscaPolicyType beforePolicyType = toscaServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
ToscaPolicyType createdPolicyType = createdServiceTemplate.getPolicyTypes().get(policyTypeKey.getName());
@@ -395,7 +395,7 @@ public class AuthorativeToscaProviderPolicyTypeTest {
assertThatThrownBy(() -> {
new AuthorativeToscaProvider().getPolicyTypes(pfDao, policyTypeKey.getName(), policyTypeKey.getVersion());
- }).hasMessage("policy types for onap.policies.NoVersion:0.0.0 do not exist");
+ }).hasMessage("policy types for onap.policies.NoVersion:0.0.1 do not exist");
}
@Test
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/mapping/LegacyOperationalPolicyMapperTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/mapping/LegacyOperationalPolicyMapperTest.java
index 0aa1da0d7..4dcfeafc9 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/mapping/LegacyOperationalPolicyMapperTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/mapping/LegacyOperationalPolicyMapperTest.java
@@ -1,7 +1,7 @@
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
- * Modifications Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2019-2020 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.
@@ -71,7 +71,7 @@ public class LegacyOperationalPolicyMapperTest {
JpaToscaServiceTemplate policyTypeServiceTemplate = new JpaToscaServiceTemplate();
policyTypeServiceTemplate.fromAuthorative(policyTypes);
- String vcpePolicyJson = ResourceUtils.getResourceAsString("policies/vCPE.policy.operational.input.json");
+ String vcpePolicyJson = ResourceUtils.getResourceAsString("policies/vCPE.policy.operational.legacy.input.json");
LegacyOperationalPolicy legacyOperationalPolicy =
standardCoder.decode(vcpePolicyJson, LegacyOperationalPolicy.class);
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider4LegacyOperationalTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider4LegacyOperationalTest.java
index ec03122a6..4d0fd6fd6 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider4LegacyOperationalTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/legacy/provider/LegacyProvider4LegacyOperationalTest.java
@@ -1,7 +1,7 @@
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
- * Modifications Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2019-2020 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.
@@ -51,8 +51,8 @@ import org.yaml.snakeyaml.Yaml;
*/
public class LegacyProvider4LegacyOperationalTest {
private static final String POLICY_ID_IS_NULL = "^policyId is marked .*on.*ull but is null$";
- private static final String VCPE_OUTPUT_JSON = "policies/vCPE.policy.operational.output.json";
- private static final String VCPE_INPUT_JSON = "policies/vCPE.policy.operational.input.json";
+ private static final String VCPE_OUTPUT_JSON = "policies/vCPE.policy.operational.legacy.output.json";
+ private static final String VCPE_INPUT_JSON = "policies/vCPE.policy.operational.legacy.input.json";
private static final String DAO_IS_NULL = "^dao is marked .*on.*ull but is null$";
private PfDao pfDao;
private StandardCoder standardCoder;
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/simple/serialization/MonitoringPolicyTypeSerializationTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/simple/serialization/MonitoringPolicyTypeSerializationTest.java
index 01a52f7bd..0a8283e98 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/simple/serialization/MonitoringPolicyTypeSerializationTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/simple/serialization/MonitoringPolicyTypeSerializationTest.java
@@ -1,7 +1,7 @@
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 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.
@@ -155,9 +155,9 @@ public class MonitoringPolicyTypeSerializationTest {
Entry<PfConceptKey, JpaToscaPolicyType> firstPolicyType = policyTypesIter.next();
assertEquals(MONITORING, firstPolicyType.getKey().getName());
- assertEquals(VERSION_000, firstPolicyType.getKey().getVersion());
+ assertEquals(VERSION_100, firstPolicyType.getKey().getVersion());
assertEquals("tosca.policies.Root", firstPolicyType.getValue().getDerivedFrom().getName());
- assertEquals("a base policy type for all policies that governs monitoring provisioning",
+ assertEquals("a base policy type for all policies that govern monitoring provisioning",
firstPolicyType.getValue().getDescription());
Entry<PfConceptKey, JpaToscaPolicyType> secondPolicyType = policyTypesIter.next();
@@ -376,13 +376,13 @@ public class MonitoringPolicyTypeSerializationTest {
assertEquals(MONITORING, firstPolicyType.getKey().getName());
assertEquals(VERSION_100, firstPolicyType.getKey().getVersion());
assertEquals("tosca.policies.Root", firstPolicyType.getValue().getDerivedFrom().getName());
- assertEquals("a base policy type for all policies that govern monitoring provision",
+ assertEquals("a base policy type for all policies that govern monitoring provisioning",
firstPolicyType.getValue().getDescription());
Entry<PfConceptKey, JpaToscaPolicyType> secondPolicyType = policyTypesIter.next();
assertEquals(DCAE, secondPolicyType.getKey().getName());
assertEquals(VERSION_100, secondPolicyType.getKey().getVersion());
- assertEquals("policy.nodes.Root", secondPolicyType.getValue().getDerivedFrom().getName());
+ assertEquals("onap.policies.Monitoring", secondPolicyType.getValue().getDerivedFrom().getName());
assertTrue(secondPolicyType.getValue().getProperties().size() == 2);
Iterator<JpaToscaProperty> propertiesIter = secondPolicyType.getValue().getProperties().values().iterator();
diff --git a/models-tosca/src/test/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtilsTest.java b/models-tosca/src/test/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtilsTest.java
index ca46de1c3..f9a0143fd 100644
--- a/models-tosca/src/test/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtilsTest.java
+++ b/models-tosca/src/test/java/org/onap/policy/models/tosca/utils/ToscaServiceTemplateUtilsTest.java
@@ -201,5 +201,19 @@ public class ToscaServiceTemplateUtilsTest {
assertEquals(dt1, dtIterator.next());
assertEquals(pt0, compositeTemplate05.getPolicyTypes().getAll(null).iterator().next());
assertEquals(p0, compositeTemplate05.getTopologyTemplate().getPolicies().getAll(null).iterator().next());
+
+ JpaToscaServiceTemplate fragmentTemplate09 = new JpaToscaServiceTemplate();
+
+ fragmentTemplate09.setDataTypes(new JpaToscaDataTypes());
+ fragmentTemplate09.getDataTypes().getConceptMap().put(dt1.getKey(), dt1);
+
+ fragmentTemplate09.setPolicyTypes(new JpaToscaPolicyTypes());
+ fragmentTemplate09.getPolicyTypes().getConceptMap().put(pt0.getKey(), pt0);
+
+ fragmentTemplate09.setTopologyTemplate(null);
+
+ JpaToscaServiceTemplate compositeTemplate06 =
+ ToscaServiceTemplateUtils.addFragment(compositeTemplate05, fragmentTemplate09);
+ assertEquals(compositeTemplate05.getTopologyTemplate(), compositeTemplate06.getTopologyTemplate());
}
}
diff --git a/models-tosca/src/test/resources/onap.policies.NoVersion.yaml b/models-tosca/src/test/resources/onap.policies.NoVersion.yaml
index 5923eb22d..2dda556a6 100644
--- a/models-tosca/src/test/resources/onap.policies.NoVersion.yaml
+++ b/models-tosca/src/test/resources/onap.policies.NoVersion.yaml
@@ -6,6 +6,7 @@ policy_types:
description: The base policy type for all policies that govern optimization
onap.policies.NoVersion:
derived_from: onap.policies.Optimization
+ version: 0.0.1
properties:
applicableResources:
type: list