diff options
20 files changed, 881 insertions, 189 deletions
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 index a65a000ed..0fe70b7ea 100644 --- 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 @@ -38,10 +38,7 @@ public class AaiActorServiceProvider extends HttpActor<HttpActorParams> { super(NAME, HttpActorParams.class); addOperator(new HttpOperator(NAME, AaiCustomQueryOperation.NAME, AaiCustomQueryOperation::new)); - - // add all "get" operators - for (String operation : AaiGetOperation.OPERATIONS) { - addOperator(new HttpOperator(NAME, operation, AaiGetOperation::new)); - } + addOperator(new HttpOperator(NAME, AaiGetTenantOperation.NAME, AaiGetTenantOperation::new)); + addOperator(new HttpOperator(NAME, AaiGetPnfOperation.NAME, AaiGetPnfOperation::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 index b00928847..2cc2a69f4 100644 --- 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 @@ -84,10 +84,10 @@ public class AaiCustomQueryOperation extends HttpOperation<String> { @Override protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { ControlLoopOperationParams tenantParams = - params.toBuilder().actor(AaiConstants.ACTOR_NAME).operation(AaiGetOperation.TENANT) + params.toBuilder().actor(AaiConstants.ACTOR_NAME).operation(AaiGetTenantOperation.NAME) .targetEntity(vserver).payload(null).retry(null).timeoutSec(null).build(); - return params.getContext().obtain(AaiGetOperation.getTenantKey(vserver), tenantParams); + return params.getContext().obtain(AaiGetTenantOperation.getKey(vserver), tenantParams); } @Override @@ -137,7 +137,7 @@ public class AaiCustomQueryOperation extends HttpOperation<String> { * Constructs the custom query using the previously retrieved tenant data. */ private Map<String, String> makeRequest() { - StandardCoderObject tenant = params.getContext().getProperty(AaiGetOperation.getTenantKey(vserver)); + StandardCoderObject tenant = params.getContext().getProperty(AaiGetTenantOperation.getKey(vserver)); String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK); if (resourceLink == null) { 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 index a20200807..07738b084 100644 --- 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 @@ -22,15 +22,10 @@ package org.onap.policy.controlloop.actor.aai; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.concurrent.CompletableFuture; import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.onap.policy.aai.AaiConstants; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation; @@ -49,17 +44,6 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> { 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 @@ -78,50 +62,22 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> { this.propertyPrefix = 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 public void generateSubRequestId(int attempt) { setSubRequestId(String.valueOf(attempt)); } - @Override - protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) { - Map<String, Object> headers = makeHeaders(); - - headers.put("Accept", MediaType.APPLICATION_JSON); - - StringBuilder str = new StringBuilder(getClient().getBaseUrl()); - - String path = getPath(); - WebTarget web = getClient().getWebTarget().path(path); - str.append(path); - - web = addQuery(web, str, "?", "search-node-type", "vserver"); - web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + params.getTargetEntity()); - - Builder webldr = web.request(); - for (Entry<String, Object> header : headers.entrySet()) { - webldr.header(header.getKey(), header.getValue()); - } - - String url = str.toString(); - - logMessage(EventType.OUT, CommInfrastructure.REST, url, null); - - return handleResponse(outcome, url, callback -> webldr.async().get(callback)); - } - - private WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) { + /** + * Adds a query parameter to a web target. + * + * @param web target to which the parameter should be added + * @param str the separator and parameter are appended here, for logging purposes + * @param separator separator to be added to "str"; that's its only use + * @param name parameter name + * @param value parameter value + * @return "web" + */ + protected WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) { str.append(separator); str.append(name); str.append('='); @@ -130,6 +86,18 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> { return web.queryParam(name, value); } + /** + * Adds headers to the web builder. + * + * @param webldr builder to which the headers should be added + * @param headers headers to be added + */ + protected void addHeaders(Builder webldr, Map<String, Object> headers) { + for (Entry<String, Object> header : headers.entrySet()) { + webldr.header(header.getKey(), header.getValue()); + } + } + @Override protected Map<String, Object> makeHeaders() { return AaiUtil.makeHeaders(params); diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java new file mode 100644 index 000000000..fbf40967c --- /dev/null +++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java @@ -0,0 +1,92 @@ +/*- + * ============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.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig; + +/** + * A&AI get-pnf operator. + */ +public class AaiGetPnfOperation extends AaiGetOperation { + private static final String URI_SEP = "/"; + + public static final String NAME = "Pnf"; + + // property prefixes + private static final String KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + NAME + "."; + + /** + * Constructs the object. + * + * @param params operation parameters + * @param config configuration for this operation + */ + public AaiGetPnfOperation(ControlLoopOperationParams params, HttpConfig config) { + super(params, config); + } + + /** + * Gets the "context key" for the PNF 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 getKey(String targetEntity) { + return (KEY_PREFIX + targetEntity); + } + + @Override + protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) { + Map<String, Object> headers = makeHeaders(); + + headers.put("Accept", MediaType.APPLICATION_JSON); + + StringBuilder str = new StringBuilder(getClient().getBaseUrl()); + + String path = getPath() + URI_SEP + URLEncoder.encode(params.getTargetEntity(), StandardCharsets.UTF_8); + WebTarget web = getClient().getWebTarget().path(path); + str.append(path); + + web = addQuery(web, str, "?", "depth", "0"); + + Builder webldr = web.request(); + addHeaders(webldr, headers); + + String url = str.toString(); + + logMessage(EventType.OUT, CommInfrastructure.REST, url, null); + + return handleResponse(outcome, url, callback -> webldr.async().get(callback)); + } +} diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java new file mode 100644 index 000000000..cbd179189 --- /dev/null +++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java @@ -0,0 +1,90 @@ +/*- + * ============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.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig; + +/** + * A&AI get-tenant operator. + */ +public class AaiGetTenantOperation extends AaiGetOperation { + + public static final String NAME = "Tenant"; + + // property prefixes + private static final String KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + NAME + "."; + + /** + * Constructs the object. + * + * @param params operation parameters + * @param config configuration for this operation + */ + public AaiGetTenantOperation(ControlLoopOperationParams params, HttpConfig config) { + super(params, config); + } + + /** + * 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 getKey(String targetEntity) { + return (KEY_PREFIX + targetEntity); + } + + @Override + protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) { + Map<String, Object> headers = makeHeaders(); + + headers.put("Accept", MediaType.APPLICATION_JSON); + + StringBuilder str = new StringBuilder(getClient().getBaseUrl()); + + String path = getPath(); + WebTarget web = getClient().getWebTarget().path(path); + str.append(path); + + web = addQuery(web, str, "?", "search-node-type", "vserver"); + web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + params.getTargetEntity()); + + Builder webldr = web.request(); + addHeaders(webldr, headers); + + String url = str.toString(); + + logMessage(EventType.OUT, CommInfrastructure.REST, url, null); + + return handleResponse(outcome, url, callback -> webldr.async().get(callback)); + } +} 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 index 12b6ca44c..97a8491b2 100644 --- 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 @@ -38,7 +38,8 @@ public class AaiActorServiceProviderTest extends BasicActor { // verify that it has the operators we expect List<String> expected = new LinkedList<>(); expected.add(AaiCustomQueryOperation.NAME); - expected.addAll(AaiGetOperation.OPERATIONS); + expected.add(AaiGetTenantOperation.NAME); + expected.add(AaiGetPnfOperation.NAME); Collections.sort(expected); 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 index aa8165e34..243a0c696 100644 --- 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 @@ -103,7 +103,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S MyTenantOperator tenantOperator = new MyTenantOperator(); when(service.getActor(AaiConstants.ACTOR_NAME)).thenReturn(tenantActor); - when(tenantActor.getOperator(AaiGetOperation.TENANT)).thenReturn(tenantOperator); + when(tenantActor.getOperator(AaiGetTenantOperation.NAME)).thenReturn(tenantOperator); oper = new AaiCustomQueryOperation(params, config); } @@ -160,7 +160,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S assertEquals(PolicyResult.SUCCESS, getResult(future2)); // tenant response should have been cached within the context - assertNotNull(context.getProperty(AaiGetOperation.getTenantKey(MY_VSERVER))); + assertNotNull(context.getProperty(AaiGetTenantOperation.getKey(MY_VSERVER))); // custom query response should have been cached within the context AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY); @@ -187,7 +187,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S assertEquals(PolicyResult.SUCCESS, getResult(future2)); // should not have replaced tenant response - assertSame(data, context.getProperty(AaiGetOperation.getTenantKey(MY_VSERVER))); + assertSame(data, context.getProperty(AaiGetTenantOperation.getKey(MY_VSERVER))); // custom query response should have been cached within the context AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY); @@ -252,8 +252,8 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S } private void preloadTenantData(StandardCoderObject data) { - context.setProperty(AaiGetOperation.getTenantKey(MY_VSERVER), data); - context.setProperty(AaiGetOperation.getTenantKey(SIM_VSERVER), data); + context.setProperty(AaiGetTenantOperation.getKey(MY_VSERVER), data); + context.setProperty(AaiGetTenantOperation.getKey(SIM_VSERVER), data); } private PolicyResult getResult(CompletableFuture<OperationOutcome> future2) @@ -267,17 +267,17 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S protected class MyTenantOperator extends HttpOperator { public MyTenantOperator() { - super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT); + super(AaiConstants.ACTOR_NAME, AaiGetTenantOperation.NAME); HttpParams http = HttpParams.builder().clientName(MY_CLIENT).path(PATH).timeoutSec(1).build(); - configure(Util.translateToMap(AaiGetOperation.TENANT, http)); + configure(Util.translateToMap(AaiGetTenantOperation.NAME, http)); start(); } @Override public Operation buildOperation(ControlLoopOperationParams params) { - return new AaiGetOperation(params, getCurrentConfig()); + return new AaiGetTenantOperation(params, getCurrentConfig()); } @Override diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java index 72b27ea61..673b6519b 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java @@ -21,37 +21,35 @@ 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.junit.Assert.assertTrue; +import static org.junit.Assert.assertSame; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Map; import java.util.concurrent.CompletableFuture; -import javax.ws.rs.client.InvocationCallback; +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.onap.policy.aai.AaiConstants; -import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; -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.HttpConfig; -import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams; -import org.onap.policy.controlloop.policy.PolicyResult; public class AaiGetOperationTest extends BasicAaiOperation<Void> { - private static final String INPUT_FIELD = "input"; - private static final String TEXT = "my-text"; + private static final String MY_NAME = "my-operation-name"; + private static final String PARAM_NAME = "my-param"; + private static final String PARAM_VALUE = "my-value"; + private static final String MY_URL = "my-url"; private AaiGetOperation oper; public AaiGetOperationTest() { - super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT); + super(AaiConstants.ACTOR_NAME, MY_NAME); } @BeforeClass @@ -73,45 +71,10 @@ public class AaiGetOperationTest extends BasicAaiOperation<Void> { oper = new AaiGetOperation(params, config); } - /** - * Tests "success" case with simulator. - */ @Test - public void testSuccess() throws Exception { - HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build(); - config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); - - params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build(); - oper = new AaiGetOperation(params, config); - - outcome = oper.start().get(); - assertEquals(PolicyResult.SUCCESS, outcome.getResult()); - } - - /** - * Tests "failure" case with simulator. - */ - @Test - public void testFailure() throws Exception { - HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build(); - config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); - - params = params.toBuilder().targetEntity("failedVserver").retry(0).timeoutSec(5).executor(blockingExecutor) - .build(); - oper = new AaiGetOperation(params, config); - - outcome = oper.start().get(); - assertEquals(PolicyResult.FAILURE, outcome.getResult()); - } - - @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)); + public void testConstructor() { + assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName()); + assertEquals(MY_NAME, oper.getName()); } @Test @@ -121,71 +84,47 @@ public class AaiGetOperationTest extends BasicAaiOperation<Void> { } @Test - @SuppressWarnings("unchecked") - 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)); + public void testAddQuery() { + WebTarget web = mock(WebTarget.class); + when(web.queryParam(any(), any())).thenReturn(web); - when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); + StringBuilder bldr = new StringBuilder(); - oper.generateSubRequestId(1); - outcome.setSubRequestId(oper.getSubRequestId()); - - CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); - assertFalse(future2.isDone()); - - executor.runAll(100); - assertTrue(future2.isDone()); - - assertEquals(PolicyResult.SUCCESS, future2.get().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)); - - assertEquals("1", future2.get().getSubRequestId()); + assertSame(web, oper.addQuery(web, bldr, ",", PARAM_NAME, PARAM_VALUE)); + assertEquals(",my-param=my-value", bldr.toString()); } - /** - * Tests startOperationAsync() when there's a failure. - */ @Test - @SuppressWarnings("unchecked") - public void testStartOperationAsyncFailure() throws Exception { + public void testAddHeaders() { + Builder bldr = mock(Builder.class); + oper.addHeaders(bldr, Map.of("hdrA", "valA", "hdrB", "valB")); - when(rawResponse.getStatus()).thenReturn(500); - when(rawResponse.readEntity(String.class)).thenReturn(""); - - when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); - - CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); - assertFalse(future2.isDone()); - - executor.runAll(100); - assertTrue(future2.isDone()); - - assertEquals(PolicyResult.FAILURE, future2.get().getResult()); - - // data should NOT have been cached within the context - assertNull(context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY))); + verify(bldr, times(2)).header(any(), any()); + verify(bldr).header("hdrA", "valA"); + verify(bldr).header("hdrB", "valB"); } @Test - public void testMakeHeaders() { - verifyHeaders(oper.makeHeaders()); + public void testPostProcessResponse() throws Exception { + StandardCoderObject resp = new StandardCoderObject(); + CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, MY_URL, null, resp); + + assertSame(outcome, future2.get()); + assertSame(resp, context.getProperty("AAI.my-operation-name.my-target")); } @Test - public void testAaiGetOperator() { - assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName()); - assertEquals(AaiGetOperation.TENANT, oper.getName()); + 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 testGetTenantKey() { - assertEquals("AAI.Tenant." + TARGET_ENTITY, AaiGetOperation.getTenantKey(TARGET_ENTITY)); + public void testMakeHeaders() { + verifyHeaders(oper.makeHeaders()); } } diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java new file mode 100644 index 000000000..22702404b --- /dev/null +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java @@ -0,0 +1,169 @@ +/*- + * ============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.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import javax.ws.rs.client.InvocationCallback; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; +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.HttpConfig; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams; +import org.onap.policy.controlloop.policy.PolicyResult; + +public class AaiGetPnfOperationTest extends BasicAaiOperation<Void> { + private static final String INPUT_FIELD = "input"; + private static final String TEXT = "my-text"; + + private AaiGetPnfOperation oper; + + public AaiGetPnfOperationTest() { + super(AaiConstants.ACTOR_NAME, AaiGetPnfOperation.NAME); + } + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + initBeforeClass(); + } + + @AfterClass + public static void tearDownAfterClass() { + destroyAfterClass(); + } + + /** + * Sets up. + */ + @Before + public void setUp() throws Exception { + super.setUpBasic(); + oper = new AaiGetPnfOperation(params, config); + } + + @Test + public void testConstructor() { + assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName()); + assertEquals(AaiGetPnfOperation.NAME, oper.getName()); + } + + /** + * Tests "success" case with simulator. + */ + @Test + public void testSuccess() throws Exception { + HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build(); + config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); + + params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build(); + oper = new AaiGetPnfOperation(params, config); + + outcome = oper.start().get(); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + } + + /** + * Tests "failure" case with simulator. + */ + @Test + public void testFailure() throws Exception { + HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build(); + config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); + + params = params.toBuilder().targetEntity("getFail").retry(0).timeoutSec(5).executor(blockingExecutor).build(); + oper = new AaiGetPnfOperation(params, config); + + outcome = oper.start().get(); + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + } + + @Test + @SuppressWarnings("unchecked") + public void testStartOperationAsync_testStartQueryAsync() 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(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); + + oper.generateSubRequestId(1); + outcome.setSubRequestId(oper.getSubRequestId()); + + CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); + assertFalse(future2.isDone()); + + executor.runAll(100); + assertTrue(future2.isDone()); + + assertEquals(PolicyResult.SUCCESS, future2.get().getResult()); + + // data should have been cached within the context + StandardCoderObject data = context.getProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY)); + assertNotNull(data); + assertEquals(TEXT, data.getString(INPUT_FIELD)); + + assertEquals("1", future2.get().getSubRequestId()); + } + + /** + * Tests startOperationAsync() when there's a failure. + */ + @Test + @SuppressWarnings("unchecked") + public void testStartOperationAsyncFailure() throws Exception { + + when(rawResponse.getStatus()).thenReturn(500); + when(rawResponse.readEntity(String.class)).thenReturn(""); + + when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); + + CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); + assertFalse(future2.isDone()); + + executor.runAll(100); + assertTrue(future2.isDone()); + + assertEquals(PolicyResult.FAILURE, future2.get().getResult()); + + // data should NOT have been cached within the context + assertNull(context.getProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY))); + } + + @Test + public void testGetKey() { + assertEquals("AAI.Pnf." + TARGET_ENTITY, AaiGetPnfOperation.getKey(TARGET_ENTITY)); + } +} diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java new file mode 100644 index 000000000..496d2ea68 --- /dev/null +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java @@ -0,0 +1,170 @@ +/*- + * ============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.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import javax.ws.rs.client.InvocationCallback; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; +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.HttpConfig; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams; +import org.onap.policy.controlloop.policy.PolicyResult; + +public class AaiGetTenantOperationTest extends BasicAaiOperation<Void> { + private static final String INPUT_FIELD = "input"; + private static final String TEXT = "my-text"; + + private AaiGetTenantOperation oper; + + public AaiGetTenantOperationTest() { + super(AaiConstants.ACTOR_NAME, AaiGetTenantOperation.NAME); + } + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + initBeforeClass(); + } + + @AfterClass + public static void tearDownAfterClass() { + destroyAfterClass(); + } + + /** + * Sets up. + */ + @Before + public void setUp() throws Exception { + super.setUpBasic(); + oper = new AaiGetTenantOperation(params, config); + } + + @Test + public void testConstructor() { + assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName()); + assertEquals(AaiGetTenantOperation.NAME, oper.getName()); + } + + /** + * Tests "success" case with simulator. + */ + @Test + public void testSuccess() throws Exception { + HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build(); + config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); + + params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build(); + oper = new AaiGetTenantOperation(params, config); + + outcome = oper.start().get(); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + } + + /** + * Tests "failure" case with simulator. + */ + @Test + public void testFailure() throws Exception { + HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build(); + config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory()); + + params = params.toBuilder().targetEntity("failedVserver").retry(0).timeoutSec(5).executor(blockingExecutor) + .build(); + oper = new AaiGetTenantOperation(params, config); + + outcome = oper.start().get(); + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + } + + @Test + @SuppressWarnings("unchecked") + public void testStartOperationAsync_testStartQueryAsync() 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(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); + + oper.generateSubRequestId(1); + outcome.setSubRequestId(oper.getSubRequestId()); + + CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); + assertFalse(future2.isDone()); + + executor.runAll(100); + assertTrue(future2.isDone()); + + assertEquals(PolicyResult.SUCCESS, future2.get().getResult()); + + // data should have been cached within the context + StandardCoderObject data = context.getProperty(AaiGetTenantOperation.getKey(TARGET_ENTITY)); + assertNotNull(data); + assertEquals(TEXT, data.getString(INPUT_FIELD)); + + assertEquals("1", future2.get().getSubRequestId()); + } + + /** + * Tests startOperationAsync() when there's a failure. + */ + @Test + @SuppressWarnings("unchecked") + public void testStartOperationAsyncFailure() throws Exception { + + when(rawResponse.getStatus()).thenReturn(500); + when(rawResponse.readEntity(String.class)).thenReturn(""); + + when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); + + CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome); + assertFalse(future2.isDone()); + + executor.runAll(100); + assertTrue(future2.isDone()); + + assertEquals(PolicyResult.FAILURE, future2.get().getResult()); + + // data should NOT have been cached within the context + assertNull(context.getProperty(AaiGetTenantOperation.getKey(TARGET_ENTITY))); + } + + @Test + public void testGetKey() { + assertEquals("AAI.Tenant." + TARGET_ENTITY, AaiGetTenantOperation.getKey(TARGET_ENTITY)); + } +} diff --git a/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml b/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml index d0c11be7b..db186028a 100644 --- a/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml +++ b/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml @@ -30,4 +30,6 @@ actors: CustomQuery: path: cq Tenant: - path: tenant
\ No newline at end of file + path: tenant + Pnf: + path: pnf diff --git a/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java b/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java index 702802d48..820f4de34 100644 --- a/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java +++ b/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java @@ -26,11 +26,15 @@ import com.google.protobuf.Struct; import com.google.protobuf.Struct.Builder; import com.google.protobuf.util.JsonFormat; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import lombok.Getter; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; import org.onap.ccsdk.cds.controllerblueprints.common.api.ActionIdentifiers; import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader; import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; @@ -38,12 +42,16 @@ import org.onap.policy.aai.AaiConstants; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.cds.client.CdsProcessorGrpcClient; import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.controlloop.actor.cds.request.CdsActionRequest; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.policy.TargetType; /** * Operation that uses gRPC to send request to CDS. @@ -54,6 +62,10 @@ public class GrpcOperation extends OperationPartial { public static final String NAME = "any"; + private static final String AAI_PNF_PREFIX = "pnf."; + private static final String AAI_VNF_ID_KEY = "generic-vnf.vnf-id"; + private static final String AAI_SERVICE_INSTANCE_ID_KEY = "service-instance.service-instance-id"; + private CdsProcessorGrpcClient client; /** @@ -62,6 +74,16 @@ public class GrpcOperation extends OperationPartial { private final GrpcConfig config; /** + * Function to request the A&AI data appropriate to the target type. + */ + private final Supplier<CompletableFuture<OperationOutcome>> aaiRequestor; + + /** + * Function to convert the A&AI data associated with the target type. + */ + private final Supplier<Map<String, String>> aaiConverter; + + /** * Constructs the object. * * @param params operation parameters @@ -70,6 +92,14 @@ public class GrpcOperation extends OperationPartial { public GrpcOperation(ControlLoopOperationParams params, GrpcConfig config) { super(params, config); this.config = config; + + if (TargetType.PNF.equals(params.getTarget().getType())) { + aaiRequestor = this::getPnf; + aaiConverter = this::convertPnfToAaiProperties; + } else { + aaiRequestor = this::getCq; + aaiConverter = this::convertCqToAaiProperties; + } } /** @@ -81,16 +111,84 @@ public class GrpcOperation extends OperationPartial { } /** - * Ensures that A&AI customer query has been performed. + * Ensures that A&AI query has been performed, and runs the guard. */ @Override @SuppressWarnings("unchecked") protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + // run A&AI Query and Guard, in parallel + return allOf(aaiRequestor, this::startGuardAsync); + } + + /** + * Requests the A&AI PNF data. + * + * @return a future to get the PNF data + */ + private CompletableFuture<OperationOutcome> getPnf() { + ControlLoopOperationParams pnfParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) + .operation(AaiGetPnfOperation.NAME).payload(null).retry(null).timeoutSec(null).build(); + + return params.getContext().obtain(AaiGetPnfOperation.getKey(params.getTargetEntity()), pnfParams); + } + + /** + * Requests the A&AI Custom Query data. + * + * @return a future to get the custom query data + */ + private CompletableFuture<OperationOutcome> getCq() { ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) .operation(AaiCustomQueryOperation.NAME).payload(null).retry(null).timeoutSec(null).build(); - // run Custom Query and Guard, in parallel - return allOf(() -> params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams), this::startGuardAsync); + return params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams); + } + + /** + * Converts the A&AI PNF data to a map suitable for passing via the "aaiProperties" + * field in the CDS request. + * + * @return a map of the PNF data + */ + private Map<String, String> convertPnfToAaiProperties() { + // convert PNF data to a Map + StandardCoderObject pnf = params.getContext().getProperty(AaiGetPnfOperation.getKey(params.getTargetEntity())); + Map<String, Object> source = Util.translateToMap(getFullName(), pnf); + + Map<String, String> result = new LinkedHashMap<>(); + + for (Entry<String, Object> ent : source.entrySet()) { + result.put(AAI_PNF_PREFIX + ent.getKey(), ent.getValue().toString()); + } + + return result; + } + + /** + * Converts the A&AI Custom Query data to a map suitable for passing via the + * "aaiProperties" field in the CDS request. + * + * @return a map of the custom query data + */ + private Map<String, String> convertCqToAaiProperties() { + AaiCqResponse aaicq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); + + Map<String, String> result = new LinkedHashMap<>(); + + ServiceInstance serviceInstance = aaicq.getServiceInstance(); + if (serviceInstance == null) { + throw new IllegalArgumentException("Target service instance could not be found"); + } + + GenericVnf genericVnf = aaicq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID()); + if (genericVnf == null) { + throw new IllegalArgumentException("Target generic vnf could not be found"); + } + + result.put(AAI_SERVICE_INSTANCE_ID_KEY, serviceInstance.getServiceInstanceId()); + result.put(AAI_VNF_ID_KEY, genericVnf.getVnfId()); + + return result; } @Override @@ -152,7 +250,10 @@ public class GrpcOperation extends OperationPartial { // implementation to inject whatever AAI parameters are of interest to them. // E.g. For vFW usecase El-Alto inject service-instance-id, generic-vnf-id as // needed by CDS. - request.setAaiProperties(params.getContext().getEnrichment()); + // + // Note: that is a future enhancement. For now, the actor is hard-coded to + // use the A&AI query result specific to the target type + request.setAaiProperties(aaiConverter.get()); // Inject any additional event parameters that may be present in the onset event if (params.getContext().getEvent().getAdditionalEventParams() != null) { diff --git a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java index 5dca2909f..9477a1585 100644 --- a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java +++ b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java @@ -42,30 +42,44 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.cds.client.CdsProcessorGrpcClient; import org.onap.policy.cds.properties.CdsServerProperties; +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.time.PseudoExecutor; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.controlloop.actorserviceprovider.ActorService; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; public class GrpcOperationTest { - + private static final String TARGET_ENTITY = "entity"; + private static final String MY_VNF = "my-vnf"; + private static final String MY_SVC_ID = "my-service-instance-id"; + private static final String RESOURCE_ID = "my-resource-id"; private static final String CDS_BLUEPRINT_NAME = "vfw-cds"; private static final String CDS_BLUEPRINT_VERSION = "1.0.0"; private static final UUID REQUEST_ID = UUID.randomUUID(); + private static final Coder coder = new StandardCoder(); @Mock private CdsProcessorGrpcClient cdsClient; private CdsServerProperties cdsProps; private VirtualControlLoopEvent onset; private PseudoExecutor executor; + private Target target; private GrpcOperation operation; /** @@ -92,6 +106,10 @@ public class GrpcOperationTest { // Setup executor executor = new PseudoExecutor(); + + target = new Target(); + target.setType(TargetType.VM); + target.setResourceID(RESOURCE_ID); } @Test @@ -106,7 +124,7 @@ public class GrpcOperationTest { ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").build(); + .targetEntity(TARGET_ENTITY).target(target).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config) { @@ -128,10 +146,65 @@ public class GrpcOperationTest { assertTrue(future3.isDone()); } + /** + * Tests startPreprocessorAsync() when the target type is PNF. + */ + @Test + public void testStartPreprocessorAsyncPnf() throws InterruptedException, ExecutionException, TimeoutException { + + CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>(); + ControlLoopEventContext context = mock(ControlLoopEventContext.class); + when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future2); + when(context.getEvent()).thenReturn(onset); + + AtomicBoolean guardStarted = new AtomicBoolean(); + + target.setType(TargetType.PNF); + + ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) + .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) + .targetEntity(TARGET_ENTITY).target(target).build(); + GrpcConfig config = new GrpcConfig(executor, cdsProps); + + operation = new GrpcOperation(params, config) { + @Override + protected CompletableFuture<OperationOutcome> startGuardAsync() { + guardStarted.set(true); + return future2; + } + }; + + CompletableFuture<OperationOutcome> future3 = operation.startPreprocessorAsync(); + assertNotNull(future3); + assertTrue(guardStarted.get()); + verify(context).obtain(eq(AaiGetPnfOperation.getKey(TARGET_ENTITY)), any()); + + future2.complete(params.makeOutcome()); + assertTrue(executor.runAll(100)); + assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult()); + assertTrue(future3.isDone()); + } + @Test public void testStartOperationAsync() throws Exception { ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadCqData(context); + + verifyOperation(context); + } + + /** + * Tests startOperationAsync() when the target type is PNF. + */ + @Test + public void testStartOperationAsyncPnf() throws Exception { + + target.setType(TargetType.PNF); + + ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadPnfData(context); + verifyOperation(context); } @@ -142,6 +215,7 @@ public class GrpcOperationTest { additionalParams.put("test", "additionalParams"); onset.setAdditionalEventParams(additionalParams); ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadCqData(context); verifyOperation(context); } @@ -151,7 +225,7 @@ public class GrpcOperationTest { ControlLoopEventContext context = new ControlLoopEventContext(onset); ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").build(); + .targetEntity(TARGET_ENTITY).target(target).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config); @@ -166,7 +240,7 @@ public class GrpcOperationTest { ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").payload(payloadMap).build(); + .targetEntity(TARGET_ENTITY).target(target).payload(payloadMap).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config); @@ -177,4 +251,25 @@ public class GrpcOperationTest { CompletableFuture<OperationOutcome> future3 = operation.startOperationAsync(1, params.makeOutcome()); assertNotNull(future3); } + + private void loadPnfData(ControlLoopEventContext context) throws CoderException { + String json = "{'dataA': 'valueA', 'dataB': 'valueB'}".replace('\'', '"'); + StandardCoderObject sco = coder.decode(json, StandardCoderObject.class); + + context.setProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY), sco); + } + + private void loadCqData(ControlLoopEventContext context) { + GenericVnf genvnf = new GenericVnf(); + genvnf.setVnfId(MY_VNF); + + ServiceInstance serviceInstance = new ServiceInstance(); + serviceInstance.setServiceInstanceId(MY_SVC_ID); + + AaiCqResponse cq = mock(AaiCqResponse.class); + when(cq.getGenericVnfByModelInvariantId(any())).thenReturn(genvnf); + when(cq.getServiceInstance()).thenReturn(serviceInstance); + + context.setProperty(AaiCqResponse.CONTEXT_KEY, cq); + } } diff --git a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java index 2fd54e40c..cfb20ab6c 100644 --- a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java +++ b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2020 Bell Canada. All rights reserved. + * Modifications 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. @@ -35,6 +36,8 @@ import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; public class GrpcOperatorTest { @@ -85,8 +88,10 @@ public class GrpcOperatorTest { public void testBuildOperation() { VirtualControlLoopEvent event = new VirtualControlLoopEvent(); ControlLoopEventContext context = new ControlLoopEventContext(event); + Target target = new Target(); + target.setType(TargetType.VM); ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) - .operation(GrpcOperation.NAME).context(context).build(); + .operation(GrpcOperation.NAME).context(context).target(target).build(); // not configured yet assertThatIllegalStateException().isThrownBy(() -> operation.buildOperation(params)); diff --git a/models-interactions/model-impl/cds/pom.xml b/models-interactions/model-impl/cds/pom.xml index 96a94263c..02a4c5a33 100644 --- a/models-interactions/model-impl/cds/pom.xml +++ b/models-interactions/model-impl/cds/pom.xml @@ -102,6 +102,12 @@ <artifactId>common-parameters</artifactId> <version>${policy.common.version}</version> </dependency> + <dependency> + <groupId>org.onap.policy.common</groupId> + <artifactId>policy-endpoints</artifactId> + <version>${policy.common.version}</version> + <scope>provided</scope> + </dependency> <!-- junit dependencies --> <dependency> diff --git a/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorGrpcClient.java b/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorGrpcClient.java index b8ec7acf5..efa8369bc 100644 --- a/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorGrpcClient.java +++ b/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorGrpcClient.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2019 Bell Canada. + * Modifications 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. @@ -55,11 +56,19 @@ public class CdsProcessorGrpcClient implements AutoCloseable { Preconditions.checkState(validationResult.getStatus().isValid(), "Error validating CDS server " + "properties: " + validationResult.getResult()); + StringBuilder bldr = new StringBuilder("gRPC://"); + bldr.append(props.getHost()); + bldr.append(":"); + bldr.append(props.getPort()); + bldr.append('/'); + + String url = bldr.toString(); + this.channel = NettyChannelBuilder.forAddress(props.getHost(), props.getPort()) .nameResolverFactory(new DnsNameResolverProvider()) .loadBalancerFactory(new PickFirstLoadBalancerProvider()) .intercept(new BasicAuthClientHeaderInterceptor(props)).usePlaintext().build(); - this.handler = new CdsProcessorHandler(listener); + this.handler = new CdsProcessorHandler(listener, url); LOGGER.info("CdsProcessorListener started"); } diff --git a/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorHandler.java b/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorHandler.java index 5c011d83b..84baecdf1 100644 --- a/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorHandler.java +++ b/models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorHandler.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2019 Bell Canada. + * Modifications 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. @@ -27,6 +28,9 @@ import org.onap.ccsdk.cds.controllerblueprints.processing.api.BluePrintProcessin import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput; import org.onap.policy.cds.api.CdsProcessorListener; +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.NetLoggerUtil.EventType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,9 +39,11 @@ public class CdsProcessorHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CdsProcessorHandler.class); private CdsProcessorListener listener; + private String url; - CdsProcessorHandler(final CdsProcessorListener listener) { + CdsProcessorHandler(final CdsProcessorListener listener, String url) { this.listener = listener; + this.url = url; } CountDownLatch process(ExecutionServiceInput request, ManagedChannel channel) { @@ -50,11 +56,18 @@ public class CdsProcessorHandler { final StreamObserver<ExecutionServiceOutput> responseObserver = new StreamObserver<ExecutionServiceOutput>() { @Override public void onNext(ExecutionServiceOutput output) { + LOGGER.info("[{}|{}|{}|]{}{}", EventType.IN, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS, + output.toString()); + NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, url, output.toString()); + listener.onMessage(output); } @Override public void onError(Throwable throwable) { + LOGGER.info("[{}|{}|{}|]{}{}", EventType.IN, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS, + throwable.toString()); + NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, url, throwable.toString()); listener.onError(throwable); finishLatch.countDown(); } @@ -69,6 +82,10 @@ public class CdsProcessorHandler { final StreamObserver<ExecutionServiceInput> requestObserver = asyncStub.process(responseObserver); try { + LOGGER.info("[{}|{}|{}|]{}{}", EventType.OUT, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS, + request.toString()); + NetLoggerUtil.log(EventType.OUT, CommInfrastructure.REST, url, request.toString()); + // Send the message to CDS backend for processing requestObserver.onNext(request); // Mark the end of requests diff --git a/models-interactions/model-impl/cds/src/test/java/org/onap/policy/cds/client/CdsProcessorGrpcClientTest.java b/models-interactions/model-impl/cds/src/test/java/org/onap/policy/cds/client/CdsProcessorGrpcClientTest.java index 9d01ec851..0922fc4cb 100644 --- a/models-interactions/model-impl/cds/src/test/java/org/onap/policy/cds/client/CdsProcessorGrpcClientTest.java +++ b/models-interactions/model-impl/cds/src/test/java/org/onap/policy/cds/client/CdsProcessorGrpcClientTest.java @@ -92,7 +92,7 @@ public class CdsProcessorGrpcClientTest { .register(InProcessChannelBuilder.forName(SERVER_NAME).directExecutor().build()); // Create an instance of the gRPC client - client = new CdsProcessorGrpcClient(channel, new CdsProcessorHandler(listener)); + client = new CdsProcessorGrpcClient(channel, new CdsProcessorHandler(listener, "gRPC://localhost:1234/")); // Implement the test gRPC server BluePrintProcessingServiceImplBase testCdsBlueprintServerImpl = new BluePrintProcessingServiceImplBase() { diff --git a/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AaiSimulatorJaxRs.java b/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AaiSimulatorJaxRs.java index 8c96ee533..8a3d6a803 100644 --- a/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AaiSimulatorJaxRs.java +++ b/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AaiSimulatorJaxRs.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * simulators * ================================================================================ - * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2018, 2020 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,7 +51,7 @@ public class AaiSimulatorJaxRs { @Path("/v8/network/generic-vnfs/generic-vnf/{vnfId}") @Consumes(MediaType.APPLICATION_JSON) @Produces("application/json") - public String aaiGetQuery(@PathParam("vnfID") final String vnfId) { + public String aaiGetQuery(@PathParam("vnfId") final String vnfId) { return "{\"relationship-list\": {\"relationship\":[{\"related-to-property\": [{\"property-key\": " + "\"service-instance.service-instance-name\"}]},{\"related-to-property\": [ {\"property-key\": " + "\"vserver.vserver-name\",\"property-value\": \"USUCP0PCOIL0110UJZZ01-vsrx\" }]} ]}}"; @@ -96,6 +96,25 @@ public class AaiSimulatorJaxRs { } /** + * A&AI get PNF query. + * + * @return the result + * @throws IOException if a response file cannot be read + */ + @GET + @Path("/v16/network/pnfs/pnf/{pnfName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces("application/json") + public String aaiGetPnfQuery(@PathParam("pnfName") final String pnfName) throws IOException { + if (GETFAIL.equals(pnfName)) { + throw new IllegalArgumentException("query failed, as requested"); + } + + return IOUtils.toString(getClass().getResource("aai/AaiGetPnfResponse.json"), + StandardCharsets.UTF_8); + } + + /** * Get by VNF name. * * @param vnfName the VNF name diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json new file mode 100644 index 000000000..ce8eb75a7 --- /dev/null +++ b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json @@ -0,0 +1,12 @@ +{ + "equip-vendor":"Vendor-A", + "ipaddress-v4-oam":"10.10.10.10", + "in-maint":false, + "pnf-ipv4-address":"3.3.3.3", + "resource-version":"1570746989505", + "nf-role":"ToR DC101", + "equip-type":"Router", + "equip-model":"model-123456", + "frame-id":"3", + "pnf-name":"demo-pnf" +} |