From 7150a5f7027725b5eed9c723c6224c8b3d5307dd Mon Sep 17 00:00:00 2001 From: liamfallon Date: Tue, 20 Mar 2018 15:30:17 +0000 Subject: Add timeout to SO to wait for success The timeout implementation assumes that a finished request is a HTTP-200 together with either a request state of COMPLETE or FAILED in the embedded request in the response in the JSON. This is the same as what is done earlier in this class and in, for example, VFC. Unit test for timeout has also been added. Change-Id: I637dbecb8d230b8060f7ced76d92d11ec482503e Issue-ID: POLICY-448 Signed-off-by: liamfallon --- controlloop/common/model-impl/so/pom.xml | 6 +- .../main/java/org/onap/policy/so/SOManager.java | 526 ++++++++++++--------- .../org/onap/policy/so/DummyWorkingMemory.java | 314 ++++++++++++ .../java/org/onap/policy/so/TestSOManager.java | 455 +++++++++--------- .../java/org/onap/policy/so/TestSoDummyServer.java | 272 +++++++++++ controlloop/common/simulators/pom.xml | 1 - .../onap/policy/simulators/SoSimulatorJaxRs.java | 38 +- .../src/main/config/so.success.json | 10 +- 8 files changed, 1168 insertions(+), 454 deletions(-) create mode 100644 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/DummyWorkingMemory.java create mode 100644 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoDummyServer.java diff --git a/controlloop/common/model-impl/so/pom.xml b/controlloop/common/model-impl/so/pom.xml index a026236a6..cc31464a7 100644 --- a/controlloop/common/model-impl/so/pom.xml +++ b/controlloop/common/model-impl/so/pom.xml @@ -60,9 +60,9 @@ provided - org.mockito - mockito-core - 2.13.0 + org.glassfish.jersey.containers + jersey-container-grizzly2-http + 2.25.1 test diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOManager.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOManager.java index 35227d310..a40a2d10f 100644 --- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOManager.java +++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOManager.java @@ -20,235 +20,323 @@ package org.onap.policy.so; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; + import java.util.Base64; import java.util.HashMap; import java.util.Map; - -import org.onap.policy.so.util.Serialization; -import org.onap.policy.drools.system.PolicyEngine; -import org.onap.policy.rest.RESTManager; -import org.onap.policy.rest.RESTManager.Pair; -import org.drools.core.WorkingMemory; - +import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.drools.core.WorkingMemory; +import org.onap.policy.drools.system.PolicyEngine; +import org.onap.policy.rest.RESTManager; +import org.onap.policy.rest.RESTManager.Pair; +import org.onap.policy.so.util.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; +/** + * This class handles the interface towards SO (Service Orchestrator) for the ONAP Policy Framework. The SO + * API is defined at this link: + * http://onap.readthedocs.io/en/latest/submodules/so.git/docs/SO_R1_Interface.html#get-orchestration-request + * + */ public final class SOManager { - - private static final Logger logger = LoggerFactory.getLogger(SOManager.class); - private static final Logger netLogger = LoggerFactory.getLogger(org.onap.policy.drools.event.comm.Topic.NETWORK_LOGGER); - private static ExecutorService executors = Executors.newCachedThreadPool(); - - static final String MEDIA_TYPE = "application/json"; - - static final String LINE_SEPARATOR = System.lineSeparator(); - - // REST get timeout value in milliseconds - private static final long DEFAULT_GET_REQUEST_TIMEOUT = 20000; - - // The REST manager used for processing REST calls for this VFC manager - private RESTManager restManager; - - private long restGetTimeout = DEFAULT_GET_REQUEST_TIMEOUT; - - public SOManager() { - restManager = new RESTManager(); - } - - public SOResponse createModuleInstance(String url, String urlBase, String username, String password, SORequest request) { - - // - // Call REST - // - Map headers = new HashMap<>(); - headers.put("Accept", MEDIA_TYPE); - - // - // 201 - CREATED - you are done just return - // - String requestJson = Serialization.gsonPretty.toJson(request); - netLogger.info("[OUT|{}|{}|{}|{}|{}|{}|]{}{}", "SO", url, username, password, headers, MEDIA_TYPE, LINE_SEPARATOR, requestJson); - Pair httpDetails = restManager.post(url, username, password, headers, MEDIA_TYPE, requestJson); - - if (httpDetails == null) { - return null; - } - - if (httpDetails.a != 202) { - return null; - } - - try { - SOResponse response = Serialization.gsonPretty.fromJson(httpDetails.b, SOResponse.class); - - String body = Serialization.gsonPretty.toJson(response); - logger.debug("***** Response to post:"); - logger.debug(body); - - String requestId = response.getRequestReferences().getRequestId(); - int attemptsLeft = 20; - - String urlGet = urlBase + "/orchestrationRequests/v2/" + requestId; - SOResponse responseGet = null; - - while (attemptsLeft-- > 0) { - Pair httpDetailsGet = restManager.get(urlGet, username, password, headers); - if (httpDetailsGet == null) { - return null; - } - - responseGet = Serialization.gsonPretty.fromJson(httpDetailsGet.b, SOResponse.class); - netLogger.info("[IN|{}|{}|]{}{}", "SO", urlGet, LINE_SEPARATOR, httpDetailsGet.b); - - body = Serialization.gsonPretty.toJson(responseGet); - logger.debug("***** Response to get:"); - logger.debug(body); - - if (httpDetailsGet.a == 200 && - (responseGet.getRequest().getRequestStatus().getRequestState().equalsIgnoreCase("COMPLETE") - || responseGet.getRequest().getRequestStatus().getRequestState().equalsIgnoreCase("FAILED"))) { - logger.debug("***** ######## VF Module Creation {}", - responseGet.getRequest().getRequestStatus().getRequestState()); - return responseGet; - } - Thread.sleep(restGetTimeout); - } - - if (responseGet != null && responseGet.getRequest() != null - && responseGet.getRequest().getRequestStatus() != null - && responseGet.getRequest().getRequestStatus().getRequestState() != null) { - logger.warn("***** ######## VF Module Creation timeout. Status: ( {})", - responseGet.getRequest().getRequestStatus().getRequestState()); - } - - return responseGet; - } - catch (JsonSyntaxException e) { - logger.error("Failed to deserialize into SOResponse: ", e); - } - catch (InterruptedException e) { - logger.error("Interrupted exception: ", e); - Thread.currentThread().interrupt(); - } - - return null; - } - - /** - * - * @param wm - * @param url - * @param urlBase - * @param username - * @param password - * @param request - * - * This method makes an asynchronous Rest call to MSO and inserts the response into the - * Drools working memory - * @return - */ - public Future asyncSORestCall(String requestID, WorkingMemory wm, String serviceInstanceId, String vnfInstanceId, SORequest request) { - return executors.submit(new AsyncSORestCallThread(requestID, wm, serviceInstanceId, vnfInstanceId, request)); - } - - private class AsyncSORestCallThread implements Runnable { - final String requestID; - final WorkingMemory wm; - final String serviceInstanceId; - final String vnfInstanceId; - final SORequest request; - - private AsyncSORestCallThread(final String requestID, final WorkingMemory wm, final String serviceInstanceId, final String vnfInstanceId, final SORequest request) { - this.requestID = requestID; - this.wm = wm; - this.serviceInstanceId = serviceInstanceId; - this.vnfInstanceId = vnfInstanceId; - this.request = request; - } - - @Override - public void run() { - try { - String serverRoot = PolicyEngine.manager.getEnvironmentProperty("so.url"); - String username = PolicyEngine.manager.getEnvironmentProperty("so.username"); - String password = PolicyEngine.manager.getEnvironmentProperty("so.password"); - - String url = serverRoot + "/serviceInstances/v5/" + serviceInstanceId + "/vnfs/" - + vnfInstanceId + "/vfModules"; - - String auth = username + ":" + password; - - Map headers = new HashMap<>(); - byte[] encodedBytes = Base64.getEncoder().encode(auth.getBytes()); - headers.put("Accept", MEDIA_TYPE); - headers.put("Authorization", "Basic " + new String(encodedBytes)); - - Gson gsonPretty = - new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); - - String soJson = gsonPretty.toJson(request); - - SOResponse so = new SOResponse(); - netLogger.info("[OUT|{}|{}|]{}{}", "SO", url, LINE_SEPARATOR, soJson); - Pair httpResponse = restManager.post(url, "policy", "policy", headers, MEDIA_TYPE, soJson); - - if (httpResponse != null) { - if (httpResponse.b != null && httpResponse.a != null) { - netLogger.info("[IN|{}|{}|]{}{}", url, "SO", LINE_SEPARATOR, httpResponse.b); - - Gson gson = new Gson(); - so = gson.fromJson(httpResponse.b, SOResponse.class); - so.setHttpResponseCode(httpResponse.a); - } - else { - logger.error("SO Response status/code is null."); - so.setHttpResponseCode(999); - } - - } - else { - logger.error("SO Response returned null."); - so.setHttpResponseCode(999); - } - - SOResponseWrapper soWrapper = new SOResponseWrapper(so, requestID); - wm.insert(soWrapper); - if (logger.isInfoEnabled()) { - logger.info("SOResponse inserted " + gsonPretty.toJson(soWrapper)); - } - } - catch (Exception e) { - logger.error("Error while performing asyncSORestCall: " + e.getMessage(), e); - - // create dummy SO object to trigger cleanup - SOResponse so = new SOResponse(); - so.setHttpResponseCode(999); - wm.insert(so); - } - } - } - - /** - * method to allow tuning of REST get timeout - * @param restGetTimeout the timeout value - */ - protected void setRestGetTimeout(final long restGetTimeout) { - this.restGetTimeout = restGetTimeout; - } - - /** - * Protected setter for rest manager to allow mocked rest manager to be used for testing - * @param restManager the test REST manager - */ - protected void setRestManager(final RESTManager restManager) { - this.restManager = restManager; - } + private static final Logger logger = LoggerFactory.getLogger(SOManager.class); + private static final Logger netLogger = LoggerFactory.getLogger(org.onap.policy.drools.event.comm.Topic.NETWORK_LOGGER); + private static ExecutorService executors = Executors.newCachedThreadPool(); + + private static final int SO_RESPONSE_ERROR = 999; + private static final String MEDIA_TYPE = "application/json"; + private static final String LINE_SEPARATOR = System.lineSeparator(); + + // REST get timeout value in milliseconds + private static final int GET_REQUESTS_BEFORE_TIMEOUT = 20; + private static final long GET_REQUEST_WAIT_INTERVAL = 20000; + + // The REST manager used for processing REST calls for this VFC manager + private RESTManager restManager; + + private long restGetTimeout = GET_REQUEST_WAIT_INTERVAL; + + /** + * Default constructor + */ + public SOManager() { + restManager = new RESTManager(); + } + + /** + * Create a service instance in SO. + * @param url the SO URL + * @param urlBase the base URL + * @param username user name on SO + * @param password password on SO + * @param request the request to issue to SO + * @return + */ + public SOResponse createModuleInstance(final String url, final String urlBase, final String username, final String password, final SORequest request) { + // Issue the HTTP POST request to SO to create the service instance + String requestJson = Serialization.gsonPretty.toJson(request); + netLogger.info("[OUT|{}|{}|{}|{}|{}|{}|]{}{}", "SO", url, username, password, createSimpleHeaders(), MEDIA_TYPE, LINE_SEPARATOR, requestJson); + Pair httpResponse = restManager.post(url, username, password, createSimpleHeaders(), MEDIA_TYPE, requestJson); + + // Process the response from SO + SOResponse response = waitForSOOperationCompletion(urlBase, username, password, url, httpResponse); + if (SO_RESPONSE_ERROR != response.getHttpResponseCode()) { + return response; + } + else { + return null; + } + } + + /** + * This method makes an asynchronous Rest call to MSO and inserts the response into Drools working memory. + * @param wm the Drools working memory + * @param url the URL to use on the POST request + * @param urlBase the SO base URL + * @param username user name for SO requests + * @param password password for SO requests + * @param request the SO request + * @return a concurrent Future for the thread that handles the request + */ + public Future asyncSORestCall(final String requestID, final WorkingMemory wm, final String serviceInstanceId, final String vnfInstanceId, final SORequest request) { + return executors.submit(new AsyncSORestCallThread(requestID, wm, serviceInstanceId, vnfInstanceId, request)); + } + + /** + * This class handles an asynchronous request to SO as a thread. + */ + private class AsyncSORestCallThread implements Callable { + final String requestID; + final WorkingMemory wm; + final String serviceInstanceId; + final String vnfInstanceId; + final SORequest request; + + /** + * Constructor, sets the context of the request. + * @param requestID The request ID + * @param wm reference to the Drools working memory + * @param serviceInstanceId the service instance in SO to use + * @param vnfInstanceId the VNF instance that is the subject of the request + * @param request the request itself + */ + private AsyncSORestCallThread(final String requestID, final WorkingMemory wm, final String serviceInstanceId, final String vnfInstanceId, final SORequest request) { + this.requestID = requestID; + this.wm = wm; + this.serviceInstanceId = serviceInstanceId; + this.vnfInstanceId = vnfInstanceId; + this.request = request; + } + + /** + * Process the asynchronous SO request. + */ + @Override + public SOResponse call() { + String urlBase = PolicyEngine.manager.getEnvironmentProperty("so.url"); + String username = PolicyEngine.manager.getEnvironmentProperty("so.username"); + String password = PolicyEngine.manager.getEnvironmentProperty("so.password"); + + // The URL of the request we will POST + String url = urlBase + "/serviceInstances/v5/" + serviceInstanceId + "/vnfs/" + + vnfInstanceId + "/vfModules"; + + // Create a JSON representation of the request + String soJson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create().toJson(request); + + netLogger.info("[OUT|{}|{}|]{}{}", "SO", url, LINE_SEPARATOR, soJson); + Pair httpResponse = restManager.post(url, "policy", "policy", createAuthenticateHeaders(username, password), MEDIA_TYPE, soJson); + + // Process the response from SO + SOResponse response = waitForSOOperationCompletion(urlBase, username, password, url, httpResponse); + + // Return the response to Drools in its working memory + SOResponseWrapper soWrapper = new SOResponseWrapper(response, requestID); + wm.insert(soWrapper); + + return response; + } + + /** + * Create HTTP headers for authenticated requests to SO. + * @param username user name on SO + * @param password password on SO + * @return the HTTP headers + */ + private Map createAuthenticateHeaders(final String username, final String password) { + String auth = username + ":" + password; + + Map headers = new HashMap<>(); + byte[] encodedBytes = Base64.getEncoder().encode(auth.getBytes()); + headers.put("Accept", MEDIA_TYPE); + headers.put("Authorization", "Basic " + new String(encodedBytes)); + + return headers; + } + } + + /** + * Wait for the SO operation we have ordered to complete. + * @param urlBaseSO The base URL for SO + * @param username user name on SO + * @param password password on SO + * @param initialRequestURL The URL of the initial HTTP request + * @param initialHTTPResponse The initial HTTP message returned from SO + * @return The parsed final response of SO to the request + */ + private SOResponse waitForSOOperationCompletion(final String urlBaseSO, final String username, final String password, + final String initialRequestURL, final Pair initialHTTPResponse) { + // Process the initial response from SO, the response to a post + SOResponse response = processSOResponse(initialRequestURL, initialHTTPResponse); + if (SO_RESPONSE_ERROR == response.getHttpResponseCode()) { + return response; + } + + // The SO URL to use to get the status of orchestration requests + String urlGet = urlBaseSO + "/orchestrationRequests/v5/" + response.getRequestReferences().getRequestId(); + + // The HTTP status code of the latest response + Pair latestHTTPResponse = initialHTTPResponse; + + // Wait for the response from SO + for (int attemptsLeft = GET_REQUESTS_BEFORE_TIMEOUT; attemptsLeft >= 0; attemptsLeft--) { + // The SO request may have completed even on the first request so we check the response here before + // issuing any other requests + if (isRequestStateFinished(latestHTTPResponse, response)) { + return response; + } + + // Wait for the defined interval before issuing a get + try { + Thread.sleep(restGetTimeout); + } + catch (InterruptedException e) { + logger.error("Interrupted exception: ", e); + Thread.currentThread().interrupt(); + response.setHttpResponseCode(SO_RESPONSE_ERROR); + return response; + } + + // Issue a GET to find the current status of our request + netLogger.info("[OUT|{}|{}|{}|{}|{}|{}|]{}", "SO", urlGet, username, password, createSimpleHeaders(), MEDIA_TYPE, LINE_SEPARATOR); + Pair httpResponse = restManager.get(urlGet, username, password, createSimpleHeaders()); + + // Get our response + response = processSOResponse(urlGet, httpResponse); + if (SO_RESPONSE_ERROR == response.getHttpResponseCode()) { + return response; + } + + // Our latest HTTP response code + latestHTTPResponse = httpResponse; + } + + // We have timed out on the SO request + response.setHttpResponseCode(SO_RESPONSE_ERROR); + return response; + } + + /** + * Parse the response message from SO into a SOResponse object. + * @param requestURL The URL of the HTTP request + * @param httpDetails The HTTP message returned from SO + * @return The parsed response + */ + private SOResponse processSOResponse(final String requestURL, final Pair httpResponse) { + SOResponse response = new SOResponse(); + + // A null httpDetails indicates a HTTP problem, a valid response from SO must be either 200 or 202 + if (!httpResultIsNullFree(httpResponse) || (httpResponse.a != 200 && httpResponse.a != 202)) { + logger.error("Invalid HTTP response received from SO"); + response.setHttpResponseCode(SO_RESPONSE_ERROR); + return response; + } + + // Parse the JSON of the response into our POJO + try { + response = Serialization.gsonPretty.fromJson(httpResponse.b, SOResponse.class); + } + catch (JsonSyntaxException e) { + logger.error("Failed to deserialize HTTP response into SOResponse: ", e); + response.setHttpResponseCode(SO_RESPONSE_ERROR); + return response; + } + + // Set the HTTP response code of the response if needed + if (response.getHttpResponseCode() == 0) { + response.setHttpResponseCode(httpResponse.a); + } + + netLogger.info("[IN|{}|{}|]{}{}", "SO", requestURL, LINE_SEPARATOR, httpResponse.b); + + if (logger.isDebugEnabled()) { + logger.debug("***** Response to SO Request to URL {}:", requestURL); + logger.debug(httpResponse.b); + } + + return response; + } + + /** + * Method to allow tuning of REST get timeout. + * @param restGetTimeout the timeout value + */ + protected void setRestGetTimeout(final long restGetTimeout) { + this.restGetTimeout = restGetTimeout; + } + + /** + * Check that the request state of a response is defined. + * @param response The response to check + * @return true if the request for the response is defined + */ + private boolean isRequestStateDefined(final SOResponse response) { + return response != null && + response.getRequest() != null && + response.getRequest().getRequestStatus() != null && + response.getRequest().getRequestStatus().getRequestState() != null; + } + + /** + * Check that the request state of a response is finished. + * @param latestHTTPDetails the HTTP details of the response + * @param response The response to check + * @return true if the request for the response is finished + */ + private boolean isRequestStateFinished(final Pair latestHTTPDetails, final SOResponse response) { + if (latestHTTPDetails != null && 200 == latestHTTPDetails.a && isRequestStateDefined(response)) { + String requestState = response.getRequest().getRequestStatus().getRequestState(); + return "COMPLETE".equalsIgnoreCase(requestState) || "FAILED".equalsIgnoreCase(requestState); + } + else { + return false; + } + } + + /** + * Check that a HTTP operation result has no nulls. + * @param httpOperationResult the result to check + * @return true if no nulls are found + */ + private boolean httpResultIsNullFree(Pair httpOperationResult) { + return httpOperationResult != null && httpOperationResult.a != null && httpOperationResult.b != null; + } + + /** + * Create simple HTTP headers for unauthenticated requests to SO. + * @return the HTTP headers + */ + private Map createSimpleHeaders() { + Map headers = new HashMap<>(); + headers.put("Accept", MEDIA_TYPE); + return headers; + } } diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/DummyWorkingMemory.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/DummyWorkingMemory.java new file mode 100644 index 000000000..af7ddc426 --- /dev/null +++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/DummyWorkingMemory.java @@ -0,0 +1,314 @@ +/*- + * ============LICENSE_START======================================================= + * so + * ================================================================================ + * Copyright (C) 2018 Ericsson. 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.so; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +import org.drools.core.WorkingMemory; +import org.drools.core.WorkingMemoryEntryPoint; +import org.drools.core.common.InternalFactHandle; +import org.drools.core.impl.InternalKnowledgeBase; +import org.drools.core.spi.AsyncExceptionHandler; +import org.drools.core.spi.GlobalResolver; +import org.kie.api.event.kiebase.KieBaseEventListener; +import org.kie.api.event.rule.AgendaEventListener; +import org.kie.api.event.rule.RuleRuntimeEventListener; +import org.kie.api.runtime.Environment; +import org.kie.api.runtime.ObjectFilter; +import org.kie.api.runtime.process.ProcessInstance; +import org.kie.api.runtime.process.WorkItemManager; +import org.kie.api.runtime.rule.Agenda; +import org.kie.api.runtime.rule.AgendaFilter; +import org.kie.api.runtime.rule.FactHandle; +import org.kie.api.runtime.rule.FactHandle.State; +import org.kie.api.runtime.rule.QueryResults; +import org.kie.api.time.SessionClock; + +public class DummyWorkingMemory implements WorkingMemory { + + @Override + public void addEventListener(RuleRuntimeEventListener listener) { + } + + @Override + public void removeEventListener(RuleRuntimeEventListener listener) { + } + + @Override + public Collection getRuleRuntimeEventListeners() { + return null; + } + + @Override + public void addEventListener(AgendaEventListener listener) { + } + + @Override + public void removeEventListener(AgendaEventListener listener) { + } + + @Override + public Collection getAgendaEventListeners() { + return null; + } + + @Override + public void addEventListener(KieBaseEventListener listener) { + } + + @Override + public void removeEventListener(KieBaseEventListener listener) { + } + + @Override + public Collection getKieBaseEventListeners() { + return null; + } + + @Override + public FactHandle insert(Object object, boolean dynamic) { + return null; + } + + @Override + public void dispose() { + } + + @Override + public String getEntryPointId() { + return null; + } + + @Override + public FactHandle insert(Object object) { + return null; + } + + @Override + public void retract(FactHandle handle) { + } + + @Override + public void delete(FactHandle handle) { + } + + @Override + public void delete(FactHandle handle, State fhState) { + + + } + + @Override + public void update(FactHandle handle, Object object) { + } + + @Override + public void update(FactHandle handle, Object object, String... modifiedProperties) { + } + + @Override + public Collection getObjects() { + return null; + } + + @Override + public Collection getObjects(ObjectFilter filter) { + return null; + } + + @Override + public Collection getFactHandles() { + return null; + } + + @Override + public Collection getFactHandles(ObjectFilter filter) { + return null; + } + + @Override + public long getFactCount() { + return 0; + } + + @Override + public Agenda getAgenda() { + return null; + } + + @Override + public void setGlobal(String identifier, Object value) { + } + + @Override + public Object getGlobal(String identifier) { + return null; + } + + @Override + public Environment getEnvironment() { + return null; + } + + @Override + public void setGlobalResolver(GlobalResolver globalResolver) { + } + + @Override + public GlobalResolver getGlobalResolver() { + return null; + } + + @Override + public InternalKnowledgeBase getKnowledgeBase() { + return null; + } + + @Override + public int fireAllRules() { + return 0; + } + + @Override + public int fireAllRules(AgendaFilter agendaFilter) { + return 0; + } + + @Override + public int fireAllRules(int fireLimit) { + return 0; + } + + @Override + public int fireAllRules(AgendaFilter agendaFilter, int fireLimit) { + return 0; + } + + @Override + public Object getObject(FactHandle handle) { + return null; + } + + @Override + public FactHandle getFactHandle(Object object) { + return null; + } + + @Override + public FactHandle getFactHandleByIdentity(Object object) { + return null; + } + + @Override + public Iterator iterateObjects() { + return null; + } + + @Override + public Iterator iterateObjects(ObjectFilter filter) { + return null; + } + + @Override + public Iterator iterateFactHandles() { + return null; + } + + @Override + public Iterator iterateFactHandles(ObjectFilter filter) { + return null; + } + + @Override + public void setFocus(String focus) { + } + + @Override + public QueryResults getQueryResults(String query, Object... arguments) { + return null; + } + + @Override + public void setAsyncExceptionHandler(AsyncExceptionHandler handler) { + } + + @Override + public void clearAgenda() { + } + + @Override + public void clearAgendaGroup(String group) { + } + + @Override + public void clearActivationGroup(String group) { + } + + @Override + public void clearRuleFlowGroup(String group) { + } + + @Override + public ProcessInstance startProcess(String processId) { + return null; + } + + @Override + public ProcessInstance startProcess(String processId, Map parameters) { + return null; + } + + @Override + public Collection getProcessInstances() { + return null; + } + + @Override + public ProcessInstance getProcessInstance(long id) { + return null; + } + + @Override + public ProcessInstance getProcessInstance(long id, boolean readOnly) { + return null; + } + + @Override + public WorkItemManager getWorkItemManager() { + return null; + } + + @Override + public void halt() { + } + + @Override + public WorkingMemoryEntryPoint getWorkingMemoryEntryPoint(String id) { + return null; + } + + @Override + public SessionClock getSessionClock() { + return null; + } + +} diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java index a2beb57b5..864362649 100644 --- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java +++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java @@ -19,234 +19,249 @@ */ package org.onap.policy.so; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.anyMap; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.startsWith; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.io.IOException; +import java.net.URI; import java.util.UUID; import java.util.concurrent.Future; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.drools.core.WorkingMemory; -import org.junit.Before; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.onap.policy.drools.system.PolicyEngine; -import org.onap.policy.rest.RESTManager; -import org.onap.policy.rest.RESTManager.Pair; -import org.onap.policy.so.util.Serialization; public class TestSOManager { - private static WorkingMemory mockedWorkingMemory; - - private RESTManager mockedRESTManager; - - private Pair httpResponsePutOK; - private Pair httpResponseGetOK; - private Pair httpResponsePostOK; - private Pair httpResponseErr; - - private SORequest request; - private SOResponse response; - - @BeforeClass - public static void beforeTestSOManager() { - mockedWorkingMemory = mock(WorkingMemory.class); - } - - @Before - public void setupMockedRest() { - mockedRESTManager = mock(RESTManager.class); - - httpResponsePutOK = mockedRESTManager.new Pair<>(202, Serialization.gsonPretty.toJson(response)); - httpResponseGetOK = mockedRESTManager.new Pair<>(200, Serialization.gsonPretty.toJson(response)); - httpResponsePostOK = mockedRESTManager.new Pair<>(202, Serialization.gsonPretty.toJson(response)); - httpResponseErr = mockedRESTManager.new Pair<>(200, "{"); - } - - @Before - public void createRequestAndResponse() { - request = new SORequest(); - SORequestStatus requestStatus = new SORequestStatus(); - requestStatus.setRequestState("COMPLETE"); - request.setRequestStatus(requestStatus); - request.setRequestId(UUID.randomUUID()); - - response = new SOResponse(); - - SORequestReferences requestReferences = new SORequestReferences(); - String requestId = UUID.randomUUID().toString(); - requestReferences.setRequestId(requestId); - response.setRequestReferences(requestReferences); - - response.setRequest(request); - } - - @Test - public void testSOInitiation() { - assertNotNull(new SOManager()); - } - - @Test - public void testCreateModuleInstance() throws InterruptedException { - SOManager manager = new SOManager(); - manager.setRestManager(mockedRESTManager); - - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "OK", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("Null"), anyMap(), anyString(), anyString())) - .thenReturn(null); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "Null", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("Not202"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponseErr); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "Not202", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetNull"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetNull"), anyMap())) - .thenReturn(null); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetNull", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOK"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOK"), anyMap())) - .thenReturn(httpResponseGetOK); - request.getRequestStatus().setRequestState("COMPLETE"); - SOResponse response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOK", request); - assertNotNull(response); - assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); - - response.getRequest().getRequestStatus().setRequestState("FAILED"); - Pair httpResponseGetOKRequestFailed = mockedRESTManager.new Pair<>(200, Serialization.gsonPretty.toJson(response)); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOKReqFailed"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOKReqFailed"), anyMap())) - .thenReturn(httpResponseGetOKRequestFailed); - response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOKReqFailed", request); - assertNotNull(response); - assertEquals("FAILED", response.getRequest().getRequestStatus().getRequestState()); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetBadJSON"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetBadJSON"), anyMap())) - .thenReturn(httpResponseErr); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetBadJSON", request)); - - response.getRequest().getRequestStatus().setRequestState("IN-PROGRESS"); - Pair httpResponseGetOKRequestTimeout = mockedRESTManager.new Pair<>(200, Serialization.gsonPretty.toJson(response)); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOKReqTimeout"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOKReqTimeout"), anyMap())) - .thenReturn(httpResponseGetOKRequestTimeout); - - manager.setRestGetTimeout(10); - response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOKReqTimeout", request); - assertNotNull(response); - assertEquals("IN-PROGRESS", response.getRequest().getRequestStatus().getRequestState()); - } - - @Test - public void testAsyncSORestCall() throws InterruptedException { - PolicyEngine.manager.getEnvironment().put("so.url", "http://somewhere.over.the.rainbow.null"); - PolicyEngine.manager.getEnvironment().put("so.username", "Dorothy"); - PolicyEngine.manager.getEnvironment().put("so.password", "OK"); - - SOManager manager = new SOManager(); - manager.setRestManager(mockedRESTManager); - - String serviceInstanceId = UUID.randomUUID().toString(); - String vnfInstanceId = UUID.randomUUID().toString(); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow.null"), eq("policy"), eq("policy"), anyMap(), anyString(), anyString())) - .thenReturn(null); - - Future asyncRestCallFuture = manager.asyncSORestCall(request.getRequestId().toString(), mockedWorkingMemory, serviceInstanceId, vnfInstanceId, request); - try { - assertNull(asyncRestCallFuture.get()); - } - catch (Exception e) { - fail("test should not throw an exception"); - } - - PolicyEngine.manager.getEnvironment().put("so.url", "http://somewhere.over.the.rainbow.err"); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow.err"), eq("policy"), eq("policy"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponseErr); - - asyncRestCallFuture = manager.asyncSORestCall(request.getRequestId().toString(), mockedWorkingMemory, serviceInstanceId, vnfInstanceId, request); - try { - assertNull(asyncRestCallFuture.get()); - } - catch (Exception e) { - System.err.println(e); - fail("test should not throw an exception"); - } - - PolicyEngine.manager.getEnvironment().put("so.url", "http://somewhere.over.the.rainbow.ok"); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow.ok"), eq("policy"), eq("policy"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePostOK); - - asyncRestCallFuture = manager.asyncSORestCall(request.getRequestId().toString(), mockedWorkingMemory, serviceInstanceId, vnfInstanceId, request); - try { - assertNull(asyncRestCallFuture.get()); - } - catch (Exception e) { - System.err.println(e); - fail("test should not throw an exception"); - } -/* - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("Null"), anyMap(), anyString(), anyString())) - .thenReturn(null); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "Null", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("Not202"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponseErr); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "Not202", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetNull"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetNull"), anyMap())) - .thenReturn(null); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetNull", request)); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOK"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOK"), anyMap())) - .thenReturn(httpResponseGetOK); - request.getRequestStatus().setRequestState("COMPLETE"); - SOResponse response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOK", request); - assertNotNull(response); - assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); - - response.getRequest().getRequestStatus().setRequestState("FAILED"); - Pair httpResponseGetOKRequestFailed = mockedRESTManager.new Pair<>(200, Serialization.gsonPretty.toJson(response)); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOKReqFailed"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOKReqFailed"), anyMap())) - .thenReturn(httpResponseGetOKRequestFailed); - response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOKReqFailed", request); - assertNotNull(response); - assertEquals("FAILED", response.getRequest().getRequestStatus().getRequestState()); - - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetBadJSON"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetBadJSON"), anyMap())) - .thenReturn(httpResponseErr); - assertNull(manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetBadJSON", request)); - - response.getRequest().getRequestStatus().setRequestState("IN-PROGRESS"); - Pair httpResponseGetOKRequestTimeout = mockedRESTManager.new Pair<>(200, Serialization.gsonPretty.toJson(response)); - when(mockedRESTManager.post(startsWith("http://somewhere.over.the.rainbow"), eq("Dorothy"), eq("PutOKGetOKReqTimeout"), anyMap(), anyString(), anyString())) - .thenReturn(httpResponsePutOK); - when(mockedRESTManager.get(startsWith("http://somewhere.over.the.rainbow/InOz"), eq("Dorothy"), eq("PutOKGetOKReqTimeout"), anyMap())) - .thenReturn(httpResponseGetOKRequestTimeout); - - manager.setRestGetTimeout(10); - response = manager.createModuleInstance("http://somewhere.over.the.rainbow", "http://somewhere.over.the.rainbow/InOz", "Dorothy", "PutOKGetOKReqTimeout", request); - assertNotNull(response); - assertEquals("FAILED", response.getRequest().getRequestStatus().getRequestState()); - */ - } + private static final String BASE_URI = "http://localhost:46553/TestSOManager"; + private static final String BASE_SO_URI = BASE_URI + "/SO"; + private static HttpServer server; + + @BeforeClass + public static void setUp() { + final ResourceConfig rc = new ResourceConfig(TestSoDummyServer.class); + server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc); + } + + @AfterClass + public static void tearDown() throws Exception { + server.shutdown(); + } + + @Test + public void testGrizzlyServer() throws ClientProtocolException, IOException { + CloseableHttpClient httpclient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet("http://localhost:46553/TestSOManager/SO/Stats"); + CloseableHttpResponse response = httpclient.execute(httpGet); + + String returnBody = EntityUtils.toString(response.getEntity(), "UTF-8"); + assertTrue(returnBody.matches("^\\{\"GET\": [0-9]*,\"STAT\": [0-9]*,\"POST\": [0-9]*,\"PUT\": [0-9]*\\}$")); + } + + @Test + public void testServiceInstantiation() throws IOException { + SOManager manager = new SOManager(); + assertNotNull(manager); + manager.setRestGetTimeout(100); + + SOResponse response = manager.createModuleInstance("http:/localhost:99999999", BASE_SO_URI, "sean", "citizen", null); + assertNull(response); + + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", null); + assertNull(response); + + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", new SORequest()); + assertNull(response); + + SORequest request = new SORequest(); + request.setRequestId(UUID.randomUUID()); + request.setRequestScope("Test"); + request.setRequestType("ReturnBadJson"); + request.setStartTime("2018-03-23 16:31"); + request.setRequestStatus(new SORequestStatus()); + request.getRequestStatus().setRequestState("ONGOING"); + + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNull(response); + + request.setRequestType("ReturnCompleted"); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNotNull(response); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + + request.setRequestType("ReturnFailed"); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNotNull(response); + assertEquals("FAILED", response.getRequest().getRequestStatus().getRequestState()); + + // Use scope to set the number of iterations we'll wait for + + request.setRequestType("ReturnOnging200"); + request.setRequestScope(new Integer(10).toString()); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNotNull(response); + assertNotNull(response.getRequest()); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + + request.setRequestType("ReturnOnging202"); + request.setRequestScope(new Integer(20).toString()); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNotNull(response); + assertNotNull(response.getRequest()); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + + // Test timeout after 20 attempts for a response + request.setRequestType("ReturnOnging202"); + request.setRequestScope(new Integer(21).toString()); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNull(response); + + // Test bad response after 3 attempts for a response + request.setRequestType("ReturnBadAfterWait"); + request.setRequestScope(new Integer(3).toString()); + response = manager.createModuleInstance(BASE_SO_URI + "/serviceInstances/v5", BASE_SO_URI, "sean", "citizen", request); + assertNull(response); + } + + @Test + public void testVfModuleCreation() throws IOException { + SOManager manager = new SOManager(); + assertNotNull(manager); + manager.setRestGetTimeout(100); + + PolicyEngine.manager.setEnvironmentProperty("so.username", "sean"); + PolicyEngine.manager.setEnvironmentProperty("so.password", "citizen"); + + WorkingMemory wm = new DummyWorkingMemory(); + + PolicyEngine.manager.setEnvironmentProperty("so.url", "http:/localhost:99999999"); + Future asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), null); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + PolicyEngine.manager.setEnvironmentProperty("so.url", BASE_SO_URI); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), null); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), new SORequest()); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + SORequest request = new SORequest(); + request.setRequestId(UUID.randomUUID()); + request.setRequestScope("Test"); + request.setRequestType("ReturnBadJson"); + request.setStartTime("2018-03-23 16:31"); + request.setRequestStatus(new SORequestStatus()); + request.getRequestStatus().setRequestState("ONGOING"); + + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + request.setRequestType("ReturnCompleted"); + + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + request.setRequestType("ReturnFailed"); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals("FAILED", response.getRequest().getRequestStatus().getRequestState()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + // Use scope to set the number of iterations we'll wait for + + request.setRequestType("ReturnOnging200"); + request.setRequestScope(new Integer(10).toString()); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertNotNull(response.getRequest()); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + request.setRequestType("ReturnOnging202"); + request.setRequestScope(new Integer(20).toString()); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertNotNull(response.getRequest()); + assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + // Test timeout after 20 attempts for a response + request.setRequestType("ReturnOnging202"); + request.setRequestScope(new Integer(21).toString()); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + + // Test bad response after 3 attempts for a response + request.setRequestType("ReturnBadAfterWait"); + request.setRequestScope(new Integer(3).toString()); + asyncRestCallFuture = manager.asyncSORestCall(UUID.randomUUID().toString(), wm, UUID.randomUUID().toString(), UUID.randomUUID().toString(), request); + try { + SOResponse response = asyncRestCallFuture.get(); + assertEquals(999, response.getHttpResponseCode()); + } + catch (Exception e) { + fail("test should not throw an exception"); + } + } } diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoDummyServer.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoDummyServer.java new file mode 100644 index 000000000..907ca69bc --- /dev/null +++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoDummyServer.java @@ -0,0 +1,272 @@ +/*- + * ============LICENSE_START======================================================= + * so + * ================================================================================ + * Copyright (C) 2018 Ericsson. 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.so; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import com.google.gson.Gson; + +@Path("/SO") +public class TestSoDummyServer { + + private static int postMessagesReceived = 0; + private static int putMessagesReceived = 0; + private static int statMessagesReceived = 0; + private static int getMessagesReceived = 0; + + private static Map ongoingRequestMap = new ConcurrentHashMap<>(); + + @GET + @Path("/Stats") + public Response serviceGetStats() { + statMessagesReceived++; + return Response.status(200).entity("{\"GET\": " + getMessagesReceived + ",\"STAT\": " + statMessagesReceived + ",\"POST\": " + postMessagesReceived + ",\"PUT\": " + putMessagesReceived + "}").build(); + } + + @GET + @Path("/OneStat/{statType}") + public Response serviceGetStat(@PathParam("statType") final String statType) { + statMessagesReceived++; + return Response.status(200).entity("{\"TYPE\": " + statType + "}").build(); + } + + @POST + @Path("/serviceInstances/v5") + public Response servicePostRequest(final String jsonString) { + postMessagesReceived++; + + if (jsonString == null) { + return Response.status(400).build(); + } + + SORequest request = null; + try { + request = new Gson().fromJson(jsonString, SORequest.class); + } + catch (Exception e) { + return Response.status(400).build(); + } + + if (request == null) { + return Response.status(400).build(); + } + + if (request.getRequestType() == null) { + return Response.status(400).build(); + } + + if ("ReturnBadJson".equals(request.getRequestType())) { + return Response.status(200) + .entity("{\"GET\": , " + getMessagesReceived + ",\"STAT\": " + statMessagesReceived + ",\"POST\": , " + postMessagesReceived + ",\"PUT\": " + putMessagesReceived + "}") + .build(); + } + + SOResponse response = new SOResponse(); + response.setRequest(request); + response.setRequestReferences(new SORequestReferences()); + response.getRequestReferences().setRequestId(request.getRequestId().toString()); + + if ("ReturnCompleted".equals(request.getRequestType())) { + response.getRequest().getRequestStatus().setRequestState("COMPLETE"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnFailed".equals(request.getRequestType())) { + response.getRequest().getRequestStatus().setRequestState("FAILED"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnOnging202".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(202); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnOnging200".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + + if ("ReturnBadAfterWait".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + return null; + } + + @POST + @Path("/serviceInstances/v5/{serviceInstanceId}/vnfs/{vnfInstanceId}/vfModules") + public Response servicePostRequestVfModules( + @PathParam("serviceInstanceId") final String serviceInstanceId, + @PathParam("vnfInstanceId") final String vnfInstanceId, + final String jsonString) { + postMessagesReceived++; + + if (jsonString == null) { + return Response.status(400).build(); + } + + SORequest request = null; + try { + request = new Gson().fromJson(jsonString, SORequest.class); + } + catch (Exception e) { + return Response.status(400).build(); + } + + if (request == null) { + return Response.status(400).build(); + } + + if (request.getRequestType() == null) { + return Response.status(400).build(); + } + + if ("ReturnBadJson".equals(request.getRequestType())) { + return Response.status(200) + .entity("{\"GET\": , " + getMessagesReceived + ",\"STAT\": " + statMessagesReceived + ",\"POST\": , " + postMessagesReceived + ",\"PUT\": " + putMessagesReceived + "}") + .build(); + } + + SOResponse response = new SOResponse(); + response.setRequest(request); + response.setRequestReferences(new SORequestReferences()); + response.getRequestReferences().setRequestId(request.getRequestId().toString()); + + if ("ReturnCompleted".equals(request.getRequestType())) { + response.getRequest().getRequestStatus().setRequestState("COMPLETE"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnFailed".equals(request.getRequestType())) { + response.getRequest().getRequestStatus().setRequestState("FAILED"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnOnging202".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(202); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + if ("ReturnOnging200".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + + if ("ReturnBadAfterWait".equals(request.getRequestType())) { + ongoingRequestMap.put(request.getRequestId().toString(), response); + + response.getRequest().getRequestStatus().setRequestState("ONGOING"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + return null; + } + + @GET + @Path("/orchestrationRequests/v5/{nsInstanceId}") + public Response soRequestStatus(@PathParam("nsInstanceId") final String nsInstanceId) { + + SOResponse response = ongoingRequestMap.get(nsInstanceId); + + int iterationsLeft = Integer.valueOf(response.getRequest().getRequestScope()); + if (--iterationsLeft > 0) { + response.getRequest().setRequestScope(new Integer(iterationsLeft).toString()); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } + + ongoingRequestMap.remove(nsInstanceId); + + if ("ReturnBadAfterWait".equals(response.getRequest().getRequestType())) { + return Response.status(400).build(); + } + + response.getRequest().getRequestStatus().setRequestState("COMPLETE"); + response.getRequest().setRequestScope("0"); + response.setHttpResponseCode(200); + String responseString = new Gson().toJson(response, SOResponse.class); + return Response.status(response.getHttpResponseCode()) + .entity(responseString) + .build(); + } +} diff --git a/controlloop/common/simulators/pom.xml b/controlloop/common/simulators/pom.xml index c256d13ac..1c613eaba 100644 --- a/controlloop/common/simulators/pom.xml +++ b/controlloop/common/simulators/pom.xml @@ -51,7 +51,6 @@ org.onap.policy.drools-applications.controlloop.common.model-impl so ${project.version} - test org.onap.policy.drools-applications.controlloop.common.model-impl diff --git a/controlloop/common/simulators/src/main/java/org/onap/policy/simulators/SoSimulatorJaxRs.java b/controlloop/common/simulators/src/main/java/org/onap/policy/simulators/SoSimulatorJaxRs.java index 1547fd41f..9b623a646 100644 --- a/controlloop/common/simulators/src/main/java/org/onap/policy/simulators/SoSimulatorJaxRs.java +++ b/controlloop/common/simulators/src/main/java/org/onap/policy/simulators/SoSimulatorJaxRs.java @@ -20,6 +20,8 @@ package org.onap.policy.simulators; +import java.util.UUID; + import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -27,10 +29,17 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import org.onap.policy.so.SORequest; +import org.onap.policy.so.SORequestReferences; +import org.onap.policy.so.SORequestStatus; +import org.onap.policy.so.SOResponse; + +import com.att.aft.dme2.internal.gson.Gson; + @Path("/serviceInstances") public class SoSimulatorJaxRs { - - /** + + /** * SO post query. * * @param serviceInstanceId the service instance Id @@ -41,14 +50,23 @@ public class SoSimulatorJaxRs { @Path("/v5/{serviceInstanceId}/vnfs/{vnfInstanceId}/vfModules") @Consumes(MediaType.APPLICATION_JSON) @Produces("application/json") - public String soPostQuery(@PathParam("serviceInstanceId") String serviceInstanceId, - @PathParam("vnfInstanceId") String vnfInstanceId) { - - // the requestID contained in the SO Response is a newly generated requestID - // with no relation to the requestID in Policy controlLoopEvent - return "{\"requestReferences\": {\"instanceId\": \"ff305d54-75b4-ff1b-bdb2-eb6b9e5460ff\", \"requestId\": \"" - + "rq1234d1-5a33-ffdf-23ab-12abad84e331\" }}"; + public String soPostQuery(@PathParam("serviceInstanceId") String serviceInstanceId, @PathParam("vnfInstanceId") String vnfInstanceId) + { + SORequest request = new SORequest(); + SORequestStatus requestStatus = new SORequestStatus(); + requestStatus.setRequestState("COMPLETE"); + request.setRequestStatus(requestStatus); + request.setRequestId(UUID.randomUUID()); + + SOResponse response = new SOResponse(); + + SORequestReferences requestReferences = new SORequestReferences(); + String requestId = UUID.randomUUID().toString(); + requestReferences.setRequestId(requestId); + response.setRequestReferences(requestReferences); + + response.setRequest(request); + return new Gson().toJson(response); } - } diff --git a/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/config/so.success.json b/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/config/so.success.json index 8f3387e4d..6d617b4bf 100644 --- a/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/config/so.success.json +++ b/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/config/so.success.json @@ -3,5 +3,13 @@ "instanceId": "ff305d54-75b4-ff1b-bdb2-eb6b9e5460ff", "requestId": "e4f95e0c-a013-4530-8e59-c5c5f9e539b6" }, + "request": { + "requestId": "e4f95e0c-a013-4530-8e59-c5c5f9e539b6", + "requestStatus": { + "percentProgress": 100, + "requestState": "COMPLETE", + "wasRolledBack": false + } + }, "httpResponseCode": 200 -} \ No newline at end of file +} -- cgit 1.2.3-korg