From 65f5fcc147c8dcc43b9c30742c81545859ab3e02 Mon Sep 17 00:00:00 2001
From: liamfallon <liam.fallon@ericsson.com>
Date: Tue, 30 Jan 2018 17:06:20 +0000
Subject: Fix technical debt/JUnit on SO/VFC/SO ACTOR

Unit test expanded for SO POJOs, technical debt removed in SO actor and VFC pojos.

Change-Id: I23b886c40c1ac6ac8dc2ebbaade315b71cca9dd0
Signed-off-by: liamfallon <liam.fallon@ericsson.com>
Issue-ID: POLICY-455
---
 controlloop/common/model-impl/so/pom.xml           |  62 ++--
 .../main/java/org/onap/policy/so/SOManager.java    | 381 +++++++++++----------
 .../java/org/onap/policy/so/SOPolicyException.java |  57 ---
 .../onap/policy/so/SOPolicyExceptionHolder.java    |  57 +++
 .../java/org/onap/policy/so/SORequestDetails.java  |  14 +-
 .../java/org/onap/policy/so/SORequestError.java    |  12 +-
 .../java/org/onap/policy/so/SOResponseWrapper.java |  18 +-
 .../org/onap/policy/so/SOServiceException.java     |  66 ----
 .../onap/policy/so/SOServiceExceptionHolder.java   |  66 ++++
 .../java/org/onap/policy/so/TestSOManager.java     | 252 ++++++++++++++
 .../org/onap/policy/so/TestSoPolicyException.java  |  48 ---
 .../policy/so/TestSoPolicyExceptionHolder.java     |  48 +++
 .../org/onap/policy/so/TestSoRequestDetails.java   | 106 ++++++
 .../org/onap/policy/so/TestSoRequestError.java     |   4 +-
 .../org/onap/policy/so/TestSoResponseWrapper.java  |  55 +++
 .../org/onap/policy/so/TestSoServiceException.java |  50 ---
 .../policy/so/TestSoServiceExceptionHolder.java    |  50 +++
 17 files changed, 907 insertions(+), 439 deletions(-)
 delete mode 100644 controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyException.java
 create mode 100644 controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyExceptionHolder.java
 delete mode 100644 controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceException.java
 create mode 100644 controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceExceptionHolder.java
 create mode 100644 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java
 delete mode 100755 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyException.java
 create mode 100755 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyExceptionHolder.java
 delete mode 100755 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceException.java
 create mode 100755 controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceExceptionHolder.java

(limited to 'controlloop/common/model-impl/so')

diff --git a/controlloop/common/model-impl/so/pom.xml b/controlloop/common/model-impl/so/pom.xml
index 05d225888..718a82eef 100644
--- a/controlloop/common/model-impl/so/pom.xml
+++ b/controlloop/common/model-impl/so/pom.xml
@@ -19,9 +19,9 @@
   -->
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+	<modelVersion>4.0.0</modelVersion>
 
-  <artifactId>so</artifactId>
+	<artifactId>so</artifactId>
 
 	<parent>
 		<groupId>org.onap.policy.drools-applications</groupId>
@@ -29,35 +29,41 @@
 		<version>1.2.0-SNAPSHOT</version>
 	</parent>
 
-  <dependencies>
-	<dependency>
-		<groupId>junit</groupId>
-		<artifactId>junit</artifactId>
-		<version>4.12</version>
-		<scope>provided</scope>
-	</dependency>
-	<dependency>
-		<groupId>com.google.code.gson</groupId>
-		<artifactId>gson</artifactId>
-		<version>2.5</version>
-		<scope>provided</scope>
-	</dependency>
-	<dependency>
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.google.code.gson</groupId>
+			<artifactId>gson</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
 			<groupId>org.drools</groupId>
 			<artifactId>drools-core</artifactId>
 			<version>6.5.0.Final</version>
 			<scope>provided</scope>
 		</dependency>
