From 9bd821d6a2b49dacb7286d58f11d5cd1cc7e0aa2 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Mon, 2 Mar 2020 16:17:36 -0500 Subject: Fix path issues A&AI tenant query is prepending the target entity with "/", but it should not. Fixed it. Modified A&AI and SO actors to get path prefixes from parameters. Fixed a bug in an A&AI simulator response (extra "}" at the end. Issue-ID: POLICY-2349 Signed-off-by: Jim Hahn Change-Id: I71f8b1e5fb8a4bd29b4f616a7757d366c7d58127 --- .../actor/aai/AaiCustomQueryOperation.java | 39 +++++++++++++++++----- .../controlloop/actor/aai/AaiGetOperation.java | 36 ++++++++++++++++---- .../actor/aai/AaiCustomQueryOperationTest.java | 17 ++++++---- .../controlloop/actor/aai/AaiGetOperationTest.java | 9 +++-- .../actor.aai/src/test/resources/service.yaml | 2 +- .../controlloop/actor/so/VfModuleCreate.java | 8 ++--- .../controlloop/actor/so/VfModuleCreateTest.java | 2 +- .../actor.so/src/test/resources/service.yaml | 4 +-- .../controlloop/actor/test/BasicHttpOperation.java | 31 ++++++++++++++++- .../actorserviceprovider/impl/HttpOperation.java | 2 +- .../onap/policy/simulators/AaiSimulatorJaxRs.java | 2 +- 11 files changed, 116 insertions(+), 36 deletions(-) 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 613b6689d..5b4aa0527 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 @@ -21,8 +21,11 @@ package org.onap.policy.controlloop.actor.aai; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import javax.ws.rs.client.Entity; +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 lombok.Getter; @@ -54,6 +57,7 @@ public class AaiCustomQueryOperation extends HttpOperation { public static final String RESOURCE_LINK = "resource-link"; public static final String RESULT_DATA = "result-data"; + // TODO make this configurable private static final String PREFIX = "/aai/v16"; @Getter @@ -89,21 +93,38 @@ public class AaiCustomQueryOperation extends HttpOperation { @Override protected CompletableFuture startOperationAsync(int attempt, OperationOutcome outcome) { - Map request = makeRequest(); + final Map request = makeRequest(); + Map headers = makeHeaders(); - Entity> entity = Entity.entity(request, MediaType.APPLICATION_JSON); + StringBuilder str = new StringBuilder(getClient().getBaseUrl()); - Map headers = makeHeaders(); + String path = getPath(); + WebTarget web = getClient().getWebTarget().path(path); + str.append(path); + + web = addQuery(web, str, "?", "format", "resource"); + + Builder webldr = web.request(); + for (Entry header : headers.entrySet()) { + webldr.header(header.getKey(), header.getValue()); + } - headers.put("Accept", MediaType.APPLICATION_JSON); - String url = makeUrl(); + String url = str.toString(); logMessage(EventType.OUT, CommInfrastructure.REST, url, request); - // @formatter:off - return handleResponse(outcome, url, - callback -> getClient().put(callback, makePath(), entity, headers)); - // @formatter:on + Entity> entity = Entity.entity(request, MediaType.APPLICATION_JSON); + + return handleResponse(outcome, url, callback -> webldr.async().put(entity, callback)); + } + + private WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) { + str.append(separator); + str.append(name); + str.append('='); + str.append(value); + + return web.queryParam(name, value); } /** 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 408c1a0b1..4c4124189 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 @@ -21,8 +21,11 @@ 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; @@ -92,14 +95,35 @@ public class AaiGetOperation extends HttpOperation { Map headers = makeHeaders(); headers.put("Accept", MediaType.APPLICATION_JSON); - String url = makeUrl(); + + 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 header : headers.entrySet()) { + webldr.header(header.getKey(), header.getValue()); + } + + String url = str.toString(); logMessage(EventType.OUT, CommInfrastructure.REST, url, null); - // @formatter:off - return handleResponse(outcome, url, - callback -> getClient().get(callback, makePath(), headers)); - // @formatter:on + return handleResponse(outcome, url, callback -> webldr.async().get(callback)); + } + + private WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) { + str.append(separator); + str.append(name); + str.append('='); + str.append(value); + + return web.queryParam(name, value); } @Override @@ -109,7 +133,7 @@ public class AaiGetOperation extends HttpOperation { @Override public String makePath() { - return (getPath() + "/" + params.getTargetEntity()); + return (getPath() + params.getTargetEntity()); } /** 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 78ffc50e0..c24e45db7 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 @@ -38,6 +38,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -109,11 +110,12 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation future2 = oper.start(); @@ -131,13 +133,14 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation future2 = oper.start(); @@ -157,17 +160,18 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation request = new TreeMap<>(entityCaptor.getValue().getEntity()); @@ -176,12 +180,13 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation future2 = oper.start(); 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 4681d9ef4..13560ccf3 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 @@ -30,6 +30,7 @@ import static org.mockito.Mockito.when; import java.util.Map; import java.util.concurrent.CompletableFuture; +import javax.ws.rs.client.InvocationCallback; import org.junit.Before; import org.junit.Test; import org.onap.policy.aai.AaiConstants; @@ -69,13 +70,14 @@ public class AaiGetOperationTest extends BasicAaiOperation { } @Test + @SuppressWarnings("unchecked") public void testStartOperationAsync_testStartQueryAsync_testPostProcessResponse() throws Exception { // return a map in the reply Map 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)); + when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); CompletableFuture future2 = oper.startOperationAsync(1, outcome); assertFalse(future2.isDone()); @@ -95,12 +97,13 @@ public class AaiGetOperationTest extends BasicAaiOperation { * 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(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse)); + when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse)); CompletableFuture future2 = oper.startOperationAsync(1, outcome); assertFalse(future2.isDone()); @@ -121,7 +124,7 @@ public class AaiGetOperationTest extends BasicAaiOperation { @Test public void testMakePath() { - assertEquals(PATH + "/" + TARGET_ENTITY, oper.makePath()); + assertEquals(PATH + TARGET_ENTITY, oper.makePath()); } @Test 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 9f6561de0..d0c11be7b 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 @@ -21,7 +21,7 @@ httpClients: - clientName: my-client hostname: localhost port: 80 - basePath: base-url + basePath: base-url/ managed: true actors: AAI: diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java index fb8fe6072..4c35f9abe 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java @@ -107,7 +107,7 @@ public class VfModuleCreate extends SoOperation { resetGetCount(); Pair pair = makeRequest(); - String path = pair.getLeft(); + String path = getPath() + pair.getLeft(); SoRequest request = pair.getRight(); Entity entity = Entity.entity(request, MediaType.APPLICATION_JSON); @@ -115,8 +115,6 @@ public class VfModuleCreate extends SoOperation { logMessage(EventType.OUT, CommInfrastructure.REST, url, request); - // TODO should this use "path" or the full "url"? - return handleResponse(outcome, url, callback -> getClient().post(callback, path, entity, null)); } @@ -208,8 +206,8 @@ public class VfModuleCreate extends SoOperation { buildConfigurationParameters().ifPresent(request.getRequestDetails()::setConfigurationParameters); // compute the path - String path = "/serviceInstantiation/v7/serviceInstances/" + vnfServiceItem.getServiceInstanceId() + "/vnfs/" - + vnfItem.getVnfId() + "/vfModules/scaleOut"; + String path = "/serviceInstances/" + vnfServiceItem.getServiceInstanceId() + "/vnfs/" + vnfItem.getVnfId() + + "/vfModules/scaleOut"; return Pair.of(path, request); } diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java index 98c645b16..8bd607f32 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java @@ -202,7 +202,7 @@ public class VfModuleCreateTest extends BasicSoOperation { // @formatter:off assertEquals( - "/serviceInstantiation/v7/serviceInstances/my-service-instance-id/vnfs/my-vnf-id/vfModules/scaleOut", + "/serviceInstances/my-service-instance-id/vnfs/my-vnf-id/vfModules/scaleOut", pair.getLeft()); // @formatter:on diff --git a/models-interactions/model-actors/actor.so/src/test/resources/service.yaml b/models-interactions/model-actors/actor.so/src/test/resources/service.yaml index b1ac162a4..4bf074fc5 100644 --- a/models-interactions/model-actors/actor.so/src/test/resources/service.yaml +++ b/models-interactions/model-actors/actor.so/src/test/resources/service.yaml @@ -21,11 +21,11 @@ httpClients: - clientName: my-client hostname: localhost port: 80 - basePath: base-url + basePath: base-url/ managed: true actors: SO: clientName: my-client operations: VF Module Create: - path: create \ No newline at end of file + path: serviceInstantiation/v7 \ No newline at end of file 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 e803df8c9..6228756bd 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 @@ -20,12 +20,16 @@ package org.onap.policy.controlloop.actor.test; +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.AsyncInvoker; import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.client.InvocationCallback; +import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; import org.mockito.ArgumentCaptor; import org.mockito.Captor; @@ -55,6 +59,12 @@ public class BasicHttpOperation extends BasicOperation { @Mock protected HttpConfig config; @Mock + protected WebTarget webTarget; + @Mock + protected Builder webBuilder; + @Mock + protected AsyncInvoker webAsync; + @Mock protected HttpClient client; @Mock protected HttpClientFactory factory; @@ -90,6 +100,14 @@ public class BasicHttpOperation extends BasicOperation { when(rawResponse.getStatus()).thenReturn(200); + when(webBuilder.async()).thenReturn(webAsync); + + when(webTarget.request()).thenReturn(webBuilder); + when(webTarget.path(any())).thenReturn(webTarget); + when(webTarget.queryParam(any(), any())).thenReturn(webTarget); + + when(client.getWebTarget()).thenReturn(webTarget); + when(client.getBaseUrl()).thenReturn(BASE_URI); initConfig(); @@ -110,8 +128,19 @@ public class BasicHttpOperation extends BasicOperation { * @return a function that provides the response to the call */ protected Answer> provideResponse(Response response) { + return provideResponse(response, 0); + } + + /** + * Provides a response to an asynchronous HttpClient call. + * + * @param response response to be provided to the call + * @param index index of the callback within the arguments + * @return a function that provides the response to the call + */ + protected Answer> provideResponse(Response response, int index) { return args -> { - InvocationCallback cb = args.getArgument(0); + InvocationCallback cb = args.getArgument(index); cb.completed(response); return CompletableFuture.completedFuture(response); }; 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 4c007ea19..aa98c0d36 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 @@ -116,7 +116,7 @@ public abstract class HttpOperation extends OperationPartial { } /** - * Makes the URL to which the "get" request should be posted. This ir primarily used + * Makes the URL to which the "get" request should be posted. This is primarily used * for logging purposes. This particular method returns the base URL appended with the * return value from {@link #makePath()}. * 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 3b1772342..8c96ee533 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 @@ -73,7 +73,7 @@ public class AaiSimulatorJaxRs { return "{\"result-data\":[{\"resource-type\": \"vserver\",\"resource-link\":\"/aai/v15/" + "cloud-infrastructure/cloud-regions/cloud-region/CloudOwner/RegionOne/tenants" + "/tenant/3f2aaef74ecb4b19b35e26d0849fe9a2/vservers/vserver/" - + "6c3b3714-e36c-45af-9f16-7d3a73d99497\"}]}}"; + + "6c3b3714-e36c-45af-9f16-7d3a73d99497\"}]}"; } else { return null; } -- cgit 1.2.3-korg