diff options
8 files changed, 1168 insertions, 454 deletions
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 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>2.13.0</version> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-grizzly2-http</artifactId> + <version>2.25.1</version> <scope>test</scope> </dependency> </dependencies> 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<String, String> 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<Integer, String> 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<Integer, String> 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<String, String> 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<Integer, String> 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<Integer, String> 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<SOResponse> 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<SOResponse> { + 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<Integer, String> 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<String, String> createAuthenticateHeaders(final String username, final String password) { + String auth = username + ":" + password; + + Map<String, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<String, String> createSimpleHeaders() { + Map<String, String> 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<RuleRuntimeEventListener> getRuleRuntimeEventListeners() { + return null; + } + + @Override + public void addEventListener(AgendaEventListener listener) { + } + + @Override + public void removeEventListener(AgendaEventListener listener) { + } + + @Override + public Collection<AgendaEventListener> getAgendaEventListeners() { + return null; + } + + @Override + public void addEventListener(KieBaseEventListener listener) { + } + + @Override + public void removeEventListener(KieBaseEventListener listener) { + } + + @Override + public Collection<KieBaseEventListener> 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<? extends Object> getObjects() { + return null; + } + + @Override + public Collection<? extends Object> getObjects(ObjectFilter filter) { + return null; + } + + @Override + public <T extends FactHandle> Collection<T> getFactHandles() { + return null; + } + + @Override + public <T extends FactHandle> Collection<T> 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<InternalFactHandle> iterateFactHandles() { + return null; + } + + @Override + public Iterator<InternalFactHandle> 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<String, Object> parameters) { + return null; + } + + @Override + public Collection<ProcessInstance> 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<Integer, String> httpResponsePutOK; - private Pair<Integer, String> httpResponseGetOK; - private Pair<Integer, String> httpResponsePostOK; - private Pair<Integer, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<Integer, String> 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<SOResponse> 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<String, SOResponse> 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 @@ <groupId>org.onap.policy.drools-applications.controlloop.common.model-impl</groupId> <artifactId>so</artifactId> <version>${project.version}</version> - <scope>test</scope> </dependency> <dependency> <groupId>org.onap.policy.drools-applications.controlloop.common.model-impl</groupId> 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 +} |