-	<dependency>
-		<groupId>org.onap.policy.drools-applications</groupId>
-		<artifactId>rest</artifactId>
-		<version>${project.version}</version>
-	</dependency>
-	<dependency>
-		   <groupId>org.onap.policy.drools-pdp</groupId>
-		   <artifactId>policy-management</artifactId>
-		   <version>${project.version}</version>
-		   <scope>provided</scope>
-	</dependency>
-  </dependencies>
+		<dependency>
+			<groupId>org.onap.policy.drools-applications</groupId>
+			<artifactId>rest</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.onap.policy.drools-pdp</groupId>
+			<artifactId>policy-management</artifactId>
+			<version>${project.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+			<version>2.13.0</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
 </project>
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 4b1d1d630..35227d310 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
@@ -32,6 +32,7 @@ import org.drools.core.WorkingMemory;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,176 +43,212 @@ import com.google.gson.JsonSyntaxException;
 
 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();
-
-    public static 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, LINE_SEPARATOR, requestJson);
-        Pair<Integer, String> httpDetails =
-                new RESTManager().post(url, username, password, headers, MEDIA_TYPE, requestJson);
-
-        if (httpDetails == null) {
-            return null;
-        }
-
-        if (httpDetails.a == 202) {
-            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 =
-                            new RESTManager().get(urlGet, username, password, headers);
-                    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) {
-                        if (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(20000);
-                }
-
-                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
-     */
-    public void asyncSORestCall(String requestID, WorkingMemory wm, String serviceInstanceId,
-            String vnfInstanceId, SORequest request) {
-        executors.submit(new Runnable() {
-            @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 = new 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);
-                    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);
-                }
-            }
-        });
-    }
-
+	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;
+	}
 }
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyException.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyException.java
deleted file mode 100644
index 7065feaac..000000000
--- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyException.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * so
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.so;
-
-import java.io.Serializable;
-
-import com.google.gson.annotations.SerializedName;
-
-public class SOPolicyException implements Serializable {
-
-    private static final long serialVersionUID = -3283942659786236032L;
-
-    @SerializedName("messageId")
-    private String messageId;
-
-    @SerializedName("text")
-    private String text;
-
-    public SOPolicyException() {
-      //required by author
-    }
-
-    public String getMessageId() {
-        return messageId;
-    }
-
-    public String getText() {
-        return text;
-    }
-
-    public void setMessageId(String messageId) {
-        this.messageId = messageId;
-    }
-
-    public void setText(String text) {
-        this.text = text;
-    }
-
-}
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyExceptionHolder.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyExceptionHolder.java
new file mode 100644
index 000000000..cab396d01
--- /dev/null
+++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOPolicyExceptionHolder.java
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * so
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.so;
+
+import java.io.Serializable;
+
+import com.google.gson.annotations.SerializedName;
+
+public class SOPolicyExceptionHolder implements Serializable {
+
+    private static final long serialVersionUID = -3283942659786236032L;
+
+    @SerializedName("messageId")
+    private String messageId;
+
+    @SerializedName("text")
+    private String text;
+
+    public SOPolicyExceptionHolder() {
+      //required by author
+    }
+
+    public String getMessageId() {
+        return messageId;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setMessageId(String messageId) {
+        this.messageId = messageId;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+}
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestDetails.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestDetails.java
index a86418198..72e35d96e 100644
--- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestDetails.java
+++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestDetails.java
@@ -58,6 +58,7 @@ public class SORequestDetails implements Serializable {
         this.requestInfo = soRequestDetails.requestInfo;
         this.relatedInstanceList = soRequestDetails.relatedInstanceList;
         this.requestParameters = soRequestDetails.requestParameters;
+        this.subscriberInfo = soRequestDetails.subscriberInfo;
     }
 
     @Override
@@ -99,6 +100,12 @@ public class SORequestDetails implements Serializable {
         }
         else if (!requestParameters.equals(other.requestParameters))
             return false;
+        if (subscriberInfo == null) {
+            if (other.subscriberInfo != null)
+                return false;
+        }
+        else if (!subscriberInfo.equals(other.subscriberInfo))
+            return false;
         return true;
     }
 
@@ -160,11 +167,16 @@ public class SORequestDetails implements Serializable {
         this.subscriberInfo = subscriberInfo;
     }
 
+    public void setRelatedInstanceList(List<SORelatedInstanceListElement> relatedInstanceList) {
+        this.relatedInstanceList = relatedInstanceList;
+    }
+
     @Override
     public String toString() {
         return "SORequestDetails [modelInfo=" + modelInfo + ", cloudConfiguration="
                 + cloudConfiguration + ", requestInfo=" + requestInfo + ", relatedInstanceList="
-                + relatedInstanceList + ", requestParameters=" + requestParameters + "]";
+                + relatedInstanceList + ", requestParameters=" + requestParameters +
+                ", subscriberInfo=" + subscriberInfo + "]";
     }
 
 }
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestError.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestError.java
index c9dad036a..49860417c 100644
--- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestError.java
+++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SORequestError.java
@@ -29,28 +29,28 @@ public class SORequestError implements Serializable {
     private static final long serialVersionUID = -3283942659786236032L;
 
     @SerializedName("policyException")
-    private SOPolicyException policyException;
+    private SOPolicyExceptionHolder policyException;
 
     @SerializedName("serviceException")
-    private SOServiceException serviceException;
+    private SOServiceExceptionHolder serviceException;
 
     public SORequestError() {
         // required by author
     }
 
-    public SOPolicyException getPolicyException() {
+    public SOPolicyExceptionHolder getPolicyException() {
         return policyException;
     }
 
-    public SOServiceException getServiceException() {
+    public SOServiceExceptionHolder getServiceException() {
         return serviceException;
     }
 
-    public void setPolicyException(SOPolicyException policyException) {
+    public void setPolicyException(SOPolicyExceptionHolder policyException) {
         this.policyException = policyException;
     }
 
-    public void setServiceException(SOServiceException serviceException) {
+    public void setServiceException(SOServiceExceptionHolder serviceException) {
         this.serviceException = serviceException;
     }
 
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOResponseWrapper.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOResponseWrapper.java
index 184ae5ef1..e18cbb62d 100644
--- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOResponseWrapper.java
+++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOResponseWrapper.java
@@ -29,12 +29,12 @@ public class SOResponseWrapper implements Serializable {
     private static final long serialVersionUID = 7673023687132889069L;
 
     @SerializedName("SoResponse")
-    private SOResponse SoResponse;
+    private SOResponse soResponse;
 
     private transient String requestID;
 
     public SOResponseWrapper(SOResponse response, String reqID) {
-        this.SoResponse = response;
+        this.soResponse = response;
         this.requestID = reqID;
     }
 
@@ -50,12 +50,12 @@ public class SOResponseWrapper implements Serializable {
             return false;
         }
         SOResponseWrapper other = (SOResponseWrapper) obj;
-        if (SoResponse == null) {
-            if (other.SoResponse != null) {
+        if (soResponse == null) {
+            if (other.soResponse != null) {
                 return false;
             }
         }
-        else if (!SoResponse.equals(other.SoResponse)) {
+        else if (!soResponse.equals(other.soResponse)) {
             return false;
         }
         if (requestID == null) {
@@ -74,14 +74,14 @@ public class SOResponseWrapper implements Serializable {
     }
 
     public SOResponse getSoResponse() {
-        return SoResponse;
+        return soResponse;
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
-        result = prime * result + ((SoResponse == null) ? 0 : SoResponse.hashCode());
+        result = prime * result + ((soResponse == null) ? 0 : soResponse.hashCode());
         result = prime * result + ((requestID == null) ? 0 : requestID.hashCode());
         return result;
     }
@@ -91,12 +91,12 @@ public class SOResponseWrapper implements Serializable {
     }
 
     public void setSoResponse(SOResponse sOResponse) {
-        SoResponse = sOResponse;
+        soResponse = sOResponse;
     }
 
     @Override
     public String toString() {
-        return "SOResponseWrapper [SOResponse=" + SoResponse + ", RequestID=" + requestID + "]";
+        return "SOResponseWrapper [SOResponse=" + soResponse + ", RequestID=" + requestID + "]";
     }
 
 }
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceException.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceException.java
deleted file mode 100644
index 3290f2e41..000000000
--- a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * so
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.so;
-
-import java.io.Serializable;
-import java.util.LinkedList;
-import java.util.List;
-
-import com.google.gson.annotations.SerializedName;
-
-public class SOServiceException implements Serializable {
-
-    private static final long serialVersionUID = -3283942659786236032L;
-
-    @SerializedName("messageId")
-    private String messageId;
-
-    @SerializedName("text")
-    private String text;
-
-    @SerializedName("variables")
-    private List<String> variables = new LinkedList<>();
-
-    public SOServiceException() {
-        // required by author
-    }
-
-    public String getMessageId() {
-        return messageId;
-    }
-
-    public String getText() {
-        return text;
-    }
-
-    public List<String> getVariables() {
-        return variables;
-    }
-
-    public void setMessageId(String messageId) {
-        this.messageId = messageId;
-    }
-
-    public void setText(String text) {
-        this.text = text;
-    }
-
-}
diff --git a/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceExceptionHolder.java b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceExceptionHolder.java
new file mode 100644
index 000000000..61366d3c5
--- /dev/null
+++ b/controlloop/common/model-impl/so/src/main/java/org/onap/policy/so/SOServiceExceptionHolder.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * so
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.so;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+
+public class SOServiceExceptionHolder implements Serializable {
+
+    private static final long serialVersionUID = -3283942659786236032L;
+
+    @SerializedName("messageId")
+    private String messageId;
+
+    @SerializedName("text")
+    private String text;
+
+    @SerializedName("variables")
+    private List<String> variables = new LinkedList<>();
+
+    public SOServiceExceptionHolder() {
+        // required by author
+    }
+
+    public String getMessageId() {
+        return messageId;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public List<String> getVariables() {
+        return variables;
+    }
+
+    public void setMessageId(String messageId) {
+        this.messageId = messageId;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+}
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
new file mode 100644
index 000000000..a2beb57b5
--- /dev/null
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSOManager.java
@@ -0,0 +1,252 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * TestSOManager
+ * ================================================================================
+ * 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 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 java.util.UUID;
+import java.util.concurrent.Future;
+
+import org.drools.core.WorkingMemory;
+import org.junit.Before;
+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());
+		*/
+	}
+}
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyException.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyException.java
deleted file mode 100755
index b2ba7f4d0..000000000
--- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * so
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.so;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class TestSoPolicyException {
-
-    @Test
-    public void testConstructor() {
-        SOPolicyException obj = new SOPolicyException();
-
-        assertTrue(obj.getMessageId() == null);
-        assertTrue(obj.getText() == null);
-    }
-
-    @Test
-    public void testSetGet() {
-        SOPolicyException obj = new SOPolicyException();
-
-        obj.setMessageId("messageId");
-        assertEquals("messageId", obj.getMessageId());
-
-        obj.setText("text");
-        assertEquals("text", obj.getText());
-    }
-}
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyExceptionHolder.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyExceptionHolder.java
new file mode 100755
index 000000000..978ec8a59
--- /dev/null
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoPolicyExceptionHolder.java
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * so
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.so;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestSoPolicyExceptionHolder {
+
+    @Test
+    public void testConstructor() {
+        SOPolicyExceptionHolder obj = new SOPolicyExceptionHolder();
+
+        assertTrue(obj.getMessageId() == null);
+        assertTrue(obj.getText() == null);
+    }
+
+    @Test
+    public void testSetGet() {
+        SOPolicyExceptionHolder obj = new SOPolicyExceptionHolder();
+
+        obj.setMessageId("messageId");
+        assertEquals("messageId", obj.getMessageId());
+
+        obj.setText("text");
+        assertEquals("text", obj.getText());
+    }
+}
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestDetails.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestDetails.java
index 5c3c1a411..42dfe0805 100755
--- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestDetails.java
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestDetails.java
@@ -21,8 +21,14 @@
 package org.onap.policy.so;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.junit.Test;
 
 public class TestSoRequestDetails {
@@ -65,4 +71,104 @@ public class TestSoRequestDetails {
         obj.setSubscriberInfo(subscriberInfo);
         assertEquals(subscriberInfo, obj.getSubscriberInfo());
     }
+    
+	@Test
+	public void testSOMRequestDetailsMethods() {
+		SORequestDetails details = new SORequestDetails();
+		assertNotNull(details);
+		assertNotEquals(0, details.hashCode());
+		
+		SOCloudConfiguration cloudConfiguration = new SOCloudConfiguration();
+		details.setCloudConfiguration(cloudConfiguration);
+		assertEquals(cloudConfiguration, details.getCloudConfiguration());
+		assertNotEquals(0, details.hashCode());
+		
+		SOModelInfo modelInfo = new SOModelInfo();
+		details.setModelInfo(modelInfo);
+		assertEquals(modelInfo, details.getModelInfo());
+		assertNotEquals(0, details.hashCode());
+		
+		List<SORelatedInstanceListElement> relatedInstanceList = new ArrayList<>();
+		details.setRelatedInstanceList(relatedInstanceList);
+		assertEquals(relatedInstanceList, details.getRelatedInstanceList());
+		assertNotEquals(0, details.hashCode());
+		
+		SORequestInfo requestInfo = new SORequestInfo();
+		details.setRequestInfo(requestInfo);
+		assertEquals(requestInfo, details.getRequestInfo());
+		assertNotEquals(0, details.hashCode());
+		
+		SORequestParameters requestParameters = new SORequestParameters();
+		details.setRequestParameters(requestParameters);
+		assertEquals(requestParameters, details.getRequestParameters());
+		assertNotEquals(0, details.hashCode());
+		
+		SOSubscriberInfo subscriberInfo = new SOSubscriberInfo();
+		details.setSubscriberInfo(subscriberInfo);
+		assertEquals(subscriberInfo, details.getSubscriberInfo());
+		assertNotEquals(0, details.hashCode());
+		
+		assertEquals("SORequestDetails [modelInfo=org.onap.policy.so", details.toString().substring(0,  46));
+		
+		SORequestDetails copiedDetails = new SORequestDetails(details);
+
+        assertTrue(details.equals(details));
+        assertTrue(details.equals(copiedDetails));
+        assertFalse(details.equals(null));
+        assertFalse(details.equals("Hello"));
+        
+        details.setCloudConfiguration(null);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setCloudConfiguration(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setCloudConfiguration(cloudConfiguration);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setCloudConfiguration(cloudConfiguration);
+        assertTrue(details.equals(copiedDetails));
+
+        details.setModelInfo(null);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setModelInfo(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setModelInfo(modelInfo);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setModelInfo(modelInfo);
+        assertTrue(details.equals(copiedDetails));
+        
+        details.setRequestInfo(null);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setRequestInfo(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setRequestInfo(requestInfo);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setRequestInfo(requestInfo);
+        assertTrue(details.equals(copiedDetails));
+		
+        details.setRequestParameters(null);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setRequestParameters(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setRequestParameters(requestParameters);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setRequestParameters(requestParameters);
+        assertTrue(details.equals(copiedDetails));
+		
+        details.setSubscriberInfo(null);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setSubscriberInfo(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setSubscriberInfo(subscriberInfo);
+        assertFalse(details.equals(copiedDetails));
+        copiedDetails.setSubscriberInfo(subscriberInfo);
+        assertTrue(details.equals(copiedDetails));
+		
+        details.setRelatedInstanceList(null);
+        assertFalse(details.equals(copiedDetails));
+		copiedDetails.setRelatedInstanceList(null);
+        assertTrue(details.equals(copiedDetails));
+        details.setRelatedInstanceList(relatedInstanceList);
+        assertFalse(details.equals(copiedDetails));
+		copiedDetails.setRelatedInstanceList(relatedInstanceList);
+        assertTrue(details.equals(copiedDetails));
+	}
 }
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestError.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestError.java
index 31f3b6c54..1108daf3d 100755
--- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestError.java
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoRequestError.java
@@ -39,11 +39,11 @@ public class TestSoRequestError {
     public void testSetGet() {
         SORequestError obj = new SORequestError();
 
-        SOPolicyException policyException = new SOPolicyException();
+        SOPolicyExceptionHolder policyException = new SOPolicyExceptionHolder();
         obj.setPolicyException(policyException);
         assertEquals(policyException, obj.getPolicyException());
 
-        SOServiceException serviceException = new SOServiceException();
+        SOServiceExceptionHolder serviceException = new SOServiceExceptionHolder();
         obj.setServiceException(serviceException);
         assertEquals(serviceException, obj.getServiceException());
     }
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoResponseWrapper.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoResponseWrapper.java
index 93549a21d..7b4830125 100755
--- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoResponseWrapper.java
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoResponseWrapper.java
@@ -21,6 +21,11 @@
 package org.onap.policy.so;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.UUID;
 
 import org.junit.Test;
 
@@ -48,4 +53,54 @@ public class TestSoResponseWrapper {
         obj.setRequestID("id2");
         assertEquals("id2", obj.getRequestID());
     }
+    
+	@SuppressWarnings("unlikely-arg-type")
+	@Test
+	public void testSOResponseWrapperMethods() {
+		String requestID = UUID.randomUUID().toString();
+		SOResponse response = new SOResponse();
+
+		SOResponseWrapper responseWrapper = new SOResponseWrapper(response, requestID);
+		assertNotNull(responseWrapper);
+		assertNotEquals(0, responseWrapper.hashCode());
+		
+		assertEquals(response, responseWrapper.getSoResponse());
+		
+		assertNotEquals(0, responseWrapper.hashCode());
+		
+		assertEquals("SOResponseWrapper [SOResponse=org.onap.policy.", responseWrapper.toString().substring(0,  46));
+		
+		SOResponseWrapper identicalResponseWrapper = new SOResponseWrapper(response, requestID);
+
+        assertEquals(responseWrapper,  responseWrapper);
+        assertEquals(responseWrapper,  identicalResponseWrapper);
+        assertNotEquals(null, responseWrapper);
+        assertNotEquals("Hello", responseWrapper);
+        assertFalse(responseWrapper.equals(null));
+        assertFalse(responseWrapper.equals("AString"));
+        
+        assertEquals(new SOResponseWrapper(null, null), new SOResponseWrapper(null, null));
+        assertNotEquals(new SOResponseWrapper(null, null), identicalResponseWrapper);
+        
+		assertNotEquals(0, new SOResponseWrapper(null, null).hashCode());
+
+		identicalResponseWrapper.setSoResponse(new SOResponse());
+        assertNotEquals(responseWrapper,  identicalResponseWrapper);
+        identicalResponseWrapper.setSoResponse(response);
+        assertEquals(responseWrapper,  identicalResponseWrapper);
+        
+        identicalResponseWrapper.setRequestID(UUID.randomUUID().toString());
+        assertNotEquals(responseWrapper,  identicalResponseWrapper);
+        identicalResponseWrapper.setRequestID(requestID);
+        assertEquals(responseWrapper,  identicalResponseWrapper);
+        
+        responseWrapper.setRequestID(null);
+        assertNotEquals(responseWrapper,  identicalResponseWrapper);
+        identicalResponseWrapper.setRequestID(null);
+        assertEquals(responseWrapper,  identicalResponseWrapper);
+        responseWrapper.setRequestID(requestID);
+        assertNotEquals(responseWrapper,  identicalResponseWrapper);
+        identicalResponseWrapper.setRequestID(requestID);
+        assertEquals(responseWrapper,  identicalResponseWrapper);
+	}
 }
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceException.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceException.java
deleted file mode 100755
index cae8d1955..000000000
--- a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * so
- * ================================================================================
- * 
- * ================================================================================
- * 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class TestSoServiceException {
-
-    @Test
-    public void testConstructor() {
-        SOServiceException obj = new SOServiceException();
-
-        assertTrue(obj.getMessageId() == null);
-        assertTrue(obj.getText() == null);
-        assertTrue(obj.getVariables() != null);
-        assertEquals(0, obj.getVariables().size());
-    }
-
-    @Test
-    public void testSetGet() {
-        SOServiceException obj = new SOServiceException();
-
-        obj.setMessageId("messageId");
-        assertEquals("messageId", obj.getMessageId());
-
-        obj.setText("text");
-        assertEquals("text", obj.getText());
-    }
-}
diff --git a/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceExceptionHolder.java b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceExceptionHolder.java
new file mode 100755
index 000000000..877ea7146
--- /dev/null
+++ b/controlloop/common/model-impl/so/src/test/java/org/onap/policy/so/TestSoServiceExceptionHolder.java
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * so
+ * ================================================================================
+ * 
+ * ================================================================================
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestSoServiceExceptionHolder {
+
+    @Test
+    public void testConstructor() {
+        SOServiceExceptionHolder obj = new SOServiceExceptionHolder();
+
+        assertTrue(obj.getMessageId() == null);
+        assertTrue(obj.getText() == null);
+        assertTrue(obj.getVariables() != null);
+        assertEquals(0, obj.getVariables().size());
+    }
+
+    @Test
+    public void testSetGet() {
+        SOServiceExceptionHolder obj = new SOServiceExceptionHolder();
+
+        obj.setMessageId("messageId");
+        assertEquals("messageId", obj.getMessageId());
+
+        obj.setText("text");
+        assertEquals("text", obj.getText());
+    }
+}
-- 
cgit